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,184 @@
1
+ export const scene3d = {
2
+ components: [
3
+ "toolbar",
4
+ "panel",
5
+ "pane",
6
+ "slider",
7
+ "number-input",
8
+ "colour-picker",
9
+ "status-bar",
10
+ ],
11
+ extraDeps: {
12
+ three: "^0.170.0",
13
+ "@react-three/fiber": "^8.17.0",
14
+ "@react-three/drei": "^9.117.0",
15
+ },
16
+ extraDevDeps: {
17
+ "@types/three": "^0.170.0",
18
+ },
19
+ app: () => `import { useState, useRef } from "react"
20
+ import { Canvas } from "@react-three/fiber"
21
+ import { OrbitControls, Grid, Environment } from "@react-three/drei"
22
+ import {
23
+ Toolbar,
24
+ ToolbarToggleGroup,
25
+ ToolbarToggle,
26
+ ToolbarSeparator,
27
+ } from "@/components/substrate/toolbar"
28
+ import { Panel } from "@/components/substrate/panel"
29
+ import {
30
+ Pane,
31
+ PaneHeader,
32
+ PaneLabel,
33
+ PaneContent,
34
+ } from "@/components/substrate/pane"
35
+ import { NumberInput } from "@/components/substrate/number-input"
36
+ import { Slider } from "@/components/substrate/slider"
37
+ import { ColourPicker } from "@/components/substrate/colour-picker"
38
+ import { StatusBar, StatusBarSection, StatusBarItem } from "@/components/substrate/status-bar"
39
+ import {
40
+ RiCursorLine,
41
+ RiDragMoveLine,
42
+ RiRefreshLine,
43
+ RiExpandDiagonal2Line,
44
+ } from "@remixicon/react"
45
+
46
+ interface SceneObject {
47
+ id: string
48
+ type: "box" | "sphere"
49
+ position: [number, number, number]
50
+ colour: string
51
+ roughness: number
52
+ }
53
+
54
+ const INITIAL_OBJECTS: SceneObject[] = [
55
+ { id: "box-1", type: "box", position: [-1.5, 0.5, 0], colour: "#6366f1", roughness: 0.4 },
56
+ { id: "sphere-1", type: "sphere", position: [1.5, 0.6, 0], colour: "#f43f5e", roughness: 0.2 },
57
+ ]
58
+
59
+ function SceneMesh({
60
+ object,
61
+ selected,
62
+ onSelect,
63
+ }: {
64
+ object: SceneObject
65
+ selected: boolean
66
+ onSelect: () => void
67
+ }) {
68
+ return (
69
+ <mesh position={object.position} onClick={onSelect}>
70
+ {object.type === "box" ? (
71
+ <boxGeometry args={[1, 1, 1]} />
72
+ ) : (
73
+ <sphereGeometry args={[0.6, 32, 32]} />
74
+ )}
75
+ <meshStandardMaterial
76
+ color={object.colour}
77
+ roughness={object.roughness}
78
+ emissive={selected ? "#ffffff" : "#000000"}
79
+ emissiveIntensity={selected ? 0.05 : 0}
80
+ />
81
+ </mesh>
82
+ )
83
+ }
84
+
85
+ export default function App() {
86
+ const [mode, setMode] = useState("select")
87
+ const [objects, setObjects] = useState(INITIAL_OBJECTS)
88
+ const [selectedId, setSelectedId] = useState<string | null>(null)
89
+
90
+ const selected = objects.find((o) => o.id === selectedId) ?? null
91
+
92
+ function updateSelected(patch: Partial<SceneObject>) {
93
+ if (!selectedId) return
94
+ setObjects((prev) =>
95
+ prev.map((o) => (o.id === selectedId ? { ...o, ...patch } : o))
96
+ )
97
+ }
98
+
99
+ return (
100
+ <div className="flex h-screen flex-col bg-background text-foreground">
101
+ <div className="relative flex flex-1 overflow-hidden">
102
+ <div className="flex-1 bg-canvas">
103
+ <Canvas camera={{ position: [4, 3, 4], fov: 50 }}>
104
+ <ambientLight intensity={0.4} />
105
+ <directionalLight position={[5, 8, 5]} intensity={1} />
106
+ <Environment preset="studio" />
107
+ <Grid infiniteGrid fadeDistance={20} cellColor="#333" sectionColor="#555" />
108
+ <OrbitControls makeDefault />
109
+ {objects.map((obj) => (
110
+ <SceneMesh
111
+ key={obj.id}
112
+ object={obj}
113
+ selected={obj.id === selectedId}
114
+ onSelect={() => setSelectedId(obj.id)}
115
+ />
116
+ ))}
117
+ </Canvas>
118
+ </div>
119
+
120
+ <Panel position="right">
121
+ {selected ? (
122
+ <>
123
+ <Pane>
124
+ <PaneHeader>
125
+ <PaneLabel>Position</PaneLabel>
126
+ </PaneHeader>
127
+ <PaneContent>
128
+ <div className="grid grid-cols-3 gap-2">
129
+ <NumberInput label="X" value={selected.position[0]} step={0.1} onChange={(v) => updateSelected({ position: [v, selected.position[1], selected.position[2]] })} />
130
+ <NumberInput label="Y" value={selected.position[1]} step={0.1} onChange={(v) => updateSelected({ position: [selected.position[0], v, selected.position[2]] })} />
131
+ <NumberInput label="Z" value={selected.position[2]} step={0.1} onChange={(v) => updateSelected({ position: [selected.position[0], selected.position[1], v] })} />
132
+ </div>
133
+ </PaneContent>
134
+ </Pane>
135
+ <Pane>
136
+ <PaneHeader>
137
+ <PaneLabel>Material</PaneLabel>
138
+ </PaneHeader>
139
+ <PaneContent className="space-y-3">
140
+ <ColourPicker value={selected.colour} onChange={(c) => updateSelected({ colour: c })} />
141
+ <Slider label="Roughness" min={0} max={1} step={0.01} value={[selected.roughness]} onValueChange={([v]) => updateSelected({ roughness: v })} />
142
+ </PaneContent>
143
+ </Pane>
144
+ </>
145
+ ) : (
146
+ <Pane>
147
+ <PaneContent>
148
+ <p className="text-sm text-muted-foreground">Click an object to inspect</p>
149
+ </PaneContent>
150
+ </Pane>
151
+ )}
152
+ </Panel>
153
+ </div>
154
+
155
+ <Toolbar>
156
+ <ToolbarToggleGroup value={mode} onValueChange={setMode}>
157
+ <ToolbarToggle value="select" tooltip="Select" shortcut="V">
158
+ <RiCursorLine className="size-4" />
159
+ </ToolbarToggle>
160
+ <ToolbarSeparator />
161
+ <ToolbarToggle value="translate" tooltip="Translate" shortcut="G">
162
+ <RiDragMoveLine className="size-4" />
163
+ </ToolbarToggle>
164
+ <ToolbarToggle value="rotate" tooltip="Rotate" shortcut="R">
165
+ <RiRefreshLine className="size-4" />
166
+ </ToolbarToggle>
167
+ <ToolbarToggle value="scale" tooltip="Scale" shortcut="S">
168
+ <RiExpandDiagonal2Line className="size-4" />
169
+ </ToolbarToggle>
170
+ </ToolbarToggleGroup>
171
+ </Toolbar>
172
+
173
+ <StatusBar>
174
+ <StatusBarSection>
175
+ <StatusBarItem label="Mode" value={mode} />
176
+ {selected && <StatusBarItem label="Selected" value={selected.id} />}
177
+ </StatusBarSection>
178
+ </StatusBar>
179
+ </div>
180
+ )
181
+ }
182
+ `,
183
+ };
184
+ //# sourceMappingURL=3d-scene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"3d-scene.js","sourceRoot":"","sources":["../../src/surfaces/3d-scene.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,QAAQ;QACR,cAAc;QACd,eAAe;QACf,YAAY;KACb;IACD,SAAS,EAAE;QACT,KAAK,EAAE,UAAU;QACjB,oBAAoB,EAAE,SAAS;QAC/B,mBAAmB,EAAE,UAAU;KAChC;IACD,YAAY,EAAE;QACZ,cAAc,EAAE,UAAU;KAC3B;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAmKZ;CACA,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { SurfaceConfig } from "./types.js";
2
+ export declare const animation: SurfaceConfig;
3
+ //# sourceMappingURL=animation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.d.ts","sourceRoot":"","sources":["../../src/surfaces/animation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,SAAS,EAAE,aAiNvB,CAAA"}
@@ -0,0 +1,211 @@
1
+ export const animation = {
2
+ components: [
3
+ "toolbar",
4
+ "panel",
5
+ "pane",
6
+ "timeline",
7
+ "easing-curve-editor",
8
+ "slider",
9
+ "number-input",
10
+ "history-controls",
11
+ "status-bar",
12
+ ],
13
+ extraDeps: {
14
+ gsap: "^3.12.0",
15
+ },
16
+ app: () => `import { useState, useRef, useEffect } from "react"
17
+ import {
18
+ Toolbar,
19
+ ToolbarToggleGroup,
20
+ ToolbarToggle,
21
+ ToolbarSeparator,
22
+ } from "@/components/substrate/toolbar"
23
+ import { Panel } from "@/components/substrate/panel"
24
+ import {
25
+ Pane,
26
+ PaneHeader,
27
+ PaneLabel,
28
+ PaneContent,
29
+ } from "@/components/substrate/pane"
30
+ import { Timeline } from "@/components/substrate/timeline"
31
+ import { EasingCurveEditor } from "@/components/substrate/easing-curve-editor"
32
+ import { NumberInput } from "@/components/substrate/number-input"
33
+ import { Slider } from "@/components/substrate/slider"
34
+ import { HistoryControls } from "@/components/substrate/history-controls"
35
+ import { StatusBar, StatusBarSection, StatusBarItem } from "@/components/substrate/status-bar"
36
+ import {
37
+ RiPlayLine,
38
+ RiPauseLine,
39
+ RiStopLine,
40
+ RiSkipBackLine,
41
+ } from "@remixicon/react"
42
+
43
+ interface Keyframe {
44
+ id: string
45
+ time: number
46
+ value: number
47
+ }
48
+
49
+ interface Track {
50
+ id: string
51
+ label: string
52
+ keyframes: Keyframe[]
53
+ }
54
+
55
+ const INITIAL_TRACKS: Track[] = [
56
+ {
57
+ id: "position-x",
58
+ label: "Position X",
59
+ keyframes: [
60
+ { id: "k1", time: 0, value: 50 },
61
+ { id: "k2", time: 30, value: 300 },
62
+ { id: "k3", time: 60, value: 150 },
63
+ ],
64
+ },
65
+ {
66
+ id: "opacity",
67
+ label: "Opacity",
68
+ keyframes: [
69
+ { id: "k4", time: 0, value: 100 },
70
+ { id: "k5", time: 20, value: 30 },
71
+ { id: "k6", time: 50, value: 100 },
72
+ ],
73
+ },
74
+ ]
75
+
76
+ export default function App() {
77
+ const [playing, setPlaying] = useState(false)
78
+ const [currentFrame, setCurrentFrame] = useState(0)
79
+ const [totalFrames] = useState(60)
80
+ const [tracks] = useState(INITIAL_TRACKS)
81
+ const [easing, setEasing] = useState<[number, number, number, number]>([0.4, 0, 0.2, 1])
82
+ const animRef = useRef<number | null>(null)
83
+ const boxRef = useRef<HTMLDivElement>(null)
84
+
85
+ useEffect(() => {
86
+ if (!playing) {
87
+ if (animRef.current) cancelAnimationFrame(animRef.current)
88
+ return
89
+ }
90
+
91
+ let frame = currentFrame
92
+ const tick = () => {
93
+ frame = (frame + 1) % totalFrames
94
+ setCurrentFrame(frame)
95
+ animRef.current = requestAnimationFrame(tick)
96
+ }
97
+ animRef.current = requestAnimationFrame(tick)
98
+ return () => {
99
+ if (animRef.current) cancelAnimationFrame(animRef.current)
100
+ }
101
+ }, [playing])
102
+
103
+ // Interpolate position and opacity from keyframes
104
+ const posX = interpolate(tracks[0].keyframes, currentFrame)
105
+ const opacity = interpolate(tracks[1].keyframes, currentFrame) / 100
106
+
107
+ return (
108
+ <div className="flex h-screen flex-col bg-background text-foreground">
109
+ <div className="relative flex flex-1 overflow-hidden">
110
+ {/* Preview stage */}
111
+ <div className="flex flex-1 items-center justify-center bg-canvas">
112
+ <div
113
+ ref={boxRef}
114
+ className="size-20 rounded-lg bg-primary"
115
+ style={{
116
+ transform: \`translateX(\${posX - 150}px)\`,
117
+ opacity,
118
+ }}
119
+ />
120
+ </div>
121
+
122
+ <Panel position="right">
123
+ <Pane>
124
+ <PaneHeader>
125
+ <PaneLabel>Easing</PaneLabel>
126
+ </PaneHeader>
127
+ <PaneContent>
128
+ <EasingCurveEditor value={easing} onChange={setEasing} />
129
+ </PaneContent>
130
+ </Pane>
131
+ <Pane>
132
+ <PaneHeader>
133
+ <PaneLabel>Keyframe</PaneLabel>
134
+ </PaneHeader>
135
+ <PaneContent>
136
+ <div className="grid grid-cols-2 gap-2">
137
+ <NumberInput label="Frame" value={currentFrame} onChange={setCurrentFrame} min={0} max={totalFrames} />
138
+ <NumberInput label="Value" defaultValue={0} />
139
+ </div>
140
+ </PaneContent>
141
+ </Pane>
142
+ </Panel>
143
+ </div>
144
+
145
+ {/* Timeline */}
146
+ <div className="h-48 border-t border-border bg-panel">
147
+ <Timeline
148
+ tracks={tracks}
149
+ currentFrame={currentFrame}
150
+ totalFrames={totalFrames}
151
+ onFrameChange={setCurrentFrame}
152
+ />
153
+ </div>
154
+
155
+ <Toolbar>
156
+ <ToolbarToggle
157
+ value="back"
158
+ tooltip="Go to start"
159
+ onPressedChange={() => { setCurrentFrame(0); setPlaying(false) }}
160
+ >
161
+ <RiSkipBackLine className="size-4" />
162
+ </ToolbarToggle>
163
+ <ToolbarToggle
164
+ value="play"
165
+ pressed={playing}
166
+ tooltip={playing ? "Pause" : "Play"}
167
+ shortcut="Space"
168
+ onPressedChange={() => setPlaying(!playing)}
169
+ >
170
+ {playing ? <RiPauseLine className="size-4" /> : <RiPlayLine className="size-4" />}
171
+ </ToolbarToggle>
172
+ <ToolbarToggle
173
+ value="stop"
174
+ tooltip="Stop"
175
+ onPressedChange={() => { setPlaying(false); setCurrentFrame(0) }}
176
+ >
177
+ <RiStopLine className="size-4" />
178
+ </ToolbarToggle>
179
+ </Toolbar>
180
+
181
+ <StatusBar>
182
+ <StatusBarSection>
183
+ <StatusBarItem label="Frame" value={\`\${currentFrame} / \${totalFrames}\`} />
184
+ <StatusBarItem label="State" value={playing ? "Playing" : "Stopped"} />
185
+ </StatusBarSection>
186
+ <StatusBarSection>
187
+ <HistoryControls canUndo={false} canRedo={false} onUndo={() => {}} onRedo={() => {}} />
188
+ </StatusBarSection>
189
+ </StatusBar>
190
+ </div>
191
+ )
192
+ }
193
+
194
+ function interpolate(keyframes: Keyframe[], frame: number): number {
195
+ if (keyframes.length === 0) return 0
196
+ if (frame <= keyframes[0].time) return keyframes[0].value
197
+ if (frame >= keyframes[keyframes.length - 1].time) return keyframes[keyframes.length - 1].value
198
+
199
+ for (let i = 0; i < keyframes.length - 1; i++) {
200
+ const a = keyframes[i]
201
+ const b = keyframes[i + 1]
202
+ if (frame >= a.time && frame <= b.time) {
203
+ const t = (frame - a.time) / (b.time - a.time)
204
+ return a.value + (b.value - a.value) * t
205
+ }
206
+ }
207
+ return 0
208
+ }
209
+ `,
210
+ };
211
+ //# sourceMappingURL=animation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animation.js","sourceRoot":"","sources":["../../src/surfaces/animation.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,SAAS,GAAkB;IACtC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,UAAU;QACV,qBAAqB;QACrB,QAAQ;QACR,cAAc;QACd,kBAAkB;QAClB,YAAY;KACb;IACD,SAAS,EAAE;QACT,IAAI,EAAE,SAAS;KAChB;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiMZ;CACA,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { SurfaceConfig } from "./types.js";
2
+ export declare const blank: SurfaceConfig;
3
+ //# sourceMappingURL=blank.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blank.d.ts","sourceRoot":"","sources":["../../src/surfaces/blank.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,KAAK,EAAE,aAsEnB,CAAA"}
@@ -0,0 +1,72 @@
1
+ export const blank = {
2
+ components: [
3
+ "toolbar",
4
+ "panel",
5
+ "pane",
6
+ "surface",
7
+ "empty-state",
8
+ "status-bar",
9
+ ],
10
+ app: () => `import { useState } from "react"
11
+ import {
12
+ Toolbar,
13
+ ToolbarToggleGroup,
14
+ ToolbarToggle,
15
+ ToolbarSeparator,
16
+ } from "@/components/substrate/toolbar"
17
+ import { Panel } from "@/components/substrate/panel"
18
+ import { Surface } from "@/components/substrate/surface"
19
+ import { EmptyState } from "@/components/substrate/empty-state"
20
+ import { StatusBar, StatusBarSection, StatusBarItem } from "@/components/substrate/status-bar"
21
+ import { RiCursorLine, RiHand } from "@remixicon/react"
22
+
23
+ export default function App() {
24
+ const [tool, setTool] = useState("select")
25
+
26
+ return (
27
+ <div className="flex h-screen flex-col bg-background text-foreground">
28
+ <div className="relative flex flex-1 overflow-hidden">
29
+ <Panel position="left">
30
+ <EmptyState
31
+ title="Left panel"
32
+ description="Add layers, assets, or navigation here"
33
+ />
34
+ </Panel>
35
+
36
+ <Surface className="flex-1">
37
+ <EmptyState
38
+ title="Your surface here"
39
+ description="Replace this with your rendering engine — canvas, Three.js, timeline, or anything else"
40
+ />
41
+ </Surface>
42
+
43
+ <Panel position="right">
44
+ <EmptyState
45
+ title="Right panel"
46
+ description="Add property controls and inspectors here"
47
+ />
48
+ </Panel>
49
+ </div>
50
+
51
+ <Toolbar>
52
+ <ToolbarToggleGroup value={tool} onValueChange={setTool}>
53
+ <ToolbarToggle value="select" tooltip="Select" shortcut="V">
54
+ <RiCursorLine className="size-4" />
55
+ </ToolbarToggle>
56
+ <ToolbarToggle value="hand" tooltip="Hand" shortcut="H">
57
+ <RiHand className="size-4" />
58
+ </ToolbarToggle>
59
+ </ToolbarToggleGroup>
60
+ </Toolbar>
61
+
62
+ <StatusBar>
63
+ <StatusBarSection>
64
+ <StatusBarItem label="Tool" value={tool} />
65
+ </StatusBarSection>
66
+ </StatusBar>
67
+ </div>
68
+ )
69
+ }
70
+ `,
71
+ };
72
+ //# sourceMappingURL=blank.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blank.js","sourceRoot":"","sources":["../../src/surfaces/blank.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,KAAK,GAAkB;IAClC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,SAAS;QACT,aAAa;QACb,YAAY;KACb;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4DZ;CACA,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { SurfaceConfig } from "./types.js";
2
+ export declare const canvas2d: SurfaceConfig;
3
+ //# sourceMappingURL=canvas-2d.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-2d.d.ts","sourceRoot":"","sources":["../../src/surfaces/canvas-2d.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,QAAQ,EAAE,aAyItB,CAAA"}
@@ -0,0 +1,139 @@
1
+ export const canvas2d = {
2
+ components: [
3
+ "design-canvas",
4
+ "toolbar",
5
+ "panel",
6
+ "pane",
7
+ "slider",
8
+ "layer-list",
9
+ "number-input",
10
+ "colour-picker",
11
+ "history-controls",
12
+ "status-bar",
13
+ "zoom-controls",
14
+ ],
15
+ app: () => `import { useState } from "react"
16
+ import { DesignCanvas } from "@/components/substrate/design-canvas"
17
+ import {
18
+ Toolbar,
19
+ ToolbarToggleGroup,
20
+ ToolbarToggle,
21
+ ToolbarSeparator,
22
+ } from "@/components/substrate/toolbar"
23
+ import { Panel } from "@/components/substrate/panel"
24
+ import {
25
+ Pane,
26
+ PaneHeader,
27
+ PaneLabel,
28
+ PaneContent,
29
+ } from "@/components/substrate/pane"
30
+ import { LayerList, LayerItem, LayerIcon, LayerName } from "@/components/substrate/layer-list"
31
+ import { NumberInput } from "@/components/substrate/number-input"
32
+ import { ColourPicker } from "@/components/substrate/colour-picker"
33
+ import { HistoryControls } from "@/components/substrate/history-controls"
34
+ import { StatusBar, StatusBarSection, StatusBarItem } from "@/components/substrate/status-bar"
35
+ import { ZoomControls } from "@/components/substrate/zoom-controls"
36
+ import {
37
+ RiCursorLine,
38
+ RiHand,
39
+ RiSquareLine,
40
+ RiCircleLine,
41
+ RiSubtractLine,
42
+ RiText,
43
+ RiArtboard2Line,
44
+ } from "@remixicon/react"
45
+
46
+ const TOOLS = [
47
+ { value: "select", icon: RiCursorLine, label: "Select", shortcut: "V" },
48
+ { value: "hand", icon: RiHand, label: "Hand", shortcut: "H" },
49
+ "separator",
50
+ { value: "rectangle", icon: RiSquareLine, label: "Rectangle", shortcut: "R" },
51
+ { value: "ellipse", icon: RiCircleLine, label: "Ellipse", shortcut: "O" },
52
+ { value: "line", icon: RiSubtractLine, label: "Line", shortcut: "L" },
53
+ { value: "text", icon: RiText, label: "Text", shortcut: "T" },
54
+ { value: "frame", icon: RiArtboard2Line, label: "Frame", shortcut: "F" },
55
+ ] as const
56
+
57
+ export default function App() {
58
+ const [tool, setTool] = useState("select")
59
+ const [zoom, setZoom] = useState(1)
60
+
61
+ return (
62
+ <div className="flex h-screen flex-col bg-background text-foreground">
63
+ <div className="relative flex flex-1 overflow-hidden">
64
+ <Panel position="left">
65
+ <Pane>
66
+ <PaneHeader>
67
+ <PaneLabel>Layers</PaneLabel>
68
+ </PaneHeader>
69
+ <PaneContent>
70
+ <LayerList>
71
+ <LayerItem>
72
+ <LayerIcon><RiSquareLine className="size-3.5" /></LayerIcon>
73
+ <LayerName>Rectangle 1</LayerName>
74
+ </LayerItem>
75
+ <LayerItem>
76
+ <LayerIcon><RiCircleLine className="size-3.5" /></LayerIcon>
77
+ <LayerName>Ellipse 1</LayerName>
78
+ </LayerItem>
79
+ </LayerList>
80
+ </PaneContent>
81
+ </Pane>
82
+ </Panel>
83
+
84
+ <DesignCanvas />
85
+
86
+ <Panel position="right">
87
+ <Pane>
88
+ <PaneHeader>
89
+ <PaneLabel>Transform</PaneLabel>
90
+ </PaneHeader>
91
+ <PaneContent>
92
+ <div className="grid grid-cols-2 gap-2">
93
+ <NumberInput label="X" defaultValue={0} />
94
+ <NumberInput label="Y" defaultValue={0} />
95
+ <NumberInput label="W" defaultValue={100} />
96
+ <NumberInput label="H" defaultValue={100} />
97
+ </div>
98
+ </PaneContent>
99
+ </Pane>
100
+ <Pane>
101
+ <PaneHeader>
102
+ <PaneLabel>Fill</PaneLabel>
103
+ </PaneHeader>
104
+ <PaneContent>
105
+ <ColourPicker />
106
+ </PaneContent>
107
+ </Pane>
108
+ </Panel>
109
+ </div>
110
+
111
+ <Toolbar>
112
+ <ToolbarToggleGroup value={tool} onValueChange={setTool}>
113
+ {TOOLS.map((t, i) =>
114
+ t === "separator" ? (
115
+ <ToolbarSeparator key={i} />
116
+ ) : (
117
+ <ToolbarToggle key={t.value} value={t.value} tooltip={t.label} shortcut={t.shortcut}>
118
+ <t.icon className="size-4" />
119
+ </ToolbarToggle>
120
+ )
121
+ )}
122
+ </ToolbarToggleGroup>
123
+ </Toolbar>
124
+
125
+ <StatusBar>
126
+ <StatusBarSection>
127
+ <StatusBarItem label="Tool" value={tool} />
128
+ </StatusBarSection>
129
+ <StatusBarSection>
130
+ <HistoryControls canUndo={false} canRedo={false} onUndo={() => {}} onRedo={() => {}} />
131
+ <ZoomControls zoom={zoom} onZoomIn={() => setZoom((z) => Math.min(z * 1.25, 10))} onZoomOut={() => setZoom((z) => Math.max(z / 1.25, 0.1))} onReset={() => setZoom(1)} />
132
+ </StatusBarSection>
133
+ </StatusBar>
134
+ </div>
135
+ )
136
+ }
137
+ `,
138
+ };
139
+ //# sourceMappingURL=canvas-2d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas-2d.js","sourceRoot":"","sources":["../../src/surfaces/canvas-2d.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,UAAU,EAAE;QACV,eAAe;QACf,SAAS;QACT,OAAO;QACP,MAAM;QACN,QAAQ;QACR,YAAY;QACZ,cAAc;QACd,eAAe;QACf,kBAAkB;QAClB,YAAY;QACZ,eAAe;KAChB;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0HZ;CACA,CAAA"}
@@ -0,0 +1,3 @@
1
+ import type { SurfaceConfig } from "./types.js";
2
+ export declare const dataVis: SurfaceConfig;
3
+ //# sourceMappingURL=data-vis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"data-vis.d.ts","sourceRoot":"","sources":["../../src/surfaces/data-vis.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,OAAO,EAAE,aA6KrB,CAAA"}