diff options
| author | Somhairle H. Marisol <[email protected]> | 2026-09-21 02:03:45 +0800 |
|---|---|---|
| committer | Somhairle H. Marisol <[email protected]> | 2026-09-21 02:07:13 +0800 |
| commit | dd75aaf6e82799ce88d8e66b01a3d53ba05301c9 (patch) | |
| tree | ef1601be2954f7c995f5fd47544241b457a7791e /README.md | |
| parent | 7e7166e9a7dfe6d619dbb2d3baa54ee97dfce1b9 (diff) | |
| download | somhairles-dream-fsharp-dd75aaf6e82799ce88d8e66b01a3d53ba05301c9.tar.gz | |
feat(viewer): fit camera to loaded model and add checked-in browser acceptance driver
- add three.js Box3/Camera bindings and bbox-driven camera framing
(fov-fit with margin, recenters the model so group rotation orbits
in place); refit on canvas resize instead of reverting to replay
placeholder geometry
- expose window.SOMHAIRLES_VIEWER debug handle for numeric verification
- add tools/acceptance/e2e_acceptance.py: self-provisioning playwright
driver (isolated port/artifact root, unique run ids) asserting framing,
frozen-screenshot determinism, GLB hash equality, failure surfacing
- gitignore scratch/ and tools/acceptance/deps/; document the
clean-checkout verification sequence (fable before build)
Diffstat (limited to 'README.md')
| -rw-r--r-- | README.md | 63 |
1 files changed, 59 insertions, 4 deletions
@@ -45,6 +45,58 @@ Three.js r160 and GLTFLoader are vendored under `public/vendor/` (import map plus a `three-setup.js` shim exposing `window.THREE`/`window.GLTFLoader`). They are MIT-licensed third-party dependencies, not project assets. +## Browser acceptance driver + +`tools/acceptance/e2e_acceptance.py` is the checked-in end-to-end gate. It +starts the server on an isolated port with its own artifact root, launches +headless chromium, and drives a full run through the page form twice +(desktop 1440x1000 and narrow 390x844 viewports, `?freeze=1`), plus a +failure-path run. It fails unless every check passes; exit code 0 means +green. Checks include: + +- idle page (`待机`, empty-state text), SSE connection, live per-stage + viewport ingestion (`运行中` + `steps/01-foundation.glb`, then `已完成` + + `steps/03-cabin.glb`), manifest link exposure +- geometry framing asserted from the live scene (`window.SOMHAIRLES_VIEWER` + + `THREE.Box3` projected to screen space): model fully inside the canvas + with margins >= 2% of the smaller canvas dimension, pixel coverage within + 40%-95%, center offset <= 10%, on both viewports; stage-1 vs stage-3 + bounding boxes must differ by >= 5% +- frozen-viewport determinism: two consecutive canvas screenshots are + byte-identical (sha256) +- served GLB sha256 equality with pinned reference hashes + (`01-foundation`, `03-cabin`) and `model/gltf-binary` content type +- failure run (pre-existing run directory) surfaces `失败` and the pipeline + error in `run-message`; zero browser console/page errors overall + +Playwright is self-provisioned into the gitignored +`tools/acceptance/deps/` directory (`pip --target --break-system-packages`, +pinned to an already-installed version when detectable) so the driver never +installs into system site-packages; the chromium browser binary is reused +from the user cache when present. + +Full verification from a clean checkout: + +```sh +dotnet tool restore +# Fable must run BEFORE the solution build: the server serves the frontend +# from public/ (copied into wwwroot at build time), and a fresh checkout has +# no fable_modules/App.js yet. Also run the frontend project restore first, +# and use --noCache: fable's project-options cache (keyed by fsproj content) +# is shared across checkouts of the same project and can yield spurious +# "Fable namespace not defined" errors on a fresh clone. +dotnet restore src/SomhairlesDream.Frontend/SomhairlesDream.Frontend.fsproj +dotnet fable src/SomhairlesDream.Frontend/SomhairlesDream.Frontend.fsproj \ + --outDir public --noRestore --noCache +dotnet build SomhairlesDream.sln -c Release +dotnet test SomhairlesDream.sln -c Release --no-build +python3 tools/acceptance/e2e_acceptance.py --port 18201 \ + --bpython /tmp/bpyenv/bin/python +``` + +`--bpython` must point at a Python that can `import bpy` (see below); the +driver refuses to start without it. + ## Server ```sh @@ -130,9 +182,12 @@ dotnet run --project src/SomhairlesDream.Cli -- run \ reference run; a failure run (pre-existing run directory) shows status `失败` with the error surfaced in `run-message`; zero console errors on all pages. -- Frozen-viewport evidence (`?freeze=1` stops rotation): canvas screenshots - of placeholder vs stage-1 vs stage-3 differ in pixel hashes, and the three - stages are visually distinct cubes/frames/house. Evidence lives in a - scratch directory and is not committed. +- Browser acceptance driver (see above), 45/45 checks green on desktop and + narrow viewports: framing asserted numerically from the projected scene + bounding box (not by trusting whole-canvas hashes alone), frozen + screenshots byte-deterministic, GLB hash equality, failure surfacing, + zero console errors. The frontend refits the camera to the loaded model + (`THREE.Box3`-based framing) whenever the canvas resizes, and a resize + never reverts the viewport to replay placeholder geometry. - NOT verified: production deployment of the old site remains untouched; `--render` PNG renders; replay button flow against a historical run. |
