Skip to content

Releases: Fade78/lightwebpres

v0.43.1

v0.43.1 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 20 Aug 09:06
216378c

A contrast level is a note about a theme, not a bar it has to clear

The documents had grown a doctrine out of a measurement. A theme's contrast level was written as a standard: §9.5.2 stated an admission barème per role — AAA body text, AA secondary text and accents, 3:1 rules — §9.5 said "ce qui est exigé est double", and the README promised "a documented readability target, checked by measurement". None of that was ever true of the program. Nothing in this executable has ever refused, rewritten, reordered or hidden a theme for what it measures, and the same sections said so two paragraphs later.

Written at that weight, the axis became the frame every reader picked up. It produced two backlog entries about which themes fail a bar nobody enforces, three paragraphs of the spec accounting for which ones fail it, and — the reason this is being corrected now — reviewers who turn it back on the tools themselves and report, as a defect, that a piece of software "fails the standard it enforces on its output". There is no such standard. Deciding what a good theme is was never this software's trade.

So the axis is demoted to what it is. §9.5.2 is no longer "critères d'admission" but how a theme is drawn: there is no bar, the project's own palettes are drawn and then measured, and the measurement is published so an author knows what they are choosing. §9.5's "ce qui est exigé" is gone; a level is not a goal. The README's "readability target" and "higher accessibility standard" are gone; the measurement is a design note about that theme. --help says the same in one sentence.

What survives untouched, because it is not about grading: colour is never the only carrier of an information — a comparison table's verdicts each carry a shape marker, and that is a property of the FORMAT no palette can undo. And audit's two colour warnings, which do not speak of levels at all: a navigation control the reader can no longer make out, and text almost exactly the colour of what it sits on. A broken control and words out of reach — things that do not work, never things that could be prettier. Their thresholds sit far below AA on purpose, and they block nothing.

v0.43.0

v0.43.0 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 20 Aug 08:11
49567c1

A card is called what its author declared, and nothing else.

One rule replaces five. A card's id is the slug: line its author wrote. Nothing derives it, nothing falls back to its position, and no ordinary edit moves it — not reordering the deck, not inserting a card, not tags: excluded, and not rewriting the heading. That last one is what the derived identity could not hold: it was stable exactly as long as the title was, and a title is what an author retouches. A link you have already given out, or printed as a QR code, now survives everything except you changing the slug on purpose.

slug: is required. A card without one stops the build with an error that names the remedy, because someone meeting it for the first time has a series that will not build and no way to guess a command exists to fix it.

Two new commands. lightwebpres series slug lists every card of the series and the name it is published under, in text or JSON — status answers by article, which is the unit series.json describes, and a link points at a card. lightwebpres series slug set writes a slug into every card that has none, and only those. It is the one command in this tool that edits your articles, which is why it is a verb you type rather than a flag on the build: a build that rewrote its own inputs would surprise a read-only CI, a version-controlled tree that comes back dirty, and an encrypted series in the browser editor. --dry-run says what it would write and writes nothing.

What it writes is random, not derived from your title. Once the value is in the file it IS the identity, and deriving it would make it look as though it still followed the title it came from. Rename it to something readable before you publish: slug: barrage-de-vajont is worth more than slug: 3f7c1a9e, and the error message says so too.

Two cards on one slug is now an error rather than a silent -2. Two values you declared that happen to match are a typing mistake, and a suffix appended in silence would publish an anchor nobody wrote while the card you meant to reach keeps the other.

Gone with the derivation: the Latin-mark folding, the truncated hash, the sN and sN-series aliases, the collision suffix, and the audit finding about identities that are not durable. The only visible change to a built page is the disappearance of those empty alias spans.

slug_prefix: survives, and is now the only thing left that can change what you wrote: it puts a namespace in front of every card id on the page, which is what a series whose pages reuse card names needs.

Also in this release: one rule for the ampersand across both grammars — a & outside a tag is escaped, what is inside a tag is left verbatim — so a source: line carrying ?q=marks&copy=1 no longer reaches the reader as ?q=marks©=1. A CommonMark autolink is refused by name instead of being blamed on a tag nobody wrote. --build-stamp is legible on every theme. And the shell completion offers each command only the options that command accepts, on every typed path.

v0.42.3

v0.42.3 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 23:05
d8864dd

One rule for the ampersand, in both grammars

A structural field escaped nothing and the body escaped everything, and each was wrong at one end. source: https://x.test/rechercher?q=marks&copy=1&reg=2 reached the reader as …?q=marks©=1®=2 — &copy and &reg without a semicolon are in HTML5's legacy character-reference list, so a query string carrying either was silently destroyed. At the other end, the body escaped every & including inside your own raw HTML, so a hand-written <a href="?a=1&amp;b=2"> came out &amp;amp;: a dead link.

One sentence now covers both: escape an & outside a tag, leave what is inside one verbatim. It splits on the typography engine's own pattern, literally the same one — two mechanisms disagreeing about where a tag begins would protect different halves of the same document.

What stops being corrected, and is written down rather than discovered: a bare & inside a raw tag. That is your HTML, and repairing it would be the interference this tool declares it does not do.

An autolink is refused by name

<https://x.test> and <contact@x.test> still fail the build — <...> belongs to raw inline HTML here, and the two syntaxes want the same two characters. What changes is the diagnosis: it used to answer "unbalanced raw HTML (an unclosed or mismatched tag, e.g. a <div> in a fact-box)", which sends someone who wrote ordinary Markdown hunting for a tag they never typed.

It now names the autolink, quotes what you wrote, and gives the remedy for the form in front of it: [url](url) for an http(s) address, raw <a href="…"> for anything else — because a Markdown link takes http(s) and nothing else, so advising [a@b](mailto:a@b) would have been advice that does not work.

Migration

Rebuild. Nothing in the format changes, and no page of this repository moves.

v0.42.2

v0.42.2 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 22:09
9d69583

Selection is the platform's again on a phone

The deck had been reaching into the browser's own gesture handling, and every attempt to steer it cost the reader something they already had. user-select was switched off while the navigation chrome was idle, so a phone could not select a word without waking the chrome first; the wake gesture then lifted that gate mid-gesture and the browser's pending word-selection completed on top of it; and contextmenu was cancelled outright, which on a touch screen is the long press — holding a word threw the reader back a card and took the copy callout with it.

None of that is the deck's business. A long press is the platform's, and so is a selection. The gate, its lift, the timer and the "a live selection holds the chrome up" rule are gone, and contextmenu is handled only where there is a fine pointer, which is the right-click it was written for. The double tap still switches the navigation chrome on and off, and it no longer competes with anything.

Completion offers each command the options it accepts, and no others

build --<Tab> put --polarity, --hue, --family, --shell and --format in front of you, and build --polarity dark then answered "Unknown option: --polarity (not an option of build)". The script emitted one list — the union of every command's options — for every command, so it was the program dictating what the program would reject.

It now reads the same table the parser refuses against, and emits one entry per command, keyed by what you type rather than by the internal name: build and series build are one command and two paths. series theme and series theme set are two commands and get two entries — keyed on the reading one, the writing one was offered --format, which it refuses, and never --theme, which is the whole reason to type it. Before a command there are no command options at all (lightwebpres --polarity dark theme list answers "Unknown command"), so that position offers the globals only, and a bare series/theme/template offers --help, which is all a node takes.

The build stamp can be read

--build-stamp painted a literal #6B6B7D at opacity: 0.75 — a grey chosen against no particular ground. Measured against all 57 built-in themes, that pair cleared 4.5:1 on none of them and 3:1 on five, bottoming out at 1.27:1 on pop-red.

No fixed colour can work, and no fixed opacity either: opacity always pulls ink towards its ground, so a palette sitting on the 4.5:1 floor is put under it by any fade at all. The marker inherits its colour now, with no opacity, which gives it exactly the contrast the theme already guarantees for its body text. Discretion is the 11px and the corner, not a colour nobody can read.

It also moved into the first card. Emitted beside the cards it inherited the body's ink, and on a light theme the cover paints its ground with the page's ink — so on nord it was writing #2E3440 onto #2E3440, at 1.00:1. Measured after the move: nord 1.92:1 → 10.84:1, solarized 2.18:1 → 13.92:1, midnight 2.62:1 → 17.61:1. It sits at the top-left of the first card and scrolls away with it, as the option has always specified — not pinned to the window, and not repeated on every card.

The rendered-contrast sweep builds its probe with the flag now, and a second instrument runs beside it: an overlay takes its ground from whichever sibling the painter drew there, not from its ancestors, so a DOM walk had called the marker legible on the very page where it was painting its own colour.

Migration

Rebuild. Nothing about the format, the identities or the pages changes.

If the build warns that templates/nav.js differs from the built-in version, the touch fixes above are not reaching your readers — that copy is what the build uses. lightwebpres template update . goes back to the built-in one and keeps yours as nav.js.bak; settings.conf and custom.css are never touched.

v0.42.1

v0.42.1 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 20:13

The tool now says the version it was released as

v0.42.0 was tagged on a tree whose VERSION still read 0.41.2, so the
published executable announces the previous release: --version says
0.41.2, and the browser GUI prints "Loaded lightwebpres v0.41.2" for a
0.42.0 vendor. Nothing else differs — a series built with v0.42.0 and
rebuilt with this one produces byte-identical pages.

A guard now compares the tool against the release rather than against
itself: if HEAD is the newest tag, VERSION must equal it; if HEAD is
ahead, VERSION must be strictly greater. It cannot fire before a tag
exists, and fires on the first run after it.

A link to the series-navigation card lands again

The alias that keeps pre-0.42 links working was the card's rank, and for
every card but one that was right. A series-nav's id was sN-series —
the name written into the address bar when a reader arrived there, and
the name its own pagination dot linked to. v0.42.0 emitted only sN for
it, so #s3-series pointed at nothing in a rebuilt series.

Both names are emitted for that type now, and only for that type. Found
by rehearsing the upgrade — building a demo with v0.41.1, rebuilding it
with this version, and looking for a landing place for every id the first
build had.

Migration

From v0.42.0: rebuild, and the series-navigation anchor works again.
Nothing else changes.

From v0.41.x: as for v0.42.0 — nothing to do, old links keep working
through the alias.

v0.42.0

v0.42.0 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 19:49

A link to a card now survives editing the article

A card's identity used to be its rank — s1, s2. Any insertion, any
reorder, any tags: excluded therefore repointed every link after it, in
silence. Measured on a four-card page under a tag filter: s1 s2 s3 s4
becomes s1 s2 s3, and a reader following a link to #s4 lands nowhere.
On a printed QR code, that is irreversible.

It is now derived from what the author wrote: a slug: if you give one,
otherwise a hash of the card's heading, of a long-form card's article:
file, or the fixed name series-nav. The rank remains the last resort
rather than the default. Reorder, insert, exclude — the links you have
already given out still land where they did.

The normalisation that precedes the hash folds what does not change the
meaning — case, runs of spaces, full-width forms, ligatures, the
non-breaking space the typography engine inserts — and folds combining
marks only on Latin bases. "Strip the accents" is a Latin speaker's
instruction: it turns हिन्दी into हिनदी, which is not a word, and does the
same to vocalised Arabic and Hebrew. Vietnamese stays exposed — má and
ma land on one identity — and that is the accepted cost the collision
report exists to surface.

slug_prefix: (meta block, or series_meta) puts a namespace in front of
every identity on the page, declared and derived alike. Two cards landing
on one identity are separated deterministically and the build says so.
audit adds the one finding a build cannot make: a card with no heading,
no file and no slug falls back to its rank, and that is the link that will
break.

Nothing you have already shared breaks. Every card also carries an
empty anchor holding its old sN name. An old link lands — including on a
card the reader's own tag filter is hiding, which a native fragment jump
cannot reach at all — and the address bar is then corrected to the durable
name.

The navigation buttons can finally be put away on a phone

They were exempt by design, and the reason recorded in the code was that
there is no cursor to wake them again. True of the mechanism, and it left
the one device where the buttons sit on the reader's own text as the one
device that could not put them away.

The same 3-second delay now applies everywhere; only the way back differs.
A double tap is the switch, both ways — it brings them back, and it puts
them away at once when you have seen enough. It is detected on the touch
events themselves rather than on synthesised clicks: a mobile engine can
hold a synthesised click back by around 300ms, so two taps 60ms apart
reach a click handler too far apart to read as one gesture. A faded button
also stops answering the finger, so touching the corner of your own text
is safe. Fullscreen stays the ⛶ button in that bar.

The address bar follows the reader who scrolls

The fragment was written only by a deliberate jump, so a reader who
scrolled to a card kept whatever id their last jump had left behind —
press F5 and the page obeyed it, teleporting them to a card they had left
minutes before. The scroll observer now writes it too, always with
replaceState: the fragment is a position, not a visit, and one history
entry per card scrolled past would turn Back — the only way out of a deck
— into a slow rewind of the article just read. A freshly opened page still
carries no fragment until the reader moves.

Migration

Nothing to do. Old links keep working through the alias. An explicit
slug: is only worth writing when you want a readable address or want to
pin one by hand. After this build, audit may report cards with no
heading — a finding, not a block.

v0.41.2

v0.41.2 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 13:56
079e47e

The documents stop teaching commands the tool refuses

A pass over every document, the browser tool and the two packaged skills, against what the last six releases added and took away.

The theme gallery's footer told every reader that a theme fix reaches install --theme on the next regeneration. install is one of the eight spellings v0.41.0 retired — following that sentence gets a fatal error. theme gallery is the one command whose output you publish, so a retired spelling in it travels furthest. Regenerate your gallery to pick this up.

An unknown theme property answered with "theme-info lists every one of them" — a refused command, and wrong besides: theme show never listed properties. It names templates/settings.conf now, which does list all 431 of them, commented out at your theme's values.

--help's SERIES DIRECTORY block still said init writes templates/nav.js and the two language packs, five releases after it stopped. It is split by who writes each entry now — init, build, or nobody — and a test scaffolds a series and compares the listing against the disk, so it cannot drift again.

Smaller: two retired spellings in the specification, and one in the article-format skill.

Nothing changes in what a build produces.

v0.41.1

v0.41.1 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 13:33
38c8fce

Every page answers the screen the same way

A series is one document in two shapes — the index that lists it and the articles that are it — and you move between them by clicking. The two adapted to the screen differently, at both ends of the scale, and neither page looked wrong on its own.

The index carried its layout inline, in a style attribute on <body>: a place the theme engine cannot reach and no media query can override.

Wide screens. A fixed cap of 1200px sat beside a padding in vw, so the index got narrower as the screen got wider while the article got wider. Measured, index against article: 970 against 1210 at 1440, 893 against 1613 at 1920, 790 against 2150 at 2560.

Phones. The breakpoint turns .slide down to 40px/24px, and an inline style outranks it, so a 390-wide phone gave the index 31px of side padding against the article's 24.

The body now carries a class, and its rule lives in the composed sheet beside the .slide rules it has to agree with. Both resolve page.content-max, both turn at the same breakpoint. Measured after: identical column and identical padding at 390, 600, 900, 1440, 1920, 2560 and 3840 — and setting page.content-max in settings.conf now moves the index too, which it never did.

Rebuild a series to get it. Nothing to change in your files.

v0.41.0

v0.41.0 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 13:07
1417588

The old command spellings are gone

Eight names from before the CLI was reorganised are no longer commands:

Retired What to type
install init
check verify
refresh-templates template update
themes theme list
theme-info theme show <slug> for the catalogue, series theme [dir] for a series
set-theme series theme set
themes-gallery theme gallery
series-info status

They were deprecated aliases: each printed a [WARNING] and then did the work. That teaches the old spelling as readily as the new one, and the shell completion is where it showed — install was offered beside init, check beside verify, with nothing in the list to say which of the pair was the one to learn. A command that works after complaining is a command people keep typing.

They are refused, not unknown. Typing one is an error that names the form to use. An unknown token prints the whole help and leaves you to find the word; this hands it over. Nothing runs — install used to scaffold a whole series before its warning was read.

They are also gone from the completion, from --help, from the README and from the specification.

theme show <directory> goes with them

It was the last surviving shape of theme-info, the one verb that read both the catalogue and a series. Those are not the same question, and the refusal names series theme <directory>.

theme show with no argument, standing inside a series, still reads that series — that is not the inherited form, it is the habit build, verify, audit, status and clean all keep.

If you have scripts

Run them once. Any line using a retired spelling stops with a message naming its replacement, so the change is a word per line and the tool tells you which word. A .gitlab-ci.yml written by init has never used these names.

v0.40.3

v0.40.3 Pre-release
Pre-release

Choose a tag to compare

@Fade78 Fade78 released this 19 Aug 10:59
1f78309

The scroll bar is navigation

It was the last thing still answering to the pointer on its own. With the buttons and the cursor correctly hidden, moving the mouse painted an overlay bar down the edge of the wall — which is what a scroll bar is for, and exactly what should not appear behind a speaker who has stopped touching the mouse. It says where you are and it invites a drag: navigation on both counts.

It now carries the same idle state as the buttons, the dots and the counter, and comes back on the same condition — 250 ms of continuous movement.

It fades rather than being removed: only its colour changes, so a scroll bar that takes layout space keeps its gutter and the page never reflows when the chrome hides or returns. A browser that does not support the property keeps its bar rather than moving the text under it.

Nothing else changes.