Three clone-fidelity fixes from manual review of the acceptance screenshots. Fix 1 — mobile nav chip-strip overlap (generate/css.ts). A horizontally scrollable flex strip (overflow-x:auto flex <ul>) of nowrap chips collapsed because the base viewport reported min-width:0px on the chips (a mobile-only strip that is 0-wide at desktop), so the generator emitted `min-w-0`, letting the chips shrink below their content instead of overflowing — the nowrap text then collided. Suppress `min-w-0` for a nowrap flex item whose flex parent scrolls horizontally; scoped away from legitimate min-w-0 truncation (whose parent does not scroll-x). Verified on a fresh ooni.com clone: 0 chip overlaps at 375, scrollWidth 776 > clientWidth 375. Fix 2 — reveal-replay stagger leaves tiles unpainted (generate/motion.ts). DittoMotion re-hid each revealed element and replayed its entrance on scroll-into-view preserving the captured delay/duration, so a fast scroll / full-page screenshot caught most grid tiles mid-entrance. Cap the replayed delay (<=300ms) and duration (<=600ms), settle each tile per-element a bounded time after it enters view, and make the global failsafe settle (not re-animate) so nothing stays hidden. Validator settle path (__dittoMotionStop) unchanged. Verified: cropin cotton renders 12/12 crop tiles in a normal full-page pass; motion gate reveals 24/24. Fix 3 — scroll-linked text-fill frozen at end state (capture/stabilize.ts, capture/capture.ts, generate/css.ts). A view-timeline text-fill (animation-duration resolves to `auto`) was baked filled: the clone has no scroll timeline, so emitting the animation made it jump to its end keyframe via fill-mode:both. Capture-side, cancel scroll/view-timeline animations before each snapshot so the DOM records the at-rest state; generation-side, suppress the animation-* props when animation-duration is `auto` (we render the at-rest state, never replay a scroll-linked animation). Teach the motion gate to exclude these from the static-CSS expectation so the gate stays honest. Verified on a fresh ooni clone: the "world's no.1 pizza ovens" em is white/gray (rgb 240,240, 240), not filled yellow, at rest; motion gate still passes. Tests: +7 fixtures (css scroll-strip + scroll-timeline, reveal-replay caps, motion-gate scroll-timeline exclusion); 123/123 compiler tests green, full test suite green, typecheck clean. No gate regression on the fresh ooni run vs the 20260704-024247 baseline (all gate pass/fail unchanged; perceptual within 0.0004; motion restored to pass). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ditto.site Compiler
This workspace contains the deterministic compiler used by ditto.site. It captures a source URL, builds a render IR, infers assets/fonts/tokens/sections/recipes/SEO, generates a Next.js App Router app by default or a Vite React app on request, and validates the result with deterministic gates.
The full architecture overview lives in ../README.md. This file keeps only compiler-local commands and notes.
Commands
cd compiler
npm install
npx playwright install chromium
npm run clone -- https://example.com/
npm run clone -- https://example.com/ --serve # then npm install + npm run dev
npm run clone -- https://example.com/ --open # ...and open the browser too
npm run clone -- https://example.com/ --mode=multi --styling=tailwind
npm run clone -- https://example.com/ --mode=single --framework=vite
npm run clone-site -- https://example.com/
npm run validate-site -- ../runs/site-example.com/<timestamp>
npm run clone -- https://example.com/ --mode=multi --concurrency=5
npm run clone -- https://example.com/ --mode=multi --validate --validate-concurrency=3 --viewport-concurrency=2
npm run validate-site -- ../runs/site-example.com/<timestamp> --validate-concurrency=3 --viewport-concurrency=2
npm run bench -- --tier=easy
npm run bench-site
npm run quality -- ../runs/example.com/<timestamp>
npm run audit -- ../runs/example.com/<timestamp>
npm test
npm run typecheck
Root-level scripts forward to these commands, so npm run clone -- <url> works
from the repository root too.
("Clone" here = generating a codebase from a live URL, not git clone; no source
repo required.) On success the CLI prints a copy-paste-safe summary: a single
quoted cd … && npm install && npm run dev line plus safe-to-edit pointers. Pass
--serve to run install + dev automatically, or --open to also launch the
browser. Without --out, a runs/<site>/latest symlink always points at the
newest run so paths aren't timestamp-fragile.
Multi-page generation defaults to the fast no-validation path. Use --validate
when the clone command itself should run the full build/render/gates QA pass, or
run validate-site separately. --concurrency controls source route capture;
--validate-concurrency controls how many routes validation grades at once; and
--viewport-concurrency controls how many clone viewports each route renders at
once.
Generated App Shape
Default Next generated apps use src/app/ditto.css and optional helpers under
src/app/ditto/. Vite generated apps use src/ditto.css and optional helpers
under src/ditto/, with multi-route pages under src/routes/. Validation builds
keep data-cid attributes for source/clone alignment; delivered apps strip those
validation ids and keep only required data-ditto-id anchors.