Skip to content

Competition hardening: diagnostics, cold start, recognition - #8

Merged
karanheart96 merged 6 commits into
mainfrom
competition-hardening
Nov 11, 2026
Merged

karanheart96 merged 6 commits into
mainfrom
competition-hardening

Conversation

@karanheart96

Copy link
Copy Markdown
Contributor

Workstreams 1, 3 and 4 for the Meta VR Start Developer Competition (details in #4, #5, #6):

  • WS1 Diagnostics: ?diag overlay and beacon, /api/diag, scripts/diag/summarize.mjs, docs/DEVICE-TEST.md.
  • WS3 Cold start: main chunk 6.8 MB -> 2.4 MB (668 KB gzip), role-based loading, loading glow, compression and cache headers, /healthz, judging deploy commands in docs/DEPLOY.md.
  • WS4 Recognition: robust to tracking noise (all shapes 95-100% under jitter, occlusion and dropouts), 0 false triggers, settings apply at once, near-miss nudges.

Merge after #7 (which brings WS3 and WS4 into competition-hardening).

🤖 Generated with Claude Code

Nexus Agent and others added 6 commits November 10, 2026 16:09
?diag (never without it; a separate 8.8 KB chunk) adds a small panel under
the stage: fps and frame time (avg, p95, worst over 5 s), quality level
and shadow map size, per-hand tracking and recognised shape with scores,
the match and target, planes / vertical planes / meshes, placement (wall
or screen, wall size and distance, stage width), visibility, the session
frame rate, JS heap and startup timings (load to XR, XR to placed). It
asks the headset for 72 Hz and records the result.

The same data goes to POST /api/diag every 5 s and on events (placed,
quality step, beat, recognition trigger, visibility, page hide, errors
with stacks). The server accepts numbers, booleans and short ids only
(plus error text), rate limits per client (60/min) and caps size (32 KB),
and appends lines to diag/<date>/<session>.jsonl (local disk, or the
bucket in batched writes).

scripts/diag/summarize.mjs prints per-session fps percentiles, windows
under 60 fps, quality steps, placement, startup, triggers by shape, story
progress and errors. docs/DEVICE-TEST.md is the room-by-room checklist
for Quest 3 and 3S with a session id per run.

Tests: frame statistics (tests/), diagnostics validation, rate limit and
healthz (server); npm test runs unit, server and recognition tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Bundle
- @drawcall/uikitml's kit loader imported every Lucide icon (4.1 MB, 60% of
  the main chunk). '@pmndrs/uikit-lucide' now resolves to the two icons the
  Horizon kit uses (src/vendor/lucide-subset.ts).
- Code by role: the headset loads its own systems (lamp, journal, settings,
  family controls and setup, inbox) and never the viewer's; the family
  viewer loads its UI and camera hands and never the headset's; Live loads
  when someone goes live or joins; the recognition lab only in test
  builds. Samples are per role (the headset no longer downloads Dad's
  2.8 MB story, only Mia's 0.2 MB goodnight).
- Critical path: 1,750 KB -> 668 KB gzip (536 KB brotli). Report with
  scripts/sim/bundle-report.mjs.

Start
- A plain HTML/CSS lamp glow shows until the first frame (and a readable
  message if the app cannot start).

Server
- Brotli or gzip for text-like files (compressed once, in memory, warmed at
  startup), Vary: Accept-Encoding, immutable caching for hashed assets,
  no-cache for everything else, HEAD support, /healthz.

Judging setup (docs/DEPLOY.md, not run): min/max one instance, CPU always
allocated, 1 GiB, a tagged 'competition' revision with traffic pinned, a
/healthz uptime check with email alerting. smoke.mjs now checks /healthz,
compression and cache headers, and cold-load bytes on the wire.

Tests: static serving (compression, cache headers, HEAD). npm test, build,
role check (each page loads only its chunks and sample), playtest and
live-family pass.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…apply at once

Measured first: the recognition lab (in-app pipeline) showed crocodile at
60% and 14 false triggers on resting hands (cup 8, fist 5, dog 1); a new
sweep with Quest-like noise (+/-5 mm joint jitter, an occluded finger,
100 ms dropouts) showed fish 38-63%, swan 53%, crocodile 8-48%, and 197
false triggers.

- Joint positions are smoothed for recognition only (alpha 0.35 at 72 Hz,
  ~26 ms): jitter is zero-mean in position but biases the angle features
  (a jittery straight finger looks bent). Shadows keep the raw joints.
- Templates recalibrated to what each shape measures through that
  pipeline; spread (the noisiest feature) carries little weight; cup leans
  on finger curl and a curled-in thumb and needs a closer match (0.88 at
  Normal); a 'resting hand' template makes relaxed hands count as nothing.
- Two-hand rules: open hands for bird and deer need straight fingers and
  thumbs not bent across (rules out an OK sign); the crocodile drops the
  spread rule; cupped hands need one clear cup and one cup-like hand.
- The request gate, pair rules and hold timer live in recognition-rules.ts
  (pure) and the sweep tests exactly that code.

Result (sweep, all conditions): one-hand shapes 95-100%, two-hand 95-100%,
every shape triggers over time (~0.5 s), 0 false triggers in 320 negative
sequences, negatives accepted as cup 0.1% of frames. Lab: crocodile 100%,
false triggers only 'fist' (never accepted by any story or Free Stage).

Settings: the story's assist ladder now writes its own assistTolerance,
added by the matcher to the player's setting, so changing Tolerance takes
effect at once and is no longer overwritten or reverted mid-request.

Nudges: when a requested shape is nearly there for ~1 s, a small pill above
the caption says 'Almost! Hold it still...' or 'Bring your hand into the
lamplight.'

Tools: scripts/recognition/lab-run.mjs runs the in-app lab headless and
reports per-shape accuracy and false triggers.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
WS1: device diagnostics (?diag overlay, beacon, summarizer, checklist)
WS4: recognition robust to tracking noise, zero false triggers, settings apply at once
WS3 + WS4 into competition-hardening (cold start, recognition)
@karanheart96
karanheart96 merged commit 6fa202c into main Nov 11, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant