Files
Portfolio/docs/superpowers/plans/2026-10-10-night-shift.md

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-hidden or 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-10 gives 14 months 9 days; a now before start clamps to zero.
  • Test: bucharestClock(new Date('2026-01-15T10:05:00Z')) is 12: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.