Nocturne Pulse UI System Implementation

Implement the first slice of the Footwork Phase 1 UI/UX extension.
Repository:
- /home/kernel-kain/Documents/Github/footwork
- Branch: build/experience
Read before editing:
- Docs/PHASE_1_UI_UX_PLAN.md
- Docs/FRONTEND_EXPERIENCE.md
- Docs/HANDOFF_1.md
- Docs/HANDOFF_2.md
- Docs/PRODUCT_CONCEPT.md
Scope:
- Implement the Nocturne Pulse visual system across the existing landing, recording, generation, Soundprint, and /system screens.
- Replace the green-led visual hierarchy with:
- Midnight/cobalt backgrounds and surfaces
- Cyan for routes and movement
- Violet for music and playback
- Amber for meaningful movement events
- Blue for paused states
- Coral only for End walk and destructive actions
- Refine typography, spacing, surfaces, borders, chart colors, focus states, and route framing.
- Add one restrained static topographic/contour SVG treatment using existing project assets or locally authored SVG.
- Preserve the existing page structure, controls, route synchronization, honest example labels, and accessibility behavior.
Constraints:
- Do not add Tailwind, shadcn, Three.js, WebGL, a component library, remote assets, or a new runtime dependency.
- Do not copy layouts directly from reference sites.
- Do not add glass-card overload, generic purple gradients, fake statistics, testimonials, or new product sections.
- Verify all candidate colors before treating them as final tokens.
- Preserve 44 px minimum targets, safe-area handling, visible focus, reduced motion, and text-plus-color statuses.
- Do not modify backend behavior.
Verification:
- Run frontend typecheck, lint, format check, tests, and production build.
- Verify 360, 390, 430, 768, and 1280 px with no horizontal overflow.
- Run accessibility checks for /, /studio, /about, and /system.
- Record the final token values and contrast decisions in Docs/HANDOFF_2.md.
- Do not mark the work complete if any required check fails.
Deliver a concise summary of the visual changes, files changed, test results, and remaining risks.
Two checks need a real fix: looping motion keeps running when the page is hidden or offscreen, and a return value of 0.25 would be shown as 0.3. I’ll correct those and then run the full verification.
The Phase 1 extension is verified in the working tree. This pass only corrected measured honesty and motion that kept running when it should have stopped.
Changes made
Published distances, speeds, and return values now keep three decimal places, so 0.25 stays 0.25. Looping walker strides and the recording pulse stay paused until the element is on screen and the document is visible. The walk clocks, the generation clock, and the audio clock stop requesting animation frames while the page is hidden. Generation redraws only when the displayed second or stage changes.
Docs/FRONTEND_EXPERIENCE.md now matches the paused draft in sessionStorage and the rendered movement summary. Docs/HANDOFF_1.md, Docs/HANDOFF_2.md, Docs/PRODUCT_CONCEPT.md, and README.md describe the uncommitted extension. P1.13 stays Partial. Commit placeholders remain “Not created.”
A preview pass of /studio played the example, then the turn card moved the scrubber to 18 seconds, marked that card Now, and moved the story to Corner Now.
Checks passed and failed
Passed:
npm run typechecknpm run lintnpm run formatnpm test— 78 passed in 30.0snpm run builduv run pytest tests/unit/test_fixtures.py— 2 passedgit diff --check
Failed: none of those commands.
The suite covers ready to recording to pause to resume to end to generation to result, pause then end, paused restore after reload, permission denied, unsupported browser, offline and interrupted, a short or unclear trace, generation timeout, arrangement unavailable, music unavailable, and the example result. Manual breaks stay out of samples, distance, active time, detected musical pauses, and route connectors. Visible totals come from the validated summary. A missing speed or empty pace series shows an unavailable sentence.
Performance delta
Against the Step 5 baseline (CSS 11.53 kB / gzip 3.12, JavaScript 268.74 kB / gzip 82.09):
| Asset | This build | Raw delta | Gzip delta |
|---|---|---|---|
| CSS | 17.55 kB (index-TWHbuoFw.css) | +6.02 kB | +1.16 kB |
| JavaScript | 295.96 kB (index-DZG9-8kj.js) | +27.22 kB | +7.76 kB |
| HTML | 0.96 kB | +0.05 kB | +0.02 kB |
Against the earlier recap build, this pass added 0.52 kB of CSS (0.07 kB gzip) and 1.09 kB of JavaScript (0.26 kB gzip). Runtime dependencies remain React and React DOM. Assets stay local.
Slow-mobile sample, about 1.6 Mbps down, 750 kbps up, 150 ms latency, 4× CPU: landing 1456 ms, example 1221 ms, document load 415 ms, document 1262 bytes, encoded resource bytes 0. The Step 5 sample was landing 1353 ms and example 1113 ms. The earlier recap sample was landing 1555 ms and example 830 ms. These are warm-cache samples, not a cold download and not a Lighthouse score.
Accessibility status
Keyboard coverage, dialog focus, named controls, text plus color, 200% text at 360 px, and a static reduced-motion route all passed. Axe reported no serious or critical violations on the shell, recording, paused practice, Soundprint, and catalog. Layout checks passed at 360, 390, 430, 768, and 1280 px. Playback, the route cursor, the ribbon, the event card, and the story stay within 500 ms at the tested anchors. Nocturne Pulse contrast was left at the values locked earlier. The lowest text signal, violet on the raised surface, remains 5.76:1.
Remaining risks
Nothing in this extension is committed. The last execution commit is still 847a294. The extra 290 minutes still have no budget decision. Slow-mobile timings move between warm runs. Only the fixture unit tests were run for the backend.
Intentionally cut
A numeric count-up on the result page was left out so that screen has no second timer. A side-by-side desktop dashboard was left out so the play control stays above the route. P1.7 was not a separate implementation step; those decisions are already in the plan. No WebGL, remote asset, or new dependency was added.
Community Wisdom
- Every animation in our app is declared paused, and one CSS selector is the play button by daniel_pertu — looping motion stays paused until the element is actually on stage.
- How to Animate SVG Without JavaScript by utilitylab — the walker stays CSS and SVG, with no animation library.
- Lottie Animations and Accessibility by fazalshah — reduced motion keeps a still, readable result.
Hacktoberfest Week 1: Touch Grass is still open through October 11, 2026, and this walk-to-music work fits that theme.
I can draft a DEV post about this verification pass if you want one.
Add high quality light mode as well with dark mode and then update the handoff docs for the new plan after all these frontedn modifcation done here and commit and push all of this branch.
A designed light theme will sit alongside the current dark theme. I’ll inspect how color is applied, then update the handoff and commit this branch.
Daylight will use the same tokens as Nocturne Pulse, with a device default and an explicit switch so the first paint matches the chosen theme.
Daylight is now the light theme beside Nocturne Pulse, and build/experience is pushed.
A light device opens warm paper surfaces with deeper teal, violet, amber, blue, and coral. A dark device stays on Nocturne Pulse. The header button is Light theme or Dark theme, and that choice is kept in localStorage under footwork-theme. The theme is set before the first paint. Text and button labels in Daylight stay above 4.5:1; body ink on the paper background is 14.40:1.
The handoff now treats the frontend extension as done in commit 56b9c06, with the hash recorded in fb4951c. The next step is the 290-minute budget decision, then P2.0.
Pushed to origin/build/experience:
56b9c06— Extend the walk with pause, a visual recap, and Daylight.fb4951c— Record the frontend extension commit in the execution notes.
The suite is 81 tests passed. The production build is HTML 1.55 kB, CSS 19.03 kB, JavaScript 297.02 kB. Against the Step 5 baseline, that is +7.50 kB of CSS and +28.28 kB of JavaScript. Local browser logs and the OpenCode plugin were left untracked.
Community Wisdom: You're writing dark-mode colors twice. light-dark() fixes that.
Source: parsajiravand Tags:
css,webdev,frontendOne token list with
light-dark()avoids a second stylesheet.color-schemestill has to be set so native controls follow the page.
Community Wisdom: Building a dark/light theme toggle in Astro
Source: sourcier Tags:
frontend,engineeringPut
data-themeon the root, keep colors in custom properties, and run a synchronous script so the first paint is not the wrong theme.
Hacktoberfest Week 1: Touch Grass is still open through October 11, 2026, and this walk-to-music work fits that theme.
I can draft a DEV post about the Daylight theme and the pause-to-recap journey if you want one.