From 0c996d31723d91174168e8aa86821c755c02b563 Mon Sep 17 00:00:00 2001 From: DecodedXR Date: Sat, 4 Jul 2026 11:41:29 -0600 Subject: [PATCH] feat: persistent top-center title + "by Noah Federovitch" credit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Surface the "Live Depth Field" name from the boot loader onto the running app — persistently at the top-middle of the screen — and add the author credit "by Noah Federovitch" beneath it. Both are static presentational chrome: an inline #app-title overlay in index.html (like #boot-loader, so it paints from the first frame and is testable in the raw server bytes) styled in src/style.css to mirror the boot loader's phosphor-green .boot-title. pointer-events:none keeps it from intercepting orbit drags on the canvas; z-index:5 sits below the loader's 10 so the loader still fully covers it during boot. No JS changes — the render loop, OrbitControls, geometry/shader, and the M4 decoupling machinery are byte-unchanged. Smoke test asserts both strings ship in the raw HTML and the live title is visible, horizontally centered near the top, and does not capture pointer events over the canvas. Proven non-tautological (RED on the prior HTML). Autopilot: user-directed polish (title + credit) Co-Authored-By: Claude Opus 4.8 (1M context) --- STATUS.md | 27 +++++++++++++++++--- index.html | 11 ++++++++ src/style.css | 31 +++++++++++++++++++++++ tests/smoke.spec.js | 62 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 128 insertions(+), 3 deletions(-) diff --git a/STATUS.md b/STATUS.md index 3b9b0f9..9294fa4 100644 --- a/STATUS.md +++ b/STATUS.md @@ -4,9 +4,10 @@ Single source of truth for "what's next." One milestone per PR/run. Autopilot: pick the one task under **NEXT**, ship it, stop. Do **not** start anything under **BLOCKED**. -_Last updated: 2026-07-04 — Milestone 6 (Web Worker WASM inference) done; two -user-directed polish items (boot loading bar, then a black+green "coding" -aesthetic) landed on top; queue empty pending an M7 proposal._ +_Last updated: 2026-07-04 — Milestone 6 (Web Worker WASM inference) done; three +user-directed polish items (boot loading bar, a black+green "coding" aesthetic, +then a persistent title + author credit) landed on top; queue empty pending an +M7 proposal._ --- @@ -195,6 +196,26 @@ aesthetic) landed on top; queue empty pending an M7 proposal._ 30.7fps). Deployed to the linked Netlify site (`live-depth-field`). Pre-change HEAD (rollback) `d455809`. +- **Polish — persistent title + author credit (user-directed, not a milestone).** + The "Live Depth Field" name previously lived only on the boot loader; it now + also sits **persistently at the top-middle of the running app**, with the + author credit **"by Noah Federovitch"** beneath it. Both are static + presentational chrome — an inline `#app-title` overlay in `index.html` (like + `#boot-loader`, so it's in the page from the first paint and testable in the + raw server bytes) styled in `src/style.css` to mirror the boot loader's + phosphor-green `.boot-title` (uppercase name in `--accent` with a green glow, + dimmer `--accent-dim` credit line, monospace). `pointer-events: none` keeps the + overlay from ever intercepting orbit drags on the canvas underneath, and + `z-index: 5` (below the loader's 10) means the loader still fully covers it + during boot. **No JS** — `src/main.js`, the render loop, OrbitControls, the + geometry/shader, and the M4 decoupling machinery are byte-unchanged. Smoke test + asserts both strings ship in the raw HTML AND the live title is visible, + horizontally centered near the top, and does not capture pointer events over + the canvas (`elementFromPoint` at its center returns the canvas). Proven + non-tautological (RED on the prior HTML: no `#app-title`). Verified visually on + a real build (centered green title + credit above the orbiting cloud, ~21fps). + Pre-change HEAD (rollback) `d5546e8`. + **Carry-over facts from M3/M4 (do not re-derive):** - Depth output contract: `depth` RawImage, Uint8, 1 channel, input W×H, 0–255 diff --git a/index.html b/index.html index bb2924b..0eb44f8 100644 --- a/index.html +++ b/index.html @@ -83,6 +83,17 @@
+ +
+
Live Depth Field
+
by Noah Federovitch
+
diff --git a/src/style.css b/src/style.css index 29eeb2e..b6f855c 100644 --- a/src/style.css +++ b/src/style.css @@ -21,6 +21,37 @@ canvas { display: block; } +/* Persistent title + author credit, docked top-middle over the canvas. Mirrors + the boot loader's phosphor-green .boot-title so the name carries over from the + loading screen. pointer-events:none so the overlay never steals orbit drags + from the canvas underneath; z-index sits below #boot-loader (10) so the loader + still fully covers it during boot. */ +#app-title { + position: fixed; + top: 12px; + left: 50%; + transform: translateX(-50%); + z-index: 5; + text-align: center; + pointer-events: none; + user-select: none; +} + +#app-title .app-title-name { + font: 600 15px/1 var(--mono); + letter-spacing: 0.2em; + text-transform: uppercase; + color: var(--accent); + text-shadow: 0 0 12px rgba(0, 255, 156, 0.6); +} + +#app-title .app-title-credit { + margin-top: 5px; + font: 11px/1 var(--mono); + letter-spacing: 0.08em; + color: var(--accent-dim); +} + /* Milestone 2: live splat-uniform sliders, docked top-left over the canvas. */ #controls { position: fixed; diff --git a/tests/smoke.spec.js b/tests/smoke.spec.js index 0d29b7a..68cf0ef 100644 --- a/tests/smoke.spec.js +++ b/tests/smoke.spec.js @@ -717,6 +717,68 @@ test('aesthetic: pre-upload cloud tint reads green (coding aesthetic)', async ({ expect(errors, `unexpected page errors:\n${errors.join('\n')}`).toEqual([]); }); +// Title + credit (user-directed, not a milestone). The "Live Depth Field" name +// from the boot loader must ALSO live on the running app — persistently, at the +// top-middle of the screen — and the project must carry the author credit +// "by Noah Federovitch". Both are static presentational chrome inlined in the +// initial HTML (like the boot loader), so this asserts (a) they ship in the raw +// server bytes AND (b) the name sits horizontally centered near the top of the +// live page, and (c) the title overlay never intercepts pointer input (so it +// can't block orbiting the cloud underneath it). Non-tautological: no #app-title +// exists before this change — every assertion is RED on the prior HTML. +test('title: Live Depth Field name + Noah Federovitch credit shown at top center', async ({ + page, +}) => { + const errors = []; + page.on('pageerror', (e) => errors.push(`pageerror: ${e}`)); + page.on('console', (m) => { + if (m.type() === 'error') errors.push(`console.error: ${m.text()}`); + }); + + // (a) Both strings ship in the exact bytes the server sends — static chrome, + // not JS-injected. Fetched raw so a scripted node can't satisfy it. + const html = await (await page.request.get('/')).text(); + expect(html, 'initial HTML must contain an #app-title overlay').toMatch( + /id=["']app-title["']/, + ); + expect(html, 'the title must show the app name').toContain('Live Depth Field'); + expect(html, 'the project must carry the author credit').toContain( + 'by Noah Federovitch', + ); + + // (b) Live: the title is visible and its text is present once the page loads. + await page.goto('/'); + const title = page.locator('#app-title'); + await expect(title).toBeVisible(); + await expect(title).toContainText('Live Depth Field'); + await expect(title).toContainText(/by Noah Federovitch/i); + + // Top-middle placement: horizontally centered on the viewport, near the top. + const box = await title.boundingBox(); + const viewport = page.viewportSize(); + const titleCenter = box.x + box.width / 2; + const viewportCenter = viewport.width / 2; + expect( + Math.abs(titleCenter - viewportCenter), + `title must be horizontally centered (center ${titleCenter} vs ${viewportCenter})`, + ).toBeLessThan(40); + expect(box.y, 'title must sit near the top of the screen').toBeLessThan(80); + + // (c) The overlay sits over the canvas but must not steal orbit input — the + // element under its center point must be the canvas, not the title. + const underCenter = await page.evaluate(() => { + const el = document.getElementById('app-title'); + const r = el.getBoundingClientRect(); + const hit = document.elementFromPoint(r.left + r.width / 2, r.top + r.height / 2); + return hit ? hit.tagName.toLowerCase() : null; + }); + expect(underCenter, 'title must not capture pointer events over the canvas').toBe( + 'canvas', + ); + + expect(errors, `unexpected page errors:\n${errors.join('\n')}`).toEqual([]); +}); + // Milestone 6: WASM inference moves into a Web Worker so the main thread stays // responsive during a pass. The worker itself can't run in CI (it loads the // real ~100MB model — the worker-path proof is a local real-model probe, like