create-substrate 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (81) hide show
  1. package/dist/index.d.ts +3 -0
  2. package/dist/index.d.ts.map +1 -0
  3. package/dist/index.js +27 -0
  4. package/dist/index.js.map +1 -0
  5. package/dist/prompts.d.ts +6 -0
  6. package/dist/prompts.d.ts.map +1 -0
  7. package/dist/prompts.js +127 -0
  8. package/dist/prompts.js.map +1 -0
  9. package/dist/scaffold.d.ts +10 -0
  10. package/dist/scaffold.d.ts.map +1 -0
  11. package/dist/scaffold.js +395 -0
  12. package/dist/scaffold.js.map +1 -0
  13. package/dist/surfaces/3d-scene.d.ts +3 -0
  14. package/dist/surfaces/3d-scene.d.ts.map +1 -0
  15. package/dist/surfaces/3d-scene.js +184 -0
  16. package/dist/surfaces/3d-scene.js.map +1 -0
  17. package/dist/surfaces/animation.d.ts +3 -0
  18. package/dist/surfaces/animation.d.ts.map +1 -0
  19. package/dist/surfaces/animation.js +211 -0
  20. package/dist/surfaces/animation.js.map +1 -0
  21. package/dist/surfaces/blank.d.ts +3 -0
  22. package/dist/surfaces/blank.d.ts.map +1 -0
  23. package/dist/surfaces/blank.js +72 -0
  24. package/dist/surfaces/blank.js.map +1 -0
  25. package/dist/surfaces/canvas-2d.d.ts +3 -0
  26. package/dist/surfaces/canvas-2d.d.ts.map +1 -0
  27. package/dist/surfaces/canvas-2d.js +139 -0
  28. package/dist/surfaces/canvas-2d.js.map +1 -0
  29. package/dist/surfaces/data-vis.d.ts +3 -0
  30. package/dist/surfaces/data-vis.d.ts.map +1 -0
  31. package/dist/surfaces/data-vis.js +175 -0
  32. package/dist/surfaces/data-vis.js.map +1 -0
  33. package/dist/surfaces/image-gen.d.ts +3 -0
  34. package/dist/surfaces/image-gen.d.ts.map +1 -0
  35. package/dist/surfaces/image-gen.js +193 -0
  36. package/dist/surfaces/image-gen.js.map +1 -0
  37. package/dist/surfaces/index.d.ts +4 -0
  38. package/dist/surfaces/index.d.ts.map +1 -0
  39. package/dist/surfaces/index.js +17 -0
  40. package/dist/surfaces/index.js.map +1 -0
  41. package/dist/surfaces/node-editor.d.ts +3 -0
  42. package/dist/surfaces/node-editor.d.ts.map +1 -0
  43. package/dist/surfaces/node-editor.js +211 -0
  44. package/dist/surfaces/node-editor.js.map +1 -0
  45. package/dist/surfaces/types.d.ts +22 -0
  46. package/dist/surfaces/types.d.ts.map +1 -0
  47. package/dist/surfaces/types.js +10 -0
  48. package/dist/surfaces/types.js.map +1 -0
  49. package/dist/utils/detect-pm.d.ts +5 -0
  50. package/dist/utils/detect-pm.d.ts.map +1 -0
  51. package/dist/utils/detect-pm.js +20 -0
  52. package/dist/utils/detect-pm.js.map +1 -0
  53. package/dist/utils/fs.d.ts +7 -0
  54. package/dist/utils/fs.d.ts.map +1 -0
  55. package/dist/utils/fs.js +52 -0
  56. package/dist/utils/fs.js.map +1 -0
  57. package/dist/utils/logger.d.ts +10 -0
  58. package/dist/utils/logger.d.ts.map +1 -0
  59. package/dist/utils/logger.js +15 -0
  60. package/dist/utils/logger.js.map +1 -0
  61. package/dist/utils/shell.d.ts +7 -0
  62. package/dist/utils/shell.d.ts.map +1 -0
  63. package/dist/utils/shell.js +28 -0
  64. package/dist/utils/shell.js.map +1 -0
  65. package/package.json +35 -0
  66. package/skills/3d-scene/SKILL.md +172 -0
  67. package/skills/animation/SKILL.md +194 -0
  68. package/skills/canvas-2d/SKILL.md +132 -0
  69. package/skills/composing-panels/SKILL.md +309 -0
  70. package/skills/create-custom-tool/SKILL.md +157 -0
  71. package/skills/data-visualisation/SKILL.md +228 -0
  72. package/skills/image-generation/SKILL.md +211 -0
  73. package/skills/scaffold-playground/SKILL.md +141 -0
  74. package/skills/substrate-canvas/SKILL.md +217 -0
  75. package/skills/substrate-controls/SKILL.md +242 -0
  76. package/skills/substrate-feedback/SKILL.md +219 -0
  77. package/skills/substrate-interaction/SKILL.md +286 -0
  78. package/skills/substrate-nodes/SKILL.md +208 -0
  79. package/skills/substrate-scaffold/SKILL.md +206 -0
  80. package/skills/theming/SKILL.md +117 -0
  81. package/skills/wire-interactions/SKILL.md +155 -0
@@ -0,0 +1,228 @@
1
+ # Data visualisation
2
+
3
+ Guide to building interactive data exploration tools with Substrate — charts, graphs, dashboards, and visual analytics playgrounds.
4
+
5
+ ## When to use this surface
6
+
7
+ Use a data visualisation surface when the app involves exploring, filtering, and presenting data visually: dashboard builders, chart editors, data exploration tools, analytics playgrounds, or any tool where users interact with visual representations of datasets.
8
+
9
+ ## Surface setup
10
+
11
+ Data visualisation tools combine a **chart surface** (where visualisations render) with **data controls** (filters, axis selectors, aggregation options). The rendering engine is typically a charting library layered over SVG or Canvas.
12
+
13
+ ### Dependencies
14
+
15
+ ```bash
16
+ npm install recharts d3
17
+ npm install -D @types/d3
18
+ ```
19
+
20
+ Recharts handles the common chart types (line, bar, area, pie, scatter) with a React-friendly API. D3 provides lower-level control for custom visualisations. Use both — Recharts for standard charts, D3 for anything bespoke.
21
+
22
+ ### Layout
23
+
24
+ Data visualisation tools often work best with a flexible layout:
25
+
26
+ ```
27
+ ┌──────────┬────────────────────────┬──────────┐
28
+ │ │ │ │
29
+ │ Left │ Chart surface │ Right │
30
+ │ panel │ (visualisation) │ panel │
31
+ │ │ │ │
32
+ │ Data │ │ Chart │
33
+ │ sources │ │ config │
34
+ │ Filters │ │ Style │
35
+ │ │ │ │
36
+ └──────────┴────────────────────────┴──────────┘
37
+ [ Toolbar ]
38
+ ```
39
+
40
+ For dashboard builders, the surface area might contain multiple chart tiles arranged in a grid — in that case, the surface acts more like a 2D canvas where chart widgets are the "elements".
41
+
42
+ ## Store architecture
43
+
44
+ ### Data store
45
+
46
+ ```ts
47
+ interface DataState {
48
+ datasets: Record<string, Dataset>
49
+ activeDatasetId: string | null
50
+ filters: Filter[]
51
+ computedData: Record[] | null // Filtered + transformed data
52
+ }
53
+
54
+ interface Dataset {
55
+ id: string
56
+ name: string
57
+ source: "upload" | "url" | "inline"
58
+ rawData: Record<string, unknown>[]
59
+ columns: ColumnDef[]
60
+ }
61
+
62
+ interface ColumnDef {
63
+ key: string
64
+ label: string
65
+ type: "number" | "string" | "date" | "boolean"
66
+ }
67
+
68
+ interface Filter {
69
+ id: string
70
+ column: string
71
+ operator: "eq" | "gt" | "lt" | "gte" | "lte" | "contains" | "between"
72
+ value: unknown
73
+ }
74
+ ```
75
+
76
+ ### Chart store
77
+
78
+ ```ts
79
+ interface ChartState {
80
+ charts: ChartConfig[]
81
+ selectedChartId: string | null
82
+ }
83
+
84
+ interface ChartConfig {
85
+ id: string
86
+ type: "line" | "bar" | "area" | "pie" | "scatter" | "radar" | "custom"
87
+ title: string
88
+ xAxis: string // Column key
89
+ yAxis: string[] // One or more column keys
90
+ groupBy?: string // Column key for series grouping
91
+ aggregation?: "sum" | "avg" | "count" | "min" | "max"
92
+ colorScheme: string[]
93
+ position?: { x: number; y: number; width: number; height: number } // For dashboard layout
94
+ }
95
+ ```
96
+
97
+ ## Chart surface
98
+
99
+ ### Single chart mode
100
+
101
+ For a focused exploration tool, the chart fills the surface area:
102
+
103
+ ```tsx
104
+ "use client"
105
+
106
+ import { ResponsiveContainer, LineChart, Line, XAxis, YAxis, Tooltip, CartesianGrid } from "recharts"
107
+
108
+ export function ChartSurface() {
109
+ const data = useDataStore((s) => s.computedData)
110
+ const chart = useChartStore((s) => s.charts[0])
111
+
112
+ if (!data || !chart) return <EmptyState />
113
+
114
+ return (
115
+ <div className="absolute inset-0 flex items-center justify-center bg-canvas p-8">
116
+ <ResponsiveContainer width="100%" height="100%">
117
+ <LineChart data={data}>
118
+ <CartesianGrid strokeDasharray="3 3" />
119
+ <XAxis dataKey={chart.xAxis} />
120
+ <YAxis />
121
+ <Tooltip />
122
+ {chart.yAxis.map((key, i) => (
123
+ <Line key={key} dataKey={key} stroke={chart.colorScheme[i]} />
124
+ ))}
125
+ </LineChart>
126
+ </ResponsiveContainer>
127
+ </div>
128
+ )
129
+ }
130
+ ```
131
+
132
+ ### Dashboard mode
133
+
134
+ For a dashboard builder, the surface contains a grid of chart tiles. Each tile is a chart config rendered at a specific position. Use the 2D canvas interaction patterns (drag to move, resize handles) for layout editing, but render each tile as a React component with Recharts inside.
135
+
136
+ ## Wiring to Substrate chrome
137
+
138
+ ### Toolbar
139
+
140
+ | Tool | Purpose | Shortcut |
141
+ |---|---|---|
142
+ | Select | Select chart tiles (dashboard mode) | V |
143
+ | Add chart | Insert a new chart widget | A |
144
+ | Pan | Pan the dashboard canvas | H |
145
+ | Zoom | Zoom to fit / zoom level | Cmd+0 |
146
+ | Export | Export as PNG/SVG/PDF | Cmd+E |
147
+
148
+ In single-chart mode, the toolbar might switch between chart types instead.
149
+
150
+ ### Left panel — data
151
+
152
+ - **Dataset pane** — list loaded datasets, import CSV/JSON, paste data
153
+ - **Columns pane** — show available columns with type badges, drag to assign axes
154
+ - **Filters pane** — active filter list, add/remove filters with operator dropdowns and value inputs
155
+
156
+ ### Right panel — chart configuration
157
+
158
+ - **Chart type pane** — visual selector for chart type (icons for line, bar, area, pie, etc.)
159
+ - **Axes pane** — X axis column, Y axis columns (multi-select), group-by column
160
+ - **Aggregation pane** — how to aggregate grouped data (sum, average, count)
161
+ - **Style pane** — colour scheme selector, show/hide grid, legend position, label formatting
162
+
163
+ ## Data loading
164
+
165
+ ### CSV upload
166
+
167
+ Use the HTML file input to accept CSVs, parse with PapaParse or a simple parser:
168
+
169
+ ```ts
170
+ import Papa from "papaparse"
171
+
172
+ function handleFileUpload(file: File) {
173
+ Papa.parse(file, {
174
+ header: true,
175
+ dynamicTyping: true,
176
+ complete: (results) => {
177
+ dataStore.addDataset({
178
+ name: file.name,
179
+ rawData: results.data,
180
+ columns: inferColumns(results.data),
181
+ })
182
+ },
183
+ })
184
+ }
185
+ ```
186
+
187
+ ### Column type inference
188
+
189
+ Scan the first N rows to infer column types (number, string, date). Store these on the `ColumnDef` so the UI can offer appropriate filter operators and chart axis options.
190
+
191
+ ## Interaction patterns
192
+
193
+ ### Axis assignment
194
+
195
+ Let users drag column names from the data panel onto drop zones on the chart (X axis, Y axis, colour/group). This is a drag-and-drop interaction between panels and the surface.
196
+
197
+ ### Brushing and linking
198
+
199
+ In dashboard mode, selecting a data range on one chart can filter the data for all other charts. This is managed through the filter store — a brush interaction adds a temporary filter that all charts respond to.
200
+
201
+ ### Tooltip and crosshair
202
+
203
+ Recharts provides built-in tooltips. For custom tooltips, read the active data point and render a positioned DOM element over the chart surface.
204
+
205
+ ## Theming
206
+
207
+ Charts should read from CSS variables for consistency with the Substrate theme:
208
+
209
+ - Chart background → `bg-canvas`
210
+ - Grid lines → derive from `--border` or `--canvas-foreground`
211
+ - Text/labels → `--foreground` or `--muted-foreground`
212
+ - Colour schemes → define as an array of CSS variables or provide sensible defaults
213
+
214
+ ## What to build
215
+
216
+ Some examples of what this surface enables:
217
+
218
+ - **Data explorer** — upload a CSV, choose chart type, filter and group interactively
219
+ - **Dashboard builder** — multiple chart widgets on a grid, drag to rearrange, shared filters
220
+ - **Analytics playground** — connect to a live data source, real-time updating charts
221
+ - **Comparison tool** — side-by-side charts with linked brushing
222
+ - **Chart editor** — design a single publication-quality chart with fine-grained style controls
223
+
224
+ ## Related reference skills
225
+
226
+ - **substrate-scaffold** — Toolbar, Panel, StatusBar, DocumentTabs for the app shell
227
+ - **substrate-controls** — Select, NumberInput, Slider, ColourPicker for chart configuration
228
+ - **substrate-feedback** — Toast, EmptyState, CommandPalette for data loading feedback
@@ -0,0 +1,211 @@
1
+ # Image generation
2
+
3
+ Guide to building prompt-driven image creation tools with Substrate — generation controls, preview surfaces, galleries, and parameter tuning.
4
+
5
+ ## When to use this surface
6
+
7
+ Use an image generation surface when the app involves AI-generated visuals: text-to-image tools, style transfer, inpainting/outpainting editors, texture generators, or any workflow where users iterate on generated images through prompts and parameters.
8
+
9
+ ## Surface setup
10
+
11
+ The image generation surface replaces the spatial canvas with a preview area and generation controls. The rendering engine is an API (such as fal.ai, Replicate, or a local Stable Diffusion endpoint) rather than a canvas or 3D renderer.
12
+
13
+ ### Dependencies
14
+
15
+ ```bash
16
+ npm install @fal-ai/client
17
+ ```
18
+
19
+ For other providers, install their SDK instead. The architecture is provider-agnostic — wrap the API call in a generation function and swap providers without changing the UI.
20
+
21
+ ### Environment
22
+
23
+ Store API keys in `.env.local`:
24
+
25
+ ```
26
+ FAL_KEY=your-key-here
27
+ ```
28
+
29
+ Create a server action or API route to proxy generation requests — never expose keys to the client.
30
+
31
+ ## Architecture
32
+
33
+ Unlike spatial canvases, image generation is **request/response** rather than **continuous rendering**. The core loop is:
34
+
35
+ ```
36
+ User adjusts parameters (prompt, model, seed, etc.)
37
+ → Trigger generation (server action / API route)
38
+ → Show loading state in preview
39
+ → Display result in preview area
40
+ → Optionally save to gallery/history
41
+ ```
42
+
43
+ ### Generation store
44
+
45
+ Create a Zustand store for generation state:
46
+
47
+ ```ts
48
+ interface GenerationState {
49
+ prompt: string
50
+ negativePrompt: string
51
+ model: string
52
+ parameters: Record<string, number | string | boolean>
53
+ isGenerating: boolean
54
+ currentImage: string | null
55
+ history: GenerationResult[]
56
+ error: string | null
57
+ }
58
+
59
+ interface GenerationResult {
60
+ id: string
61
+ prompt: string
62
+ imageUrl: string
63
+ parameters: Record<string, number | string | boolean>
64
+ timestamp: number
65
+ seed: number
66
+ }
67
+ ```
68
+
69
+ Actions: `setPrompt`, `setParameter`, `generate`, `saveToHistory`, `loadFromHistory`.
70
+
71
+ ### Server action
72
+
73
+ ```ts
74
+ "use server"
75
+
76
+ import { fal } from "@fal-ai/client"
77
+
78
+ export async function generateImage(params: GenerationParams) {
79
+ const result = await fal.subscribe("fal-ai/flux/schnell", {
80
+ input: {
81
+ prompt: params.prompt,
82
+ image_size: params.size,
83
+ num_inference_steps: params.steps,
84
+ seed: params.seed,
85
+ },
86
+ })
87
+ return result.data
88
+ }
89
+ ```
90
+
91
+ ## Layout
92
+
93
+ The image generation layout differs from the spatial canvas layout:
94
+
95
+ ```
96
+ ┌──────────┬────────────────────────┬──────────┐
97
+ │ │ │ │
98
+ │ Left │ Preview surface │ Right │
99
+ │ panel │ (generated image) │ panel │
100
+ │ │ │ │
101
+ │ History │ │ Params │
102
+ │ Gallery │ │ Prompt │
103
+ │ │ │ │
104
+ └──────────┴────────────────────────┴──────────┘
105
+ [ Toolbar ]
106
+ ```
107
+
108
+ ### Preview surface
109
+
110
+ A simple container that displays the current image with zoom/pan controls:
111
+
112
+ ```tsx
113
+ export function PreviewSurface() {
114
+ const currentImage = useGenerationStore((s) => s.currentImage)
115
+ const isGenerating = useGenerationStore((s) => s.isGenerating)
116
+
117
+ return (
118
+ <div className="absolute inset-0 flex items-center justify-center bg-canvas">
119
+ {isGenerating && <LoadingSpinner />}
120
+ {currentImage && (
121
+ <img
122
+ src={currentImage}
123
+ alt="Generated image"
124
+ className="max-h-full max-w-full object-contain"
125
+ />
126
+ )}
127
+ {!currentImage && !isGenerating && (
128
+ <p className="text-canvas-foreground text-sm">
129
+ Enter a prompt and generate
130
+ </p>
131
+ )}
132
+ </div>
133
+ )
134
+ }
135
+ ```
136
+
137
+ ## Wiring to Substrate chrome
138
+
139
+ ### Toolbar
140
+
141
+ The toolbar serves a different purpose here — mode switching and actions rather than spatial tools:
142
+
143
+ | Action | Purpose | Shortcut |
144
+ |---|---|---|
145
+ | Generate | Trigger image generation | Cmd+Enter |
146
+ | Compare | Side-by-side with previous | C |
147
+ | Zoom to fit | Reset preview zoom | Cmd+0 |
148
+ | Save | Download current image | Cmd+S |
149
+ | Copy prompt | Copy prompt to clipboard | Cmd+Shift+C |
150
+
151
+ ### Left panel — history and gallery
152
+
153
+ Show a scrollable grid of previously generated images. Clicking one loads it into the preview and restores its parameters. Use the Pane component for the container.
154
+
155
+ ### Right panel — generation controls
156
+
157
+ Use Pane/Action/Slider to build parameter controls:
158
+
159
+ - **Prompt pane** — textarea for the prompt, optional negative prompt
160
+ - **Model pane** — dropdown to select the model/checkpoint
161
+ - **Parameters pane** — sliders for inference steps, CFG scale, seed, image size selector
162
+ - **Style pane** (optional) — style preset buttons, LoRA weight sliders
163
+
164
+ The Action/ActionLabel/ActionControls pattern works well for each parameter row.
165
+
166
+ ## Interaction patterns
167
+
168
+ ### Prompt editing
169
+
170
+ Use a textarea in the right panel. Bind Cmd+Enter globally to trigger generation — this is the primary interaction, equivalent to pressing play.
171
+
172
+ ### Seed management
173
+
174
+ Show the current seed in the parameters pane. Provide a "randomise" button and a "lock" toggle. When locked, regenerating uses the same seed — useful for iterating on prompt wording while keeping composition stable.
175
+
176
+ ### Image comparison
177
+
178
+ When the user presses C or selects compare mode, show the current and previous image side by side or with a slider divider. This helps evaluate prompt changes.
179
+
180
+ ### Inpainting extension
181
+
182
+ For more advanced tools, the preview surface can include a canvas overlay for painting masks:
183
+
184
+ 1. Add a "mask" tool to the toolbar
185
+ 2. When active, overlay a transparent canvas on the preview image
186
+ 3. Let the user paint white (inpaint) regions
187
+ 4. Send the mask alongside the prompt to the API
188
+ 5. Use the same `useCanvasDrag` pattern for brush strokes
189
+
190
+ This is where the 2D canvas skill and image generation skill intersect.
191
+
192
+ ## Theming
193
+
194
+ The preview surface uses `bg-canvas` for its background. The generation controls in the right panel inherit panel theming. No special theming considerations beyond the standard Substrate tokens.
195
+
196
+ ## What to build
197
+
198
+ Some examples of what this surface enables:
199
+
200
+ - **Prompt studio** — iterate on prompts with parameter controls, build a gallery of results
201
+ - **Texture generator** — generate tileable textures with specific material properties
202
+ - **Character designer** — generate character variations, save favourites, export sprite sheets
203
+ - **Mood board builder** — generate images for different themes, arrange in a gallery layout
204
+ - **Inpainting editor** — upload an image, mask regions, regenerate specific areas
205
+
206
+ ## Related reference skills
207
+
208
+ - **substrate-scaffold** — Toolbar, Panel, StatusBar for the app shell
209
+ - **substrate-controls** — Slider, NumberInput, TextArea, Select for generation parameters
210
+ - **substrate-feedback** — Toast, ProgressBar for generation status, EmptyState for no results
211
+ - **substrate-canvas** — useViewport for inpainting canvas pan/zoom
@@ -0,0 +1,141 @@
1
+ # Scaffold a Substrate playground
2
+
3
+ Step-by-step guide to bootstrapping a new interactive playground from Substrate primitives.
4
+
5
+ ## What is a Substrate playground?
6
+
7
+ A Substrate playground is a creative app built from composable primitives: a **surface** (the central area where the main interaction happens), **chrome** (toolbar, panels, panes), and **stores** (Zustand state management with undo/redo). You bring the creative idea — Substrate provides the shell.
8
+
9
+ ## Prerequisites
10
+
11
+ A Next.js 14+ project with Tailwind CSS and the shadcn CLI configured. If you don't have one, run:
12
+
13
+ ```bash
14
+ npx substrate create my-playground
15
+ ```
16
+
17
+ This scaffolds a full project with dependencies, globals.css with Substrate tokens, and a starter playground page.
18
+
19
+ To add Substrate to an existing project instead:
20
+
21
+ ```bash
22
+ npx substrate-kit init
23
+ ```
24
+
25
+ This installs skills, CLAUDE.md, components.json, and registers the MCP server.
26
+
27
+ ## 1. Choose your surface
28
+
29
+ The surface is the heart of the playground — the central area where the main interaction happens. Substrate supports several surface types:
30
+
31
+ | Surface | Best for | Skill |
32
+ | ------------------ | --------------------------------------------------------- | --------------------------------------------- |
33
+ | 2D canvas | Shape editors, diagrams, whiteboards, node graphs | [canvas-2d](./canvas-2d.md) |
34
+ | 3D scene | Product viewers, scene builders, shader playgrounds | [3d-scene](./3d-scene.md) |
35
+ | Animation | Timeline editors, motion prototyping, easing explorers | [animation](./animation.md) |
36
+ | Image generation | Prompt-driven image tools, texture generators, inpainting | [image-generation](./image-generation.md) |
37
+ | Data visualisation | Chart editors, dashboard builders, data explorers | [data-visualisation](./data-visualisation.md) |
38
+
39
+ Read the relevant surface skill for setup instructions, dependencies, and architecture patterns.
40
+
41
+ ## 2. Install chrome primitives
42
+
43
+ Regardless of surface type, most playgrounds use the same chrome components:
44
+
45
+ ```bash
46
+ # UI chrome
47
+ npx shadcn@latest add https://substrate.georgedrury.co.uk/r/toolbar
48
+ npx shadcn@latest add https://substrate.georgedrury.co.uk/r/panel
49
+ npx shadcn@latest add https://substrate.georgedrury.co.uk/r/pane
50
+ npx shadcn@latest add https://substrate.georgedrury.co.uk/r/action
51
+ npx shadcn@latest add https://substrate.georgedrury.co.uk/r/slider
52
+ ```
53
+
54
+ For the 2D canvas surface specifically, also install:
55
+
56
+ ```bash
57
+ npx shadcn@latest add https://substrate.georgedrury.co.uk/r/design-canvas
58
+ ```
59
+
60
+ ## 3. Compose the layout
61
+
62
+ Every playground follows the same layout pattern — surface in the centre, optional panels on left/right, toolbar floating at the bottom:
63
+
64
+ ```tsx
65
+ "use client"
66
+
67
+ import { Panel } from "@/registry/substrate/components/panel"
68
+ import {
69
+ Toolbar,
70
+ ToolbarToggleGroup,
71
+ ToolbarToggle,
72
+ ToolbarSeparator,
73
+ } from "@/registry/substrate/components/toolbar"
74
+ import { usePanelStore } from "@/registry/substrate/stores/panel-store"
75
+ import { useToolStore } from "@/registry/substrate/stores/tool-store"
76
+
77
+ export default function PlaygroundPage() {
78
+ const leftPanel = usePanelStore((s) => s.leftPanel)
79
+ const rightPanel = usePanelStore((s) => s.rightPanel)
80
+ const activeTool = useToolStore((s) => s.activeTool)
81
+ const setTool = useToolStore((s) => s.setTool)
82
+
83
+ return (
84
+ <div className="h-screen w-screen bg-canvas">
85
+ {leftPanel && (
86
+ <Panel position="left">
87
+ {/* Layers, data sources, history — depends on surface type */}
88
+ </Panel>
89
+ )}
90
+
91
+ {/* Your surface goes here */}
92
+ {/* <DesignCanvas /> or <SceneViewport /> or <PreviewSurface /> etc. */}
93
+
94
+ {rightPanel && (
95
+ <Panel position="right">
96
+ {/* Properties, parameters, configuration — depends on surface type */}
97
+ </Panel>
98
+ )}
99
+
100
+ <Toolbar>
101
+ <ToolbarToggleGroup value={activeTool} onValueChange={setTool}>
102
+ {/* Tool toggles — depends on surface type */}
103
+ </ToolbarToggleGroup>
104
+ </Toolbar>
105
+ </div>
106
+ )
107
+ }
108
+ ```
109
+
110
+ ## 4. What the chrome gives you
111
+
112
+ Once scaffolded, the chrome primitives provide:
113
+
114
+ - **Toolbar** — floating bottom bar with toggle groups, separators, and tooltip/shortcut hints
115
+ - **Panels** — side panels (left/right) with visibility controlled by `usePanelStore`
116
+ - **Panes** — collapsible sections within panels, with headers, labels, and action buttons
117
+ - **Actions** — labelled property rows (label + controls) for building inspectors
118
+ - **Sliders** — range inputs for numeric properties
119
+
120
+ These are surface-agnostic — they work the same whether you're building a 3D scene editor or an image generation tool.
121
+
122
+ ## 5. Next steps
123
+
124
+ - **Build your surface** — read the surface skill for your chosen type
125
+ - **Add property panels** — see [composing panels](./composing-panels.md)
126
+ - **Wire keyboard shortcuts** — see [wire interactions](./wire-interactions.md)
127
+ - **Create custom tools** — see [create custom tool](./create-custom-tool.md)
128
+ - **Customise appearance** — see [theming](./theming.md)
129
+
130
+ ## Component reference skills
131
+
132
+ For a full catalogue of available components, hooks, and utilities organised by domain:
133
+
134
+ | Domain | Skill | What it covers |
135
+ | --- | --- | --- |
136
+ | App shell | **substrate-scaffold** | Toolbar, Panel, Pane, DocumentTabs, StatusBar, ZoomControls, Breadcrumbs, Resizer |
137
+ | Input controls | **substrate-controls** | NumberInput, Slider, NumberSlider, Select, Toggle, TextArea, ColourPicker, ActionControls |
138
+ | Spatial primitives | **substrate-canvas** | useViewport, useSelection, snap, boundingBox, hit testing, coordinate maths |
139
+ | Node graph | **substrate-nodes** | Node cards, typed ports, port colour theming |
140
+ | Status and communication | **substrate-feedback** | Toast, ProgressBar, Badge, EmptyState, CommandPalette, ContextMenu, ShortcutOverlay |
141
+ | Editing flows | **substrate-interaction** | useUndoable, useClipboard, createKeyboardShortcuts, HistoryControls, LayerList, TreeList |