Port steps 0-1: scaffold, the oracle, and the pure bottom
Scaffolds frontend/ (shadow-cljs, reagent 1.2.0, re-frame 1.4.3) and ports
everything below the data model, with the JS kept as a numeric oracle.
domain/landmarks index tables, verbatim
domain/ring subsample, offset, simplicity
domain/geom similarity fit, procrustes, moving average
domain/raster indexed scanline fill, stencil, disc, rect
domain/palette the ramp, and the no-sampled-RGB rule
58 tests, 166 assertions. Parity with js/ on the identical 72-frame synthetic
track: fit-similarity, procrustes-mean, fit-residual, moving-average,
smooth-transforms, offset-ring and subsample-slots to 1e-9; the raster
pixel-for-pixel over the whole buffer.
Three deviations from the JS, each for a reason:
- synth.cljs jitters from a SEEDED generator, not Math.random. Parity is only
checkable if both sides can be handed the same track, and a failing assertion
has to be reproducible. `:rand-fn` takes the generator over, so oracle.mjs
stubs js/Math.random and js/ itself stays untouched.
- raster/->rgba replaces toImageData. ImageData is a DOM type and domain/ may
not touch the DOM; returning plain bytes also lets the
no-intermediate-colours assertion run in node. ui/canvas wraps it later.
- offset-ring lives in domain/ring, not domain/geom, per architecture.md: it is
an operation on an ordered traversal, not on a transform.
Step 1's "done" also names the swapped-iris vote, but pairIrises is in
pipeline.js and belongs to step 7. The precondition is asserted instead --
`:swap-iris` really does move both blocks -- so the vote will have a track that
disagrees with it when it arrives.
One finding, recorded in full in the test that measures it: smooth-transforms
buys nothing on the synthetic track. Against jitter-free ground truth, radius 1
helps by 17% on one noise realisation and hurts by 0.5% on another, so its
benefit is within noise; from radius 2 up the cost is unambiguous, and by radius
5 the filter is below the true motion's own high-frequency energy, i.e.
smoothing away performance. The test pins the shape of the knob rather than a
preferred value. This may say more about the synth's jitter being unrealistically
small (+/-0.001 normalised) than about the knob; step 6 settles it on real
footage.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-27 14:43:34 -04:00
|
|
|
# Toolchain for both halves of the repo: the CLJS frontend and the Django
|
|
|
|
|
# backend. `mise install` from the repo root is the whole setup.
|
|
|
|
|
#
|
|
|
|
|
# java must be 21+. The current closure-compiler is built for it, and on an
|
|
|
|
|
# older JDK shadow-cljs fails with "CompilerOptions has been compiled by a more
|
|
|
|
|
# recent version of the Java Runtime" — which reads like a shadow-cljs bug and
|
|
|
|
|
# is not one.
|
|
|
|
|
|
|
|
|
|
[tools]
|
|
|
|
|
java = "temurin-21"
|
|
|
|
|
node = "20"
|
|
|
|
|
clojure = "latest"
|
|
|
|
|
python = "3.12"
|
|
|
|
|
|
|
|
|
|
[env]
|
|
|
|
|
_.python.venv = { path = ".venv", create = true }
|