Add Starlight docs site with API reference, guides, and embedding docs

Starlight site at docs-site/ following warehack.ing cookie-cutter pattern
(3-compose split, Caddy prod stage, Makefile targets). 15 content pages
covering simulation engines, waveform viewer, schematics, embedding with
postMessage theme sync, and full REST API reference adapted from llms.txt.
Blue accent theme matching SpiceBook's application palette. Adds docs link
to homepage reference section.
This commit is contained in:
Ryan Malloy 2026-03-06 11:55:21 -07:00
parent b96f11b4af
commit ad7e80c722
32 changed files with 9662 additions and 0 deletions

6
docs-site/.dockerignore Normal file
View File

@ -0,0 +1,6 @@
node_modules
dist
.astro
.env
.git
*.md

10
docs-site/.env.example Normal file
View File

@ -0,0 +1,10 @@
# SpiceBook docs environment configuration
COMPOSE_PROJECT_NAME=spicebook-docs
# MODE: dev | prod
MODE=dev
# Domain configuration
DOMAIN=spicebook-docs.l.warehack.ing
# Production: spicebook-docs.warehack.ing
# Dev (local): spicebook-docs.l.warehack.ing

4
docs-site/.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
node_modules/
dist/
.astro/
.env

68
docs-site/Dockerfile Normal file
View File

@ -0,0 +1,68 @@
# ── Dev target ────────────────────────────────────────────────
FROM node:22-slim AS dev
WORKDIR /app
COPY package*.json ./
COPY patches/ patches/
RUN npm ci
COPY . .
EXPOSE 4321
CMD ["npm", "run", "dev"]
# ── Prod build stage ─────────────────────────────────────────
FROM node:22-slim AS build
WORKDIR /app
COPY package*.json ./
COPY patches/ patches/
RUN npm ci
COPY . .
RUN npm run build
# ── Prod serve stage ─────────────────────────────────────────
FROM caddy:2-alpine AS prod
RUN addgroup -g 1001 -S app && \
adduser -S app -u 1001 -G app
COPY --from=build /app/dist /srv
COPY <<'CADDYFILE' /etc/caddy/Caddyfile
:8080 {
root * /srv
file_server
encode gzip zstd
header {
X-Content-Type-Options nosniff
X-Frame-Options DENY
Referrer-Policy strict-origin-when-cross-origin
Cache-Control "public, max-age=31536000, immutable"
}
handle /health {
respond "ok" 200
}
handle_errors {
rewrite * /404.html
file_server
}
}
CADDYFILE
RUN chown -R app:app /srv
USER app
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
CMD wget -qO- http://127.0.0.1:8080/health || exit 1
CMD ["caddy", "run", "--config", "/etc/caddy/Caddyfile"]

50
docs-site/Makefile Normal file
View File

@ -0,0 +1,50 @@
include .env
export
COMPOSE_BASE := docker compose -f docker-compose.yml -f docker-compose.$(MODE).yml
.PHONY: dev prod build logs stop clean restart status help
## dev: start in dev mode with HMR and follow logs
dev:
@echo "Starting dev on $(DOMAIN) ..."
MODE=dev docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build -d
MODE=dev docker compose -f docker-compose.yml -f docker-compose.dev.yml logs -f
## prod: build and start in production mode
prod:
@echo "Deploying prod on $(DOMAIN) ..."
MODE=prod docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d
MODE=prod docker compose -f docker-compose.yml -f docker-compose.prod.yml logs --tail=40
## build: build containers using current MODE from .env
build:
$(COMPOSE_BASE) build
## logs: follow container logs
logs:
$(COMPOSE_BASE) logs -f
## stop: stop containers
stop:
$(COMPOSE_BASE) down
## down: alias for stop
down: stop
## restart: rebuild and restart
restart: stop
$(COMPOSE_BASE) up --build -d
$(COMPOSE_BASE) logs --tail=20
## clean: stop, remove volumes and local images
clean:
$(COMPOSE_BASE) down -v --rmi local
## status: show running container status
status:
$(COMPOSE_BASE) ps
## help: show available targets
help:
@grep '^## ' Makefile | sed 's/^## //' | column -t -s ':'

View File

@ -0,0 +1,79 @@
import { defineConfig } from 'astro/config';
import starlight from '@astrojs/starlight';
import tailwindcss from '@tailwindcss/vite';
export default defineConfig({
site: 'https://spicebook-docs.warehack.ing',
telemetry: false,
devToolbar: { enabled: false },
integrations: [
starlight({
title: 'SpiceBook',
tagline: 'Circuit simulation notebooks',
social: [
{ icon: 'external', label: 'SpiceBook', href: 'https://spicebook.warehack.ing' },
{ icon: 'external', label: 'mcltspice', href: 'https://mcltspice.warehack.ing' },
],
customCss: ['./src/styles/custom.css'],
expressiveCode: {
themes: ['dracula', 'github-light'],
},
sidebar: [
{
label: 'Getting Started',
items: [
{ label: 'What is SpiceBook?', slug: '' },
{ label: 'Quick Start', slug: 'getting-started/quick-start' },
{ label: 'Editor Basics', slug: 'getting-started/editor-basics' },
],
},
{
label: 'Simulation',
items: [
{ label: 'Engines', slug: 'simulation/engines' },
{ label: 'Running Simulations', slug: 'simulation/running' },
{ label: 'Waveform Viewer', slug: 'simulation/waveforms' },
],
},
{
label: 'Schematics',
items: [
{ label: 'Auto-Generated Diagrams', slug: 'schematics/auto-generated' },
{ label: 'Color-Coded Resistors', slug: 'schematics/resistor-colors' },
],
},
{
label: 'Embedding',
items: [
{ label: 'Embed a Notebook', slug: 'embedding/embed-notebook' },
{ label: 'Theme Sync', slug: 'embedding/theme-sync' },
],
},
{
label: 'API',
collapsed: false,
items: [
{ label: 'REST API Overview', slug: 'api/overview' },
{ label: 'Notebooks', slug: 'api/notebooks' },
{ label: 'Cells', slug: 'api/cells' },
{ label: 'Simulation', slug: 'api/simulation' },
{ label: 'Waveforms & Schematics', slug: 'api/waveforms-schematics' },
],
},
],
}),
],
vite: {
plugins: [tailwindcss()],
server: {
host: '0.0.0.0',
...(process.env.VITE_HMR_HOST && {
hmr: {
host: process.env.VITE_HMR_HOST,
protocol: 'wss',
clientPort: 443,
},
}),
},
},
});

View File

@ -0,0 +1,19 @@
services:
docs:
environment:
- VITE_HMR_HOST=${DOMAIN}
volumes:
- ./src:/app/src
- ./public:/app/public
- ./astro.config.mjs:/app/astro.config.mjs
labels:
caddy.reverse_proxy: "{{upstreams 4321}}"
# HMR WebSocket support -- keeps Vite hot-reload alive through Caddy
caddy.reverse_proxy.flush_interval: "-1"
caddy.reverse_proxy.transport: http
caddy.reverse_proxy.transport.read_timeout: "0"
caddy.reverse_proxy.transport.write_timeout: "0"
caddy.reverse_proxy.transport.keepalive: "5m"
caddy.reverse_proxy.transport.keepalive_idle_conns: "10"
caddy.reverse_proxy.stream_timeout: "24h"
caddy.reverse_proxy.stream_close_delay: "5s"

View File

@ -0,0 +1,15 @@
services:
docs:
labels:
caddy.reverse_proxy: "{{upstreams 8080}}"
caddy.header.Cache-Control: "public, max-age=31536000, immutable"
caddy.header.X-Content-Type-Options: nosniff
caddy.header.X-Frame-Options: DENY
caddy.header.Referrer-Policy: strict-origin-when-cross-origin
security_opt:
- no-new-privileges:true
read_only: true
tmpfs:
- /tmp:noexec,nosuid,size=50m
- /config/caddy:size=10m
- /data/caddy:size=10m

View File

@ -0,0 +1,24 @@
services:
docs:
build:
context: .
dockerfile: Dockerfile
target: ${MODE:-dev}
container_name: spicebook-docs
restart: unless-stopped
environment:
- ASTRO_TELEMETRY_DISABLED=1
networks:
- caddy
labels:
caddy: ${DOMAIN}
caddy.encode: gzip
logging:
driver: json-file
options:
max-size: "5m"
max-file: "3"
networks:
caddy:
external: true

7988
docs-site/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

19
docs-site/package.json Normal file
View File

@ -0,0 +1,19 @@
{
"name": "spicebook-docs",
"type": "module",
"private": true,
"scripts": {
"postinstall": "node patches/fix-starlight-head.mjs",
"dev": "astro dev --host 0.0.0.0",
"build": "astro build",
"preview": "astro preview --host 0.0.0.0"
},
"dependencies": {
"astro": "^5.17.2",
"@astrojs/starlight": "^0.37.6",
"@astrojs/starlight-tailwind": "^4.0.2",
"@tailwindcss/vite": "^4.1.0",
"tailwindcss": "^4.1.0",
"sharp": "^0.33.0"
}
}

View File

@ -0,0 +1,35 @@
/**
* Patches @astrojs/starlight to handle undefined `data.head` in frontmatter.
*
* Starlight 0.37.x assumes docsSchema() defaults `head` to [] via Zod, but
* the content loader doesn't always apply this default, causing:
* "Cannot read properties of undefined (reading 'some')"
*
* This adds a nullish coalescing fallback: `data.head ?? []`
*/
import { readFileSync, writeFileSync } from 'node:fs';
const file = 'node_modules/@astrojs/starlight/utils/head.ts';
try {
let src = readFileSync(file, 'utf8');
const target = 'config.head, data.head)';
const replacement = 'config.head, data.head ?? [])';
if (src.includes(replacement)) {
console.log('[patch] head.ts already patched, skipping.');
process.exit(0);
}
if (!src.includes(target)) {
console.warn('[patch] Could not find target string in head.ts — Starlight may have been updated.');
process.exit(0);
}
src = src.replace(target, replacement);
writeFileSync(file, src, 'utf8');
console.log('[patch] Patched head.ts: data.head ?? []');
} catch (err) {
console.warn('[patch] Could not patch head.ts:', err.message);
}

View File

@ -0,0 +1,4 @@
User-agent: *
Allow: /
Sitemap: https://spicebook-docs.warehack.ing/sitemap-index.xml

View File

@ -0,0 +1,7 @@
import { defineCollection } from 'astro:content';
import { docsLoader } from '@astrojs/starlight/loaders';
import { docsSchema } from '@astrojs/starlight/schema';
export const collections = {
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
};

View File

@ -0,0 +1,120 @@
---
title: Cells
description: Add, update, delete, and reorder cells within SpiceBook notebooks via the REST API.
---
import { Aside } from '@astrojs/starlight/components';
Cells are ordered elements within a notebook. Each cell has a `type` and `source` (text content). The API lets you manipulate cells individually without replacing the entire notebook.
## Cell Types
| Type | Description |
|------|-------------|
| `markdown` | Documentation text, rendered as formatted markdown |
| `spice` | SPICE netlist, executable via the simulation endpoints |
| `python` | Python code (execution planned for future release) |
| `schematic` | Auto-generated circuit diagram (read-only display) |
## Add Cell
```
POST /api/notebooks/{notebook_id}/cells
```
**Request body:**
```json
{
"type": "spice",
"source": "V1 1 0 DC 5\nR1 1 0 1k\n.op\n.end",
"after_cell_id": "cell-a1b2c3d4e5f6"
}
```
`after_cell_id` is optional — omit it to append the cell at the end.
**Response** `201`:
```json
{
"id": "cell-b2c3d4e5f6a7",
"type": "spice",
"source": "V1 1 0 DC 5\nR1 1 0 1k\n.op\n.end",
"outputs": []
}
```
## Update Cell
```
PUT /api/notebooks/{notebook_id}/cells/{cell_id}
```
**Request body:**
```json
{
"source": "V1 1 0 DC 10\nR1 1 0 2k\n.op\n.end",
"type": "spice"
}
```
Both fields are optional — only provided fields are updated. Changing `source` does not automatically re-run the simulation; call the [run endpoint](/api/simulation/#run-cell-in-notebook) to execute.
**Response** `200` — updated cell object.
## Delete Cell
```
DELETE /api/notebooks/{notebook_id}/cells/{cell_id}
```
**Response** `204` — no content.
## Reorder Cells
```
PUT /api/notebooks/{notebook_id}/cells/reorder
```
**Request body:**
```json
{
"cell_ids": ["cell-b2c3d4e5f6a7", "cell-a1b2c3d4e5f6"]
}
```
The array must include every cell ID in the notebook exactly once. This replaces the cell order entirely.
**Response** `200` — array of cell objects in the new order.
<Aside type="note">
Cell IDs are generated server-side and are stable — they don't change when cells are reordered or when other cells are added/removed.
</Aside>
## Cell Data Model
```json
{
"id": "cell-a1b2c3d4e5f6",
"type": "spice",
"source": "V1 1 0 DC 5\n.op\n.end",
"outputs": [
{
"output_type": "simulation_result",
"data": {
"success": true,
"waveform": { "..." },
"log": "...",
"error": null,
"elapsed_seconds": 0.3
},
"timestamp": "2026-02-13T18:35:00+00:00"
}
]
}
```
The `outputs` array contains results from previous simulation runs. Each entry includes a timestamp so you can track when the cell was last executed.

View File

@ -0,0 +1,149 @@
---
title: Notebooks
description: Create, read, update, delete, and compose SpiceBook notebooks via the REST API.
---
import { Aside } from '@astrojs/starlight/components';
## List Notebooks
```
GET /api/notebooks
```
Returns an array of notebook summaries:
```json
[
{
"id": "rc-low-pass-a1b2c3d4",
"title": "RC Low-Pass Filter",
"engine": "ngspice",
"tags": ["filter", "rc"],
"cell_count": 3,
"modified": "2026-02-13T18:30:00+00:00"
}
]
```
## Create Notebook
```
POST /api/notebooks
```
**Request body:**
```json
{
"title": "My Circuit",
"engine": "ngspice"
}
```
Both fields are optional. Defaults: title = `"Untitled Notebook"`, engine = `"ngspice"`. Supported engines: `"ngspice"`, `"ltspice"`.
**Response** `201` — the full notebook with an auto-generated `id`:
```json
{
"id": "my-circuit-f8e2a91b",
"spicebook_version": "2026-02-13",
"metadata": {
"title": "My Circuit",
"engine": "ngspice",
"tags": [],
"created": "2026-02-13T18:30:00+00:00",
"modified": "2026-02-13T18:30:00+00:00"
},
"cells": [
{
"id": "cell-a1b2c3d4e5f6",
"type": "markdown",
"source": "# My Circuit\n\nAdd SPICE cells below to begin simulating.",
"outputs": []
}
]
}
```
New notebooks start with a single markdown cell containing a heading.
## Get Notebook
```
GET /api/notebooks/{notebook_id}
```
**Response** `200` — full notebook object (same shape as the create response, without the top-level `id` wrapper).
## Update Notebook
```
PUT /api/notebooks/{notebook_id}
```
**Request body** — full notebook object. This replaces the entire notebook, including all cells and metadata.
**Response** `200` — the saved notebook.
## Delete Notebook
```
DELETE /api/notebooks/{notebook_id}
```
**Response** `204` — no content.
<Aside type="caution">
Only user-created notebooks can be deleted. Built-in example notebooks return a `403` error.
</Aside>
## Compose Notebook
```
POST /api/notebooks/compose
```
Creates a fully-populated notebook with multiple cells in a single call. This is the preferred way to create notebooks programmatically.
**Request body:**
```json
{
"title": "RC Low-Pass Filter",
"engine": "ngspice",
"tags": ["filter", "rc", "analog"],
"cells": [
{
"type": "markdown",
"source": "# RC Low-Pass Filter\n\nA simple first-order low-pass filter."
},
{
"type": "spice",
"source": "V1 in 0 AC 1\nR1 in out 1k\nC1 out 0 1u\n.ac dec 100 1 1meg\n.end"
},
{
"type": "markdown",
"source": "## Analysis\n\nThe -3dB cutoff is at f = 1/(2*pi*R*C) = 159 Hz."
}
],
"run": false
}
```
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `title` | string | `"Untitled Notebook"` | Notebook title |
| `engine` | string | `"ngspice"` | Simulation engine |
| `tags` | string[] | `[]` | Searchable tags |
| `cells` | object[] | (required) | Cells to create, each with `type` and `source` |
| `run` | boolean | `false` | If `true`, execute each SPICE cell after creation |
**Response** `201` — same shape as `POST /api/notebooks`.
When `run` is `true`, each SPICE cell is executed sequentially using the notebook's engine. Simulation results are stored in each cell's `outputs` array. Non-SPICE cells are unaffected.
<Aside type="tip">
The compose endpoint is what [mcltspice](https://mcltspice.warehack.ing) uses to publish simulation results as SpiceBook notebooks. Pass `run: true` to auto-execute all SPICE cells on creation.
</Aside>

View File

@ -0,0 +1,66 @@
---
title: REST API Overview
description: SpiceBook REST API basics — base URL, response format, and endpoint structure.
---
import { LinkCard, CardGrid, Aside } from '@astrojs/starlight/components';
SpiceBook exposes a REST API for programmatic access to notebooks, simulation, and rendering. All endpoints accept and return JSON unless noted otherwise.
## Base URL
```
https://spicebook.warehack.ing/api
```
All endpoint paths below are relative to this base.
## Authentication
None. The API is open — no API keys or tokens are required. This makes it straightforward to integrate with scripts, CI pipelines, or AI assistants like [mcltspice](https://mcltspice.warehack.ing).
## Response Format
Successful responses return JSON with the appropriate HTTP status code (`200`, `201`, or `204`). Error responses include a detail message:
```json
{
"detail": "Notebook not found"
}
```
Common status codes:
| Code | Meaning |
|------|---------|
| `200` | Success |
| `201` | Created (new notebook or cell) |
| `204` | Deleted (no response body) |
| `404` | Resource not found |
| `422` | Validation error (malformed request body) |
| `500` | Internal server error (simulation crash, etc.) |
## Health Check
```
GET /health
```
Returns the API version and status:
```json
{"status": "ok", "version": "2026.02.13"}
```
## Endpoint Groups
<CardGrid>
<LinkCard title="Notebooks" description="Create, read, update, delete, and compose notebooks." href="/api/notebooks/" />
<LinkCard title="Cells" description="Add, update, delete, and reorder cells within notebooks." href="/api/cells/" />
<LinkCard title="Simulation" description="Run SPICE netlists standalone or within notebook cells." href="/api/simulation/" />
<LinkCard title="Waveforms & Schematics" description="Generate SVG plots and circuit diagrams." href="/api/waveforms-schematics/" />
</CardGrid>
<Aside type="tip">
The SpiceBook backend also serves interactive API docs at [`/docs`](https://spicebook.warehack.ing/docs) (Swagger UI) and [`/openapi.json`](https://spicebook.warehack.ing/openapi.json) (OpenAPI spec).
</Aside>

View File

@ -0,0 +1,113 @@
---
title: Simulation
description: Run SPICE netlists standalone or within notebook cells via the SpiceBook REST API.
---
import { Aside } from '@astrojs/starlight/components';
## Run Standalone Simulation
```
POST /api/simulate
```
Run a SPICE netlist without creating or modifying a notebook. Useful for one-off simulations or integration testing.
**Request body:**
```json
{
"netlist": "V1 1 0 DC 5\nR1 1 2 1k\nR2 2 0 2k\n.op\n.end",
"engine": "ngspice"
}
```
**Response** `200`:
```json
{
"success": true,
"waveform": {
"variables": [
{"name": "v(1)", "type": "voltage"},
{"name": "v(2)", "type": "voltage"}
],
"points": 1,
"x_data": [0.0],
"y_data": {"v(1)": [5.0], "v(2)": [3.333]},
"x_type": "time",
"is_complex": false,
"y_magnitude_db": null,
"y_phase_deg": null
},
"log": "ngspice output...",
"error": null,
"elapsed_seconds": 0.42
}
```
## Run Cell in Notebook
```
POST /api/notebooks/{notebook_id}/cells/{cell_id}/run
```
No request body. Uses the cell's `source` as the netlist and the notebook's `engine` setting.
**Response** `200` — same `SimulationResponse` shape as standalone. The cell's `outputs` array is updated in the saved notebook.
## SimulationResponse
| Field | Type | Description |
|-------|------|-------------|
| `success` | boolean | Whether the simulation completed without errors |
| `waveform` | WaveformData \| null | Simulation results (null if simulation failed) |
| `log` | string | Raw simulator output (stdout/stderr) |
| `error` | string \| null | Error message if simulation failed |
| `elapsed_seconds` | number | Wall-clock simulation time |
## WaveformData
```json
{
"variables": [{"name": "v(out)", "type": "voltage"}],
"points": 100,
"x_data": [0.0, 0.001, ...],
"y_data": {"v(out)": [0.0, 0.5, ...]},
"x_type": "time",
"is_complex": false,
"y_magnitude_db": null,
"y_phase_deg": null
}
```
| Field | Type | Description |
|-------|------|-------------|
| `variables` | array | Signal names and types (voltage, current) |
| `points` | integer | Number of data points |
| `x_data` | number[] | Horizontal axis values (time or frequency) |
| `y_data` | object | Signal name → value array mapping |
| `x_type` | string | `"time"` or `"frequency"` |
| `is_complex` | boolean | `true` for AC analysis |
| `y_magnitude_db` | object \| null | Per-signal magnitude in dB (AC only) |
| `y_phase_deg` | object \| null | Per-signal phase in degrees (AC only) |
<Aside type="note">
For AC analysis (`is_complex: true`), use `y_magnitude_db` and `y_phase_deg` for Bode plots rather than `y_data`. The `x_type` will be `"frequency"` and `x_data` contains frequency values in Hz.
</Aside>
## Error Handling
When a simulation fails (syntax error, convergence failure, missing model), the response still returns `200` but with `success: false`:
```json
{
"success": false,
"waveform": null,
"log": "Error: unknown subcircuit...",
"error": "Simulation failed: unknown subcircuit 'LM741'",
"elapsed_seconds": 0.1
}
```
Check the `log` field for the full simulator output — it often contains line numbers and detailed diagnostics that aren't in the `error` summary.

View File

@ -0,0 +1,129 @@
---
title: Waveforms & Schematics
description: Generate SVG waveform plots and circuit schematic diagrams via the SpiceBook REST API.
---
import { Aside } from '@astrojs/starlight/components';
## Generate Waveform SVG (JSON-Wrapped)
```
POST /api/waveforms/svg
```
Renders waveform data as an SVG plot, returned inside a JSON wrapper.
**Request body:**
```json
{
"waveform": { "...WaveformData from simulation response..." },
"title": "Output Voltage",
"width": 800,
"height": 500,
"signals": ["v(2)"]
}
```
| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `waveform` | WaveformData | (required) | Simulation result data |
| `title` | string | `""` | Plot title |
| `width` | integer | `800` | SVG width in pixels |
| `height` | integer | `500` | SVG height in pixels |
| `signals` | string[] | all | Signals to include in the plot |
**Response** `200`:
```json
{
"svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" ...>...</svg>"
}
```
## Generate Waveform SVG (Raw)
```
POST /api/waveforms/svg/raw
```
Same request body as above, but returns the raw SVG string with `Content-Type: image/svg+xml`. Useful for piping directly to a file:
```bash
curl -X POST https://spicebook.warehack.ing/api/waveforms/svg/raw \
-H "Content-Type: application/json" \
-d '{
"waveform": { ...waveform data... },
"title": "DC Sweep",
"signals": ["v(2)"]
}' \
-o plot.svg
```
## Generate Schematic
```
POST /api/notebooks/{notebook_id}/cells/{cell_id}/schematic
```
No request body. The cell must be type `spice`. Parses the cell's netlist and renders a circuit diagram.
**Response** `200`:
```json
{
"svg": "<svg xmlns=\"http://www.w3.org/2000/svg\" ...>...</svg>",
"success": true,
"error": null,
"component_map": {
"R1": "resistor",
"V1": "voltage_source",
"C1": "capacitor"
}
}
```
| Field | Type | Description |
|-------|------|-------------|
| `svg` | string | SVG markup of the circuit diagram |
| `success` | boolean | Whether generation succeeded |
| `error` | string \| null | Error message if generation failed |
| `component_map` | object | Component reference → type mapping |
The SVG includes standard IEEE symbols for components. Resistors with parseable values (0.01Ω1GΩ) render with [color-coded bands](/schematics/resistor-colors/) on the zigzag symbol.
<Aside type="tip">
Both waveform and schematic SVGs are self-contained — they include all styling inline and can be saved as standalone `.svg` files or embedded directly in HTML.
</Aside>
## End-to-End Example
Simulate a circuit and generate both a waveform plot and schematic:
```bash
# 1. Create a notebook with a SPICE cell and run it
RESPONSE=$(curl -s -X POST https://spicebook.warehack.ing/api/notebooks/compose \
-H "Content-Type: application/json" \
-d '{
"title": "RC Filter",
"cells": [
{"type": "spice", "source": "V1 in 0 AC 1\nR1 in out 1k\nC1 out 0 1u\n.ac dec 100 1 1meg\n.end"}
],
"run": true
}')
# 2. Extract IDs
NB_ID=$(echo $RESPONSE | jq -r '.id')
CELL_ID=$(echo $RESPONSE | jq -r '.cells[0].id')
# 3. Generate schematic
curl -s -X POST "https://spicebook.warehack.ing/api/notebooks/$NB_ID/cells/$CELL_ID/schematic" \
| jq -r '.svg' > schematic.svg
# 4. Generate waveform plot from simulation results
WAVEFORM=$(echo $RESPONSE | jq '.cells[0].outputs[0].data.waveform')
curl -s -X POST https://spicebook.warehack.ing/api/waveforms/svg/raw \
-H "Content-Type: application/json" \
-d "{\"waveform\": $WAVEFORM, \"title\": \"Bode Plot\"}" \
-o bode.svg
```

View File

@ -0,0 +1,54 @@
---
title: Embed a Notebook
description: Embed interactive SpiceBook notebooks on any webpage with a simple iframe snippet.
---
import { Aside, Code } from '@astrojs/starlight/components';
Any SpiceBook notebook can be embedded on a third-party page via iframe. No API key or authentication is required — embeds are public and read-only, but viewers can still run simulations and see results.
## Embed URL
```
https://spicebook.warehack.ing/embed/{notebook_id}?theme=dark
```
| Parameter | Values | Default | Description |
|-----------|--------|---------|-------------|
| `theme` | `dark`, `light` | `dark` | Initial color theme |
## iframe Snippet
```html
<iframe
src="https://spicebook.warehack.ing/embed/{notebook_id}?theme=dark"
width="100%" height="600"
style="border: 1px solid #334155; border-radius: 8px;"
allow="clipboard-write"
></iframe>
```
Replace `{notebook_id}` with your notebook's ID (visible in the browser URL bar when editing, or returned by the API).
<Aside type="tip">
The easiest way to get the embed snippet is from SpiceBook itself — open any notebook, click the **Embed** button in the toolbar, and copy the pre-filled iframe code.
</Aside>
## What Viewers Can Do
Embedded notebooks render in a read-only mode with working simulation:
- **Read** markdown cells and SPICE netlist source
- **Run** SPICE cells and see waveform results
- **View** previously-generated schematics and plots
- **Copy** code from cells via clipboard
Viewers cannot edit cell content, add or delete cells, or change notebook metadata.
## Sizing
The iframe adapts to the width of its container. Set `width="100%"` for responsive layouts. The `height` should be tall enough to show the notebook content without excessive scrolling — `600px` works well for notebooks with 2-4 cells.
## CORS
The SpiceBook backend allows framing from any origin by default. If your deployment uses a restricted `CORS_EXTRA_ORIGINS` configuration, ensure the embedding domain is included.

View File

@ -0,0 +1,77 @@
---
title: Theme Sync
description: Control an embedded SpiceBook notebook's theme from the parent page using the postMessage API.
---
import { Aside } from '@astrojs/starlight/components';
Embedded notebooks support runtime theme switching via the browser's `postMessage` API. This lets the parent page keep the embed's appearance in sync with its own dark/light mode toggle.
## Setting the Initial Theme
Use the `theme` query parameter on the embed URL:
```
https://spicebook.warehack.ing/embed/{id}?theme=light
```
This sets the theme when the iframe first loads. To change it after load, use `postMessage`.
## Switching Themes at Runtime
Send a message to the iframe's content window:
```javascript
const iframe = document.querySelector('iframe');
iframe.contentWindow.postMessage(
{ type: 'spicebook-theme', theme: 'light' },
'*'
);
```
### Message Format
| Field | Type | Values | Description |
|-------|------|--------|-------------|
| `type` | string | `"spicebook-theme"` | Message identifier (required) |
| `theme` | string | `"dark"`, `"light"` | Target theme |
Messages with any other `type` value are ignored by the embed.
## Example: Sync with Parent Toggle
A common pattern is to listen for your page's theme change and forward it to the embed:
```javascript
// Assuming your page toggles a data-theme attribute on <html>
const observer = new MutationObserver(() => {
const theme = document.documentElement.dataset.theme || 'dark';
iframe.contentWindow.postMessage(
{ type: 'spicebook-theme', theme },
'*'
);
});
observer.observe(document.documentElement, {
attributes: true,
attributeFilter: ['data-theme'],
});
```
<Aside type="note">
The embed responds to theme messages immediately — there's no transition delay. The entire UI (backgrounds, text, code blocks, waveform plots) switches to the requested theme.
</Aside>
## Security
The `postMessage` call uses `'*'` as the target origin for simplicity. If you want stricter security, specify the SpiceBook origin:
```javascript
iframe.contentWindow.postMessage(
{ type: 'spicebook-theme', theme: 'dark' },
'https://spicebook.warehack.ing'
);
```
The embed only acts on messages with `type: 'spicebook-theme'` — all other messages are silently ignored.

View File

@ -0,0 +1,59 @@
---
title: Editor Basics
description: Cell types, toolbar actions, and keyboard shortcuts in the SpiceBook notebook editor.
---
import { Aside } from '@astrojs/starlight/components';
A SpiceBook notebook is a vertical sequence of cells. Each cell has a type that determines how it behaves and renders.
## Cell Types
| Type | Purpose | Editor |
|------|---------|--------|
| **Markdown** | Documentation, headings, LaTeX-style math | Rich text with live preview |
| **SPICE** | Circuit netlists for simulation | Code editor with SPICE syntax highlighting |
| **Python** | Computation and scripting | Code editor (execution planned) |
| **Schematic** | Auto-generated circuit diagrams | Read-only SVG display |
Markdown cells render immediately as you type. SPICE cells require you to click **Run** to execute the netlist and see simulation results.
## Toolbar
The notebook toolbar sits at the top of the editor and provides:
- **Run All** — executes every SPICE cell in order, top to bottom
- **Engine selector** — switch between ngspice and LTspice for the entire notebook
- **Embed** — opens a popover with a ready-to-copy iframe snippet for sharing
- **Tags** — add searchable tags to organize notebooks on the homepage
Each individual SPICE cell also has its own run and schematic buttons in the cell toolbar.
## Adding and Reordering Cells
Click **+ Add Cell** between any two cells to insert a new one. The dropdown lets you choose the cell type.
Cells can be reordered by dragging, or programmatically via the [reorder API endpoint](/api/cells/#reorder-cells).
To delete a cell, use the cell menu (three dots) and select **Delete**.
## Code Editor
SPICE cells use a code editor with:
- **Syntax highlighting** for SPICE netlist keywords (`.tran`, `.ac`, `.op`, etc.)
- **Line numbers** for referencing specific netlist lines
- **Auto-indentation** following SPICE conventions
<Aside type="note">
The editor uses the SpiceBook dark theme by default — slate backgrounds with a blue cursor. The color scheme matches the rest of the application.
</Aside>
## Notebook Metadata
Every notebook tracks:
- **Title** — displayed in the gallery and browser tab
- **Engine** — `ngspice` or `ltspice`, applies to all SPICE cells
- **Tags** — free-form labels for filtering in the notebook gallery
- **Created / Modified** — ISO-8601 timestamps, set automatically

View File

@ -0,0 +1,67 @@
---
title: Quick Start
description: Create a notebook, write a SPICE netlist, run a simulation, and see waveforms — in under five minutes.
---
import { Steps, Aside } from '@astrojs/starlight/components';
This guide walks through creating your first SpiceBook notebook. You'll build a voltage divider, simulate it, and see the results — all in the browser.
<Steps>
1. **Open SpiceBook**
Go to [spicebook.warehack.ing](https://spicebook.warehack.ing) and click **New Notebook**. You'll get a blank notebook with a single markdown cell.
2. **Add a SPICE cell**
Click the **+ Add Cell** button and select **SPICE**. Paste this netlist:
```
* Voltage Divider
V1 1 0 DC 5
R1 1 2 1k
R2 2 0 2k
.op
.end
```
This creates a 5V source with two resistors. The `.op` directive runs a DC operating point analysis — it computes the steady-state voltages at every node.
3. **Run the simulation**
Click the **Run** button on the SPICE cell (or use the keyboard shortcut). The backend sends the netlist to ngspice and returns the results:
- `V(1) = 5.0V` — the supply voltage
- `V(2) = 3.333V` — the divided voltage: `5 × 2k / (1k + 2k)`
4. **Try a transient analysis**
Replace the netlist with a time-domain simulation:
```
* RC Charging Curve
V1 1 0 PULSE(0 5 0 1n 1n 5m 10m)
R1 1 2 1k
C1 2 0 1u
.tran 1u 20m
.end
```
Run it again. This time you'll see a waveform plot showing the capacitor voltage rising exponentially toward 5V with a time constant of `RC = 1ms`.
5. **Generate a schematic**
Click the **Schematic** button on any SPICE cell. SpiceBook parses the netlist and draws a circuit diagram as an SVG — resistors render as IEEE zigzag symbols with color-coded bands matching their values.
</Steps>
<Aside type="tip">
You can also create notebooks programmatically via the [compose endpoint](/api/notebooks/#compose-notebook), which accepts multiple cells and can auto-run SPICE cells in a single API call.
</Aside>
## Next Steps
- **[Editor Basics](/getting-started/editor-basics/)** — cell types, toolbar actions, keyboard shortcuts
- **[Engines](/simulation/engines/)** — choosing between ngspice and LTspice
- **[Waveform Viewer](/simulation/waveforms/)** — interactive plots, oscilloscope mode, AC bode plots

View File

@ -0,0 +1,50 @@
---
title: What is SpiceBook?
description: Notebook interface for SPICE circuit simulation — write netlists, simulate with ngspice or LTspice, and visualize waveforms in a single document.
template: splash
hero:
tagline: Write SPICE netlists, simulate, and visualize waveforms — all in one document.
actions:
- text: Quick Start
link: /getting-started/quick-start/
icon: right-arrow
variant: primary
- text: Open SpiceBook
link: https://spicebook.warehack.ing
icon: external
variant: minimal
---
import { Card, CardGrid, LinkCard } from '@astrojs/starlight/components';
## What SpiceBook Does
SpiceBook is a notebook interface for SPICE circuit simulation. Each notebook is a sequence of cells — markdown for documentation, SPICE netlists for circuits, and auto-generated schematics and waveform plots for visualization.
You write a netlist, run it against ngspice or LTspice, and see the results inline. No file management, no separate plotting tools, no context switching between editor and simulator.
<CardGrid>
<Card title="Dual Engines" icon="setting">
Choose ngspice (built-in) or LTspice (via [mcltspice](https://mcltspice.warehack.ing)) per notebook. Same netlist format, different solver characteristics.
</Card>
<Card title="Waveform Plots" icon="line-chart">
Transient, DC sweep, and AC analysis results render as interactive SVG plots with an oscilloscope display mode.
</Card>
<Card title="Auto Schematics" icon="puzzle">
SPICE netlists are parsed into circuit diagrams automatically — resistors even render with IEEE zigzag symbols and 4-band color codes.
</Card>
<Card title="Embeddable" icon="laptop">
Any notebook can be embedded on a third-party page via iframe. Viewers can run simulations directly in the embed.
</Card>
</CardGrid>
## How It Fits Together
SpiceBook is part of the [warehack.ing](https://warehack.ing) project family. It pairs with [mcltspice](https://mcltspice.warehack.ing), an MCP server that gives AI assistants access to LTspice simulation — notebooks created by mcltspice are viewable and editable in SpiceBook.
<CardGrid>
<LinkCard title="Quick Start" description="Create a notebook and run your first simulation." href="/getting-started/quick-start/" />
<LinkCard title="REST API" description="Programmatic access to notebooks, simulation, and rendering." href="/api/overview/" />
<LinkCard title="Embedding" description="Embed interactive notebooks on any page." href="/embedding/embed-notebook/" />
<LinkCard title="Engines" description="ngspice vs LTspice — differences and how to choose." href="/simulation/engines/" />
</CardGrid>

View File

@ -0,0 +1,62 @@
---
title: Auto-Generated Diagrams
description: How SpiceBook converts SPICE netlists into circuit diagram SVGs automatically.
---
import { Aside } from '@astrojs/starlight/components';
SpiceBook can generate a schematic diagram from any SPICE cell. Click the **Schematic** button in the cell toolbar, and the backend parses the netlist into a circuit diagram rendered as an inline SVG.
## How It Works
The schematic generator:
1. **Parses the netlist** to identify components (resistors, capacitors, inductors, voltage sources, current sources) and their node connections
2. **Determines layout** by walking the circuit graph and positioning components to minimize wire crossings
3. **Renders SVG** with standard electrical engineering symbols — IEEE zigzag for resistors, parallel plates for capacitors, coil for inductors, ± symbols for sources
4. **Labels components** with their reference designator (`R1`, `C1`, `V1`) and value
The result is a clean, readable diagram that matches what you'd draw by hand.
## Supported Components
| Component | Netlist Prefix | Symbol |
|-----------|---------------|--------|
| Resistor | `R` | IEEE zigzag (with optional color bands) |
| Capacitor | `C` | Parallel plates |
| Inductor | `L` | Coil |
| Voltage source | `V` | Circle with ± |
| Current source | `I` | Circle with arrow |
| Ground | node `0` | Standard ground symbol |
## Component Map
The schematic endpoint returns a `component_map` alongside the SVG, listing each component and its type:
```json
{
"svg": "<svg ...>...</svg>",
"success": true,
"component_map": {
"R1": "resistor",
"V1": "voltage_source",
"C1": "capacitor"
}
}
```
This is useful for programmatic tools that need to know what's in the circuit without parsing the SVG.
## API Access
Generate schematics programmatically:
```bash
curl -X POST https://spicebook.warehack.ing/api/notebooks/{id}/cells/{cell_id}/schematic
```
The cell must be type `spice`. No request body is needed — the cell's `source` netlist is used directly. See the [Waveforms & Schematics API reference](/api/waveforms-schematics/) for the full response format.
<Aside type="note">
Schematic generation works for both ngspice and LTspice netlists. The generator parses the netlist text directly rather than relying on engine-specific features, so it works identically with either engine.
</Aside>

View File

@ -0,0 +1,71 @@
---
title: Color-Coded Resistors
description: IEEE zigzag resistor symbols with 4-band color codes rendered directly on schematic diagrams.
---
import { Aside } from '@astrojs/starlight/components';
When SpiceBook generates a schematic, resistors with parseable values render as IEEE zigzag symbols with color-coded segments matching the standard 4-band resistor color code.
## How It Works
A resistor value like `1k` (1000Ω) is decomposed into:
- **1st significant digit:** 1 → Brown
- **2nd significant digit:** 0 → Black
- **Multiplier:** ×100 → Red
- **Tolerance:** ±5% → Gold (default)
These colors are applied directly to the zigzag segments in the SVG, mimicking how a physical resistor looks.
## Band-to-Segment Mapping
The IEEE zigzag symbol has 7 sub-segments. Each is assigned a color role:
| Segment | Role | Color |
|---------|------|-------|
| 0 (entry) | Wire | Default wire color |
| 1 | 1st significant digit | Color band |
| 2 | 2nd significant digit | Color band |
| 3 | Multiplier | Color band |
| 4 (gap) | Physical spacing | Default wire color |
| 5 | Tolerance | Color band |
| 6 (exit) | Wire | Default wire color |
The entry/exit segments and the gap before the tolerance band use the default wire color. This mimics the physical spacing on a real resistor that indicates reading direction — you read bands from the end closest to the first band.
## Color Code Reference
| Digit | Color | Hex |
|-------|-------|-----|
| 0 | Black | `#1a1a1a` |
| 1 | Brown | `#8B4513` |
| 2 | Red | `#cc0000` |
| 3 | Orange | `#ff6600` |
| 4 | Yellow | `#cccc00` |
| 5 | Green | `#006400` |
| 6 | Blue | `#0000cc` |
| 7 | Violet | `#7b1fa2` |
| 8 | Gray | `#555555` |
| 9 | White | `#e0e0e0` |
**Multiplier bands** use the same color mapping (Black = ×1, Brown = ×10, Red = ×100, etc.).
**Tolerance:** Gold (±5%) is the default when no tolerance is specified.
## Value Range
Color-coded rendering applies to resistor values between **0.01Ω and 1GΩ**. Outside this range, or for parametric values (e.g., `{R_val}`), the resistor falls back to a standard monochrome zigzag.
<Aside type="tip">
SpiceBook also has a dedicated [Resistor Color Codes reference page](https://spicebook.warehack.ing/reference/resistor-colors) in the main application where you can look up any value interactively.
</Aside>
## Example
A `4.7k` resistor renders with:
- **Yellow** (4) — 1st digit
- **Violet** (7) — 2nd digit
- **Red** (×100) — multiplier
- **Gold** (±5%) — tolerance
The result is immediately recognizable to anyone who's read resistor bands by hand — the schematic tells you both the circuit topology and the component values at a glance.

View File

@ -0,0 +1,60 @@
---
title: Engines
description: ngspice vs LTspice — differences, availability, and how to choose a simulation engine in SpiceBook.
---
import { Aside } from '@astrojs/starlight/components';
SpiceBook supports two SPICE simulation engines. Each notebook is bound to one engine, selected when you create it (or changed later via the toolbar).
## ngspice
The default engine. ngspice is an open-source circuit simulator that runs natively on the SpiceBook backend — no additional setup required.
**Strengths:**
- Always available — built into the backend container
- Broad analysis support: `.op`, `.dc`, `.tran`, `.ac`, `.noise`, `.pz`
- Well-documented netlist syntax with extensive model libraries
- Fast for small-to-medium circuits
**Typical use:** General-purpose simulation, educational circuits, quick prototyping.
## LTspice
Available when the SpiceBook backend is configured with [mcltspice](https://mcltspice.warehack.ing), an MCP server that automates LTspice via Wine on Linux.
**Strengths:**
- Proprietary solver with strong convergence for switching circuits
- Extensive built-in component library (power semiconductors, op-amps, regulators)
- Better performance on large circuits with many timesteps
- Tight `.meas` directive support for automated measurements
**Typical use:** Power electronics, switching regulators, circuits using manufacturer models.
<Aside type="caution">
LTspice availability depends on the server configuration. If mcltspice isn't running, selecting "ltspice" as the engine will return an error when you try to simulate. The engine selector in the toolbar shows which engines are available.
</Aside>
## Differences That Matter
| Feature | ngspice | LTspice |
|---------|---------|---------|
| Availability | Always | Requires mcltspice |
| Operating point (`.op`) | Yes | Yes |
| Transient (`.tran`) | Yes | Yes |
| AC sweep (`.ac`) | Yes | Yes |
| Convergence on switchers | Fair | Excellent |
| Built-in device models | Community libs | Extensive vendor libs |
| Output format | Raw binary | Raw binary |
Both engines produce the same `WaveformData` structure in SpiceBook — the waveform viewer, SVG plots, and schematic generation work identically regardless of which engine ran the simulation.
## Choosing an Engine
For most circuits, ngspice works well and requires no configuration. Reach for LTspice when you need:
- A specific manufacturer model that ships with LTspice (LT1234, LTC3780, etc.)
- Better convergence on circuits with fast switching edges
- `.meas` directives for automated waveform measurements
You can switch engines on an existing notebook at any time — the netlist syntax is largely compatible. Re-run cells after switching to regenerate results with the new engine.

View File

@ -0,0 +1,118 @@
---
title: Running Simulations
description: How to execute SPICE cells, interpret results, and use Run All for multi-cell notebooks.
---
import { Aside } from '@astrojs/starlight/components';
## Running a Single Cell
Every SPICE cell has a **Run** button in its toolbar. Clicking it sends the cell's netlist to the backend, which:
1. Writes the netlist to a temp file
2. Invokes the selected engine (ngspice or LTspice)
3. Parses the raw output into structured `WaveformData`
4. Returns results to the browser and saves them in the cell's `outputs` array
Results appear inline beneath the cell — either a data table (for `.op`) or a waveform plot (for `.tran`, `.dc`, `.ac`).
## Run All
The toolbar's **Run All** button executes every SPICE cell in the notebook from top to bottom, sequentially. Each cell's results are saved before the next cell runs.
This is useful for notebooks where later cells depend on understanding earlier results, or when you want to regenerate all outputs after changing the engine.
## Analysis Types
The analysis directive in your netlist determines what kind of results you get:
### DC Operating Point (`.op`)
```
V1 1 0 DC 5
R1 1 2 1k
R2 2 0 2k
.op
.end
```
Returns a single set of node voltages and branch currents. Displayed as a table.
### Transient (`.tran`)
```
V1 1 0 PULSE(0 5 0 1n 1n 5u 10u)
R1 1 2 1k
C1 2 0 100n
.tran 10n 50u
.end
```
Returns time-series data. Displayed as an XY waveform plot with time on the horizontal axis.
### DC Sweep (`.dc`)
```
V1 1 0 DC 5
R1 1 2 1k
R2 2 0 2k
.dc V1 0 10 0.5
.end
```
Sweeps a source value and returns node voltages at each step. Displayed as a waveform plot with the swept parameter on the horizontal axis.
### AC Analysis (`.ac`)
```
V1 in 0 AC 1
R1 in out 1k
C1 out 0 1u
.ac dec 100 1 1meg
.end
```
Returns complex frequency-domain data. Displayed as a Bode plot — magnitude in dB and phase in degrees versus frequency on a log scale.
<Aside type="tip">
AC analysis results include `y_magnitude_db` and `y_phase_deg` fields in the waveform data. The viewer automatically switches to Bode plot mode when these are present.
</Aside>
## Output Format
Every simulation returns a `SimulationResponse`:
```json
{
"success": true,
"waveform": {
"variables": [{"name": "v(out)", "type": "voltage"}],
"points": 100,
"x_data": [0.0, 0.001, ...],
"y_data": {"v(out)": [0.0, 0.5, ...]},
"x_type": "time",
"is_complex": false
},
"log": "ngspice output...",
"error": null,
"elapsed_seconds": 0.42
}
```
If the simulation fails (syntax error, convergence failure), `success` is `false` and `error` contains the diagnostic message. The simulator log is always available in the `log` field for debugging.
## Engineering Notation
SPICE uses its own suffix convention for component values — be aware that **`M` means milli** (10⁻³), not mega. Use `meg` for 10⁶.
| Suffix | Multiplier | Example |
|--------|-----------|---------|
| `T` | 10¹² | `1T` |
| `G` | 10⁹ | `2.2G` |
| `meg` | 10⁶ | `1meg` |
| `k` | 10³ | `4.7k` |
| `m` | 10⁻³ | `10m` |
| `u` | 10⁻⁶ | `100u` |
| `n` | 10⁻⁹ | `47n` |
| `p` | 10⁻¹² | `10p` |
| `f` | 10⁻¹⁵ | `1f` |

View File

@ -0,0 +1,76 @@
---
title: Waveform Viewer
description: Interactive waveform plots, oscilloscope display mode, and AC Bode plots in SpiceBook.
---
import { Aside } from '@astrojs/starlight/components';
After running a simulation, SpiceBook renders the results as interactive SVG plots directly beneath the SPICE cell. The viewer adapts to the analysis type automatically.
## Plot Types
### Time-Domain (Transient / DC Sweep)
Transient (`.tran`) and DC sweep (`.dc`) results display as standard XY plots:
- **X-axis:** time (seconds) or swept parameter value
- **Y-axis:** node voltages and branch currents
- **Multiple traces** are overlaid with distinct colors from an 8-color palette
Each trace is labeled with its signal name (`v(out)`, `i(R1)`, etc.).
### Frequency-Domain (AC Analysis)
AC analysis (`.ac`) results display as a Bode plot with two subplots:
- **Top:** Magnitude in dB vs frequency (log scale)
- **Bottom:** Phase in degrees vs frequency (log scale)
The viewer detects AC data automatically when `is_complex` is `true` in the waveform data and switches to this dual-plot layout.
<Aside type="tip">
The -3dB point on a magnitude plot marks the cutoff frequency of a filter. Look for where the magnitude trace drops 3dB below its passband level.
</Aside>
### Oscilloscope Mode
The SpiceBook homepage features an animated oscilloscope display that renders waveform data in a CRT-style aesthetic — cyan traces on a dark background with phosphor-glow effects. This same rendering engine is available for waveform data throughout the application.
The oscilloscope uses a dedicated color palette:
- **Axes:** `#475569` (slate-600)
- **Grid:** `rgba(51, 65, 85, 0.5)` (slate-700 at 50%)
- **Traces:** `#2dd4bf` (cyan-500 for the classic scope look)
## Trace Colors
Multi-signal plots use an 8-color palette designed for readability on both dark and light backgrounds:
| Trace | Color |
|-------|-------|
| 1 | Blue (`#2563eb`) |
| 2 | Red (`#dc2626`) |
| 3 | Green (`#16a34a`) |
| 4 | Amber (`#ca8a04`) |
| 5 | Cyan (`#0891b2`) |
| 6 | Rose (`#e11d48`) |
| 7 | Slate (`#4b5563`) |
| 8 | Orange (`#ea580c`) |
## SVG Generation via API
Waveform plots can also be generated server-side via the REST API. Send the `waveform` data from a simulation response to the SVG endpoint:
```bash
curl -X POST https://spicebook.warehack.ing/api/waveforms/svg/raw \
-H "Content-Type: application/json" \
-d '{
"waveform": { ...waveform data... },
"title": "RC Filter Response",
"width": 800,
"height": 500,
"signals": ["v(out)"]
}' \
-o plot.svg
```
The `signals` array lets you select which traces to include. Omit it to plot all signals. See the [Waveforms & Schematics API reference](/api/waveforms-schematics/) for full details.

View File

@ -0,0 +1,43 @@
/* SpiceBook docs -- blue accent, warm slate grays
* Matches the SpiceBook application theme */
@import "@astrojs/starlight-tailwind";
@import "tailwindcss";
:root {
/* Dark mode (Starlight default: :root = dark)
* Gray scale: gray-1 = highest contrast (lightest), gray-7 = lowest */
--sl-color-accent-low: #172554; /* blue-950 — dark accent bg */
--sl-color-accent: #60a5fa; /* blue-400 — bright on dark bg */
--sl-color-accent-high: #dbeafe; /* blue-100 — light accent text */
--sl-color-gray-1: #f1f5f9; /* slate-100 */
--sl-color-gray-2: #e2e8f0; /* slate-200 */
--sl-color-gray-3: #94a3b8; /* slate-400 */
--sl-color-gray-4: #475569; /* slate-600 */
--sl-color-gray-5: #1e293b; /* slate-800 */
--sl-color-gray-6: #0f172a; /* slate-900 */
--sl-color-gray-7: #020617; /* slate-950 */
}
:root[data-theme="light"] {
/* Light mode: gray-1 = highest contrast (darkest) */
--sl-color-accent-low: #dbeafe; /* blue-100 — light accent bg */
--sl-color-accent: #2563eb; /* blue-600 — darker on light bg */
--sl-color-accent-high: #1e3a5f; /* dark blue — dark accent text */
--sl-color-gray-1: #0f172a; /* slate-900 */
--sl-color-gray-2: #1e293b; /* slate-800 */
--sl-color-gray-3: #475569; /* slate-600 */
--sl-color-gray-4: #94a3b8; /* slate-400 */
--sl-color-gray-5: #cbd5e1; /* slate-300 */
--sl-color-gray-6: #e2e8f0; /* slate-200 */
--sl-color-gray-7: #f8fafc; /* slate-50 */
}
/* Inline code styling */
:not(pre) > code {
background: var(--sl-color-gray-5);
padding: 0.15em 0.35em;
border-radius: 0.25em;
}

5
docs-site/tsconfig.json Normal file
View File

@ -0,0 +1,5 @@
{
"extends": "astro/tsconfigs/strict",
"include": ["src/**/*"],
"exclude": ["node_modules"]
}

View File

@ -132,6 +132,21 @@ try {
</div> </div>
<Icon name="lucide:chevron-right" class="w-4 h-4 text-slate-600 group-hover:text-slate-400 transition-colors" /> <Icon name="lucide:chevron-right" class="w-4 h-4 text-slate-600 group-hover:text-slate-400 transition-colors" />
</a> </a>
<a href="https://spicebook-docs.warehack.ing" target="_blank" rel="noopener noreferrer"
class="inline-flex items-center gap-4 px-5 py-3 rounded-lg border border-slate-700
hover:border-slate-500 hover:bg-slate-800/40 transition-colors group">
<Icon name="lucide:book-open" class="w-8 h-8 text-blue-400/60 flex-shrink-0" />
<div>
<span class="text-sm font-semibold text-slate-200 group-hover:text-slate-100">
Docs
</span>
<span class="block text-xs text-slate-500">
Guides, API reference, embedding
</span>
</div>
<Icon name="lucide:chevron-right" class="w-4 h-4 text-slate-600 group-hover:text-slate-400 transition-colors" />
</a>
</div> </div>
</section> </section>