3.6 KiB
Night Shift Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use superpowers:executing-plans. Steps use checkbox syntax.
Goal: Layer a cinematic, kinetic "Night Shift" identity onto the existing night-drive portfolio without breaking content, budgets or tests.
Architecture: Additive. One pure helper module with tests, one pointer composable, two small Vue components, one stylesheet imported last in App.vue. All motion honors prefers-reduced-motion and the existing motion policy.
Tech Stack: Vue 3, TypeScript, Vitest, CSS scroll-driven animations (progressive enhancement).
Spec: docs/redesign/direction.md
Global Constraints
- No new runtime dependencies; no new font files (fonts budget 120 KB).
- Initial JS budget 120 KB; HTML+critical CSS 100 KB.
- Never alter content strings in
content/public/portfolio-content.json. - Overlay UI is
aria-hiddenor non-blocking; focus rings stay visible; text contrast >= 4.5:1. - Reduced motion, forced colors, touch and webdriver (tests) show the plain site.
Review Focus
- Hydration mismatch from time-based text: render stable text on the server, fill on mount.
- Boot overlay trapping clicks/keys or hiding content from no-JS and crawlers.
- Pointer effects on touch devices.
- Uptime when clock is before the start date: clamp to zero.
- Repeat visits: boot shown once per session.
Task 1: Operations helpers
Files: Create src/lib/operations.ts; Test tests/unit/operations.test.ts
Produces: uptimeSince(start: Date, now: Date): { months: number; days: number }; bucharestClock(now: Date): string (HH:MM, 24h, Europe/Bucharest)
- Test:
uptimeSince(2025-08-01, 2025-08-01)is 0 months 0 days;2026-10-10gives 14 months 9 days; anowbefore start clamps to zero. - Test:
bucharestClock(new Date('2026-01-15T10:05:00Z'))is12:05. - Implement; run
npx vitest run tests/unit/operations.test.ts; commit.
Task 2: Headlight + pointer composable
Files: Create src/composables/useHeadlight.ts
Produces: useHeadlight(enabled: Ref<boolean>): void sets --hx/--hy on document.documentElement and --mx/--my (percent) on the hovered .project-case-study, .project-card, .portfolio-section ancestor, via one rAF-throttled passive pointermove; no-op unless (pointer: fine) and enabled.
- Implement, typecheck, commit.
Task 3: Operations strip
Files: Create src/components/OperationsStrip.vue; Modify AppShell.vue
Renders Bucharest HH:MM · On shift 14 mo · Route NN% after mount, static Bucharest text on the server. aria-hidden. Start date constant 2025-08-01 (Trupa lui Răzuș, from the content file).
- Implement, mount in AppShell beside JourneyHud, run unit tests, commit.
Task 4: Boot sequence
Files: Create src/components/BootSequence.vue; Modify AppShell.vue
Shown only after mount when motion allowed, not navigator.webdriver, not seen this session (sessionStorage guarded by try/catch). Lines use real facts. Auto-dismiss, any key/click/Escape skips, pointer-events only while visible, aria-hidden.
- Implement, commit.
Task 5: nightshift.css
Files: Create src/styles/nightshift.css; Modify src/App.vue (import last)
Kinetic hero weight, outlined chapter numerals via CSS counter, headlight layer, grain/vignette, card spotlight/tilt, scroll-driven reveals under @supports (animation-timeline: view()), all inside prefers-reduced-motion: no-preference and (pointer: fine) where relevant.
- Implement, commit.
Task 6: Verify
npm run typecheck,npm run test:unit,npm run build:preview; browser check at 1440 and 390; run browser tests; code review pass.