create-substrate 0.1.6 → 0.2.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/LICENSE +21 -0
- package/README.md +11 -4
- package/dist/index.js +25 -7
- package/dist/index.js.map +1 -1
- package/dist/prompts.d.ts +0 -2
- package/dist/prompts.d.ts.map +1 -1
- package/dist/prompts.js +6 -50
- package/dist/prompts.js.map +1 -1
- package/dist/scaffold.d.ts.map +1 -1
- package/dist/scaffold.js +82 -80
- package/dist/scaffold.js.map +1 -1
- package/dist/surfaces/3d-scene.d.ts.map +1 -1
- package/dist/surfaces/3d-scene.js +43 -74
- package/dist/surfaces/3d-scene.js.map +1 -1
- package/dist/surfaces/canvas-2d.d.ts.map +1 -1
- package/dist/surfaces/canvas-2d.js +7 -10
- package/dist/surfaces/canvas-2d.js.map +1 -1
- package/dist/surfaces/data-vis.d.ts.map +1 -1
- package/dist/surfaces/data-vis.js +37 -143
- package/dist/surfaces/data-vis.js.map +1 -1
- package/dist/surfaces/image-gen.d.ts.map +1 -1
- package/dist/surfaces/image-gen.js +15 -35
- package/dist/surfaces/image-gen.js.map +1 -1
- package/dist/surfaces/node-editor.js +1 -1
- package/dist/utils/detect-pm.d.ts +2 -0
- package/dist/utils/detect-pm.d.ts.map +1 -1
- package/dist/utils/detect-pm.js +9 -0
- package/dist/utils/detect-pm.js.map +1 -1
- package/dist/utils/package-info.d.ts +5 -0
- package/dist/utils/package-info.d.ts.map +1 -0
- package/dist/utils/package-info.js +17 -0
- package/dist/utils/package-info.js.map +1 -0
- package/package.json +4 -3
- package/skills/3d-scene/SKILL.md +2 -1
- package/skills/animation/SKILL.md +2 -1
- package/skills/canvas-2d/SKILL.md +67 -5
- package/skills/composing-panels/SKILL.md +1 -4
- package/skills/data-visualisation/SKILL.md +2 -1
- package/skills/image-generation/SKILL.md +2 -1
- package/skills/install-components/SKILL.md +22 -16
- package/skills/scaffold-playground/SKILL.md +39 -19
- package/skills/substrate-canvas/SKILL.md +5 -0
- package/skills/substrate-controls/SKILL.md +57 -2
- package/skills/substrate-interaction/SKILL.md +19 -10
- package/skills/substrate-scaffold/SKILL.md +4 -4
- package/skills/theming/SKILL.md +8 -2
- package/skills/wire-interactions/SKILL.md +6 -3
- package/templates/agents-section.md +41 -0
|
@@ -3,10 +3,8 @@ export const scene3d = {
|
|
|
3
3
|
"toolbar",
|
|
4
4
|
"panel",
|
|
5
5
|
"pane",
|
|
6
|
-
"action",
|
|
7
|
-
"slider",
|
|
8
6
|
"number-input",
|
|
9
|
-
"
|
|
7
|
+
"controls",
|
|
10
8
|
"status-bar",
|
|
11
9
|
],
|
|
12
10
|
extraDeps: {
|
|
@@ -35,10 +33,9 @@ import {
|
|
|
35
33
|
PaneAction,
|
|
36
34
|
PaneContent,
|
|
37
35
|
} from "@/components/substrate/pane"
|
|
38
|
-
import { Action, ActionLabel, ActionControls } from "@/components/substrate/action"
|
|
39
36
|
import { NumberInput } from "@/components/substrate/number-input"
|
|
40
|
-
import {
|
|
41
|
-
import {
|
|
37
|
+
import { Controls } from "@/components/substrate/controls"
|
|
38
|
+
import { useControls, type ControlsConfig } from "@/hooks/substrate/use-controls"
|
|
42
39
|
import {
|
|
43
40
|
StatusBar,
|
|
44
41
|
StatusBarSection,
|
|
@@ -107,7 +104,7 @@ const INITIAL_OBJECTS: SceneObject[] = [
|
|
|
107
104
|
]
|
|
108
105
|
|
|
109
106
|
const toolbarButton =
|
|
110
|
-
"inline-flex h-7 min-w-7 items-center justify-center rounded-md px-2 outline-none transition-
|
|
107
|
+
"inline-flex h-7 min-w-7 items-center justify-center rounded-md px-2 outline-none transition-[color,background-color,box-shadow,transform] active:scale-[0.96] hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50"
|
|
111
108
|
|
|
112
109
|
function isMode(value: string): value is Mode {
|
|
113
110
|
return MODES.some((mode) => mode === value)
|
|
@@ -184,11 +181,43 @@ function SceneMesh({
|
|
|
184
181
|
)
|
|
185
182
|
}
|
|
186
183
|
|
|
184
|
+
type Material = Pick<SceneObject, "colour" | "roughness" | "metalness">
|
|
185
|
+
|
|
186
|
+
// Material values belong to the selected object, not to the panel. Mounting
|
|
187
|
+
// this with key={object.id} gives each selection its own panel: the object's
|
|
188
|
+
// values seed the config, and edits are written back through onChange.
|
|
189
|
+
function MaterialControls({
|
|
190
|
+
object,
|
|
191
|
+
onChange,
|
|
192
|
+
}: {
|
|
193
|
+
object: SceneObject
|
|
194
|
+
onChange: (material: Material) => void
|
|
195
|
+
}) {
|
|
196
|
+
const [config] = useState(
|
|
197
|
+
() =>
|
|
198
|
+
({
|
|
199
|
+
colour: object.colour,
|
|
200
|
+
roughness: [object.roughness, 0, 1, 0.01],
|
|
201
|
+
metalness: [object.metalness, 0, 1, 0.01],
|
|
202
|
+
}) satisfies ControlsConfig,
|
|
203
|
+
)
|
|
204
|
+
const material = useControls("Material", config)
|
|
205
|
+
|
|
206
|
+
const onChangeRef = useRef(onChange)
|
|
207
|
+
onChangeRef.current = onChange
|
|
208
|
+
useEffect(() => {
|
|
209
|
+
onChangeRef.current(material)
|
|
210
|
+
}, [material])
|
|
211
|
+
|
|
212
|
+
return <Controls panel="Material" />
|
|
213
|
+
}
|
|
214
|
+
|
|
187
215
|
export default function App() {
|
|
188
216
|
const [mode, setMode] = useState<Mode>("select")
|
|
189
217
|
const [objects, setObjects] = useState(INITIAL_OBJECTS)
|
|
190
218
|
const [selectedId, setSelectedId] = useState<string | null>("box-1")
|
|
191
|
-
const
|
|
219
|
+
const lighting = useControls("Lighting", { intensity: [1.5, 0, 4, 0.05] })
|
|
220
|
+
const lightIntensity = lighting.intensity
|
|
192
221
|
const nextIndex = useRef(INITIAL_OBJECTS.length + 1)
|
|
193
222
|
|
|
194
223
|
const selected = objects.find((object) => object.id === selectedId) ?? null
|
|
@@ -362,25 +391,7 @@ export default function App() {
|
|
|
362
391
|
</PaneContent>
|
|
363
392
|
</Pane>
|
|
364
393
|
|
|
365
|
-
<
|
|
366
|
-
<PaneHeader>
|
|
367
|
-
<PaneLabel>Lighting</PaneLabel>
|
|
368
|
-
</PaneHeader>
|
|
369
|
-
<PaneContent>
|
|
370
|
-
<Action>
|
|
371
|
-
<ActionLabel>Intensity</ActionLabel>
|
|
372
|
-
<ActionControls>
|
|
373
|
-
<Slider
|
|
374
|
-
min={0}
|
|
375
|
-
max={4}
|
|
376
|
-
step={0.05}
|
|
377
|
-
value={[lightIntensity]}
|
|
378
|
-
onValueChange={([value]) => setLightIntensity(value)}
|
|
379
|
-
/>
|
|
380
|
-
</ActionControls>
|
|
381
|
-
</Action>
|
|
382
|
-
</PaneContent>
|
|
383
|
-
</Pane>
|
|
394
|
+
<Controls panel="Lighting" />
|
|
384
395
|
|
|
385
396
|
{selected ? (
|
|
386
397
|
<>
|
|
@@ -451,53 +462,11 @@ export default function App() {
|
|
|
451
462
|
</PaneContent>
|
|
452
463
|
</Pane>
|
|
453
464
|
|
|
454
|
-
<
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
<Action>
|
|
460
|
-
<ActionLabel>Colour</ActionLabel>
|
|
461
|
-
<ActionControls>
|
|
462
|
-
<ColourPicker
|
|
463
|
-
value={selected.colour}
|
|
464
|
-
onChange={(colour) => updateObject(selected.id, { colour })}
|
|
465
|
-
/>
|
|
466
|
-
<span className="font-mono text-xs text-muted-foreground">
|
|
467
|
-
{selected.colour}
|
|
468
|
-
</span>
|
|
469
|
-
</ActionControls>
|
|
470
|
-
</Action>
|
|
471
|
-
<Action>
|
|
472
|
-
<ActionLabel>Roughness</ActionLabel>
|
|
473
|
-
<ActionControls>
|
|
474
|
-
<Slider
|
|
475
|
-
min={0}
|
|
476
|
-
max={1}
|
|
477
|
-
step={0.01}
|
|
478
|
-
value={[selected.roughness]}
|
|
479
|
-
onValueChange={([value]) =>
|
|
480
|
-
updateObject(selected.id, { roughness: value })
|
|
481
|
-
}
|
|
482
|
-
/>
|
|
483
|
-
</ActionControls>
|
|
484
|
-
</Action>
|
|
485
|
-
<Action>
|
|
486
|
-
<ActionLabel>Metalness</ActionLabel>
|
|
487
|
-
<ActionControls>
|
|
488
|
-
<Slider
|
|
489
|
-
min={0}
|
|
490
|
-
max={1}
|
|
491
|
-
step={0.01}
|
|
492
|
-
value={[selected.metalness]}
|
|
493
|
-
onValueChange={([value]) =>
|
|
494
|
-
updateObject(selected.id, { metalness: value })
|
|
495
|
-
}
|
|
496
|
-
/>
|
|
497
|
-
</ActionControls>
|
|
498
|
-
</Action>
|
|
499
|
-
</PaneContent>
|
|
500
|
-
</Pane>
|
|
465
|
+
<MaterialControls
|
|
466
|
+
key={selected.id}
|
|
467
|
+
object={selected}
|
|
468
|
+
onChange={(patch) => updateObject(selected.id, patch)}
|
|
469
|
+
/>
|
|
501
470
|
</>
|
|
502
471
|
) : (
|
|
503
472
|
<Pane>
|
|
@@ -1 +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,
|
|
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,cAAc;QACd,UAAU;QACV,YAAY;KACb;IACD,SAAS,EAAE;QACT,KAAK,EAAE,UAAU;QACjB,oBAAoB,EAAE,QAAQ;QAC9B,mBAAmB,EAAE,SAAS;KAC/B;IACD,YAAY,EAAE;QACZ,cAAc,EAAE,UAAU;KAC3B;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgeZ;CACA,CAAA"}
|
|
@@ -1 +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,
|
|
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,aAgatB,CAAA"}
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
} from "@/components/substrate/status-bar"
|
|
46
46
|
import { ZoomControls } from "@/components/substrate/zoom-controls"
|
|
47
47
|
import { useDocumentStore } from "@/stores/substrate/document-store"
|
|
48
|
+
import { useCanvasTransform } from "@/hooks/substrate/use-canvas-transform"
|
|
48
49
|
import { useToolStore } from "@/stores/substrate/tool-store"
|
|
49
50
|
import { createRectangle, createEllipse } from "@/lib/substrate/element-factory"
|
|
50
51
|
import type { DesignElement, ToolType } from "@/lib/substrate/types"
|
|
@@ -82,11 +83,8 @@ const SHAPE_TOOLS: ToolDefinition[] = [
|
|
|
82
83
|
|
|
83
84
|
const TOOLS = [...POINTER_TOOLS, ...SHAPE_TOOLS]
|
|
84
85
|
|
|
85
|
-
// The colour picker edits hex values. Shapes drawn with the tools start with
|
|
86
|
-
// an oklch fill, so the picker opens on this grey until a colour is chosen.
|
|
87
|
-
const PICKER_FALLBACK = "#d4d4d4"
|
|
88
86
|
const ACTION_BUTTON =
|
|
89
|
-
"inline-flex h-7 min-w-7 items-center justify-center rounded-md px-2 outline-none transition-
|
|
87
|
+
"inline-flex h-7 min-w-7 items-center justify-center rounded-md px-2 outline-none transition-[color,background-color,box-shadow,transform] active:scale-[0.96] hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 data-active:bg-accent data-active:text-accent-foreground"
|
|
90
88
|
|
|
91
89
|
// Seed the document with a couple of shapes so the canvas is not empty.
|
|
92
90
|
// Everything on the canvas lives in the document store; replace this with
|
|
@@ -279,7 +277,6 @@ function PropertiesPanel() {
|
|
|
279
277
|
|
|
280
278
|
const id = element.id
|
|
281
279
|
const fill = element.fill
|
|
282
|
-
const fillHex = fill && fill.color.startsWith("#") ? fill.color : PICKER_FALLBACK
|
|
283
280
|
|
|
284
281
|
return (
|
|
285
282
|
<Panel position="right" className="shrink-0">
|
|
@@ -342,8 +339,8 @@ function PropertiesPanel() {
|
|
|
342
339
|
<PaneContent className="flex items-center gap-2">
|
|
343
340
|
{/* One undo step per drag: snapshot when the picker is pressed */}
|
|
344
341
|
<ColourPicker
|
|
345
|
-
value={
|
|
346
|
-
|
|
342
|
+
value={fill ? fill.color : "transparent"}
|
|
343
|
+
onStart={pushSnapshot}
|
|
347
344
|
onChange={(color) =>
|
|
348
345
|
updateElement(id, {
|
|
349
346
|
fill: { type: "solid", color, opacity: fill?.opacity ?? 1 },
|
|
@@ -367,7 +364,7 @@ function PropertiesPanel() {
|
|
|
367
364
|
function EditorStatusBar() {
|
|
368
365
|
const activeTool = useToolStore((s) => s.activeTool)
|
|
369
366
|
const zoom = useDocumentStore((s) => s.camera.zoom)
|
|
370
|
-
const
|
|
367
|
+
const { setZoom, zoomToFit } = useCanvasTransform()
|
|
371
368
|
const selectedCount = useDocumentStore((s) => s.selectedIds.size)
|
|
372
369
|
const elementCount = useDocumentStore((s) => s.elementOrder.length)
|
|
373
370
|
|
|
@@ -390,8 +387,8 @@ function EditorStatusBar() {
|
|
|
390
387
|
<StatusBarSection align="right">
|
|
391
388
|
<ZoomControls
|
|
392
389
|
zoom={zoom}
|
|
393
|
-
onZoomChange={
|
|
394
|
-
onZoomToFit={
|
|
390
|
+
onZoomChange={setZoom}
|
|
391
|
+
onZoomToFit={zoomToFit}
|
|
395
392
|
min={0.1}
|
|
396
393
|
max={10}
|
|
397
394
|
step={0.1}
|
|
@@ -1 +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,OAAO;QACP,gBAAgB;QAChB,YAAY;QACZ,iBAAiB;QACjB,eAAe;QACf,SAAS;QACT,OAAO;QACP,MAAM;QACN,YAAY;QACZ,cAAc;QACd,eAAe;QACf,kBAAkB;QAClB,YAAY;QACZ,eAAe;KAChB;IACD,GAAG,EAAE,GAAG,EAAE,CAAC
|
|
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,OAAO;QACP,gBAAgB;QAChB,YAAY;QACZ,iBAAiB;QACjB,eAAe;QACf,SAAS;QACT,OAAO;QACP,MAAM;QACN,YAAY;QACZ,cAAc;QACd,eAAe;QACf,kBAAkB;QAClB,YAAY;QACZ,eAAe;KAChB;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA8YZ;CACA,CAAA"}
|
|
@@ -1 +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,
|
|
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,aAuOrB,CAAA"}
|
|
@@ -2,12 +2,7 @@ export const dataVis = {
|
|
|
2
2
|
components: [
|
|
3
3
|
"toolbar",
|
|
4
4
|
"panel",
|
|
5
|
-
"
|
|
6
|
-
"action",
|
|
7
|
-
"select",
|
|
8
|
-
"number-slider",
|
|
9
|
-
"colour-picker",
|
|
10
|
-
"toggle-group",
|
|
5
|
+
"controls",
|
|
11
6
|
"status-bar",
|
|
12
7
|
],
|
|
13
8
|
extraDeps: {
|
|
@@ -33,22 +28,8 @@ import {
|
|
|
33
28
|
ToolbarToggleGroup,
|
|
34
29
|
} from "@/components/substrate/toolbar"
|
|
35
30
|
import { Panel } from "@/components/substrate/panel"
|
|
36
|
-
import {
|
|
37
|
-
import {
|
|
38
|
-
Action,
|
|
39
|
-
ActionControls,
|
|
40
|
-
ActionLabel,
|
|
41
|
-
} from "@/components/substrate/action"
|
|
42
|
-
import {
|
|
43
|
-
Select,
|
|
44
|
-
SelectContent,
|
|
45
|
-
SelectItem,
|
|
46
|
-
SelectTrigger,
|
|
47
|
-
SelectValue,
|
|
48
|
-
} from "@/components/substrate/select"
|
|
49
|
-
import { NumberSlider } from "@/components/substrate/number-slider"
|
|
50
|
-
import { ColourPicker } from "@/components/substrate/colour-picker"
|
|
51
|
-
import { ToggleGroup, ToggleGroupItem } from "@/components/substrate/toggle-group"
|
|
31
|
+
import { Controls } from "@/components/substrate/controls"
|
|
32
|
+
import { useControls } from "@/hooks/substrate/use-controls"
|
|
52
33
|
import {
|
|
53
34
|
StatusBar,
|
|
54
35
|
StatusBarItem,
|
|
@@ -76,17 +57,17 @@ const SAMPLE_DATA = [
|
|
|
76
57
|
{ month: "Dec", revenue: 9100, users: 7400, orders: 830 },
|
|
77
58
|
]
|
|
78
59
|
|
|
79
|
-
const METRICS = [
|
|
80
|
-
{ value: "revenue", label: "Revenue" },
|
|
81
|
-
{ value: "users", label: "Users" },
|
|
82
|
-
{ value: "orders", label: "Orders" },
|
|
83
|
-
] as const
|
|
84
|
-
|
|
85
60
|
const CHART_TYPES = ["line", "area", "bar"] as const
|
|
86
61
|
|
|
87
|
-
type Metric =
|
|
62
|
+
type Metric = "revenue" | "users" | "orders"
|
|
88
63
|
type ChartType = (typeof CHART_TYPES)[number]
|
|
89
64
|
|
|
65
|
+
const METRICS: { value: Metric; label: string }[] = [
|
|
66
|
+
{ value: "revenue", label: "Revenue" },
|
|
67
|
+
{ value: "users", label: "Users" },
|
|
68
|
+
{ value: "orders", label: "Orders" },
|
|
69
|
+
]
|
|
70
|
+
|
|
90
71
|
function isMetric(value: string): value is Metric {
|
|
91
72
|
return METRICS.some((metric) => metric.value === value)
|
|
92
73
|
}
|
|
@@ -106,12 +87,22 @@ const TOOLTIP_STYLE = {
|
|
|
106
87
|
|
|
107
88
|
export default function App() {
|
|
108
89
|
const [chartType, setChartType] = useState<ChartType>("line")
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
const
|
|
113
|
-
|
|
114
|
-
|
|
90
|
+
|
|
91
|
+
// Each useControls call is one panel; <Controls panel="..." /> renders it.
|
|
92
|
+
// Edit these objects to add, remove or retune a control.
|
|
93
|
+
const dataControls = useControls("Data", {
|
|
94
|
+
metric: { type: "select", options: METRICS, default: "revenue" },
|
|
95
|
+
months: [12, 3, SAMPLE_DATA.length, 1],
|
|
96
|
+
})
|
|
97
|
+
const style = useControls("Style", {
|
|
98
|
+
colour: "#6366f1",
|
|
99
|
+
stroke: [2, 1, 6, 0.5],
|
|
100
|
+
fill: [0.3, 0, 1, 0.05],
|
|
101
|
+
grid: true,
|
|
102
|
+
})
|
|
103
|
+
|
|
104
|
+
const metric = isMetric(dataControls.metric) ? dataControls.metric : "revenue"
|
|
105
|
+
const { months } = dataControls
|
|
115
106
|
|
|
116
107
|
const data = SAMPLE_DATA.slice(0, months)
|
|
117
108
|
const values = data.map((row) => row[metric])
|
|
@@ -120,7 +111,7 @@ export default function App() {
|
|
|
120
111
|
|
|
121
112
|
const axes = (
|
|
122
113
|
<>
|
|
123
|
-
{grid
|
|
114
|
+
{style.grid && (
|
|
124
115
|
<CartesianGrid strokeDasharray="3 3" stroke="var(--border)" vertical={false} />
|
|
125
116
|
)}
|
|
126
117
|
<XAxis dataKey="month" tick={AXIS_TICK} stroke="var(--border)" tickLine={false} />
|
|
@@ -139,46 +130,7 @@ export default function App() {
|
|
|
139
130
|
<div className="flex h-screen flex-col bg-background text-foreground">
|
|
140
131
|
<div className="flex min-h-0 flex-1">
|
|
141
132
|
<Panel position="left" className="shrink-0">
|
|
142
|
-
<
|
|
143
|
-
<PaneHeader>
|
|
144
|
-
<PaneLabel>Data</PaneLabel>
|
|
145
|
-
</PaneHeader>
|
|
146
|
-
<Action>
|
|
147
|
-
<ActionLabel>Metric</ActionLabel>
|
|
148
|
-
<ActionControls>
|
|
149
|
-
<Select
|
|
150
|
-
value={metric}
|
|
151
|
-
onValueChange={(value) => {
|
|
152
|
-
if (isMetric(value)) setMetric(value)
|
|
153
|
-
}}
|
|
154
|
-
>
|
|
155
|
-
<SelectTrigger aria-label="Metric">
|
|
156
|
-
<SelectValue />
|
|
157
|
-
</SelectTrigger>
|
|
158
|
-
<SelectContent>
|
|
159
|
-
{METRICS.map((item) => (
|
|
160
|
-
<SelectItem key={item.value} value={item.value}>
|
|
161
|
-
{item.label}
|
|
162
|
-
</SelectItem>
|
|
163
|
-
))}
|
|
164
|
-
</SelectContent>
|
|
165
|
-
</Select>
|
|
166
|
-
</ActionControls>
|
|
167
|
-
</Action>
|
|
168
|
-
<Action>
|
|
169
|
-
<ActionLabel>Months</ActionLabel>
|
|
170
|
-
<ActionControls>
|
|
171
|
-
<NumberSlider
|
|
172
|
-
value={months}
|
|
173
|
-
onChange={(value) => setMonths(Math.round(value))}
|
|
174
|
-
min={3}
|
|
175
|
-
max={SAMPLE_DATA.length}
|
|
176
|
-
step={1}
|
|
177
|
-
precision={0}
|
|
178
|
-
/>
|
|
179
|
-
</ActionControls>
|
|
180
|
-
</Action>
|
|
181
|
-
</Pane>
|
|
133
|
+
<Controls panel="Data" />
|
|
182
134
|
</Panel>
|
|
183
135
|
|
|
184
136
|
{/* Chart surface */}
|
|
@@ -199,7 +151,7 @@ export default function App() {
|
|
|
199
151
|
<Bar
|
|
200
152
|
dataKey={metric}
|
|
201
153
|
name={metricLabel}
|
|
202
|
-
fill={colour}
|
|
154
|
+
fill={style.colour}
|
|
203
155
|
radius={[4, 4, 0, 0]}
|
|
204
156
|
maxBarSize={32}
|
|
205
157
|
isAnimationActive={false}
|
|
@@ -212,10 +164,10 @@ export default function App() {
|
|
|
212
164
|
type="monotone"
|
|
213
165
|
dataKey={metric}
|
|
214
166
|
name={metricLabel}
|
|
215
|
-
stroke={colour}
|
|
216
|
-
strokeWidth={
|
|
217
|
-
fill={colour}
|
|
218
|
-
fillOpacity={
|
|
167
|
+
stroke={style.colour}
|
|
168
|
+
strokeWidth={style.stroke}
|
|
169
|
+
fill={style.colour}
|
|
170
|
+
fillOpacity={style.fill}
|
|
219
171
|
isAnimationActive={false}
|
|
220
172
|
/>
|
|
221
173
|
</AreaChart>
|
|
@@ -226,9 +178,9 @@ export default function App() {
|
|
|
226
178
|
type="monotone"
|
|
227
179
|
dataKey={metric}
|
|
228
180
|
name={metricLabel}
|
|
229
|
-
stroke={colour}
|
|
230
|
-
strokeWidth={
|
|
231
|
-
dot={{ fill: colour, r: 3 }}
|
|
181
|
+
stroke={style.colour}
|
|
182
|
+
strokeWidth={style.stroke}
|
|
183
|
+
dot={{ fill: style.colour, r: 3 }}
|
|
232
184
|
isAnimationActive={false}
|
|
233
185
|
/>
|
|
234
186
|
</LineChart>
|
|
@@ -238,65 +190,7 @@ export default function App() {
|
|
|
238
190
|
</main>
|
|
239
191
|
|
|
240
192
|
<Panel position="right" className="shrink-0">
|
|
241
|
-
<
|
|
242
|
-
<PaneHeader>
|
|
243
|
-
<PaneLabel>Style</PaneLabel>
|
|
244
|
-
</PaneHeader>
|
|
245
|
-
<Action>
|
|
246
|
-
<ActionLabel>Colour</ActionLabel>
|
|
247
|
-
<ActionControls>
|
|
248
|
-
<ColourPicker value={colour} onChange={setColour} />
|
|
249
|
-
<span className="font-mono text-xs text-muted-foreground">{colour}</span>
|
|
250
|
-
</ActionControls>
|
|
251
|
-
</Action>
|
|
252
|
-
{chartType !== "bar" && (
|
|
253
|
-
<Action>
|
|
254
|
-
<ActionLabel>Stroke</ActionLabel>
|
|
255
|
-
<ActionControls>
|
|
256
|
-
<NumberSlider
|
|
257
|
-
value={strokeWidth}
|
|
258
|
-
onChange={setStrokeWidth}
|
|
259
|
-
min={1}
|
|
260
|
-
max={6}
|
|
261
|
-
step={0.5}
|
|
262
|
-
suffix="px"
|
|
263
|
-
/>
|
|
264
|
-
</ActionControls>
|
|
265
|
-
</Action>
|
|
266
|
-
)}
|
|
267
|
-
{chartType === "area" && (
|
|
268
|
-
<Action>
|
|
269
|
-
<ActionLabel>Fill</ActionLabel>
|
|
270
|
-
<ActionControls>
|
|
271
|
-
<NumberSlider
|
|
272
|
-
value={fillOpacity}
|
|
273
|
-
onChange={setFillOpacity}
|
|
274
|
-
min={0}
|
|
275
|
-
max={100}
|
|
276
|
-
step={1}
|
|
277
|
-
precision={0}
|
|
278
|
-
suffix="%"
|
|
279
|
-
/>
|
|
280
|
-
</ActionControls>
|
|
281
|
-
</Action>
|
|
282
|
-
)}
|
|
283
|
-
<Action>
|
|
284
|
-
<ActionLabel>Grid</ActionLabel>
|
|
285
|
-
<ActionControls>
|
|
286
|
-
<ToggleGroup
|
|
287
|
-
type="single"
|
|
288
|
-
value={grid}
|
|
289
|
-
onValueChange={(value) => {
|
|
290
|
-
if (value) setGrid(value)
|
|
291
|
-
}}
|
|
292
|
-
aria-label="Grid lines"
|
|
293
|
-
>
|
|
294
|
-
<ToggleGroupItem value="on">On</ToggleGroupItem>
|
|
295
|
-
<ToggleGroupItem value="off">Off</ToggleGroupItem>
|
|
296
|
-
</ToggleGroup>
|
|
297
|
-
</ActionControls>
|
|
298
|
-
</Action>
|
|
299
|
-
</Pane>
|
|
193
|
+
<Controls panel="Style" />
|
|
300
194
|
</Panel>
|
|
301
195
|
</div>
|
|
302
196
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-vis.js","sourceRoot":"","sources":["../../src/surfaces/data-vis.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,
|
|
1
|
+
{"version":3,"file":"data-vis.js","sourceRoot":"","sources":["../../src/surfaces/data-vis.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,UAAU;QACV,YAAY;KACb;IACD,SAAS,EAAE;QACT,QAAQ,EAAE,QAAQ;KACnB;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA4NZ;CACA,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-gen.d.ts","sourceRoot":"","sources":["../../src/surfaces/image-gen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,QAAQ,EAAE,
|
|
1
|
+
{"version":3,"file":"image-gen.d.ts","sourceRoot":"","sources":["../../src/surfaces/image-gen.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAE/C,eAAO,MAAM,QAAQ,EAAE,aAibtB,CAAA"}
|
|
@@ -6,7 +6,7 @@ export const imageGen = {
|
|
|
6
6
|
"action",
|
|
7
7
|
"gallery",
|
|
8
8
|
"text-area",
|
|
9
|
-
"
|
|
9
|
+
"controls",
|
|
10
10
|
"number-input",
|
|
11
11
|
"progress-bar",
|
|
12
12
|
"status-bar",
|
|
@@ -36,7 +36,8 @@ import {
|
|
|
36
36
|
GalleryEmpty,
|
|
37
37
|
} from "@/components/substrate/gallery"
|
|
38
38
|
import { TextArea } from "@/components/substrate/text-area"
|
|
39
|
-
import {
|
|
39
|
+
import { Controls } from "@/components/substrate/controls"
|
|
40
|
+
import { useControlsController } from "@/hooks/substrate/use-controls"
|
|
40
41
|
import { NumberInput } from "@/components/substrate/number-input"
|
|
41
42
|
import { ProgressBar } from "@/components/substrate/progress-bar"
|
|
42
43
|
import {
|
|
@@ -171,12 +172,18 @@ const INITIAL_GENERATIONS: Generation[] = [
|
|
|
171
172
|
]
|
|
172
173
|
|
|
173
174
|
const TOOLBAR_BUTTON =
|
|
174
|
-
"inline-flex h-7 items-center justify-center gap-1.5 rounded-md px-2 text-xs font-medium outline-none transition-
|
|
175
|
+
"inline-flex h-7 items-center justify-center gap-1.5 rounded-md px-2 text-xs font-medium outline-none transition-[color,background-color,box-shadow,transform] active:scale-[0.96] hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50"
|
|
175
176
|
|
|
176
177
|
export default function App() {
|
|
177
178
|
const [prompt, setPrompt] = useState("Misty mountain valley at sunrise")
|
|
178
|
-
|
|
179
|
-
|
|
179
|
+
// The Parameters pane is generated from this config. The controller form
|
|
180
|
+
// of the hook adds setValues, used below to load a past result's settings.
|
|
181
|
+
const parameters = useControlsController("Parameters", {
|
|
182
|
+
steps: [30, 1, 100, 1],
|
|
183
|
+
cfgScale: [7, 1, 20, 0.5],
|
|
184
|
+
})
|
|
185
|
+
const steps = parameters.values.steps
|
|
186
|
+
const cfg = parameters.values.cfgScale
|
|
180
187
|
const [seed, setSeed] = useState(-1)
|
|
181
188
|
const [aspect, setAspect] = useState<AspectRatio>("1:1")
|
|
182
189
|
const [generating, setGenerating] = useState(false)
|
|
@@ -230,8 +237,7 @@ export default function App() {
|
|
|
230
237
|
function handleSelect(generation: Generation) {
|
|
231
238
|
setSelectedId(generation.id)
|
|
232
239
|
setPrompt(generation.prompt)
|
|
233
|
-
|
|
234
|
-
setCfg(generation.cfg)
|
|
240
|
+
parameters.setValues({ steps: generation.steps, cfgScale: generation.cfg })
|
|
235
241
|
setSeed(generation.seed)
|
|
236
242
|
setAspect(generation.aspect)
|
|
237
243
|
}
|
|
@@ -270,9 +276,10 @@ export default function App() {
|
|
|
270
276
|
{generating && <ProgressBar value={progress} aria-label="Generation progress" />}
|
|
271
277
|
</PaneContent>
|
|
272
278
|
</Pane>
|
|
279
|
+
<Controls panel="Parameters" />
|
|
273
280
|
<Pane>
|
|
274
281
|
<PaneHeader>
|
|
275
|
-
<PaneLabel>
|
|
282
|
+
<PaneLabel>Seed</PaneLabel>
|
|
276
283
|
<PaneAction
|
|
277
284
|
type="button"
|
|
278
285
|
title="Random seed"
|
|
@@ -283,33 +290,6 @@ export default function App() {
|
|
|
283
290
|
</PaneAction>
|
|
284
291
|
</PaneHeader>
|
|
285
292
|
<PaneContent className="space-y-1">
|
|
286
|
-
<Action>
|
|
287
|
-
<ActionLabel>Steps</ActionLabel>
|
|
288
|
-
<ActionControls>
|
|
289
|
-
<Slider
|
|
290
|
-
aria-label="Steps"
|
|
291
|
-
min={1}
|
|
292
|
-
max={100}
|
|
293
|
-
value={[steps]}
|
|
294
|
-
onValueChange={(value) => setSteps(value[0] ?? steps)}
|
|
295
|
-
/>
|
|
296
|
-
<span className="w-8 text-right text-xs tabular-nums">{steps}</span>
|
|
297
|
-
</ActionControls>
|
|
298
|
-
</Action>
|
|
299
|
-
<Action>
|
|
300
|
-
<ActionLabel>CFG scale</ActionLabel>
|
|
301
|
-
<ActionControls>
|
|
302
|
-
<Slider
|
|
303
|
-
aria-label="CFG scale"
|
|
304
|
-
min={1}
|
|
305
|
-
max={20}
|
|
306
|
-
step={0.5}
|
|
307
|
-
value={[cfg]}
|
|
308
|
-
onValueChange={(value) => setCfg(value[0] ?? cfg)}
|
|
309
|
-
/>
|
|
310
|
-
<span className="w-8 text-right text-xs tabular-nums">{cfg}</span>
|
|
311
|
-
</ActionControls>
|
|
312
|
-
</Action>
|
|
313
293
|
<Action>
|
|
314
294
|
<ActionLabel>Seed</ActionLabel>
|
|
315
295
|
<ActionControls>
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-gen.js","sourceRoot":"","sources":["../../src/surfaces/image-gen.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,QAAQ;QACR,SAAS;QACT,WAAW;QACX,
|
|
1
|
+
{"version":3,"file":"image-gen.js","sourceRoot":"","sources":["../../src/surfaces/image-gen.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,QAAQ,GAAkB;IACrC,UAAU,EAAE;QACV,SAAS;QACT,OAAO;QACP,MAAM;QACN,QAAQ;QACR,SAAS;QACT,WAAW;QACX,UAAU;QACV,cAAc;QACd,cAAc;QACd,YAAY;QACZ,aAAa;KACd;IACD,GAAG,EAAE,GAAG,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkaZ;CACA,CAAA"}
|
|
@@ -260,7 +260,7 @@ type Drag =
|
|
|
260
260
|
| { kind: "pan"; startX: number; startY: number; originX: number; originY: number }
|
|
261
261
|
|
|
262
262
|
const actionButton =
|
|
263
|
-
"inline-flex h-7 items-center gap-1 rounded-md px-2 text-xs font-medium outline-none transition-
|
|
263
|
+
"inline-flex h-7 items-center gap-1 rounded-md px-2 text-xs font-medium outline-none transition-[color,background-color,box-shadow,transform] active:scale-[0.96] hover:bg-muted hover:text-foreground focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:pointer-events-none disabled:opacity-50 [&_svg]:size-3.5"
|
|
264
264
|
|
|
265
265
|
export default function App() {
|
|
266
266
|
const [tool, setTool] = useState<Tool>("select")
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export type PackageManager = "npm" | "pnpm" | "bun";
|
|
2
|
+
export declare function isPackageManager(value: string): value is PackageManager;
|
|
3
|
+
export declare function detectRunningPackageManager(userAgent?: string | undefined): PackageManager | null;
|
|
2
4
|
export declare function detectPackageManager(cwd: string): PackageManager;
|
|
3
5
|
export declare function getInstallCommand(pm: PackageManager): string;
|
|
4
6
|
export declare function getRunCommand(pm: PackageManager, script: string): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"detect-pm.d.ts","sourceRoot":"","sources":["../../src/utils/detect-pm.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;AAEnD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAQhE;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxE"}
|
|
1
|
+
{"version":3,"file":"detect-pm.d.ts","sourceRoot":"","sources":["../../src/utils/detect-pm.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAA;AAEnD,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,cAAc,CAEvE;AAID,wBAAgB,2BAA2B,CACzC,SAAS,GAAE,MAAM,GAAG,SAA6C,GAChE,cAAc,GAAG,IAAI,CAGvB;AAED,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,MAAM,GAAG,cAAc,CAQhE;AAED,wBAAgB,iBAAiB,CAAC,EAAE,EAAE,cAAc,GAAG,MAAM,CAE5D;AAED,wBAAgB,aAAa,CAAC,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAGxE"}
|
package/dist/utils/detect-pm.js
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
export function isPackageManager(value) {
|
|
4
|
+
return value === "npm" || value === "pnpm" || value === "bun";
|
|
5
|
+
}
|
|
6
|
+
// npm, pnpm and bun all set npm_config_user_agent to e.g. "pnpm/9.1.0 npm/? ...",
|
|
7
|
+
// so the tool that ran `create-substrate` is the one the user prefers.
|
|
8
|
+
export function detectRunningPackageManager(userAgent = process.env.npm_config_user_agent) {
|
|
9
|
+
const name = userAgent?.split(" ")[0]?.split("/")[0];
|
|
10
|
+
return name && isPackageManager(name) ? name : null;
|
|
11
|
+
}
|
|
3
12
|
export function detectPackageManager(cwd) {
|
|
4
13
|
if (existsSync(join(cwd, "bun.lockb")) || existsSync(join(cwd, "bun.lock"))) {
|
|
5
14
|
return "bun";
|