Changelog
Every release, newest first, on the history wall.
0.7
0.7
0.7.2, the Atlas flies again
13 October 2026
- The Atlas flies from entry to entry again, as in 0.7.0. The ride with the scroll in 0.7.1 followed every step of the wheel and moved too fast to read.
- Two things from 0.7.1 stay, in the flights' own pace. A short entry still gets its landing: scroll past up to two entries during a flight and the ball stops at their places in turn, each of those legs a little quicker, while a longer jump flies straight there. And a new entry mid-flight turns the ball from where it is, with its trail unbroken, where before it jumped ahead to the place it had been flying to.
- Kept from 0.7.1 as well: outlines out of view are not drawn, the kind filter comes with the page, the caption under the pinned globe on phones keeps two lines, an entry with no place holds the globe at the one before it, and a drag cut short by the window losing focus leaves no touch behind.
- To update:
npm update @dario-loi/polytope. Nothing in the markup changes.
0.7.1, steadier loading and scrolling
13 October 2026
- A complex with
autoplay="visible"waits as bare points from the first paint. Before, the server's finished drawing showed until the script loaded, then vanished and grew again, which on a slow phone looked like a flash. Without script, or with reduced motion, it is still drawn finished, and if no script takes over within five seconds the finished drawing comes back. - The complex keeps every edge and triangle it has drawn, in order of the radius where each appears, so a new radius adds or removes only the cells in between instead of redrawing the whole figure. On a CPU slowed six times, a frame of the growth went from 16 to 6 ms at 36 points and from 57 to 11 ms at 120. Dragging the slider gets the same saving.
- The slider's printed value, the edge and triangle counts, and the complex's label are written only when they change, and the label keeps the finished counts while the complex grows.
- A growing complex's slider and counts start at 0, to match the bare points, and the script sets them as it grows. With scripts off they are hidden, since they cannot move. Printing, or switching reduced motion on mid-growth, jumps to the finished complex. A probability machine that has not run yet, or is still running, shows its settled curve on paper.
- The Atlas rides the route with the scroll. Between two entries the globe and the ball move along the great circle as the reader scrolls, and back when they scroll up. Before, a timed flight started once the next entry was current and trailed behind the reading, and a short entry passed in a moment could be skipped. A stop on the way settles on the current entry, and a fast scroll catches up through every place it passed. Dragging or zooming the globe still leaves it where the reader put it, and under reduced motion it still jumps.
- The Atlas draws less. A continent's coast is kept in runs, and a run out of view is drawn as a line between its ends, which leaves every pixel on screen the same; at a stop's zoom a frame is 15 to 45% quicker. A moving globe keeps the coarse outlines until zoom 5, and a scroll that leaves the globe where it is draws nothing. With the CPU slowed four times, a scroll through a CV on a phone drops 16% of frames, against 46% before. On phones the caption under the pinned globe keeps two lines, so a longer name no longer pushes the entries down and flips the current one back.
- The Atlas draws its kind filter on the server. Before, the script added it above the entries once it loaded, and on a phone the list moved down about 64px under the reader. With scripts off the filter is hidden. Plain HTML keeps working as before: an empty, hidden filter box is filled by the script.
<Seo citation>gives its ScholarlyArticle record an@id: the canonical address with#article. A fuller record of the same paper that a site writes with that@idnow merges with it, where before a page carried two records that counted as two works.citation.idsets another one; anoindexpage has none unless given. See SEO.<Seo>writes records that share an@idas one, with the fields given inschemawinning and the ones they leave out kept. A site's fuller record of a paper now merges into the oneSeowrites, so a page no longer lists every author twice. The Person record has an@id, the site's home with#person(orperson.id); on the home pagesiteNamewrites a WebSite record,#website; and the paper record gains its PDF, preview picture, page range, language, andmainEntityOfPagefrom the props already given.- Fixes: an Atlas entry with no place, such as remote work, holds the globe at the place before it; before, the map stopped there with an error. A drag cut short by the window losing focus no longer leaves a touch behind that turns the next drag into a pinch. A drag mid-way, or reduced motion switched on, ends the ride cleanly with the place's name back. A complex whose
pointsorradiusis not a number draws the default instead of nothing. - To update:
npm update @dario-loi/polytope. Nothing in the markup changes.
- A complex with
0.7.0, list pages
13 October 2026
- New
<Card>and<CardGrid>for list pages of papers, posts, and projects: a black panel with the entry's figure, or a complex seeded from its title, then the title, a meta line, a summary, and tags. A lead card spans the row and sets its title in wood type; a grid with fewer cards than columns shares the row between them. Labels over a figure use the newflagtokens and.ply-label--flag. See Cards. <PaperHeader fold={12}>folds a long author list to the first names, yours, and the last, with a button for the rest. The fold is in the page as built, so nothing moves while it loads; without script, and on paper, the list shows whole.<PubList fold>folds author lines as text. A link withprimary: truebecomes the header's primary button.- The pager shows a title's name and keeps its subtitle for screen readers, so a paper's long title no longer outweighs the page. Its labels balance, and
prevTextandnextTextrename the directions. - A mast without an exhibit stays one column at every width, so a list page's title is no longer squeezed beside an empty column.
<Mast compact>sets a smaller title. New<MastTitle>and<WoodTitle>set mast and header titles in your own layouts, sized from a table of Ultra's widths, and the helpers behind them (woodTitle,splitTitle,emWidth) are exported. - BibTeX wraps long fields under their value instead of scrolling;
<Code wrap>does the same for any block. A code block takes focus only while it scrolls. - Fixes: under reduced motion, a theme change no longer paints the whole Atlas tomato. The chapter menu closes on Escape, a press outside, or focus moving past it. Printed code is in ink, a long code block no longer leaves a page nearly blank, and links to other sites print their address. The wordmark, publication titles, and the author toggle grow to 44px targets under a finger, and
.ply-targetdoes the same for your own links. A segmented row fits a phone, a ghost button that wraps lines up with the row's edge, and the abstract's label is set as the other section headings. <Atlas quiet>drops the place count and drag hint from the caption.<Empty level>makes its title a heading, as a 404 needs, and its mark is now a few loose points.<PubList label={false}>drops the region name where your own section has a heading.<ThemeToggle persist={false}>keeps the choice for the page only; the docs now say the toggle storesply-themein localStorage. A slider's value is set in the text face, so a page without code loads no mono font, and@dario-loi/polytope/fonts.cssis exported for loading the CSS a component at a time.- To update:
npm install @dario-loi/polytope@^0.7.0, sincenpm updatestays within 0.6. Headers in a box that shrinks to fit its content now need a width. Pager labels with a colon show only the name, and BibTeX blocks wrap; passsplit={false}orwrap={false}to keep the old look.
- New
0.6
0.6.3, long titles
12 October 2026
- Paper and post titles size to the header's own width, not the window's, so a title in a column beside an exhibit sets as it does across the page. Before, it kept its full size there, about nine characters to a line. A title runs about 22 characters to a line, and longer lines for a long title, so most keep to three lines. On phones a long title can drop toward 24px, and a title's longest word never breaks.
- A paper title with a subtitle (the part after the first colon) sets the name in wood type and the subtitle under it in the text face. The colon stays in the heading, hidden, so screen readers and copies keep the whole title. Pass
split={false}to keep the whole title in wood type. See Research for the plain HTML. - Short hyphenated terms such as Test-Time stay on one line. The venue line is balanced, so its last word is not left alone. Author, affiliation, and tag rows keep one baseline inside
.ply-prose. - To update:
npm update. A title with a colon now shows its subtitle under the name; passsplit={false}where you want one kept whole.
0.6.2, your name in bold
12 October 2026
<PaperHeader>takesme, the author name to set in bold, as<PubList>already did. The other names drop to regular weight so yours shows; every name was semibold, so a bolder weight alone would not. In plain HTML, give yourliin.ply-authorsthe classply-me. See Research.- To update:
npm update, then passmewith your name as it reads inauthors. A header without it looks as before.
0.6.1, long routes
12 October 2026
- The Atlas route fades with time. While an entry is current, the moves into and out of its place keep the full chalk, and the rest of the route fades with each move away from it, to 0.55, 0.3, then 0.15 of the chalk, so a long CV no longer covers the globe in lines. With no entry current, as past the last entry, the whole route is chalk. The weights ease in as the current entry changes.
- A flight whose route passes near a pole turns the globe smoothly with the route and lands with north up. Before, keeping north up all the way could spin the globe half a turn in a few frames. If a drag stops a flight partway, the drag turns the globe the way the pointer moves, and the globe turns back to north up once you let go.
- To update:
npm update. Nothing to change in your pages.
0.6.0, reading pages
12 October 2026
- New:
.ply-articleand<Article>, the frame for a paper, a post, or a page of notes. The text sits at the centre of the page, the on-this-page list hangs in a rail at the left edge from 80rem, and the margin after the text holds sidenotes and margin figures. No block straddles the edge between text and margin: in an article,.ply-widekeeps to the text, and a long table or line of code scrolls in its own frame. Below 80rem the list waits in an "On this page" disclosure above the text, and the current section in the rail gets the tomato point.<Article>builds the list from the headings at build time, so it needs no script. Before, a paper page kept its text against the left edge, with the margin and the list both to its right. See Space and layout. - New:
.ply-marginand<Figure margin>put a small figure, table, or code block in the margin, beside the paragraph after it. On narrow screens it stays in the text. - New:
<PostHeader>, for posts and notes: the title set like a paper's, a lede, the date, the reading time, and tags. The new blog post pattern shows a whole post. - The margin widens with the page, from 14rem to 21rem, so sidenotes end at the page's edge. A section heading starts below any sidenote still beside the text, so a note no longer sits beside the next section. On a docs page, a wide block (
.ply-wide) also starts below the note, so it no longer runs over one, and<Figure wide>runs past the text like any wide block; before, it only dropped its maximum width. - Docs pages put the text at the centre of the page once the sidebar has room beside it, and the on-this-page list hangs under the current page in the sidebar. Sidenotes open into the margin whenever the main column has room for it, without waiting for 90rem.
- From 100rem, docs and article text is 18px in a 38rem column: the same 68 characters to a line, at a size that suits a wide screen. New tokens:
--ply-size-body-wide,--ply-layout-measure-wide, and--ply-layout-margin. <SideNav>takes acurrentslot, shown under the current page's link. On docs pages the phone menu lists the page's sections there too.- Paper and post titles balance their lines and are capped in em, so a title breaks the same way at every wide width and does not reflow when Ultra arrives. Table captions keep to the measure and stay in view while a wide table scrolls. A screen reader reads a sidenote's number once. The auto on-this-page list skips the headings of a paper or post header shown inside a page, and stays hidden until it has entries.
- To update:
npm install @dario-loi/polytope@^0.6.0. A docs grid that still has.ply-docs__tockeeps its three columns from 80rem; to move the list into the sidebar, put it in thecurrentslot of<SideNav>. A paper page built by hand can switch to<Article>, as the paper pattern's source does.
- New:
0.5
0.5.1, faster pages
12 October 2026
- Text keeps its size while the fonts load. New fallback faces scale Arial or Liberation Sans to Libre Franklin and Menlo, Liberation Mono, or Courier New to JetBrains Mono, and Ultra falls back to Liberation Serif Bold where Georgia is missing. Before, on a machine without Georgia, titles jumped when Ultra arrived. The font tokens name the new faces, which come with
polytope.css. EquationandMbring KaTeX's stylesheet, so only pages with math load it. An import ofkatex/dist/katex.min.cssin your layout is no longer needed, and keeping it does no harm.- Code blocks below the screen skip their layout until the reader nears them.
- The Atlas decodes its map and draws its first frame in short slices, so the page stays responsive while it does, and the server's globe stays up until the first frame is whole. The close outlines load once the reader scrolls, points, or presses a key. Its geometry runs about three times faster, with the same result.
- The top bar keeps the search field's word wherever the tabs fit set closer, and drops it only when they need the room. Under reduced motion it could show the menu where the tabs fit; it now measures after its own changes settle, and again when fonts arrive.
- A Copy button on a block titled with a file name reads "Copy train.py from Code panels".
- To update:
npm update. Nothing to change in your pages.
- Text keeps its size while the fonts load. New fallback faces scale Arial or Liberation Sans to Libre Franklin and Menlo, Liberation Mono, or Courier New to JetBrains Mono, and Ultra falls back to Liberation Serif Bold where Georgia is missing. Before, on a machine without Georgia, titles jumped when Ultra arrived. The font tokens name the new faces, which come with
0.5.0, search engines
12 October 2026
- New:
<Seo>writes the head tags that search engines and link previews read: the title, the description, a canonical link, Open Graph and Twitter cards, andnoindex. Withpersonit adds a Person record for a homepage or CV; withcitation, thecitation_tags Google Scholar indexes papers by and a ScholarlyArticle record. See Search engines. - The top bar shows the chapter tabs wherever they fit. Where they do not, they first set closer and the search field drops its word, then they fold into the menu. Before, between 72rem and the width the tabs needed, the bar ran past the edge of the page; on these docs that was from 1152px to about 1420px, most laptops. The new
js/topbar.jsmeasures the fit;TopBarandjs/all.jsload it. - Without the script, the tabs still show from 72rem, and tabs that do not fit scroll in their row instead of widening the page.
- These docs now have a sitemap, link previews, and structured data, all from
<Seo>and@astrojs/sitemap. - To update:
npm install @dario-loi/polytope@^0.5.0. If your own CSS shows or hides.ply-topbar__links, check it against thedata-ply-tabsattribute the script sets on the bar.
- New:
0.4
0.4.1, fixes from an audit of 0.4.0
12 October 2026
- On phones the Atlas names the entry the reader can see. Before, the pinned globe covered the entry it showed. The globe is shorter on phones, and its caption names the current entry.
- Wide tables, display equations, and
.ply-scroll-cueboxes can be scrolled from the keyboard. While their content overflows, the newjs/scroll.jsmakes each one a named region that takes focus, and when it fits again it is no longer a tab stop.js/all.jsandEquationload it. - On touch screens, Atlas pins are 44px targets. The drawn point keeps its size.
- Atlas frames cost about a quarter less to draw.
js/all.jsloads the Atlas element only on pages that have one. - The Atlas caption counts moves between places, so a return to a city counts again. When the reader reaches the end of the entries, the route lights up in the order it was travelled.
- Search lists first the pages whose title or a section heading names every word of the query, and shows the chapter links again when nothing matches. The search button answers Space.
- Each Copy button is named for the section its code sits in, as in "Copy the HTML for Text fields".
- The table of contents skips headings inside an Atlas, and sidenote numbers stay out of the search index.
- To update:
npm update. Nothing to change in your pages.
0.4.0, the Atlas
12 October 2026
- New:
<Atlas>and<AtlasStop>, a globe of the places in a CV beside the entries that happened there. As the reader scrolls, the globe turns to each entry's place and a tomato ball travels the route to it. Pins pick entries and a filter shows one kind of entry; drag, pinch, or Ctrl and scroll move the globe. See Atlas and the new CV page pattern. - The kit draws the map itself, from Natural Earth country outlines with borders as the United States recognizes them, so there are no map tiles, keys, or outside services. About 60KB, compressed, loads when an Atlas connects, and 76KB more for close views when it nears the screen.
- Without JavaScript the server draws the finished globe with its places and route. Under reduced motion the globe jumps instead of flying, and on paper it prints once above the entries.
js/all.jsnow registers<ply-atlas>. The map code and data load only on pages that have one.- To update:
npm install @dario-loi/polytope@^0.4.0. Nothing that already existed changed.
- New:
0.3
0.3.0, site search and a new emblem
12 October 2026
- Your site can have search. Put
<Search>in the top bar, runnpx pagefind --site distafter your build, and mark each page's main content withdata-pagefind-body. Readers open it with / or Ctrl+K; results come from your own pages, with nothing hosted elsewhere. See Navigation. - The Vietoris-Rips complex is the emblem: it opens these docs and draws the favicon.
<Complex autoplay="visible">grows it from bare points the first time it is seen; without the attribute nothing changes. - Inside a panel, controls now read: checkboxes, switches, ghost buttons, inline code, and tables draw in chalk on black. If you set something inside a
.ply-panelto--ply-color-textand meant black, use--ply-ink-950. - Long content no longer widens a page. A long button label wraps to two balanced lines, a long tag wraps, a segmented row longer than its space scrolls in its frame, and names in a table's first column stay whole while the table scrolls.
hiddennow hides any element, including one whose class sets a display, such as a button.- Pages written right to left mirror the switch, the select arrow, the sidebar point, the menu, the skip link, and sidenotes. Code blocks stay left to right.
- Code blocks show the soft scroll cue, and each Copy button is named for the code it copies.
.ply-wideon a block inside the reading column now runs to the edge of a main column that names itselfply-main.- A complex with many points stays responsive: past 2000 triangles its fill is drawn as one shape.
- To update:
npm install @dario-loi/polytope@^0.3.0. Check panels that hold your own content, and buttons you gave a fixed height.
- Your site can have search. Put
0.2
0.2.1, three fixes from sites that use it
11 October 2026
- A
.ply-visually-hiddenelement inside a wide table no longer widens the page. Table wraps, display equations,.ply-scroll-cue, and code blocks are now the containing block for what they scroll. - Printed pages keep the fill of primary buttons, pressed segments, the current tab, checked boxes, switches, labels, tags, and status marks. Before, their labels printed white on white and checked boxes printed empty.
- The
Emptytitle is display size again. The rule for its body text no longer matches the title.
- A
0.2.0, fixes from an accessibility audit
11 October 2026
- The Astro components load their scripts from
dist/js. In 0.1.4, six of them (ThemeToggle, Machine, Complex, Code, Slider, Toc) imported files the npm package leaves out, so a site that installed from npm failed to build.npm run check:packagenow fails CI when a packaged file points at something the package does not ship. - A hovered button fills with
--ply-color-accent-textand labels with the new--ply-color-on-accent, which keeps 4.5:1 in both themes. - Inside panels and code blocks, muted text and the focus ring take their panel values. On mustard notes the ring is black. Mark other surfaces with
data-surface="panel"ordata-surface="note". - Windows contrast themes keep checks, radio balls, switches, the current tab, and status marks visible. Pages print in the light theme with ink-on-white panels.
- On touch screens, small controls grow to 44px. The top bar and the pager fit at 320px.
- Citation cards no longer widen the page on phones, stay open under the pointer, and close with Escape (
js/cite.js). - A machine that starts by itself finishes within five seconds. Changing its attributes no longer fires
ply-machine-done, and its label reads out the counts. - Sliders set
aria-valuetext, the loading indicator announces its text, and the theme toggle is a "Dark theme" toggle button. PaperHeaderandAppShelltake alevelprop for their heading. Sidenotes stay inline when the main column has no room for the margin.- New token
--ply-size-ui(15px) for tabs, tables, notes, and sidebar links. Chart text uses--ply-size-xs. - Titles no longer jump when Ultra arrives. A new
Ultra Fallbackface scales Georgia Bold to Ultra's metrics, and the display stack lists it right after Ultra. - To update:
Statusis a live region only withlive, so add it where a script changes a status outside an app shell. Thekbdandblockquoteelement defaults moved to the base layer, and any class now wins over them.
- The Astro components load their scripts from
0.1
0.1.4, on npm and PyPI
11 October 2026
- Polytope is published as
@dario-loi/polytopeon npm andpolytope-themeon PyPI. Installs need no.npmrcline, and upgrades work withnpm update. - The design command runs as
npx @dario-loi/polytope, which can only ever fetch this package. - A release workflow publishes both packages from GitHub releases through trusted publishing, with npm provenance.
- Polytope is published as
0.1.3, no install scripts
11 October 2026
- The built
dist/is now committed and thepreparescript is gone, so installing from GitHub runs no install scripts. npm 12 no longer prints the "install scripts blocked" warning, and nothing needs approving. - CI rebuilds and fails if the committed
dist/differs from a fresh build.
- The built
0.1.2, safer install commands
11 October 2026
- Install commands quote the git address, since zsh reads an unquoted
#as a glob pattern. - The docs and the command's own messages no longer suggest
npx polytope-design, which falls back to the public npm registry when the package is missing. Use./node_modules/.bin/polytope-designor annpm runscript. - A no-npm path for static sites: fetch
DESIGN.mdanddesign.jsonpinned to a release tag.
- Install commands quote the git address, since zsh reads an unquoted
0.1.1, the design record ships
11 October 2026
- The package now includes
DESIGN.mdanddesign.json, the files Impeccable reads to know a project's visual system. - New command
polytope-designcopies them into a site;--checkreports a stale copy. - CI runs on Node 24 and the current GitHub action versions.
- The package now includes
0.1.0, first release
11 October 2026
- Tokens in the W3C format, compiled to CSS, JavaScript and TypeScript, JSON, Sass, Tailwind v4, LaTeX, a code theme, and Python.
- CSS core in cascade layers, with light and dark themes and self-hosted fonts.
- Components for buttons, navigation, notes, forms, tables, code, research pages, long-form writing, demos, and charts.
- Two working models: the probability machine and the complex.
- 32 Astro components.
- Python theme for matplotlib, plotly, Gradio, and Streamlit.
- This site, with three pattern pages.