artboards-plan.md
c122 — Plan: the contents of the Illustrator files
Status: steps 1–2 built 2026-10-23 (extraction + canvas map); steps 3–7 not started. Prompt: artboards-prompt.md.
Mode: archaeology. The iterations already exist, laid out on the canvas; this surfaces them.
Phase 2 gave each .ai file one preview, of its first artboard. Most files hold many artboards, and Mark lays quick iterations out horizontally. This plan turns every artboard into an image and keeps its position on the canvas. Mark then tags artboards and assembles sequences by hand, in post. Strips are stitched from those sequences, and the tagged sequences feed page evolution.
Revised 2026-10-23 on Mark's note: "it will be difficult to derive that yourself, I think we would want to stitch these sort of things together manually in post. Tagging?" Automatic row detection and name-based subject mapping are out. Extraction stays automatic; meaning comes from tags.
What the probe found
The probe covered 15 drive .ai files: 3 history boards plus 12 random ones from every generation, 173 artboards in all.
- Each artboard is already a PDF page. Files saved with "Create PDF compatible file" carry one PDF page per artboard. All 173 artboards matched their pages, in order and in size. Pages per file: 1–46, typically 7–18. Extrapolated, that's roughly 2,500 artboards in the 255
.aifiles (2.15 GB). - Names and canvas positions can be read without Illustrator. The file's Illustrator private data (
AIPrivateDatastreams, zstd-compressed on modern files, zlib on older ones) holds one record per artboard:Name,PositionPoint1/PositionPoint2(top-left and bottom-right on the canvas),ArtboardUUIDandIsArtboardDefaultName. A short parser (mutool+zstd) reads them. Prototype: the session scratchpad'sartboards.py. - Page order isn't canvas order.
QPT.index-v20.airuns 2, 1, 3, 4… left to right. Sequences have to come from positions. - Rows are easy to find. Artboards in a row share a top edge:
QPT.index-v20.aiis one row of 7,QPT.brochure-site-1.0.aione row of 5, andQPT.dash-1.1.ai12 artboards in 6 rows. The LinkedIn headers file is a vertical stack (10 rows of one), so columns need handling too. - Names are mostly defaults ("Artboard 18 copy 16"). The exception is the history boards: all 42 custom names were there, and each names the source file the artboard was copied from (
QPT.sketch-scratchpad.ai,QPT.glass-io-integration.ai). That's a provenance link from the boards back to the originals. - Rendering is fast:
pdftoppmdrew all 7 artboards ofQPT.index-v20.aiin 0.9 s. A stitched strip of that row (artboards-probe-index-v20.webp, canvas order) reads as the story: the header stays fixed while the second section is redrawn six times.
What we'd build
A. Extract: scripts/drive-artboards.mjs (npm run drive-artboards)
Same contract as Phase 2: read-only, and an online-only file is copied to a temp folder (which makes Drive download it) and deleted after. It's cached by size and date, takes --only/--list/--retry, and runs every tool under a timeout. Per .ai file:
pdfinfogives the page count, and the private-data parser gives the artboard records. If the counts disagree, record the mismatch and fall back to page order.pdftoppmrenders each page. Long edge capped (see open question 1) so the 9,000 px brochure pages and the 46-artboard history board stay sane.- Write
public/library/artboards/<file key>/<n>.webpplus a small thumb. - Write
server/data/drive-artboards.json. Per file:{ artboards: [{ n, uuid, name, defaultName, x, y, w, h, image, thumb }] }. These are facts only; no sequences are guessed.
Files without PDF content have no pages to render. These are likely the 9 .ai files QuickLook drew blank in Phase 2. For those, a second pass drives Illustrator itself through the existing ExtendScript-over-osascript plumbing in scripts/illustrator-export.mjs: open the file, exportForScreens each artboard, close. It runs only on the failures, on Mark's machine, with Illustrator open.
B. Tag and sequence by hand
The judgement is Mark's: which artboards are iterations of what, in what order, and what they're about. The tools make that fast, and the result is plain data in git.
Tags. Free-form, plus a few typed prefixes that other parts of the site understand:
subject:<id>uses the evolution subjects inapp/data/subjects.ts, e.g.subject:page/dashboard. New subjects can be added there.cycle:c114andphase:pre-seedset the ties Phase 3 needs. A tag beats the date-inferred phase.pickmarks the artboard that best represents a file or a sequence.- Anything else is a plain word:
pitch,nav,dark,abandoned.
Tags go on an artboard, or on a file (where they apply to all its artboards unless one overrides).
Sequences. A named, ordered list of artboards: { id, title, note, tags, items: [{ file, n }] }. A sequence can span files, e.g. QPT.index-v12 → v13 → v19 → v20, because iterations often moved to a new file. The note is a sentence or two on what changed and why, which is where the story gets written.
Stitching happens from a sequence, not from the canvas:
- On the page, a sequence renders live as a strip (images in a row at a common height), so nothing needs re-stitching while it's being edited.
npm run drive-stripswrites a stitched WebP/PNG per sequence (public/library/sequences/<id>.webp) for evolution, decks and Illustrator. Gap, height and background are options.
Where it's stored. app/data/drive-tags.json (file and artboard tags) and app/data/drive-sequences.json (sequences), committed like the rest of the design data. On :3000 the library gets an edit mode that writes these files through a dev-only API route (/api/library/tags, refused outside dev). The deployed site stays read-only and shows the committed result. Editing the JSON by hand also works, and so does asking Claude ("tag artboards 3–7 of QPT.index-v20 as subject:page/front-site").
C. /library: show what's inside a file, and curate it
For an .ai file the detail panel adds:
- A canvas map: the artboards drawn at their real relative positions and sizes, each filled with its thumb. The file's layout at a glance, the way Mark sees it in Illustrator. It's also the fastest way to pick: click, shift-click, or drag a box around a row.
- In edit mode (dev only):
- Tag the selection.
- Make a sequence from it, in canvas left-to-right order, then reorder by drag.
- Add the selection to an existing sequence.
- Sequences this file appears in, each as a strip. Clicking one opens it in the lightbox (
UxLightbox, c96), stepping artboard by artboard. - An artboard count on the file and in the generation cards.
A new Sequences view lists every sequence (title, strip, note, tags, files it spans) and filters by tag.
Links: /library?f=<path>&a=<n> points at one artboard, /library?seq=<id> at a sequence.
D. Page evolution: the drive as early moments
buildEvolution (c96) groups captures by subject into moments. It already supports:
origin: c97's pre-cycle provenance, e.g. "Gen-1 prototype", shown in place of a cycle;asOf: the date the state is from;- fans: several versions in one moment.
A hand-made sequence maps onto that directly:
| Evolution | From the drive |
|---|---|
| subject | the sequence's subject: tag |
| moment | one sequence (or one per source file, when a sequence spans files with different dates) |
| fan | the sequence's artboards, in Mark's order |
origin | { id: 'drive-1.0', label: 'Design 1.0 · QPT.index-v20.ai' } |
asOf | the source file's catalog date (name date where there is one) |
| caption | the sequence note |
| link | back to /library?seq=…, the artboard and the Drive original |
The evolution builder gains a second source next to the capture manifest: app/data/drive-sequences.json. Only tagged sequences appear; nothing is mapped by guessing. A single artboard tagged subject: + pick can stand alone as a moment.
Then, once tagged, the dashboard subject can run from 2022's QPT.dash-1.1.ai through lab.dash-3.18 (Mar 2026) into the c114/c121 lab captures, on one timeline.
E. Later, same idea for other multi-page files (not in this plan)
- PDFs (60): pages render with
pdftoppmthe same way. - InDesign (44): XMP only gives the first page. A full deck needs InDesign scripting or the matching exported PDF, which often sits beside it in the same folder.
- Sketch (9):
.sketchfiles hold pages and artboards as JSON, plus per-page previews.
Steps
- Extractor + manifest on a sample of 20 files (including the history boards and the biggest), then the whole
.aiset in the background. Report: artboards, mismatches, files without PDF content. /librarycanvas map + artboard lightbox +?a=links. Verify headless.- Tags and sequences: the JSON files, the dev-only write route, edit mode (select on the canvas map, tag, make or extend a sequence, reorder), the Sequences view. Mark tags a first file or two to test the workflow before anything else builds on it.
npm run drive-strips: stitched images per sequence.- Illustrator pass for the files without PDF content (Mark's machine, Illustrator open).
- Evolution reads tagged sequences as origin moments; verify on
/cycles/evolutionwith the sequences from step 3. - Record, captures, commit (c122 paths only).
Open questions for Mark
- Size budget. About 2,500 artboard images go into git and onto the site. Default: 1,200 px long edge WebP for the lightbox plus 320 px thumbs, roughly 100–150 MB. Alternatives: 800 px (~60 MB), or move full-size images to R2 later.
- Tag vocabulary. Free-form plus
subject:,cycle:,phase:andpick. Are there tags you already use in your heads or folder names that should be first-class (e.g.iteration,final,rejected)? - History boards. Their artboards are copies named after source files. Default: show them in the library, auto-tagged
source:<file name>from the artboard name (the one thing that is safe to derive), and in evolution link each to its source file rather than counting it as a separate moment, so nothing appears twice. - Off-artboard content. Work on the canvas but outside any artboard (scratch areas) isn't captured by page rendering. Is that fine for now?
- Where editing happens. Default: edit mode on the local dev server, writing JSON in the repo, committed with the rest. The alternative is an editable deployed page backed by a shared database, so others could tag too. That's more moving parts; worth it only if someone besides you will curate.