Update project files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
185
seed_npc.py
Normal file
185
seed_npc.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""Seed the req-planner DB with neopixel-command-calculator requirements."""
|
||||
import json
|
||||
import urllib.request
|
||||
|
||||
API = "http://localhost:8100/api"
|
||||
|
||||
def post(path, data):
|
||||
body = json.dumps(data).encode()
|
||||
req = urllib.request.Request(f"{API}/{path}", data=body, headers={
|
||||
"Content-Type": "application/json",
|
||||
"Authorization": f"Bearer {TOKEN}",
|
||||
})
|
||||
resp = urllib.request.urlopen(req)
|
||||
return json.loads(resp.read())
|
||||
|
||||
# Auth
|
||||
login = urllib.request.Request(f"{API}/auth/login",
|
||||
data=json.dumps({"password": "what_is_this_2"}).encode(),
|
||||
headers={"Content-Type": "application/json"})
|
||||
TOKEN = json.loads(urllib.request.urlopen(login).read())["token"]
|
||||
|
||||
# Project
|
||||
proj = post("projects", {
|
||||
"name": "neopixel-command-calculator",
|
||||
"description": "Engineering calculator for finding NeoPixel data transmission limits from single hardware sources. Web Components library (Lit + Vite) for CDN distribution.",
|
||||
"repo_url": "https://theres-a-git-in-this-tea.andrewawesomo.net/andrewadmin/neopixel-command-calculator",
|
||||
})
|
||||
PID = proj["id"]
|
||||
print(f"Project {PID}: {proj['name']}")
|
||||
|
||||
# Requirements data
|
||||
reqs = [
|
||||
# Root pillar
|
||||
{"id": "NPC", "title": "NeoPixel Command Calculator",
|
||||
"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.",
|
||||
"node_type": "pillar", "status": "draft", "priority": "critical", "project_id": PID,
|
||||
"acceptance_criteria": "- Library loadable via <script> tag with zero dependencies\n- Three calculator components render and produce correct results\n- Themeable via CSS custom properties\n- Engine functions usable programmatically without UI"},
|
||||
|
||||
# Sub-pillars
|
||||
{"id": "NPC-DATA", "title": "Protocol & Hardware Data Layer",
|
||||
"description": "Type-safe data definitions for LED protocols and hardware profiles. Source of truth for all timing calculations.",
|
||||
"node_type": "pillar", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC",
|
||||
"acceptance_criteria": "- All 6 protocols defined with verified timing specs\n- ESP32-WROOM-32D profile with all RMT/SPI channels\n- Data validates internally (bitPeriodNs matches dataRateBps)\n- Easy to add new protocols and hardware profiles"},
|
||||
|
||||
{"id": "NPC-ENGINE", "title": "Calculation Engine",
|
||||
"description": "Pure TypeScript functions for timing math, max LED calculation, refresh rate computation, and multi-strand optimization. No UI dependencies.",
|
||||
"node_type": "pillar", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC",
|
||||
"acceptance_criteria": "- All functions are pure (no side effects, no DOM)\n- Unit tested with known-good reference values\n- Handles edge cases (0 LEDs, impossible refresh rates)\n- Results match hand-calculated timing math"},
|
||||
|
||||
{"id": "NPC-UI", "title": "Web Components UI",
|
||||
"description": "Three Lit-based Web Components that wrap the calculation engine with interactive controls and visualizations.",
|
||||
"node_type": "pillar", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC",
|
||||
"acceptance_criteria": "- Three components register as custom elements\n- All inputs reactive (changes recalculate immediately)\n- Themeable via --npc-* CSS custom properties\n- Accessible (ARIA labels, keyboard navigation)\n- 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.",
|
||||
"node_type": "pillar", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC",
|
||||
"acceptance_criteria": "- ES and UMD bundles produced by npm run build\n- UMD bundle works via plain <script> tag\n- Lit bundled in (no peer dependency)\n- Bundle size reasonable (<100KB gzipped)"},
|
||||
|
||||
# DATA requirements
|
||||
{"id": "NPC-DATA-PROTO", "title": "LED Protocol Definitions",
|
||||
"description": "TypeScript interface and data for all supported LED protocols with timing specifications.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-DATA",
|
||||
"acceptance_criteria": "- ProtocolTiming interface with: id, name, signalType (one-wire|spi), bitsPerLed, colorOrder, bitPeriodNs, resetTimeUs, dataRateBps\n- SPI overhead fields for APA102 (startFrameBits, endFrameBitsPerLed)\n- 6 protocols: WS2812B, SK6812 RGB, SK6812 RGBW, WS2811 800kHz, WS2811 400kHz, APA102\n- Exported lookup functions: getProtocol(id), getAllProtocols()"},
|
||||
|
||||
{"id": "NPC-DATA-HW", "title": "Hardware Profile Definitions",
|
||||
"description": "TypeScript interface and data for microcontroller hardware profiles, starting with ESP32-WROOM-32D.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-DATA",
|
||||
"acceptance_criteria": "- HardwareProfile interface with: id, name, channels[], dmaBufferBytes, cpuFreqMhz\n- OutputChannel interface with: id, type (rmt|spi|i2s), supportedSignalTypes, defaultGpio\n- ESP32-WROOM-32D: 8 RMT channels + 2 SPI buses with GPIO mappings\n- Exported lookup: getProfile(id), getAllProfiles()"},
|
||||
|
||||
# DATA leaves
|
||||
{"id": "NPC-DATA-PROTO-WS", "title": "WS2812B / WS2811 Protocol Data",
|
||||
"description": "Timing definitions for WS2812B (800kHz) and WS2811 (800kHz + 400kHz variants).",
|
||||
"node_type": "leaf", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-DATA-PROTO",
|
||||
"acceptance_criteria": "- WS2812B: 24 bits/LED, 1250ns bit period, 50us reset, 800kbps, one-wire, GRB\n- WS2811 800kHz: same timing as WS2812B\n- WS2811 400kHz: 24 bits/LED, 2500ns bit period, 50us reset, 400kbps\n- Values match official datasheets",
|
||||
"code_language": "typescript", "target_impl_file": "src/data/protocols.ts"},
|
||||
|
||||
{"id": "NPC-DATA-PROTO-SK", "title": "SK6812 Protocol Data",
|
||||
"description": "Timing definitions for SK6812 RGB and SK6812 RGBW variants.",
|
||||
"node_type": "leaf", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-DATA-PROTO",
|
||||
"acceptance_criteria": "- SK6812 RGB: 24 bits/LED, 1250ns bit period, 80us reset, 800kbps, one-wire, GRB\n- SK6812 RGBW: 32 bits/LED, 1250ns bit period, 80us reset, 800kbps, one-wire, GRBW\n- Note the longer reset time vs WS2812B (80us vs 50us)",
|
||||
"code_language": "typescript", "target_impl_file": "src/data/protocols.ts"},
|
||||
|
||||
{"id": "NPC-DATA-PROTO-APA", "title": "APA102 Protocol Data",
|
||||
"description": "SPI-based APA102 protocol with configurable clock and frame overhead.",
|
||||
"node_type": "leaf", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-DATA-PROTO",
|
||||
"acceptance_criteria": "- APA102: 32 bits/LED (8 global + 24 color), SPI signal type\n- Variable bit period (depends on SPI clock, default 8MHz = 125ns)\n- No reset time\n- SPI overhead: 32-bit start frame, ceil(N/2) end frame bits\n- dataRateBps configurable (not fixed like one-wire)",
|
||||
"code_language": "typescript", "target_impl_file": "src/data/protocols.ts"},
|
||||
|
||||
{"id": "NPC-DATA-HW-ESP32", "title": "ESP32-WROOM-32D Profile",
|
||||
"description": "Complete hardware profile for the ESP32-WROOM-32D development board.",
|
||||
"node_type": "leaf", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-DATA-HW",
|
||||
"acceptance_criteria": "- 8 RMT channels (RMT0-7): one-wire support, GPIOs 16,17,18,19,21,22,23,25\n- 2 SPI buses: HSPI (GPIO 13 MOSI), VSPI (GPIO 23 MOSI)\n- DMA buffer: 4096 bytes per channel\n- CPU freq: 240 MHz\n- Notes about RMT memory sharing (8 x 64 words)",
|
||||
"code_language": "typescript", "target_impl_file": "src/data/hardware-profiles.ts"},
|
||||
|
||||
# ENGINE requirements
|
||||
{"id": "NPC-ENG-TIMING", "title": "Core Timing Functions",
|
||||
"description": "Pure functions for calculating data transmission time, frame time, and timing breakdowns for any protocol.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-ENGINE",
|
||||
"acceptance_criteria": "- calcDataTimeUs(ledCount, protocol) -> microseconds of data transmission\n- calcFrameTimeUs(ledCount, protocol) -> data time + reset time\n- calcTimingBreakdown(ledCount, protocol, targetHz) -> {dataTimeUs, resetTimeUs, frameTimeUs, budgetTimeUs, idleTimeUs, utilizationPercent}\n- One-wire: dataTime = bitsPerLed * bitPeriodNs * ledCount / 1000\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-ENGINE",
|
||||
"acceptance_criteria": "- calcMaxLeds(protocol, targetHz, maxBufferLeds?) -> number\n- Formula: floor((1M/targetHz - resetTimeUs) / (bitsPerLed * bitPeriodNs / 1000))\n- WS2812B @ 30Hz -> 1109 LEDs\n- SK6812 RGBW @ 60Hz -> 414 LEDs\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-ENGINE",
|
||||
"acceptance_criteria": "- calcRefreshRate(ledCount, protocol) -> Hz\n- Formula: 1_000_000 / frameTimeUs\n- 300 WS2812B -> ~110.5 Hz\n- 144 WS2812B -> ~185 Hz\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-ENGINE",
|
||||
"acceptance_criteria": "- optimizeStrandDistribution(totalLeds, protocol, profile) -> StrandPlanResult\n- Filters channels by protocol signal type compatibility\n- Even distribution: ceil(total / channelCount) per strand\n- Identifies bottleneck strand (longest frame time)\n- Aggregate refresh = 1M / max(frameTimeUs)\n- 300 WS2812B on ESP32 (3 RMT) -> ~327 Hz"},
|
||||
|
||||
# ENGINE leaves
|
||||
{"id": "NPC-ENG-TIMING-OW", "title": "One-Wire Timing Math",
|
||||
"description": "Timing calculation for one-wire protocols (WS2812B, SK6812, WS2811).",
|
||||
"node_type": "leaf", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-ENG-TIMING",
|
||||
"acceptance_criteria": "- dataTimeUs = (bitsPerLed * bitPeriodNs * ledCount) / 1_000_000\n- frameTimeUs = dataTimeUs + resetTimeUs\n- WS2812B 100 LEDs: dataTime = 24*1250*100/1e6 = 3000us, frame = 3050us\n- SK6812W 100 LEDs: dataTime = 32*1250*100/1e6 = 4000us, frame = 4080us",
|
||||
"code_language": "typescript", "target_impl_file": "src/engine/timing.ts", "target_test_file": "test/engine/timing.test.ts",
|
||||
"test_spec": "GIVEN a one-wire protocol and LED count\nWHEN calcDataTimeUs is called\nTHEN it returns bitsPerLed * bitPeriodNs * ledCount / 1e6\nAND calcFrameTimeUs adds resetTimeUs"},
|
||||
|
||||
{"id": "NPC-ENG-TIMING-SPI", "title": "SPI Protocol Timing Math",
|
||||
"description": "Timing calculation for SPI protocols (APA102) with frame overhead.",
|
||||
"node_type": "leaf", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-ENG-TIMING",
|
||||
"acceptance_criteria": "- totalBits = 32 + (32 * ledCount) + ceil(ledCount / 2)\n- dataTimeUs = totalBits * bitPeriodNs / 1_000_000\n- No reset time for APA102\n- At 8MHz: 100 LEDs -> totalBits = 32 + 3200 + 50 = 3282, dataTime = 410.25us",
|
||||
"code_language": "typescript", "target_impl_file": "src/engine/timing.ts", "target_test_file": "test/engine/timing.test.ts",
|
||||
"test_spec": "GIVEN APA102 protocol with SPI clock and LED count\nWHEN calcDataTimeUs is called\nTHEN it includes start frame (32 bits) + LED data + end frame (ceil(N/2) bits)"},
|
||||
|
||||
# UI requirements
|
||||
{"id": "NPC-UI-SHARED", "title": "Shared UI Primitives",
|
||||
"description": "Reusable sub-components and styles shared across all three calculators.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-UI",
|
||||
"acceptance_criteria": "- <timing-bar> stacked horizontal bar: data (blue) | reset (yellow) | idle (green)\n- <math-breakdown> expandable section with formula steps [{label, formula, value}]\n- Shared CSS custom properties with --npc-* prefix and sensible defaults\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-UI",
|
||||
"acceptance_criteria": "- Properties: protocol (string), strands (number), refresh-rate (number), hardware (string)\n- Renders: dropdowns for protocol/hardware, number inputs for strands/refresh\n- Shows: max LEDs per strand, total LEDs, utilization bar\n- Expandable 'Show the math' with step-by-step formula\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "critical", "project_id": PID, "parent_id": "NPC-UI",
|
||||
"acceptance_criteria": "- Properties: led-count (number), protocol (string), hardware (string)\n- Range slider for LED count (1 to max) with real-time updates\n- Large refresh rate display (Hz)\n- Timing budget bar chart (data | reset | idle proportional segments)\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-UI",
|
||||
"acceptance_criteria": "- Properties: total-leds (number), protocol (string), hardware (string)\n- Strand assignment table: channel ID, type, GPIO, LED count, data time, refresh rate\n- Highlights bottleneck strand\n- Aggregate refresh rate prominently displayed\n- Input for total LED count with immediate recalculation"},
|
||||
|
||||
# BUILD requirements
|
||||
{"id": "NPC-BLD-VITE", "title": "Vite Library Mode Config",
|
||||
"description": "Configure Vite to produce both ES module and UMD bundles with Lit bundled in.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-BUILD",
|
||||
"acceptance_criteria": "- vite.config.ts with lib entry, ES+UMD formats, es2021 target\n- Lit NOT externalized (bundled for CDN use)\n- Terser minification\n- Output: dist/neopixel-command-calculator.{es,umd}.js\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-BUILD",
|
||||
"acceptance_criteria": "- Plain HTML file loads UMD bundle via <script src>\n- All three components render without errors\n- No console errors about missing dependencies\n- Components are interactive (inputs trigger recalculation)\n- 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.",
|
||||
"node_type": "requirement", "status": "draft", "priority": "high", "project_id": PID, "parent_id": "NPC-BUILD",
|
||||
"acceptance_criteria": "- vitest.config.ts with node environment (pure function tests)\n- test/engine/timing.test.ts covering all timing functions\n- test/engine/strand-optimizer.test.ts covering distribution\n- Known reference values: WS2812B@30Hz=1109, SK6812W@60Hz=414\n- npm run test passes all tests"},
|
||||
]
|
||||
|
||||
for r in reqs:
|
||||
result = post("requirements", r)
|
||||
print(f" [{r['node_type'][0].upper()}] {r['id']}: {r['title']}")
|
||||
|
||||
# Satisfaction links
|
||||
links = [
|
||||
("NPC-UI-MAXLEDS", "NPC-ENG-MAXLED"),
|
||||
("NPC-UI-REFRESH", "NPC-ENG-REFRESH"),
|
||||
("NPC-UI-PLANNER", "NPC-ENG-STRAND"),
|
||||
("NPC-BLD-TEST", "NPC-ENGINE"),
|
||||
]
|
||||
for src, tgt in links:
|
||||
post("links", {"source_id": src, "target_id": tgt, "relationship_type": "also_satisfies"})
|
||||
print(f" Link: {src} -> {tgt}")
|
||||
|
||||
print(f"\nDone! {len(reqs)} requirements + {len(links)} satisfaction links created.")
|
||||
Reference in New Issue
Block a user