docs(01-foundation): create phase plan — 3 plans in 2 waves

This commit is contained in:
Claude
2026-04-05 18:40:20 +00:00
parent 519849e855
commit 5721bef791
4 changed files with 791 additions and 7 deletions

View File

@@ -0,0 +1,251 @@
---
phase: 01-foundation
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
- lightsync/frontend/index.html
- lightsync/frontend/style.css
- lightsync/frontend/app.js
autonomous: true
requirements:
- UI-01
- UI-02
- DEV-03
must_haves:
truths:
- "The web app loads in a browser showing the full DAW skeleton layout"
- "The UI has terminal/hacker aesthetic — dark background, monospace fonts, cyan accents, no generic SaaS look"
- "All final panels are visible: DEVICES, ANIMATIONS, TIMELINE, TRANSPORT — most as labeled placeholders"
- "The DEVICES panel has an add-device form and a device list area"
- "Panel headers are uppercase and borders are dimmed cyan — matching terminal window pane style"
artifacts:
- path: "lightsync/frontend/index.html"
provides: "Full DAW skeleton HTML structure with all panels"
contains: "LIGHTSYNC"
- path: "lightsync/frontend/style.css"
provides: "Terminal aesthetic CSS — dark theme, monospace, cyan accents"
contains: "--accent"
- path: "lightsync/frontend/app.js"
provides: "WebSocket client stub, device panel interactions, API fetch helpers"
contains: "new WebSocket"
key_links:
- from: "lightsync/frontend/app.js"
to: "/ws"
via: "WebSocket connection for future position broadcasts"
pattern: "new WebSocket.*ws"
- from: "lightsync/frontend/app.js"
to: "/api/devices"
via: "fetch calls for device CRUD"
pattern: "fetch.*api/devices"
- from: "lightsync/frontend/index.html"
to: "lightsync/frontend/style.css"
via: "stylesheet link"
pattern: "style.css"
---
<objective>
Build the complete terminal-aesthetic frontend shell: HTML with full DAW skeleton layout (all panels), CSS with dark theme / monospace / cyan accents, and JavaScript with WebSocket stub and device panel interactivity.
Purpose: Establishes the visual identity and layout structure that all future phases will fill in. The user sees the final app skeleton from day one.
Output: Three files in lightsync/frontend/ — index.html, style.css, app.js — that render the full DAW interface.
</objective>
<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>
<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/STATE.md
@.planning/phases/01-foundation/01-CONTEXT.md
@.planning/phases/01-foundation/01-RESEARCH.md
</context>
<tasks>
<task type="auto">
<name>Task 1: Create HTML structure and CSS terminal aesthetic</name>
<files>
lightsync/frontend/index.html
lightsync/frontend/style.css
</files>
<read_first>
.planning/phases/01-foundation/01-CONTEXT.md
.planning/phases/01-foundation/01-RESEARCH.md
</read_first>
<action>
Create lightsync/frontend/ directory.
Create lightsync/frontend/index.html with this structure (per D-06 through D-10):
DOCTYPE html, lang="en", meta charset UTF-8, viewport meta, title "LIGHTSYNC".
Link to style.css, defer script app.js.
Body layout using CSS Grid (per D-06 — full DAW skeleton from Phase 1):
HEADER (per D-07):
- div.header containing:
- ASCII art or stylized text "LIGHTSYNC" in a pre or span element (use simple ASCII block letters or styled text — not an image)
- span.status-indicator with id="status" text "OFFLINE" (will toggle to "CONNECTED" via JS)
- span.show-name with id="show-name" text "No show loaded"
LEFT SIDEBAR (per D-08):
- div.sidebar containing two panels stacked vertically:
- section.panel#devices-panel:
- h2.panel-header text "DEVICES"
- div#device-list (empty, populated by JS)
- form#add-device-form with inputs: name (text), strip_type (select: sk6812, ws2801, generic), led_count (number, min=1, max=1000), ip (text), port (number, min=1, max=65535), and a submit button text "+ ADD DEVICE"
- section.panel#animations-panel:
- h2.panel-header text "ANIMATIONS"
- div.placeholder-content text "[ Phase 3+ ]"
MAIN CENTER (per D-09):
- div.main containing:
- section.panel#timeline-panel:
- h2.panel-header text "TIMELINE"
- div.placeholder-content text "[ TIMELINE -- Phase 2+ ]"
BOTTOM BAR (per D-10):
- div.transport containing:
- section.panel#transport-panel:
- h2.panel-header text "TRANSPORT"
- div.placeholder-content text "[ TRANSPORT -- Phase 2+ ]"
Create lightsync/frontend/style.css with terminal aesthetic (per D-11 through D-15):
CSS custom properties on :root:
- --bg: #0a0a0a (per D-12)
- --bg-panel: #111111
- --accent: #00ffff (per D-11)
- --accent-dim: #004444 (dimmed cyan for borders, per D-13)
- --text: #cccccc
- --text-bright: #ffffff
- --text-dim: #666666
- --font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Consolas', monospace (per D-12)
@import url for JetBrains Mono from Google Fonts (weight 400,700).
*, *::before, *::after: box-sizing border-box, margin 0, padding 0.
html, body: height 100%, background var(--bg), color var(--text), font-family var(--font-mono), font-size 14px, overflow hidden.
Body grid layout: grid-template-areas "header header header" / "sidebar main main" / "sidebar main main" / "transport transport transport". grid-template-columns: 280px 1fr. grid-template-rows: auto 1fr auto.
.header: grid-area header, display flex, align-items center, gap 1rem, padding 8px 16px, border-bottom 1px solid var(--accent-dim), background var(--bg-panel).
.header pre (for ASCII title): color var(--accent), font-size 10px, line-height 1.1, white-space pre.
.status-indicator: font-size 11px, text-transform uppercase, padding 2px 8px, border 1px solid var(--accent-dim). When connected: color var(--accent). Default (offline): color #ff4444.
.show-name: margin-left auto, font-size 12px, color var(--text-dim).
.sidebar: grid-area sidebar, display flex, flex-direction column, gap 0, border-right 1px solid var(--accent-dim), overflow-y auto.
.main: grid-area main, display flex, flex-direction column, overflow hidden, padding 8px.
.transport: grid-area transport, border-top 1px solid var(--accent-dim).
.panel: background var(--bg-panel), border 1px solid var(--accent-dim) (per D-13), padding 0, margin 0. No border-radius (per D-15). No box-shadow (per D-15).
.panel-header: text-transform uppercase (per D-14), font-size 11px, letter-spacing 2px, color var(--accent), padding 8px 12px, border-bottom 1px solid var(--accent-dim), font-weight 700.
.placeholder-content: display flex, align-items center, justify-content center, min-height 200px, color var(--text-dim), font-size 13px, letter-spacing 1px.
#devices-panel: flex 1.
#animations-panel: flex 0 0 auto, border-top 1px solid var(--accent-dim).
#timeline-panel: flex 1, display flex, flex-direction column. The .placeholder-content inside: flex 1.
#transport-panel: padding 0.
#transport-panel .placeholder-content: min-height 48px.
#device-list: padding 8px 12px. Each .device-item: display flex, justify-content space-between, align-items center, padding 4px 0, border-bottom 1px solid var(--accent-dim), font-size 12px. .device-item .device-name: color var(--text-bright). .device-item .device-meta: color var(--text-dim), font-size 11px. .device-item .device-remove: background none, border none, color #ff4444, cursor pointer, font-family var(--font-mono), font-size 14px.
#add-device-form: padding 8px 12px, display flex, flex-direction column, gap 6px.
#add-device-form input, #add-device-form select: background var(--bg), border 1px solid var(--accent-dim), color var(--text), font-family var(--font-mono), font-size 12px, padding 4px 8px, outline none. Focus: border-color var(--accent).
#add-device-form button: background var(--accent-dim), border 1px solid var(--accent), color var(--accent), font-family var(--font-mono), font-size 12px, padding 6px, cursor pointer, text-transform uppercase, letter-spacing 1px. Hover: background var(--accent), color var(--bg).
Scrollbar styling for webkit: 6px wide, track var(--bg), thumb var(--accent-dim), thumb hover var(--accent).
</action>
<verify>
<automated>test -f /home/claude/led2/lightsync/frontend/index.html && test -f /home/claude/led2/lightsync/frontend/style.css && grep -c "LIGHTSYNC" /home/claude/led2/lightsync/frontend/index.html && grep -c "\-\-accent.*#00ffff" /home/claude/led2/lightsync/frontend/style.css && grep -c "JetBrains Mono" /home/claude/led2/lightsync/frontend/style.css</automated>
</verify>
<acceptance_criteria>
- lightsync/frontend/index.html contains "LIGHTSYNC" in header area
- lightsync/frontend/index.html contains id="devices-panel" and id="animations-panel" and id="timeline-panel" and id="transport-panel"
- lightsync/frontend/index.html contains id="add-device-form" with inputs for name, strip_type, led_count, ip, port
- lightsync/frontend/index.html contains id="device-list"
- lightsync/frontend/index.html contains "Phase 3+" in animations panel and "Phase 2+" in timeline panel and "Phase 2+" in transport panel
- lightsync/frontend/style.css contains `--accent: #00ffff` and `--bg: #0a0a0a` and `--font-mono`
- lightsync/frontend/style.css contains `text-transform: uppercase` for panel headers
- lightsync/frontend/style.css contains `border-radius` nowhere (per D-15 no rounded corners) OR only `border-radius: 0`
- lightsync/frontend/style.css contains `font-family: 'JetBrains Mono'` or references var(--font-mono) on body
- lightsync/frontend/style.css contains grid-template-areas with "header" and "sidebar" and "main" and "transport"
</acceptance_criteria>
<done>HTML renders full DAW skeleton. CSS applies terminal aesthetic with dark background, monospace font, cyan accents, flat sharp edges. All panels visible with correct labels.</done>
</task>
<task type="auto">
<name>Task 2: Create JavaScript — WebSocket client, device panel CRUD, API helpers</name>
<files>
lightsync/frontend/app.js
</files>
<read_first>
lightsync/frontend/index.html
.planning/phases/01-foundation/01-RESEARCH.md
</read_first>
<action>
Create lightsync/frontend/app.js with these modules:
1. API helper functions:
- async function apiGet(path): fetch(path), check response.ok, return response.json()
- async function apiPost(path, data): fetch(path, {method: "POST", headers: {"Content-Type": "application/json"}, body: JSON.stringify(data)}), return response.json()
- async function apiDelete(path): fetch(path, {method: "DELETE"})
2. WebSocket client stub:
- let ws = null
- function connectWebSocket(): create new WebSocket(`ws://${location.host}/ws`), set onopen to update #status text to "CONNECTED" and add .connected class, set onclose to update #status text to "OFFLINE" and remove .connected class, set onmessage to parse JSON and call handleWsMessage(data), set onerror to console.error. Auto-reconnect: onclose sets setTimeout(connectWebSocket, 2000).
- function handleWsMessage(msg): switch on msg.type — for now just console.log("WS:", msg). Phase 2 will add position/state handlers.
3. Device panel logic:
- async function loadDevices(): call apiGet("/api/devices"), for each device call renderDevice(device), populate #device-list
- function renderDevice(device): create div.device-item containing: span.device-name with device.name, span.device-meta with `${device.strip_type} | ${device.led_count} LEDs | ${device.ip}:${device.port}`, button.device-remove with text "x" and onclick calling removeDevice(device.id)
- async function removeDevice(id): call apiDelete(`/api/devices/${id}`), then loadDevices() to refresh
- Form submit handler on #add-device-form: preventDefault, collect form values (name, strip_type, led_count as int, ip, port as int), call apiPost("/api/devices", data), reset form, call loadDevices()
4. Initialization:
- document.addEventListener("DOMContentLoaded", () => { connectWebSocket(); loadDevices(); })
Add .connected CSS class to style.css for the status indicator: .status-indicator.connected { color: var(--accent); border-color: var(--accent); }
</action>
<verify>
<automated>test -f /home/claude/led2/lightsync/frontend/app.js && grep -c "new WebSocket" /home/claude/led2/lightsync/frontend/app.js && grep -c "api/devices" /home/claude/led2/lightsync/frontend/app.js && grep -c "loadDevices" /home/claude/led2/lightsync/frontend/app.js && grep -c "connectWebSocket" /home/claude/led2/lightsync/frontend/app.js</automated>
</verify>
<acceptance_criteria>
- lightsync/frontend/app.js contains `new WebSocket` connecting to `/ws`
- lightsync/frontend/app.js contains `fetch` calls to `/api/devices` for GET, POST, and DELETE
- lightsync/frontend/app.js contains `function loadDevices` and `function renderDevice` and `function removeDevice`
- lightsync/frontend/app.js contains `DOMContentLoaded` listener calling `connectWebSocket()` and `loadDevices()`
- lightsync/frontend/app.js contains `function handleWsMessage` with msg.type switch/check
- lightsync/frontend/app.js contains auto-reconnect logic (setTimeout with connectWebSocket)
- lightsync/frontend/app.js contains `apiGet` and `apiPost` and `apiDelete` helper functions
</acceptance_criteria>
<done>JavaScript connects WebSocket, displays connection status, loads device list from API, supports adding and removing devices via the form. All interactions use the API helpers.</done>
</task>
</tasks>
<verification>
1. `ls lightsync/frontend/` shows index.html, style.css, app.js
2. index.html contains all four panel IDs: devices-panel, animations-panel, timeline-panel, transport-panel
3. style.css uses --accent: #00ffff and --bg: #0a0a0a
4. app.js connects to /ws and fetches from /api/devices
</verification>
<success_criteria>
- Opening the app in a browser shows: header with LIGHTSYNC title, left sidebar with DEVICES and ANIMATIONS panels, center TIMELINE placeholder, bottom TRANSPORT placeholder
- Dark background (#0a0a0a), monospace fonts, cyan accent color throughout
- No rounded corners, drop shadows, or gradients anywhere
- Device add form is functional (sends POST to /api/devices)
- WebSocket connects and shows CONNECTED status
</success_criteria>
<output>
After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md`
</output>