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,117 @@
1
+ # Theming Substrate
2
+
3
+ Guide to customising the visual appearance of Substrate's canvas, UI chrome, and elements.
4
+
5
+ ## How theming works
6
+
7
+ Substrate uses a CSS variable fallback chain (Tailwind v4) so you can override specific tokens without redefining everything. The pattern is:
8
+
9
+ ```css
10
+ /* @theme inline block */
11
+ --color-canvas: var(--canvas, var(--color-background));
12
+ ```
13
+
14
+ Set `--canvas` to override the canvas background; if unset, it falls back to `--color-background`.
15
+
16
+ ## 1. Substrate tokens
17
+
18
+ Substrate defines its own semantic tokens that fall back to standard shadcn tokens:
19
+
20
+ | Tailwind class | CSS variable | Fallback | Used by |
21
+ |---|---|---|---|
22
+ | `bg-canvas` | `--color-canvas` → `--canvas` | `--color-background` | Canvas background |
23
+ | `text-canvas-foreground` | `--color-canvas-foreground` → `--canvas-foreground` | `--color-foreground-muted` | Canvas grid dots |
24
+ | `bg-panel` | `--color-panel` → `--panel` | `--color-card` | Panel background |
25
+ | `text-panel-foreground` | `--color-panel-foreground` → `--panel-foreground` | `--color-card-foreground` | Panel text |
26
+
27
+ Override the short-form variables in your `:root` and `.dark` blocks:
28
+
29
+ ```css
30
+ :root {
31
+ /* Canvas */
32
+ --canvas: oklch(.97 0.0 0);
33
+ --canvas-foreground: oklch(0.556 0 0);
34
+ /* Panels */
35
+ --panel: oklch(1 0 0);
36
+ --panel-foreground: oklch(0.145 0 0);
37
+ }
38
+
39
+ .dark {
40
+ --canvas: oklch(17.764% 0.00002 271.152);
41
+ --canvas-foreground: oklch(0.708 0 0);
42
+ --panel: oklch(0.205 0 0);
43
+ --panel-foreground: oklch(0.985 0 0);
44
+ }
45
+ ```
46
+
47
+ ## 2. Standard shadcn tokens
48
+
49
+ The toolbar, slider, and tooltip still use standard shadcn tokens:
50
+
51
+ ### Key tokens per component
52
+
53
+ - **Toolbar** — `bg-background`, `border`, `shadow-lg` for the container; `hover:bg-muted`, `aria-checked:bg-accent` for toggles
54
+ - **Panel** — `bg-panel`, `text-panel-foreground`, `border-border`
55
+ - **Pane** — `bg-panel` for action buttons, inherits `panel-foreground` for text
56
+ - **Slider** — track uses `bg-accent`, thumb uses `bg-foreground`
57
+ - **Tooltip** — inverted: `bg-foreground`, `text-background`
58
+
59
+ ## 3. Canvas rendering
60
+
61
+ The canvas background is now driven by the `--canvas` CSS variable, read at render time via `getComputedStyle`. This means it automatically responds to light/dark mode and custom themes.
62
+
63
+ Grid dots, selection UI, and other renderer constants are still hardcoded in `canvas/renderer.ts`:
64
+
65
+ ### Grid
66
+
67
+ Look for the grid rendering function. Key values:
68
+
69
+ - Grid line colour (default: light grey)
70
+ - Grid spacing (default: 20px world units)
71
+ - Major grid line interval
72
+
73
+ ### Selection UI
74
+
75
+ - Selection box stroke colour (default: blue `#3b82f6`)
76
+ - Resize handle fill/stroke
77
+ - Marquee selection fill (semi-transparent blue)
78
+
79
+ ### Element defaults
80
+
81
+ New element colours are set in `lib/element-factory.ts`. Each factory function defines default `fill` and `stroke` values.
82
+
83
+ ## 3. Component-level overrides with `cn()`
84
+
85
+ Every Substrate component accepts `className` and spreads it via `cn()`. You can override specific styles per-instance:
86
+
87
+ ```tsx
88
+ <Toolbar className="rounded-lg bg-zinc-900 border-zinc-800">
89
+ {/* Dark toolbar variant */}
90
+ </Toolbar>
91
+
92
+ <Panel position="left" className="w-72 bg-zinc-950">
93
+ {/* Wider, darker panel */}
94
+ </Panel>
95
+ ```
96
+
97
+ ## 4. Cursor customisation
98
+
99
+ Cursors are mapped in `design-canvas.tsx`'s `CURSOR_MAP`. You can swap these for custom cursor URLs:
100
+
101
+ ```ts
102
+ const CURSOR_MAP: Record<string, string> = {
103
+ select: "default",
104
+ hand: "grab",
105
+ rectangle: "url(/cursors/crosshair.svg) 12 12, crosshair",
106
+ // ...
107
+ }
108
+ ```
109
+
110
+ ## 5. Dark mode
111
+
112
+ Substrate UI components automatically respect dark mode when using `next-themes` or a `.dark` class on the document. The canvas renderer needs manual dark mode handling — check a CSS variable or a store flag and swap your colour constants accordingly.
113
+
114
+ ## Related reference skills
115
+
116
+ - **substrate-nodes** — port type CSS variables (7 port colours + 4 node chrome vars) follow the same fallback chain
117
+ - **substrate-controls** — ColourPicker, SwatchPalette for colour selection in property panes
@@ -0,0 +1,155 @@
1
+ # Wire interactions
2
+
3
+ Guide to connecting canvas pointer events, drag state, keyboard shortcuts, and the interaction state machine in Substrate.
4
+
5
+ ## Architecture overview
6
+
7
+ Substrate's interaction system is a layered pipeline:
8
+
9
+ ```
10
+ Pointer events (DOM)
11
+ → useCanvasInteraction (state machine)
12
+ → useCanvasDrag (drag tracking)
13
+ → useCanvasTransform (coordinate conversion)
14
+ → useHitTest (what's under the cursor)
15
+ → useDocumentStore (mutations)
16
+ → markDirty() → useCanvasRenderer (repaint)
17
+
18
+ Keyboard events (DOM)
19
+ → useKeyboardShortcuts
20
+ → useToolStore (tool switching)
21
+ → useDocumentStore (delete, undo/redo, select all, duplicate)
22
+ → useCanvasTransform (zoom)
23
+ ```
24
+
25
+ ## The interaction state machine
26
+
27
+ `useCanvasInteraction` is the central orchestrator. It manages an `InteractionMode`:
28
+
29
+ | Mode | Triggered by | During move | On release |
30
+ |---|---|---|---|
31
+ | `idle` | Default state | Update hover, cursor | — |
32
+ | `panning` | Middle-click, or hand tool drag | Update camera via `setCamera` | Return to idle |
33
+ | `creating` | Drag with shape tool on empty canvas | Preview element dimensions | Commit new element to store |
34
+ | `moving` | Drag on selected element | Update element positions | Commit positions |
35
+ | `resizing` | Drag on resize handle | Update element bounds | Commit bounds |
36
+ | `marquee_selecting` | Drag on empty canvas with select tool | Draw selection rectangle | Select contained elements |
37
+
38
+ ### Pointer down logic
39
+
40
+ ```
41
+ 1. Convert screen point → world point (useCanvasTransform)
42
+ 2. Check for resize handle hit (useHitTest)
43
+ → Yes: start "resizing" drag
44
+ 3. Check for element hit (useHitTest)
45
+ → Yes + already selected: start "moving" drag
46
+ → Yes + not selected: select it, start "moving" drag
47
+ → Yes + shift held: toggle selection
48
+ 4. No hit + shape tool active: start "creating" drag
49
+ 5. No hit + select tool: start "marquee_selecting" drag
50
+ 6. Middle button or hand tool: start "panning" drag
51
+ ```
52
+
53
+ ### Pointer move logic
54
+
55
+ ```
56
+ 1. If not dragging: update hover state via hit-test, return
57
+ 2. Convert to world coordinates
58
+ 3. Update drag state (useCanvasDrag.updateDrag)
59
+ 4. Based on drag type:
60
+ - "pan": update camera
61
+ - "create": preview element (stored on drag ref, rendered by renderer)
62
+ - "move": update element positions (delta from start)
63
+ - "resize": update element bounds respecting handle position
64
+ - "marquee": update selection rectangle
65
+ 5. Call markDirty() to trigger repaint
66
+ ```
67
+
68
+ ### Pointer up logic
69
+
70
+ ```
71
+ 1. End drag (useCanvasDrag.endDrag)
72
+ 2. Based on drag type:
73
+ - "create": push snapshot, add element to store, select it, reset tool to select
74
+ - "move"/"resize": push snapshot (positions already updated during drag)
75
+ - "marquee": select all elements within the marquee bounds
76
+ - "pan": nothing to commit
77
+ ```
78
+
79
+ ## Coordinate system
80
+
81
+ Substrate uses two coordinate systems:
82
+
83
+ - **Screen space** — pixel coordinates relative to the canvas element
84
+ - **World space** — the infinite canvas coordinate system, affected by camera pan and zoom
85
+
86
+ `useCanvasTransform` provides:
87
+
88
+ - `screenToWorld(point)` — convert screen → world
89
+ - `worldToScreen(point)` — convert world → screen
90
+ - `pan(dx, dy)` — move camera
91
+ - `zoomToPoint(point, delta)` — zoom centred on a point
92
+
93
+ Always convert pointer event coordinates to world space before doing hit-testing or element manipulation.
94
+
95
+ ## The drag state machine
96
+
97
+ `useCanvasDrag` tracks the current drag operation via a ref (not React state — avoids re-renders during high-frequency pointer moves):
98
+
99
+ ```ts
100
+ interface DragInfo {
101
+ type: DragType // "create" | "move" | "resize" | "marquee" | "pan"
102
+ startWorld: Point // Where the drag began (world space)
103
+ startScreen: Point // Where the drag began (screen space)
104
+ currentWorld: Point // Current position (updated on every move)
105
+ currentScreen: Point
106
+ handle?: HandlePosition // Which resize handle, if resizing
107
+ elementStartPositions?: Record<string, { x, y, width, height }> // Snapshot for move/resize
108
+ }
109
+ ```
110
+
111
+ ## Adding a custom interaction
112
+
113
+ To add a new interaction pattern:
114
+
115
+ 1. **Define the mode** — add to `InteractionMode` in `types.ts` if it's a new state
116
+ 2. **Entry condition** — add detection in the pointer down handler
117
+ 3. **During drag** — add a case in pointer move
118
+ 4. **Completion** — add a case in pointer up
119
+ 5. **Always call `markDirty()`** after any visual change
120
+ 6. **Always call `pushSnapshot()`** before committing mutations (for undo/redo)
121
+
122
+ ## Keyboard shortcuts
123
+
124
+ `useKeyboardShortcuts` listens globally on `window`. It:
125
+
126
+ - Skips events when an input/textarea is focused
127
+ - Supports modifier combinations (`meta+key`, `shift+key`)
128
+ - Supports temporary tool switching (hold Space for hand tool, release to restore)
129
+
130
+ To add a shortcut:
131
+
132
+ ```ts
133
+ // In the handleKeyDown callback
134
+ case "your-key": {
135
+ e.preventDefault()
136
+ // Your action
137
+ return
138
+ }
139
+ ```
140
+
141
+ For modifier combinations, check `meta` (which is `e.metaKey || e.ctrlKey` for cross-platform):
142
+
143
+ ```ts
144
+ if (meta && e.key.toLowerCase() === "k") {
145
+ e.preventDefault()
146
+ // Cmd+K action
147
+ return
148
+ }
149
+ ```
150
+
151
+ ## Related reference skills
152
+
153
+ - **substrate-interaction** — full catalogue of useUndoable, useClipboard, createKeyboardShortcuts (declarative replacement for switch statements), and formatShortcut
154
+ - **substrate-canvas** — useViewport, useSelection, useDragReorder, snap, boundingBox
155
+ - **substrate-feedback** — CommandPalette (⌘K), ShortcutOverlay (?), ContextMenu, Toast (for delete-with-undo)