6.0 KiB
Feedback
Ordered by how much I think each item matters. Praise is included only where it's load-bearing for a recommendation.
1. You are avoiding the print, and the repo shows it
Eight creative phases in six weeks, and the master pipeline — the thing the project exists for — was last fed on day two. This has the signature of a familiar creative pattern: exploring is reversible and always rewarding; printing is a commitment that risks discovering the piece doesn't work at scale. So the exploration space keeps widening (new generator, new renderer, new subject) because widening is the move that never has to survive contact with a wall.
The honest counter-argument is that the vocabulary wasn't ready. It's ready. The BEBC plates read as archival photographs; the watercolor stillwater study holds up; PRINT.md already contains the assembly recipe. Every week of further exploration is now producing information about the screen version of a wall piece. One A1/A2 test print of one strong seed would generate more course correction than any three future sketch series — it will tell you whether the grain scales, whether the δ-ray curls reward approach, whether "standing closer" works, and it will almost certainly reorder the roadmap.
2. Decisions are being deferred into the working tree
Three currently open:
- The wind-field milkweed (branch, Jun 17) vs. the botanical milkweed (working
tree, Jun 25) — two incompatible
generateUmbels. Which milkweed is the milkweed, or are they two subjects (a field study and a specimen plate)? Either answer is fine; not answering is what costs. - The watercolor renderer: 427 good lines, uncommitted for 10 days. Ten more days of this and merging the branch becomes an archaeology project.
- The GROUP_BUILDERS registry on the branch is a strictly better composition engine than what's on main, independent of milkweed. It could be cherry-picked today.
A useful rule given how you work (commits = sessions): end every session with a commit, even a WIP one. Your commits are already narrative; let them be frequent-narrative.
3. Nothing verifies that a plate contains what its scene model says
The ripple bug survived three sketch series because the only QA is your eye, and your eye judges feeling, not inventory. Determinism is the project's religion, but determinism without ground truth just means you reproducibly get the wrong image. Cheap fixes that fit the project's culture:
- A layer-census check: render a scene, assert every
idin the scene model produced a nonempty layer/group in the output. ~30 lines, would have caught the ripple drop on day one. - Golden-seed snapshots: 3–4 canonical seeds rendered per renderer, diffed on
commit (you already have headless Chrome plumbing in
shoot.sh). - Stamp the build: embed the source git hash + date in
bubble_chamber.htmlso staleness is visible instead of silent.
4. The look needs its own seam
The scene/renderer split is genuinely well-kept — which makes it strange that
the style never got the same treatment. Three renderers currently disagree
about bubble size, and each new visual feature is hand-ported (or, for PDF,
quietly not). bubbleStops() already demonstrates the fix: one shared module
of style formulas (stroke widths, alphas, radii, spectrum mixes) consumed by
all renderers. This is a half-day of consolidation that removes the largest
source of drift in the codebase. Do it before renderer #5, because there will
be a renderer #5.
5. Sketch tools: keep the data, share the harness
The 17 QFT scripts are a legitimate serial sketchbook — the variation configs
are the artwork's process record, and hardcoded OUT dirs are honest about
their one-shot nature. But the 12-line render loop, F(), paper(), and the
gallery HTML are copy-pasted across all of them, with signature drift. One
40-line renderSketch(outDir, baseSeed, variations) harness turns every future
sketch into a pure data file. Same for the deep-merge() in 5 compose tools.
Don't retrofit the old ones; they're finished documents. Change the template
for the next one.
6. Small structural debts worth an hour each
carpet.js/perspgrid.jsare compose-system primitives parked insrc/qft/— they share nothing with the QFT pipeline.src/compose/composition.jsimports parameter defaults fromsrc/ui/controls.js— the headless engine depends on the UI layer. Move defaults down; let the UI consume them.- The
MILKpigment table just colonized corepalette.jsfrom the milkweed satellite. One entry is fine; it's the precedent to watch — palettes should be injectable from the satellite that owns them. - Delete or archive:
bubble_chamber.v2.html,tools/inkwash-export.mjs(it says goodbye in its own header),tools/find-semicircle.mjs. Fix or deletecompositions/hero.mjs(currently half-ignored by the code) andtools/archive-wall.html(frozen curation), or explicitly rename them as dated snapshots. params.jsQFT: either seed the camera/perturbation params or drop the "seed → complete fingerprint" claim from the header. The claim is currently the documentation equivalent of the ripple bug.
7. What's working — keep doing these on purpose
- Literate headers. Nearly every file explains why the fake was chosen over the real. This is the best code-as-notebook practice I've seen in a personal art repo, and it's why the intent/execution comparison in this review was even possible.
- The β thesis. "Get the statistics right and the eye believes" was the founding bet and it paid; the outputs are convincing at thumbnail and at 1500 px. Protect that thesis as you add renderers — watercolor already correctly routes 1/β² into stroke weight.
- Deterministic fiction. Plate numbers and exposure dates derived from the seed hash — the forgery itself is reproducible. This idea is bigger than its current use (see ideas §2).
- Commits as sessions produce a legible creative history. The fix from §2 isn't to change the style, just the frequency.