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.
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts.d.ts +6 -0
- package/dist/prompts.d.ts.map +1 -0
- package/dist/prompts.js +127 -0
- package/dist/prompts.js.map +1 -0
- package/dist/scaffold.d.ts +10 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +395 -0
- package/dist/scaffold.js.map +1 -0
- package/dist/surfaces/3d-scene.d.ts +3 -0
- package/dist/surfaces/3d-scene.d.ts.map +1 -0
- package/dist/surfaces/3d-scene.js +184 -0
- package/dist/surfaces/3d-scene.js.map +1 -0
- package/dist/surfaces/animation.d.ts +3 -0
- package/dist/surfaces/animation.d.ts.map +1 -0
- package/dist/surfaces/animation.js +211 -0
- package/dist/surfaces/animation.js.map +1 -0
- package/dist/surfaces/blank.d.ts +3 -0
- package/dist/surfaces/blank.d.ts.map +1 -0
- package/dist/surfaces/blank.js +72 -0
- package/dist/surfaces/blank.js.map +1 -0
- package/dist/surfaces/canvas-2d.d.ts +3 -0
- package/dist/surfaces/canvas-2d.d.ts.map +1 -0
- package/dist/surfaces/canvas-2d.js +139 -0
- package/dist/surfaces/canvas-2d.js.map +1 -0
- package/dist/surfaces/data-vis.d.ts +3 -0
- package/dist/surfaces/data-vis.d.ts.map +1 -0
- package/dist/surfaces/data-vis.js +175 -0
- package/dist/surfaces/data-vis.js.map +1 -0
- package/dist/surfaces/image-gen.d.ts +3 -0
- package/dist/surfaces/image-gen.d.ts.map +1 -0
- package/dist/surfaces/image-gen.js +193 -0
- package/dist/surfaces/image-gen.js.map +1 -0
- package/dist/surfaces/index.d.ts +4 -0
- package/dist/surfaces/index.d.ts.map +1 -0
- package/dist/surfaces/index.js +17 -0
- package/dist/surfaces/index.js.map +1 -0
- package/dist/surfaces/node-editor.d.ts +3 -0
- package/dist/surfaces/node-editor.d.ts.map +1 -0
- package/dist/surfaces/node-editor.js +211 -0
- package/dist/surfaces/node-editor.js.map +1 -0
- package/dist/surfaces/types.d.ts +22 -0
- package/dist/surfaces/types.d.ts.map +1 -0
- package/dist/surfaces/types.js +10 -0
- package/dist/surfaces/types.js.map +1 -0
- package/dist/utils/detect-pm.d.ts +5 -0
- package/dist/utils/detect-pm.d.ts.map +1 -0
- package/dist/utils/detect-pm.js +20 -0
- package/dist/utils/detect-pm.js.map +1 -0
- package/dist/utils/fs.d.ts +7 -0
- package/dist/utils/fs.d.ts.map +1 -0
- package/dist/utils/fs.js +52 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/logger.d.ts +10 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +15 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/shell.d.ts +7 -0
- package/dist/utils/shell.d.ts.map +1 -0
- package/dist/utils/shell.js +28 -0
- package/dist/utils/shell.js.map +1 -0
- package/package.json +35 -0
- package/skills/3d-scene/SKILL.md +172 -0
- package/skills/animation/SKILL.md +194 -0
- package/skills/canvas-2d/SKILL.md +132 -0
- package/skills/composing-panels/SKILL.md +309 -0
- package/skills/create-custom-tool/SKILL.md +157 -0
- package/skills/data-visualisation/SKILL.md +228 -0
- package/skills/image-generation/SKILL.md +211 -0
- package/skills/scaffold-playground/SKILL.md +141 -0
- package/skills/substrate-canvas/SKILL.md +217 -0
- package/skills/substrate-controls/SKILL.md +242 -0
- package/skills/substrate-feedback/SKILL.md +219 -0
- package/skills/substrate-interaction/SKILL.md +286 -0
- package/skills/substrate-nodes/SKILL.md +208 -0
- package/skills/substrate-scaffold/SKILL.md +206 -0
- package/skills/theming/SKILL.md +117 -0
- 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 |
|