52 Commits

Author SHA1 Message Date
5db321c8e3 Add MCP chat reference architecture documentation
Comprehensive guide for building MCP-powered chat assistants with SSE
streaming, covering both Hamilton Archive (vanilla JS) and SpiceBook
(React + Zustand) implementations. Includes Caddy routing patterns,
security hardening checklist, and frontend lessons learned.
2026-02-23 14:26:05 -07:00
78350e02af Update docker-compose and astro config for chat/MCP integration
- Add ANTHROPIC_API_KEY env passthrough in docker-compose.yml
- Add astro telemetry and devToolbar disable settings
- Update CLAUDE.md with deployment notes
2026-02-23 14:25:58 -07:00
b89e520479 Consistent label offsets across all schematic layout engines
Add ofst=0.15 to all component labels for uniform clearance between
label text and component bodies. Previously, loop layout had no offsets,
grid layout was missing offsets on multi-terminal devices (BJT/FET), and
connected layout was missing offsets on transistor and horizontal labels.
2026-02-23 14:25:50 -07:00
6f239c185e Chat widget: markdown styling, KaTeX math rendering, SSE streaming fix
- Add comprehensive CSS for markdown elements in chat bubbles (headers,
  lists, tables, blockquotes, links, code blocks, horizontal rules)
- Integrate KaTeX via marked-katex-extension for inline ($) and display
  ($$) math rendering with DOMPurify whitelist for MathML/SVG elements
- Add normalizeDisplayMath() pre-processor to handle LLM output where $$
  delimiters appear inline rather than on their own lines
- Add dark theme KaTeX styles matching the SpiceBook color palette
- Fix asyncio.to_thread usage in chat SSE endpoint for streaming
2026-02-23 14:25:42 -07:00
99d1ca28d2 Add MCP server and chat assistant
- Mount FastMCP at /mcp with tools for notebook CRUD, simulation,
  and cell execution. Includes status resource and circuit_assistant
  prompt.
- Add SSE streaming chat endpoint at /api/chat/stream backed by
  GPU LLM gateway (qwen3). Chat widget sends notebook context
  (SPICE cells, markdown notes) so the assistant can reference the
  user's circuit.
- React floating chat panel with zustand-persisted conversation
  history, streaming token display, reasoning collapse, and
  keyboard shortcuts.
- Refactor main.py from deprecated on_event("startup") to lifespan
  context manager with combine_lifespans for MCP integration.
- Add notebook_id path traversal validation, decouple get_engine()
  from HTTPException for MCP compatibility, fix HTTP client init
  race condition with asyncio.Lock.
- Update Caddy labels for /mcp/* routing and SSE streaming on
  backend reverse proxy.
2026-02-22 16:49:15 -07:00
09fd59d570 Visual polish: card hover lift, gradient section dividers, editor spacing
- Cards (featured + gallery): hover adds -translate-y-1 + shadow-lg for
  subtle lift-off-surface effect
- Homepage sections: replace hard border-b with gradient-fade dividers
  that taper to transparent at edges
- Resistor button section: tighten vertical padding (py-10 → py-6)
- Notebook editor: cell spacing increased (space-y-0 → space-y-3),
  add-cell button slides up on hover instead of abrupt opacity flash,
  status bar gets more breathing room and lighter text
2026-02-21 15:28:08 -07:00
d65f23d6ee Add chevron-right to astro-icon include list
The 50Ω resistor button uses lucide:chevron-right which wasn't in the
explicit icon include list, causing SSR to crash mid-stream on the homepage.
2026-02-21 11:35:09 -07:00
26f9eb996e Move resistor color guide to /reference/resistor-colors, add 50Ω button on homepage
Promotes the full ResistorColorGuide component to a dedicated reference
page and replaces the homepage section with a compact inline SVG link
showing Green-Black-Black-Gold (50Ω ±5%) band colors.
2026-02-21 11:32:16 -07:00
0a9abd6771 Add flush_interval to prod frontend Caddy labels
Without flush_interval: -1, Caddy buffers SSR responses and can
truncate large pages (380KB homepage was cut to 70KB, dropping the
ResistorColorGuide section entirely).
2026-02-21 10:05:34 -07:00
5f5e0da3c4 Fix dev backend startup: use python -m uvicorn instead of uv run
uv pip install --system installs packages globally but uv run still
tries to create /app/.venv, which fails with permission denied.
Add PYTHONPATH=/app/src since the editable install .pth file is empty
when built without source directory present.
2026-02-21 09:17:03 -07:00
2ddc08cd3a Add schematic thumbnails, descriptions to notebook cards and resistor color guide
Notebook cards now show schematic SVG thumbnails (on Mims green background)
and description snippets extracted from the first markdown cell. The backend
extracts both from already-loaded notebook data at zero additional I/O cost.

New ResistorColorGuide section between the pipeline strip and featured
notebooks explains the 4-band color code with an annotated zigzag diagram
and reference table using the same BAND_HEX colors from the schematic renderer.

Also switches docker-compose.dev.yml from direct port mapping to Caddy labels,
matching the production routing pattern and avoiding port conflicts.
2026-02-21 08:56:48 -07:00
fe6d20afbd Add schematic pipeline step and fix vertical label spacing
Add ofst=0.15 to vertical resistor label calls preventing overlap with
color-coded zigzag bands. Add Schematic step 03 to homepage pipeline
with inline SVG voltage divider on Mims graph paper. Pipeline now
4-step with responsive 1col/2x2/4col layout.
2026-02-20 20:34:41 -07:00
65e7dbe68d Merge feature/color-coded-resistors: color-coded zigzag resistor symbols 2026-02-20 17:37:01 -07:00
7e10b87a13 Color-code resistor zigzag symbols with standard 4-band colors
Map physical resistor color bands onto the IEEE zigzag schematic symbol.
Each sub-segment is colored to match its band (digit, multiplier, tolerance),
with wire-colored entry/exit and a gap before tolerance mimicking real spacing.
Parseable values 0.01–1GΩ get color; parametric/out-of-range fall back to mono.
2026-02-20 17:36:50 -07:00
67bb47c0cd Fix oscilloscope CSS: use is:global for child component styles
Astro scopes <style> block imports to the authoring component.
Since OscilloscopeDisplay.astro is a child of index.astro, the
scoped selectors didn't match. Move the CSS import into the
component itself with is:global.
2026-02-20 16:31:20 -07:00
4b2ce896b5 Replace static hero scope with interactive XY-mode oscilloscope
Port the OscilloscopeDisplay from mcltspice docs — Web Audio API
renders stereo audio as Lissajous patterns on a canvas with teal
phosphor persistence. 6 tracks from Jerobeam Fenderson, volume
knob, skin switcher (465/545A), and the Outer Limits easter egg.

Audio: CC BY-NC-SA 4.0, oscilloscopemusic.com
Visual: Nick Watton (codepen.io/2Mogs), rsp2k
2026-02-20 16:25:13 -07:00
72cfd8191a Fix React hydration mismatch and clean up stale service workers
- Pin formatDate to timeZone: 'UTC' so server and client produce
  identical date strings (fixes React error #418)
- Add one-shot service worker unregistration since SpiceBook doesn't
  use one — clears phantom registrations from browser cache
2026-02-20 16:07:42 -07:00
3ee3cd6d8a Register arrow-right and check-circle-2 icons for pipeline strip
astro-icon requires explicit icon registration — these two were used
in PipelineStrip.astro but missing from the include list, causing
SSR render failures in production.
2026-02-20 15:31:21 -07:00
6350f15991 Merge homepage-redesign-show-dont-tell: animated scope hero, pipeline strip, featured notebooks 2026-02-20 15:26:31 -07:00
43789bdf24 Homepage redesign: show-don't-tell with animated scope hero
Restructure the homepage to lead with visuals instead of text:

- Hero: split layout with animated Tektronix 465 oscilloscope showing
  RC step response (CSS+SVG, zero JS) that links to the notebook
- Pipeline strip: 3-step Write → Simulate → Visualize with code/terminal
  previews and inline waveform SVG
- Featured notebooks: 3 curated circuits (RC, 555, common emitter) with
  pre-rendered waveform thumbnails
- Gallery cards: decorative graticule header strip, color-coded by engine
- Footer: updated copy with clearer call to action

All new sections are server-rendered Astro components. Total new client
JavaScript: zero bytes.
2026-02-20 15:16:53 -07:00
3c9c83742d Fix scope viewer: initialize div state from data range to prevent empty CRT
xDiv/yDiv were initialized as null and excluded from the main uPlot
effect's dependency array, causing the effect to bail on its null guard
and never re-run when the init effect set them to computed values.
2026-02-16 23:27:46 -07:00
ac82068b98 Merge feature/scope-skin: Tektronix oscilloscope waveform viewer 2026-02-15 18:11:21 -07:00
22d3e903db Add Tektronix oscilloscope skin for waveform viewer
Port 465/545A visual chrome from mcltspice docs into SpiceBook as a
toggleable waveform viewer skin. uPlot chart renders inside a CRT
screen with teal phosphor traces, graticule overlay, and scanlines.

Functional knobs control trace visibility (setSeries), X/Y zoom
(setScale) in standard 1-2-5 div steps. Digital readout bar shows
current trace, div values, and analysis type. Two switchable hardware
skins — 465 tan and 545A hammertone — persisted in localStorage.

New files: ScopeWaveformViewer.tsx, scope-skin.css
Modified: WaveformViewer.tsx (toggle), waveform-utils.ts (scope
palette, 1-2-5 sequence, stack-safe min/max), globals.css (scope vars)
2026-02-15 18:05:59 -07:00
b497d57890 Auto-generate schematics on mount, wire routing for grid layout
SPICE cells now auto-trigger schematic generation when they mount
without an existing diagram, so the schematic leads the UI. Template
and empty cells are skipped.

Grid fallback layout replaced with wire-connected rendering: BFS-based
node tier classification places components vertically between supply
and ground rails, then routes wires by node type (power/ground bus
rails, L-shaped signal wires, star topology for 3+ connections).
2026-02-15 14:40:25 -07:00
579f90487d Merge homepage-redesign: hero, features, categorized gallery 2026-02-14 20:46:49 -07:00
eae849fe7a Redesign homepage with hero, features, and categorized notebook gallery
SSR the notebook list in Astro frontmatter (eliminating the client-side
loading spinner). Add hero section with oscilloscope graticule background,
4-column feature highlights, and a React island gallery with category
filter pills, tag search, and grouped/flat view modes.
2026-02-14 20:45:24 -07:00
1e08be4409 Add /llms.txt API reference and POST /api/notebooks/compose endpoint
Machine-readable API docs at /llms.txt for LLM collaboration on circuit
design notebooks linked from Mims Electronics Reference Library.

Compose endpoint creates fully-populated notebooks in one call with
optional SPICE simulation. Per-cell try/except ensures partial simulation
failures don't lose the notebook.

Also extracts get_engine to spicebook.engine and makes
generate_notebook_id a public API.
2026-02-14 15:43:26 -07:00
c581786372 Add CLAUDE.md with deployment procedure and architecture notes 2026-02-14 13:34:15 -07:00
7d5d1b2d31 Use @fontsource/inter woff for OG renderer instead of broken TTF download
The Inter SemiBold TTF from GitHub was an HTML error page. Switch to
loading inter-latin-600-normal.woff from @fontsource/inter in
node_modules — always available, always valid, and Satori supports
woff natively.
2026-02-14 13:30:43 -07:00
db2ecf32c4 Fix font buffer slice and env var access for production SSR
Node.js Buffer pool shares an ArrayBuffer — slice to give Satori's
OpenType parser a standalone copy starting at byte 0. Use process.env
instead of import.meta.env for BACKEND_INTERNAL_URL since Vite only
exposes PUBLIC_* prefixed vars via import.meta.env.
2026-02-14 13:25:43 -07:00
ea66086b44 Remove named volume from prod compose, use bind mount for notebooks
The base docker-compose.yml already mounts ./notebooks:/app/notebooks.
The named Docker volume was shadowing it in prod, preventing example
notebooks from being visible. Bind mount ensures examples ship with
the repo and user notebooks persist on the host filesystem.
2026-02-14 13:16:18 -07:00
c9116c5d86 Add SEO meta tags, OG image generation, and astro-icon integration
Wire astro-seo-meta for OG, Twitter Card, and canonical tags on all
pages. Add Satori + resvg dynamic OG image endpoints at /og/[id].png
with branded dark-theme cards. Replace inline SVGs with zero-JS
astro-icon rendering. SSR fetches use 5s AbortController timeout and
shared ID validation across all dynamic routes.
2026-02-14 13:15:52 -07:00
99e47685aa Add Mims verification confirmation for embed bugfixes
All 4 embed bugs verified fixed by Mims library testing:
postMessage type sync, waveform theme colors, chart remount,
and shared component light-mode overrides. Thread closed.
2026-02-13 18:14:52 -07:00
e8ade01662 Fix embed integration bugs from Mims library testing
- postMessage type: 'theme-change' → 'spicebook-theme' to match
  SimulationEmbed.tsx namespace convention
- WaveformViewer: read axis/grid/tick colors from CSS custom
  properties via getComputedStyle instead of hardcoded dark hex
- Theme switch forces WaveformViewer remount via React key so
  uPlot picks up new CSS variable values
- Light-mode CSS overrides for shared components (SchematicViewer
  toolbar, SimulationLog borders, slate utility classes)
2026-02-13 16:31:32 -07:00
b0dc46edc2 Merge feature/schematic-phase1: schematics + Mims embed integration
Brings in auto-generated schematics from SPICE netlists with
click-to-edit values, graph paper backgrounds, and Mims-style
connected layout. Also adds embeddable notebook viewer for
cross-site iframe integration with the Mims library.
2026-02-13 15:46:43 -07:00
3f3ca58521 Add embeddable notebook viewer for Mims library integration
New /embed/[id] route renders notebooks in a read-only, chromeless
layout for iframe embedding. Supports light/dark themes via URL
param and postMessage from the parent window.

- EmbedLayout: minimal HTML shell, no navbar/footer
- EmbedViewer: fetches notebook, runs simulations, syncs theme
- EmbedCell: read-only markdown + SPICE cell renderer
- SpiceEditor: added readOnly prop (EditorState.readOnly + editable.of)
- embed-theme.css: light mode CSS variable overrides
- Astro middleware: CSP frame-ancestors on /embed/* routes
- Backend: env-configurable CORS origins, CSP header middleware

Security hardening from review:
- postMessage origin validation (ALLOWED_MESSAGE_ORIGINS)
- markdown XSS fix: isSafeUrl() blocks javascript: URIs in links
- escapeHtml now covers single quotes
- Notebook ID validated against /^[a-zA-Z0-9_-]+$/
- Theme param normalized at Astro boundary
- classList.remove/add instead of className stomping
2026-02-13 15:46:37 -07:00
a8c53f34f4 Add click-to-edit schematic values and DOMPurify sanitization
SchematicViewer now supports inline editing of component values
directly on the SVG. Clicking an editable value opens an overlay
input that updates the SPICE netlist on commit, triggering an
auto-redraw after 800ms debounce.

Added DOMPurify for SVG sanitization, netlist-utils for safe
value substitution in netlists, and wired schematic generation
through the notebook store with generation counters to discard
stale responses.
2026-02-13 15:46:14 -07:00
4f174e9d0f Add Mims-style graph paper background to schematics
Sage-green grid (minor 10pt, major 50pt) on warm off-white canvas,
injected as nested SVG patterns behind all schematic content.
Works across all three renderers (loop, connected, grid).
2026-02-13 09:14:52 -07:00
c120a179c8 Improve connected schematic label placement (Mims-style)
- Add lead stub wires (0.75 unit) from collector and emitter pins
  for clearance between transistor and first component
- Transistor label placed right of body, all chain labels on left
- Offset parallel paths (RE/CE) label on right, facing outward
- Wider parallel path spacing (2.5 units) for label breathing room
- Down-turning components label outward based on path direction
- Parameterized label_loc in _draw_vert_chain for context-aware placement
2026-02-13 08:43:11 -07:00
4bc68a58bd Add connected schematic layout for single-active-device circuits
Replace the disconnected grid fallback with a topology-aware renderer
that places BJTs/MOSFETs at center and draws connected wire paths using
SchemDraw push/pop for branching at junction points.

Layout pipeline: trace component chains from each device terminal,
classify paths by direction (supply/ground/input/output), draw with
proper Vdd/Ground terminators and junction dots at branch points.

Fallback cascade: loop → connected → grid. Supply sources shown as Vdd
rail symbols; signal sources drawn inline as SourceV in input paths.
2026-02-13 07:18:50 -07:00
de7a29c69e Add auto-schematic generation from SPICE netlists
Parse netlists into component graphs and render circuit diagrams via
SchemDraw. Two layout strategies: loop layout for simple 2-terminal
circuits (RC, RL, voltage divider) and labeled grid for complex
circuits with active devices (BJT amplifiers, MOSFET).

Backend: netlist parser, schematic engine, POST API endpoint.
Frontend: SchematicViewer with zoom/download, stacked cell layout
showing schematic + SPICE editor + waveform simultaneously.
2026-02-13 06:07:30 -07:00
42f4428295 Add 7 advanced example notebooks with real-world circuits
Buck converter, Class AB amplifier, AM radio receiver, Dickson
charge pump, transmission line signal integrity, 4th-order
Sallen-Key filter, and Colpitts RF oscillator. Multi-cell
notebooks with engineering narratives and multiple simulation
views per circuit.
2026-02-13 04:29:33 -07:00
da3532c1aa Add example notebook population script
Creates 8 curated example notebooks via the API:
- RC Lowpass Filter (AC analysis)
- Voltage Divider (DC operating point)
- RC Step Response (transient)
- RLC Bandpass Filter (AC analysis)
- Diode Half-Wave Rectifier (transient)
- LED I-V Characteristic (DC sweep)
- Inverting Op-Amp Amplifier (transient)
- CMOS Inverter (DC transfer characteristic)
2026-02-13 03:55:55 -07:00
9b2737ef77 Set PUBLIC_API_URL at build time for production
Vite inlines import.meta.env.PUBLIC_* at build time, not runtime.
Without this, the frontend falls back to localhost:8099 which doesn't
exist from the browser. Empty string means same-origin requests,
letting Caddy route /api/* to the backend.
2026-02-13 03:45:23 -07:00
fb5b911ea1 Use named volume for notebooks in production
Bind mounts inherit host UID which conflicts with the container's
non-root user. Named volumes are initialized from the image layer,
preserving the chown from the Dockerfile.
2026-02-13 03:43:09 -07:00
7ffd3f1bd3 Fix notebook directory permissions for non-root user
Pre-create /app/notebooks/{user,examples} with correct ownership
before switching to the spicebook user. Without this, the app crashes
with PermissionError when it tries to create these directories at
runtime.
2026-02-13 03:41:42 -07:00
a24375accb Fix Docker build: remove missing readme ref, disable astro telemetry 2026-02-13 03:39:00 -07:00
5aa36b252a Remove unsupported --no-editable flag from backend Dockerfile 2026-02-13 03:38:08 -07:00
4600a7b0a9 Production deployment: SSR frontend, Caddy path routing
Update frontend Dockerfile prod stage from Caddy static to Node.js
running Astro SSR server. Configure caddy-docker-proxy labels to
route /api/* to backend and everything else to frontend on the same
domain. Support empty PUBLIC_API_URL for same-origin API calls.
2026-02-13 03:37:14 -07:00
5a2c5730c0 Add project README and screenshots
Document architecture, features, quick start, file format, API
endpoints, configuration, roadmap, and tech stack. Include screenshots
of the notebook with AC Bode plot and transient step response.
2026-02-13 02:33:13 -07:00