# projects

name: neopixel-command-calculator
repo_url: https://theres-a-git-in-this-tea.andrewawesomo.net/andrewadmin/neopixel-command-calculator
created_at: 2026-03-21 17:07:38.130407
description:
Engineering calculator for finding NeoPixel data transmission limits from single hardware sources. Web Components library (Lit + Vite) for CDN distribution.


# requirement_nodes

id: NPC
title: NeoPixel Command Calculator
priority: critical
status: draft
node_type: pillar
test_status: not_written
created_at: 2026-03-21 17:07:40.165481
updated_at: 2026-03-21 17:07:40.165481
description:
A Web Components library providing engineering calculators for NeoPixel/addressable LED data transmission limits. Ships as CDN-ready ES+UMD bundles via Lit + Vite.

acceptance_criteria:
- Library loadable via <script> tag with zero dependencies
- Three calculator components render and produce correct results
- Themeable via CSS custom properties
- Engine functions usable programmatically without UI


id: NPC-DATA
title: Protocol & Hardware Data Layer
priority: critical
status: draft
node_type: pillar
parent_id: NPC
test_status: not_written
created_at: 2026-03-21 17:07:42.196364
updated_at: 2026-03-21 17:07:42.196364
description:
Type-safe data definitions for LED protocols and hardware profiles. Source of truth for all timing calculations.

acceptance_criteria:
- All 6 protocols defined with verified timing specs
- ESP32-WROOM-32D profile with all RMT/SPI channels
- Data validates internally (bitPeriodNs matches dataRateBps)
- Easy to add new protocols and hardware profiles


id: NPC-ENGINE
title: Calculation Engine
priority: critical
status: draft
node_type: pillar
parent_id: NPC
test_status: not_written
created_at: 2026-03-21 17:07:44.227525
updated_at: 2026-03-21 17:07:44.227525
description:
Pure TypeScript functions for timing math, max LED calculation, refresh rate computation, and multi-strand optimization. No UI dependencies.

acceptance_criteria:
- All functions are pure (no side effects, no DOM)
- Unit tested with known-good reference values
- Handles edge cases (0 LEDs, impossible refresh rates)
- Results match hand-calculated timing math


id: NPC-UI
title: Web Components UI
priority: critical
status: draft
node_type: pillar
parent_id: NPC
test_status: not_written
created_at: 2026-03-21 17:07:46.261058
updated_at: 2026-03-21 17:07:46.261058
description:
Three Lit-based Web Components that wrap the calculation engine with interactive controls and visualizations.

acceptance_criteria:
- Three components register as custom elements
- All inputs reactive (changes recalculate immediately)
- Themeable via --npc-* CSS custom properties
- Accessible (ARIA labels, keyboard navigation)
- Work in any framework or vanilla HTML


id: NPC-BUILD
title: Build & Distribution
description: Vite library mode build producing ES module and UMD bundles for CDN/script-tag consumption.
priority: high
status: draft
node_type: pillar
parent_id: NPC
test_status: not_written
created_at: 2026-03-21 17:07:48.296744
updated_at: 2026-03-21 17:07:48.296744
acceptance_criteria:
- ES and UMD bundles produced by npm run build
- UMD bundle works via plain <script> tag
- Lit bundled in (no peer dependency)
- Bundle size reasonable (<100KB gzipped)


id: NPC-DATA-PROTO-WS
title: WS2812B / WS2811 Protocol Data
description: Timing definitions for WS2812B (800kHz) and WS2811 (800kHz + 400kHz variants).
priority: critical
status: draft
node_type: leaf
code_language: typescript
target_impl_file: src/data/protocols.ts
test_status: not_written
created_at: 2026-03-21 17:07:54.409601
updated_at: 2026-03-21 18:21:24.812086
acceptance_criteria:
- WS2812B: 24 bits/LED, 1250ns bit period, 50us reset, 800kbps, one-wire, GRB
- WS2811 800kHz: same timing as WS2812B
- WS2811 400kHz: 24 bits/LED, 2500ns bit period, 50us reset, 400kbps
- Values match official datasheets


id: NPC-DATA-PROTO-SK
title: SK6812 Protocol Data
description: Timing definitions for SK6812 RGB and SK6812 RGBW variants.
priority: critical
status: draft
node_type: leaf
code_language: typescript
target_impl_file: src/data/protocols.ts
test_status: not_written
created_at: 2026-03-21 17:07:56.460975
updated_at: 2026-03-21 18:21:24.812550
acceptance_criteria:
- SK6812 RGB: 24 bits/LED, 1250ns bit period, 80us reset, 800kbps, one-wire, GRB
- SK6812 RGBW: 32 bits/LED, 1250ns bit period, 80us reset, 800kbps, one-wire, GRBW
- Note the longer reset time vs WS2812B (80us vs 50us)


id: NPC-DATA-PROTO-APA
title: APA102 Protocol Data
description: SPI-based APA102 protocol with configurable clock and frame overhead.
priority: high
status: draft
node_type: leaf
code_language: typescript
target_impl_file: src/data/protocols.ts
test_status: not_written
created_at: 2026-03-21 17:07:58.494382
updated_at: 2026-03-21 18:21:24.812550
acceptance_criteria:
- APA102: 32 bits/LED (8 global + 24 color), SPI signal type
- Variable bit period (depends on SPI clock, default 8MHz = 125ns)
- No reset time
- SPI overhead: 32-bit start frame, ceil(N/2) end frame bits
- dataRateBps configurable (not fixed like one-wire)


id: NPC-ENG-TIMING
title: Core Timing Functions
priority: critical
status: draft
node_type: requirement
parent_id: NPC-ENGINE
test_status: not_written
created_at: 2026-03-21 17:08:02.563241
updated_at: 2026-03-21 17:08:02.563241
description:
Pure functions for calculating data transmission time, frame time, and timing breakdowns for any protocol.

acceptance_criteria:
- calcDataTimeUs(ledCount, protocol) -> microseconds of data transmission
- calcFrameTimeUs(ledCount, protocol) -> data time + reset time
- calcTimingBreakdown(ledCount, protocol, targetHz) -> {dataTimeUs, resetTimeUs, frameTimeUs, budgetTimeUs, idleTimeUs, utilizationPercent}
- One-wire: dataTime = bitsPerLed * bitPeriodNs * ledCount / 1000
- APA102: includes 32-bit start frame + ceil(N/2) end frame bits


id: NPC-ENG-MAXLED
title: Max LED Calculator
description: Calculate maximum LED count that fits within a target refresh rate budget.
priority: critical
status: draft
node_type: requirement
parent_id: NPC-ENGINE
test_status: not_written
created_at: 2026-03-21 17:08:04.594395
updated_at: 2026-03-21 17:08:04.594395
acceptance_criteria:
- calcMaxLeds(protocol, targetHz, maxBufferLeds?) -> number
- Formula: floor((1M/targetHz - resetTimeUs) / (bitsPerLed * bitPeriodNs / 1000))
- WS2812B @ 30Hz -> 1109 LEDs
- SK6812 RGBW @ 60Hz -> 414 LEDs
- Returns MaxLedsResult with limitingFactor (timing|buffer|protocol)


id: NPC-ENG-REFRESH
title: Refresh Rate Calculator
description: Calculate achievable refresh rate for a given LED count and protocol.
priority: critical
status: draft
node_type: requirement
parent_id: NPC-ENGINE
test_status: not_written
created_at: 2026-03-21 17:08:06.631003
updated_at: 2026-03-21 17:08:06.631003
acceptance_criteria:
- calcRefreshRate(ledCount, protocol) -> Hz
- Formula: 1_000_000 / frameTimeUs
- 300 WS2812B -> ~110.5 Hz
- 144 WS2812B -> ~185 Hz
- Returns RefreshRateResult with full timing breakdown


id: NPC-ENG-STRAND
title: Multi-Strand Optimizer
description: Distribute LEDs across available hardware channels to maximize aggregate refresh rate.
priority: high
status: draft
node_type: requirement
parent_id: NPC-ENGINE
test_status: not_written
created_at: 2026-03-21 17:08:08.658395
updated_at: 2026-03-21 17:08:08.658395
acceptance_criteria:
- optimizeStrandDistribution(totalLeds, protocol, profile) -> StrandPlanResult
- Filters channels by protocol signal type compatibility
- Even distribution: ceil(total / channelCount) per strand
- Identifies bottleneck strand (longest frame time)
- Aggregate refresh = 1M / max(frameTimeUs)
- 300 WS2812B on ESP32 (3 RMT) -> ~327 Hz


id: NPC-ENG-TIMING-OW
title: One-Wire Timing Math
description: Timing calculation for one-wire protocols (WS2812B, SK6812, WS2811).
priority: critical
status: draft
node_type: leaf
parent_id: NPC-ENG-TIMING
code_language: typescript
target_test_file: test/engine/timing.test.ts
target_impl_file: src/engine/timing.ts
test_status: not_written
created_at: 2026-03-21 17:08:10.696631
updated_at: 2026-03-21 17:48:44.121465
acceptance_criteria:
- dataTimeUs = (bitsPerLed * bitPeriodNs * ledCount) / 1_000_000
- frameTimeUs = dataTimeUs + resetTimeUs
- WS2812B 100 LEDs: dataTime = 24*1250*100/1e6 = 3000us, frame = 3050us
- SK6812W 100 LEDs: dataTime = 32*1250*100/1e6 = 4000us, frame = 4080us

test_spec:
GIVEN a one-wire protocol and LED count
WHEN calcDataTimeUs is called
THEN it returns bitsPerLed * bitPeriodNs * ledCount / 1e6
AND calcFrameTimeUs adds resetTimeUs


id: NPC-ENG-TIMING-SPI
title: SPI Protocol Timing Math
description: Timing calculation for SPI protocols (APA102) with frame overhead.
priority: high
status: draft
node_type: leaf
parent_id: NPC-ENG-TIMING
code_language: typescript
target_test_file: test/engine/timing.test.ts
target_impl_file: src/engine/timing.ts
test_status: not_written
created_at: 2026-03-21 17:08:12.745704
updated_at: 2026-03-21 17:08:12.745704
acceptance_criteria:
- totalBits = 32 + (32 * ledCount) + ceil(ledCount / 2)
- dataTimeUs = totalBits * bitPeriodNs / 1_000_000
- No reset time for APA102
- At 8MHz: 100 LEDs -> totalBits = 32 + 3200 + 50 = 3282, dataTime = 410.25us

test_spec:
GIVEN APA102 protocol with SPI clock and LED count
WHEN calcDataTimeUs is called
THEN it includes start frame (32 bits) + LED data + end frame (ceil(N/2) bits)


id: NPC-UI-SHARED
title: Shared UI Primitives
description: Reusable sub-components and styles shared across all three calculators.
priority: high
status: draft
node_type: requirement
parent_id: NPC-UI
test_status: not_written
created_at: 2026-03-21 17:08:14.778600
updated_at: 2026-03-21 17:08:14.778600
acceptance_criteria:
- <timing-bar> stacked horizontal bar: data (blue) | reset (yellow) | idle (green)
- <math-breakdown> expandable section with formula steps [{label, formula, value}]
- Shared CSS custom properties with --npc-* prefix and sensible defaults
- format.ts: number formatting (commas, Hz, microseconds, percentage)


id: NPC-UI-MAXLEDS
title: <neopixel-max-leds> Component
description: Web Component calculator for maximum LED count given protocol, strands, refresh rate, and hardware.
priority: critical
status: draft
node_type: requirement
parent_id: NPC-UI
test_status: not_written
created_at: 2026-03-21 17:08:16.812463
updated_at: 2026-03-21 17:08:16.812463
acceptance_criteria:
- Properties: protocol (string), strands (number), refresh-rate (number), hardware (string)
- Renders: dropdowns for protocol/hardware, number inputs for strands/refresh
- Shows: max LEDs per strand, total LEDs, utilization bar
- Expandable 'Show the math' with step-by-step formula
- Recalculates on any input change


id: NPC-UI-REFRESH
title: <neopixel-refresh-explorer> Component
description: Web Component with interactive slider showing achievable refresh rates for different LED counts.
priority: critical
status: draft
node_type: requirement
parent_id: NPC-UI
test_status: not_written
created_at: 2026-03-21 17:08:18.846059
updated_at: 2026-03-21 17:08:18.846059
acceptance_criteria:
- Properties: led-count (number), protocol (string), hardware (string)
- Range slider for LED count (1 to max) with real-time updates
- Large refresh rate display (Hz)
- Timing budget bar chart (data | reset | idle proportional segments)
- Reference table: common LED counts and their refresh rates


id: NPC-UI-PLANNER
title: <neopixel-strand-planner> Component
description: Web Component for planning multi-strand LED configurations across hardware outputs.
priority: high
status: draft
node_type: requirement
parent_id: NPC-UI
test_status: not_written
created_at: 2026-03-21 17:08:20.894519
updated_at: 2026-03-21 17:08:20.894519
acceptance_criteria:
- Properties: total-leds (number), protocol (string), hardware (string)
- Strand assignment table: channel ID, type, GPIO, LED count, data time, refresh rate
- Highlights bottleneck strand
- Aggregate refresh rate prominently displayed
- Input for total LED count with immediate recalculation


id: NPC-BLD-VITE
title: Vite Library Mode Config
description: Configure Vite to produce both ES module and UMD bundles with Lit bundled in.
priority: high
status: draft
node_type: requirement
parent_id: NPC-BUILD
test_status: not_written
created_at: 2026-03-21 17:08:22.931147
updated_at: 2026-03-21 17:08:22.931147
acceptance_criteria:
- vite.config.ts with lib entry, ES+UMD formats, es2021 target
- Lit NOT externalized (bundled for CDN use)
- Terser minification
- Output: dist/neopixel-command-calculator.{es,umd}.js
- package.json main/module/exports fields configured


id: NPC-BLD-CDN
title: CDN/Script Tag Verification
description: Verify the UMD bundle works when loaded via a plain <script> tag in a vanilla HTML page.
priority: high
status: draft
node_type: requirement
parent_id: NPC-BUILD
test_status: not_written
created_at: 2026-03-21 17:08:24.976039
updated_at: 2026-03-21 17:08:24.976039
acceptance_criteria:
- Plain HTML file loads UMD bundle via <script src>
- All three components render without errors
- No console errors about missing dependencies
- Components are interactive (inputs trigger recalculation)
- demo/index.html serves as reference


id: NPC-BLD-TEST
title: Test Infrastructure
description: Vitest setup for unit testing the calculation engine with known reference values.
priority: high
status: draft
node_type: requirement
parent_id: NPC-BUILD
test_status: not_written
created_at: 2026-03-21 17:08:27.010940
updated_at: 2026-03-21 17:08:27.010940
acceptance_criteria:
- vitest.config.ts with node environment (pure function tests)
- test/engine/timing.test.ts covering all timing functions
- test/engine/strand-optimizer.test.ts covering distribution
- Known reference values: WS2812B@30Hz=1109, SK6812W@60Hz=414
- npm run test passes all tests


# graph_layouts

name: __autosave__
description: Auto-saved working state
created_at: 2026-03-21 18:01:12.257033
updated_at: 2026-03-21 18:01:41.611884
node_positions:
{"NPC": {"x": 1767.0, "y": 31.0}, "NPC-DATA": {"x": 475.0, "y": 173.0}, "NPC-DATA-PROTO": {"x": 273.0, "y": 310.0}, "NPC-DATA-PROTO-WS": {"x": 71.0, "y": 437.0}, "NPC-DATA-PROTO-SK": {"x": 273.0, "y": 437.0}, "NPC-DATA-PROTO-APA": {"x": 475.0, "y": 437.0}, "NPC-DATA-HW": {"x": 677.0, "y": 310.0}, "NPC-DATA-HW-ESP32": {"x": 677.0, "y": 437.0}, "NPC-ENGINE": {"x": 1323.0, "y": 173.0}, "NPC-ENG-TIMING": {"x": 990.0, "y": 310.0}, "NPC-ENG-TIMING-OW": {"x": 889.0, "y": 437.0}, "NPC-ENG-TIMING-SPI": {"x": 1091.0, "y": 437.0}, "NPC-ENG-MAXLED": {"x": 1212.0, "y": 310.0}, "NPC-ENG-REFRESH": {"x": 1434.0, "y": 310.0}, "NPC-ENG-STRAND": {"x": 1656.0, "y": 310.0}, "NPC-UI": {"x": 2211.0, "y": 173.0}, "NPC-UI-SHARED": {"x": 1878.0, "y": 310.0}, "NPC-UI-MAXLEDS": {"x": 2100.0, "y": 310.0}, "NPC-UI-REFRESH": {"x": 2322.0, "y": 310.0}, "NPC-UI-PLANNER": {"x": 2544.0, "y": 310.0}, "NPC-BUILD": {"x": 2988.0, "y": 173.0}, "NPC-BLD-VITE": {"x": 2766.0, "y": 310.0}, "NPC-BLD-CDN": {"x": 2988.0, "y": 310.0}, "NPC-BLD-TEST": {"x": 3210.0, "y": 310.0}}

viewport:
{"zoom": 0.8868686868686869, "pan": {"x": -1199.6545454545455, "y": 150.07070707070704}, "selected_node_id": "NPC-ENG-STRAND", "panel_open": true}


