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
25 changes: 22 additions & 3 deletions STATUS.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ 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; a
user-directed polish item (boot loading bar) landed on top; queue empty pending
an M7 proposal._
_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._

---

Expand Down Expand Up @@ -176,6 +176,25 @@ an M7 proposal._
dismissal was verified RED on the second assertion). Verified visually on a
real build (frozen-loader screenshot). Pre-change HEAD (rollback) `789d6ae`.

- **Polish — black + green "coding" aesthetic (user-directed, not a milestone).**
Restyled the whole UI to a phosphor-green-on-black terminal look. `src/style.css`
gains `--accent` (`#00ff9c`) / `--accent-dim` / `--mono` (monospace stack)
custom properties driving the `#controls` panel, slider labels+thumbs
(`accent-color`), the webcam/`::file-selector-button` buttons, `#status`, and
the `#hud` — all green, monospace, with a soft green outer glow on the panel.
`index.html`'s inline boot-loader CSS goes green (title + track + fill + glow),
monospace. `src/main.js`'s pre-upload point-cloud tint flips from blue-white
`(0.55, 0.78, 1.0)` to phosphor green `(0.15, 1.0, 0.45)` — the one
JS-observable change; **post-upload color still samples the image** (M3 path
untouched). `#device-note` stays amber on purpose (a caution signal that must
read distinctly against the green). Geometry, material identity, uniforms, the
render loop, and the M4 decoupling machinery are byte-unchanged. Smoke test
asserts the pre-upload `aColor` reads green (G>0.8, G dominant) — proven
non-tautological (RED on the old blue tint: G=0.78 fails G>0.8, and B=1.0
dominates). Verified visually on a real build (green splat cloud + green HUD,
30.7fps). Deployed to the linked Netlify site (`live-depth-field`).
Pre-change HEAD (rollback) `d455809`.

**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
14 changes: 8 additions & 6 deletions index.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,24 +31,26 @@
pointer-events: none;
}
#boot-loader .boot-title {
font: 600 13px/1 system-ui, sans-serif;
letter-spacing: 0.14em;
font: 600 13px/1 'JetBrains Mono', 'Fira Code', ui-monospace, Menlo,
Consolas, monospace;
letter-spacing: 0.18em;
text-transform: uppercase;
color: #8fb7ee;
color: #00ff9c;
text-shadow: 0 0 12px rgba(0, 255, 156, 0.6);
}
#boot-loader .boot-track {
width: 220px;
height: 4px;
border-radius: 4px;
background: rgba(255, 255, 255, 0.12);
background: rgba(0, 255, 156, 0.14);
overflow: hidden;
}
#boot-loader .boot-fill {
width: 0;
height: 100%;
border-radius: 4px;
background: linear-gradient(90deg, #5a8fd6, #8ec7ff);
box-shadow: 0 0 12px rgba(142, 199, 255, 0.7);
background: linear-gradient(90deg, #00b36b, #00ff9c);
box-shadow: 0 0 12px rgba(0, 255, 156, 0.75);
animation: boot-advance 2.4s cubic-bezier(0.2, 0.8, 0.2, 1) forwards;
transition: width 0.3s ease;
}
Expand Down
13 changes: 7 additions & 6 deletions src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,14 +54,15 @@ const cloudGeometry = new THREE.BufferGeometry();
cloudGeometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));

// Milestone 3: per-point color, sampled from the uploaded photo. Initialized to
// the M2 blue-white glow tint so the pre-upload cloud renders exactly as M2 did.
// (Named `aColor`, not `color` — Three injects its own `color` attribute
// declaration when vertexColors is on, and we manage this one ourselves.)
// a phosphor-green glow tint — the app's black+green "coding" accent — so the
// pre-upload cloud reads as a terminal-green splat field. (Named `aColor`, not
// `color` — Three injects its own `color` attribute declaration when
// vertexColors is on, and we manage this one ourselves.)
const colors = new Float32Array(GRID * GRID * 3);
for (let i = 0; i < colors.length; i += 3) {
colors[i] = 0.55;
colors[i + 1] = 0.78;
colors[i + 2] = 1.0;
colors[i] = 0.15;
colors[i + 1] = 1.0;
colors[i + 2] = 0.45;
}
cloudGeometry.setAttribute('aColor', new THREE.BufferAttribute(colors, 3));

Expand Down
66 changes: 58 additions & 8 deletions src/style.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,13 @@
/* Black + green "coding" aesthetic. A phosphor-green HUD on a pure-black stage,
monospace throughout, so the whole tool reads like a terminal. --accent is the
bright phosphor green; --accent-dim the calmer readout green. */
:root {
--mono: 'JetBrains Mono', 'Fira Code', 'SF Mono', ui-monospace, 'Cascadia Code',
Menlo, Consolas, monospace;
--accent: #00ff9c;
--accent-dim: #3fd68a;
}

html,
body {
margin: 0;
Expand All @@ -17,13 +27,14 @@ canvas {
top: 12px;
left: 12px;
padding: 10px 12px;
background: rgba(20, 22, 28, 0.6);
border: 1px solid rgba(255, 255, 255, 0.12);
background: rgba(0, 12, 6, 0.62);
border: 1px solid rgba(0, 255, 156, 0.28);
border-radius: 8px;
font: 12px/1.4 system-ui, sans-serif;
color: #cdd3df;
font: 12px/1.4 var(--mono);
color: var(--accent-dim);
user-select: none;
backdrop-filter: blur(4px);
box-shadow: 0 0 20px rgba(0, 255, 156, 0.12), inset 0 0 24px rgba(0, 255, 156, 0.04);
}

#controls .ctrl-row {
Expand All @@ -35,34 +46,73 @@ canvas {

#controls .ctrl-row span {
width: 52px;
color: var(--accent);
letter-spacing: 0.06em;
}

#controls input[type='range'] {
width: 130px;
accent-color: var(--accent);
}

#controls button {
font: inherit;
color: var(--accent);
background: rgba(0, 255, 156, 0.08);
border: 1px solid rgba(0, 255, 156, 0.4);
border-radius: 5px;
padding: 4px 10px;
cursor: pointer;
letter-spacing: 0.04em;
transition: background 0.15s ease, box-shadow 0.15s ease;
}

#controls button:hover:not(:disabled) {
background: rgba(0, 255, 156, 0.18);
box-shadow: 0 0 10px rgba(0, 255, 156, 0.35);
}

#controls button:disabled {
opacity: 0.5;
cursor: default;
}

/* Milestone 3: photo upload + async depth status line. */
#controls input[type='file'] {
margin-top: 6px;
max-width: 200px;
font-size: 11px;
color: #cdd3df;
font-family: var(--mono);
color: var(--accent-dim);
}

#controls input[type='file']::file-selector-button {
font: 11px var(--mono);
color: var(--accent);
background: rgba(0, 255, 156, 0.08);
border: 1px solid rgba(0, 255, 156, 0.4);
border-radius: 5px;
padding: 3px 8px;
margin-right: 8px;
cursor: pointer;
}

#status {
margin-top: 6px;
max-width: 210px;
color: #9fb4d8;
color: var(--accent-dim);
}

/* Milestone 5: FPS / inference readouts + the WASM slower-device warning. */
#hud {
margin-top: 6px;
padding-top: 6px;
border-top: 1px solid rgba(255, 255, 255, 0.12);
color: #9fb4d8;
border-top: 1px solid rgba(0, 255, 156, 0.2);
color: var(--accent-dim);
}

/* WASM slower-device warning: kept amber on purpose — a caution signal that
reads distinctly against the green so it never blends into the HUD. */
#device-note {
max-width: 210px;
color: #e8c46a;
Expand Down
32 changes: 32 additions & 0 deletions tests/smoke.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -685,6 +685,38 @@ test('boot loader: shipped in the initial HTML before JS, dismissed once the app
expect(errors, `unexpected page errors:\n${errors.join('\n')}`).toEqual([]);
});

// Polish — black + green "coding" aesthetic (user-directed, not a milestone).
// The one JS-observable part of the restyle is the pre-upload point-cloud tint:
// before any photo/webcam upload, the cloud renders in the app's accent color.
// A green coding aesthetic means that default tint reads GREEN — the green
// channel dominates and is strong. (Post-upload the cloud is colored from the
// image; this asserts only the default fill, so the M3 image-color path is
// untouched.) Non-tautological: RED on the prior blue-white (0.55, 0.78, 1.0)
// tint where blue dominates; green only once the tint is changed.
test('aesthetic: pre-upload cloud tint reads green (coding aesthetic)', 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()}`);
});
await page.goto('/');
await page.waitForFunction(() => window.__app?.getPointCount() === 128 * 128);

const tint = await page.evaluate(() => {
let cloud = null;
window.__app.scene.traverse((o) => {
if (o.isPoints) cloud = o;
});
const col = cloud.geometry.attributes.aColor;
return { r: col.getX(0), g: col.getY(0), b: col.getZ(0) };
});
// Green channel dominates and is strong — a green cloud, not blue-white.
expect(tint.g, 'green channel must be strong').toBeGreaterThan(0.8);
expect(tint.g, 'green must dominate red').toBeGreaterThan(tint.r);
expect(tint.g, 'green must dominate blue').toBeGreaterThan(tint.b);
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