derived/ is built from originals/, and you can watch it happen

The mapping: derived/ mirrors originals/ directory for directory, and where
originals holds a FILE, derived holds a DIRECTORY of the same name — extension
included — with the renditions inside it. Keeping the extension is what makes it
total: a.jpg and a.png are different originals and must not share a folder. The
inverse is pure string work, so the filesystem is the record and there is no
second copy of the truth.

Images get a WebP ladder at 320/640/960/1280/1920/2560 plus full.webp, and
nothing is ever upscaled — a rung wider than the original would be a soft file
that srcset then confidently prefers over the sharp one. full.webp always
exists because for a HEIC it is the only browser-readable copy of the picture
there is.

Video gets av-club's web-1080 and web-720 presets by name, plus a poster. Images
are named by width because srcset descriptors are widths; video by height
because that is av-club's vocabulary and nobody misreads 1080.mp4.

The ladder is fixed here and the SITE chooses from it. This never reads
website/src/media/slots.ts — a plugin that knows a website's layout is a plugin
for one website, and that boundary is the difference between a template and
something fofos-shaped.

Each derived folder carries a manifest naming the size and mtime it was built
from, so the sync is idempotent and resumable: a run that died halfway is
finished by running it again. That is what makes an in-memory job acceptable
rather than merely convenient. It builds into <name>.partial and renames, so an
interruption can never leave a folder that looks finished.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-29 11:13:56 +01:00
co-authored by Claude Opus 5
parent 1b171c3335
commit e87e19ee46
5 changed files with 708 additions and 2 deletions
+4 -2
View File
@@ -1,4 +1,5 @@
import { RootLocationBlock } from './RootLocationBlock';
import { MediaSyncBlock } from './MediaSyncBlock';
import { DatabaseBlock } from './DatabaseBlock';
/**
@@ -7,8 +8,8 @@ import { DatabaseBlock } from './DatabaseBlock';
* A list of blocks, and nothing else. Each one owns its own heading, its own state and its own status
* message; this file decides only which of them exist and in what order.
*
* The order is the order things are needed in: where the site is on this machine, then how to read its
* data.
* The order is the order things are needed in: where the site is on this machine, then turning what
* was uploaded into what the site serves, then how to read its data.
*
* ── What used to be here ──
*
@@ -21,6 +22,7 @@ import { DatabaseBlock } from './DatabaseBlock';
export const AdministrationPanel = () => (
<div className="flex size-full flex-col gap-4 overflow-auto p-5">
<RootLocationBlock />
<MediaSyncBlock />
<DatabaseBlock />
</div>
);