Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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._

---

Expand Down Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,17 @@
<div class="boot-track"><div class="boot-fill"></div></div>
</div>
<div id="app"></div>
<!--
Persistent app title + author credit, top-middle of the screen. Static
chrome (inlined here, not built by JS) so it's part of the page from the
first paint — sitting behind the #boot-loader overlay (lower z-index)
until the app boots and the loader fades. pointer-events:none (see
style.css) keeps it from ever intercepting orbit drags over the canvas.
-->
<div id="app-title">
<div class="app-title-name">Live Depth Field</div>
<div class="app-title-credit">by Noah Federovitch</div>
</div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
31 changes: 31 additions & 0 deletions src/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
62 changes: 62 additions & 0 deletions tests/smoke.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading