@substrate-kit/cli 0.1.2 → 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/.claude-plugin/plugin.json +1 -1
- package/LICENSE +21 -0
- package/README.md +25 -8
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +10 -41
- package/dist/cli.js.map +1 -1
- package/dist/commands/add.d.ts +1 -0
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +51 -109
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/docs.d.ts +4 -2
- package/dist/commands/docs.d.ts.map +1 -1
- package/dist/commands/docs.js +33 -54
- package/dist/commands/docs.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +158 -122
- package/dist/commands/init.js.map +1 -1
- package/dist/index.js +0 -0
- package/dist/mcp/server.d.ts.map +1 -1
- package/dist/mcp/server.js +8 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools/get-component.d.ts +1 -1
- package/dist/mcp/tools/get-component.d.ts.map +1 -1
- package/dist/mcp/tools/get-component.js +10 -6
- package/dist/mcp/tools/get-component.js.map +1 -1
- package/dist/mcp/tools/get-docs.d.ts +17 -0
- package/dist/mcp/tools/get-docs.d.ts.map +1 -0
- package/dist/mcp/tools/get-docs.js +23 -0
- package/dist/mcp/tools/get-docs.js.map +1 -0
- package/dist/mcp/tools/install.d.ts +2 -1
- package/dist/mcp/tools/install.d.ts.map +1 -1
- package/dist/mcp/tools/install.js +18 -27
- package/dist/mcp/tools/install.js.map +1 -1
- package/dist/mcp/tools/search.d.ts +1 -1
- package/dist/mcp/tools/search.d.ts.map +1 -1
- package/dist/mcp/tools/search.js +2 -4
- package/dist/mcp/tools/search.js.map +1 -1
- package/dist/{mcp/types.d.ts → registry.d.ts} +6 -1
- package/dist/registry.d.ts.map +1 -0
- package/dist/registry.js +48 -0
- package/dist/registry.js.map +1 -0
- package/dist/utils/agents-file.d.ts +4 -0
- package/dist/utils/agents-file.d.ts.map +1 -0
- package/dist/utils/agents-file.js +36 -0
- package/dist/utils/agents-file.js.map +1 -0
- package/dist/utils/docs.d.ts +7 -0
- package/dist/utils/docs.d.ts.map +1 -0
- package/dist/utils/docs.js +28 -0
- package/dist/utils/docs.js.map +1 -0
- package/dist/utils/shadcn.d.ts +6 -1
- package/dist/utils/shadcn.d.ts.map +1 -1
- package/dist/utils/shadcn.js +25 -12
- package/dist/utils/shadcn.js.map +1 -1
- package/dist/utils/version.d.ts +3 -0
- package/dist/utils/version.d.ts.map +1 -0
- package/dist/utils/version.js +8 -0
- package/dist/utils/version.js.map +1 -0
- package/docs/components/action.mdx +30 -0
- package/docs/components/alignment-controls.mdx +30 -0
- package/docs/components/badge.mdx +22 -0
- package/docs/components/breadcrumbs.mdx +25 -0
- package/docs/components/collapsible-pane.mdx +35 -0
- package/docs/components/colour-picker.mdx +66 -0
- package/docs/components/command-palette.mdx +36 -0
- package/docs/components/context-menu.mdx +31 -0
- package/docs/components/controls-timeline.mdx +107 -0
- package/docs/components/controls.mdx +168 -0
- package/docs/components/design-canvas.mdx +51 -0
- package/docs/components/document-tabs.mdx +25 -0
- package/docs/components/easing-curve-editor.mdx +85 -0
- package/docs/components/empty-state.mdx +26 -0
- package/docs/components/gallery.mdx +60 -0
- package/docs/components/history-controls.mdx +47 -0
- package/docs/components/image-picker.mdx +50 -0
- package/docs/components/layer-list.mdx +36 -0
- package/docs/components/node.mdx +85 -0
- package/docs/components/number-input.mdx +44 -0
- package/docs/components/number-slider.mdx +32 -0
- package/docs/components/pane.mdx +39 -0
- package/docs/components/panel.mdx +28 -0
- package/docs/components/popover.mdx +32 -0
- package/docs/components/progress-bar.mdx +24 -0
- package/docs/components/resizer.mdx +24 -0
- package/docs/components/select.mdx +31 -0
- package/docs/components/shortcut-overlay.mdx +43 -0
- package/docs/components/slider.mdx +20 -0
- package/docs/components/spring-editor.mdx +85 -0
- package/docs/components/status-bar.mdx +42 -0
- package/docs/components/surface.mdx +47 -0
- package/docs/components/swatch-palette.mdx +36 -0
- package/docs/components/text-area.mdx +26 -0
- package/docs/components/timeline.mdx +96 -0
- package/docs/components/toast.mdx +42 -0
- package/docs/components/toggle-group.mdx +40 -0
- package/docs/components/toggle.mdx +27 -0
- package/docs/components/toolbar.mdx +24 -0
- package/docs/components/tree-list.mdx +46 -0
- package/docs/components/xy-pad.mdx +49 -0
- package/docs/hooks/use-clipboard.mdx +70 -0
- package/docs/hooks/use-drag-reorder.mdx +60 -0
- package/docs/hooks/use-selection.mdx +68 -0
- package/docs/hooks/use-undoable.mdx +83 -0
- package/docs/hooks/use-viewport.mdx +75 -0
- package/docs/utilities/bounding-box.mdx +76 -0
- package/docs/utilities/keyboard-shortcuts.mdx +64 -0
- package/docs/utilities/snap.mdx +73 -0
- package/package.json +6 -4
- package/registry.json +274 -6
- 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
- package/dist/commands/browse.d.ts +0 -2
- package/dist/commands/browse.d.ts.map +0 -1
- package/dist/commands/browse.js +0 -25
- package/dist/commands/browse.js.map +0 -1
- package/dist/commands/create.d.ts +0 -9
- package/dist/commands/create.d.ts.map +0 -1
- package/dist/commands/create.js +0 -27
- package/dist/commands/create.js.map +0 -1
- package/dist/commands/variables.d.ts +0 -4
- package/dist/commands/variables.d.ts.map +0 -1
- package/dist/commands/variables.js +0 -111
- package/dist/commands/variables.js.map +0 -1
- package/dist/mcp/registry.d.ts +0 -3
- package/dist/mcp/registry.d.ts.map +0 -1
- package/dist/mcp/registry.js +0 -43
- package/dist/mcp/registry.js.map +0 -1
- package/dist/mcp/tools/theme.d.ts +0 -10
- package/dist/mcp/tools/theme.d.ts.map +0 -1
- package/dist/mcp/tools/theme.js +0 -37
- package/dist/mcp/tools/theme.js.map +0 -1
- package/dist/mcp/types.d.ts.map +0 -1
- package/dist/mcp/types.js +0 -2
- package/dist/mcp/types.js.map +0 -1
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Bounding box
|
|
3
|
+
description: Compute union bounds, intersections, and containment checks.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx shadcn@latest add https://substrate.georgedrury.co.uk/r/bounding-box
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```ts
|
|
15
|
+
import {
|
|
16
|
+
boundingBox,
|
|
17
|
+
expandBounds,
|
|
18
|
+
containsPoint,
|
|
19
|
+
intersectBounds,
|
|
20
|
+
} from "@/lib/substrate/bounding-box"
|
|
21
|
+
|
|
22
|
+
// Union of multiple element bounds
|
|
23
|
+
const union = boundingBox([
|
|
24
|
+
{ x: 0, y: 0, width: 100, height: 50 },
|
|
25
|
+
{ x: 80, y: 30, width: 60, height: 40 },
|
|
26
|
+
])
|
|
27
|
+
// → { x: 0, y: 0, width: 140, height: 70 }
|
|
28
|
+
|
|
29
|
+
// Add padding
|
|
30
|
+
const padded = expandBounds(union!, 20)
|
|
31
|
+
// → { x: -20, y: -20, width: 180, height: 110 }
|
|
32
|
+
|
|
33
|
+
// Hit testing
|
|
34
|
+
containsPoint(union!, { x: 50, y: 25 }) // → true
|
|
35
|
+
|
|
36
|
+
// Intersection
|
|
37
|
+
intersectBounds(
|
|
38
|
+
{ x: 0, y: 0, width: 100, height: 100 },
|
|
39
|
+
{ x: 50, y: 50, width: 100, height: 100 },
|
|
40
|
+
)
|
|
41
|
+
// → { x: 50, y: 50, width: 50, height: 50 }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Functions
|
|
45
|
+
|
|
46
|
+
### `boundingBox(items)`
|
|
47
|
+
|
|
48
|
+
Computes the union bounding box of an array of `Bounds`. Returns `null` if the array is empty.
|
|
49
|
+
|
|
50
|
+
### `boundingBoxFromPoints(points)`
|
|
51
|
+
|
|
52
|
+
Computes the bounding box from an array of `Point` values. Returns `null` if the array is empty.
|
|
53
|
+
|
|
54
|
+
### `expandBounds(bounds, padding)`
|
|
55
|
+
|
|
56
|
+
Expands a bounding box by `padding` pixels on every side. Negative values contract.
|
|
57
|
+
|
|
58
|
+
### `expandBoundsBy(bounds, { top?, right?, bottom?, left? })`
|
|
59
|
+
|
|
60
|
+
Expands with independent padding per side.
|
|
61
|
+
|
|
62
|
+
### `containsPoint(bounds, point)`
|
|
63
|
+
|
|
64
|
+
Returns `true` if the point lies inside the bounds.
|
|
65
|
+
|
|
66
|
+
### `containsBounds(a, b)`
|
|
67
|
+
|
|
68
|
+
Returns `true` if bounds `a` fully contains bounds `b`.
|
|
69
|
+
|
|
70
|
+
### `boundsCenter(bounds)`
|
|
71
|
+
|
|
72
|
+
Returns the centre `{ x, y }` of a bounding box.
|
|
73
|
+
|
|
74
|
+
### `intersectBounds(a, b)`
|
|
75
|
+
|
|
76
|
+
Returns the intersection of two bounds, or `null` if they don't overlap.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: createKeyboardShortcuts
|
|
3
|
+
description: Declarative keyboard shortcut registration replacing switch statements.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx shadcn@latest add https://substrate.georgedrury.co.uk/r/keyboard-shortcuts
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
```tsx
|
|
15
|
+
import {
|
|
16
|
+
createKeyboardShortcuts,
|
|
17
|
+
formatShortcut,
|
|
18
|
+
} from "@/lib/substrate/keyboard-shortcuts"
|
|
19
|
+
|
|
20
|
+
// Register shortcuts – returns a dispose function
|
|
21
|
+
const dispose = createKeyboardShortcuts([
|
|
22
|
+
{ key: "z", meta: true, handler: undo, label: "Undo", group: "Edit" },
|
|
23
|
+
{ key: "z", meta: true, shift: true, handler: redo, label: "Redo", group: "Edit" },
|
|
24
|
+
{ key: "Delete", handler: deleteSelected, label: "Delete", group: "Edit" },
|
|
25
|
+
{ key: "a", meta: true, handler: selectAll, label: "Select all", group: "Selection" },
|
|
26
|
+
{ key: "0", meta: true, handler: resetZoom, label: "Reset zoom", group: "View" },
|
|
27
|
+
])
|
|
28
|
+
|
|
29
|
+
// Later, when unmounting:
|
|
30
|
+
dispose()
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Features
|
|
34
|
+
|
|
35
|
+
Each shortcut entry declares the key and modifiers it responds to. The first matching shortcut wins – so more specific shortcuts (e.g. ⌘+Shift+Z) should be listed before less specific ones (⌘+Z).
|
|
36
|
+
|
|
37
|
+
By default, shortcuts are ignored when focus is inside an `<input>`, `<textarea>`, or `contentEditable` element. Set `ignoreInputs: false` on a specific entry to override this.
|
|
38
|
+
|
|
39
|
+
The `formatShortcut` helper converts an entry into a human-readable string for display in toolbars and overlays – e.g. `{ key: "z", meta: true, shift: true }` becomes `"⌘+Shift+Z"`.
|
|
40
|
+
|
|
41
|
+
## API
|
|
42
|
+
|
|
43
|
+
### `createKeyboardShortcuts(shortcuts, options?)`
|
|
44
|
+
|
|
45
|
+
Returns a dispose function that removes the event listener.
|
|
46
|
+
|
|
47
|
+
### ShortcutEntry
|
|
48
|
+
|
|
49
|
+
| Property | Type | Default | Description |
|
|
50
|
+
| --- | --- | --- | --- |
|
|
51
|
+
| `key` | `string` | — | The key value (e.g. `"z"`, `"Delete"`, `"ArrowUp"`) |
|
|
52
|
+
| `meta` | `boolean` | `false` | Require ⌘/Ctrl |
|
|
53
|
+
| `ctrl` | `boolean` | `false` | Require Ctrl specifically |
|
|
54
|
+
| `shift` | `boolean` | `false` | Require Shift |
|
|
55
|
+
| `alt` | `boolean` | `false` | Require Alt/Option |
|
|
56
|
+
| `handler` | `(e: KeyboardEvent) => void` | — | Callback |
|
|
57
|
+
| `preventDefault` | `boolean` | `true` | Call `e.preventDefault()` |
|
|
58
|
+
| `ignoreInputs` | `boolean` | `true` | Skip when focus is in an input |
|
|
59
|
+
| `label` | `string` | — | Human-readable label for UI |
|
|
60
|
+
| `group` | `string` | — | Group name for UI |
|
|
61
|
+
|
|
62
|
+
### `formatShortcut(shortcut)`
|
|
63
|
+
|
|
64
|
+
Returns a formatted string like `"⌘+Shift+Z"` or `"Alt+↑"`.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Snap
|
|
3
|
+
description: Grid snapping and smart edge snapping for canvas surfaces.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npx shadcn@latest add https://substrate.georgedrury.co.uk/r/snap
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Usage
|
|
13
|
+
|
|
14
|
+
### Grid snapping
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { snapToGrid, snapValueToGrid } from "@/lib/substrate/snap"
|
|
18
|
+
|
|
19
|
+
snapToGrid({ x: 37, y: 63 }, 10)
|
|
20
|
+
// → { x: 40, y: 60 }
|
|
21
|
+
|
|
22
|
+
snapToGrid({ x: 37, y: 63 }, 10, { origin: { x: 5, y: 5 } })
|
|
23
|
+
// → { x: 35, y: 65 }
|
|
24
|
+
|
|
25
|
+
snapValueToGrid(37, 10) // → 40
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Guide snapping
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { snapToGuides, guidesFromBounds } from "@/lib/substrate/snap"
|
|
32
|
+
|
|
33
|
+
// Generate guides from sibling elements
|
|
34
|
+
const guides = guidesFromBounds(otherElements.map((el) => el.bounds))
|
|
35
|
+
|
|
36
|
+
// Snap the dragged element's position
|
|
37
|
+
const result = snapToGuides(dragPosition, guides, { threshold: 5 })
|
|
38
|
+
|
|
39
|
+
result.point // → snapped { x, y }
|
|
40
|
+
result.snappedGuides // → which guides were hit (for rendering snap lines)
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Functions
|
|
44
|
+
|
|
45
|
+
### `snapToGrid(point, gridSize, options?)`
|
|
46
|
+
|
|
47
|
+
Rounds a point to the nearest grid intersection. An optional `origin` shifts the grid.
|
|
48
|
+
|
|
49
|
+
### `snapValueToGrid(value, gridSize, origin?)`
|
|
50
|
+
|
|
51
|
+
Snaps a single number to the nearest grid line.
|
|
52
|
+
|
|
53
|
+
### `snapToGuides(point, guides, options?)`
|
|
54
|
+
|
|
55
|
+
Snaps a point to nearby guide lines. Each axis snaps independently – only if a guide is within the `threshold` distance (default 5px). Returns the snapped point and an array of matched guides, which is useful for rendering alignment lines.
|
|
56
|
+
|
|
57
|
+
### `guidesFromBounds(boundsList, exclude?)`
|
|
58
|
+
|
|
59
|
+
Generates alignment guides from an array of bounding boxes. Creates six guides per box – left edge, horizontal centre, right edge, top edge, vertical centre, bottom edge. Pass the element being dragged as `exclude` to avoid self-snapping.
|
|
60
|
+
|
|
61
|
+
## Types
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
type Guide = {
|
|
65
|
+
axis: "x" | "y"
|
|
66
|
+
value: number
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type SnapResult = {
|
|
70
|
+
point: Point
|
|
71
|
+
snappedGuides: Guide[]
|
|
72
|
+
}
|
|
73
|
+
```
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@substrate-kit/cli",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Add Substrate components, skills and docs to a project, with an MCP server for agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"substrate-kit": "./dist/index.js"
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"dev": "tsx src/index.ts",
|
|
12
|
-
"prepack": "
|
|
13
|
-
"prepublishOnly": "
|
|
12
|
+
"prepack": "node ../../scripts/bundle-cli-assets.mjs && npm run build",
|
|
13
|
+
"prepublishOnly": "node ../../scripts/release-stamp.mjs verify"
|
|
14
14
|
},
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
@@ -26,6 +26,8 @@
|
|
|
26
26
|
"files": [
|
|
27
27
|
"dist",
|
|
28
28
|
"skills",
|
|
29
|
+
"templates",
|
|
30
|
+
"docs",
|
|
29
31
|
"registry.json",
|
|
30
32
|
".claude-plugin"
|
|
31
33
|
],
|
package/registry.json
CHANGED
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"name": "math",
|
|
33
33
|
"type": "registry:lib",
|
|
34
34
|
"title": "Math",
|
|
35
|
-
"description": "Geometry helpers — rotate point, bounds checking, ellipse hit test, screen/world coordinate conversion, normalize bounds, distance, and
|
|
35
|
+
"description": "Geometry helpers — rotate point, bounds checking, ellipse hit test, screen/world coordinate conversion, normalize bounds, distance, clamping, plus rotation and handle maths: rotated bounds, snap angle, and resizing a rotated box.",
|
|
36
36
|
"author": "George Drury <info@georgedrury.co.uk>",
|
|
37
37
|
"categories": [
|
|
38
38
|
"substrate",
|
|
@@ -120,7 +120,8 @@
|
|
|
120
120
|
"zustand"
|
|
121
121
|
],
|
|
122
122
|
"registryDependencies": [
|
|
123
|
-
"https://substrate.georgedrury.co.uk/r/types"
|
|
123
|
+
"https://substrate.georgedrury.co.uk/r/types",
|
|
124
|
+
"https://substrate.georgedrury.co.uk/r/id"
|
|
124
125
|
],
|
|
125
126
|
"meta": {
|
|
126
127
|
"lineage": [
|
|
@@ -239,7 +240,8 @@
|
|
|
239
240
|
"canvas"
|
|
240
241
|
],
|
|
241
242
|
"registryDependencies": [
|
|
242
|
-
"https://substrate.georgedrury.co.uk/r/types"
|
|
243
|
+
"https://substrate.georgedrury.co.uk/r/types",
|
|
244
|
+
"https://substrate.georgedrury.co.uk/r/math"
|
|
243
245
|
],
|
|
244
246
|
"meta": {
|
|
245
247
|
"lineage": [
|
|
@@ -326,7 +328,8 @@
|
|
|
326
328
|
"registryDependencies": [
|
|
327
329
|
"https://substrate.georgedrury.co.uk/r/types",
|
|
328
330
|
"https://substrate.georgedrury.co.uk/r/math",
|
|
329
|
-
"https://substrate.georgedrury.co.uk/r/document-store"
|
|
331
|
+
"https://substrate.georgedrury.co.uk/r/document-store",
|
|
332
|
+
"https://substrate.georgedrury.co.uk/r/bounding-box"
|
|
330
333
|
],
|
|
331
334
|
"meta": {
|
|
332
335
|
"lineage": [
|
|
@@ -489,7 +492,9 @@
|
|
|
489
492
|
"https://substrate.georgedrury.co.uk/r/tool-store",
|
|
490
493
|
"https://substrate.georgedrury.co.uk/r/use-canvas-renderer",
|
|
491
494
|
"https://substrate.georgedrury.co.uk/r/use-canvas-interaction",
|
|
492
|
-
"https://substrate.georgedrury.co.uk/r/use-keyboard-shortcuts"
|
|
495
|
+
"https://substrate.georgedrury.co.uk/r/use-keyboard-shortcuts",
|
|
496
|
+
"https://substrate.georgedrury.co.uk/r/document-store",
|
|
497
|
+
"https://substrate.georgedrury.co.uk/r/types"
|
|
493
498
|
],
|
|
494
499
|
"cssVars": {
|
|
495
500
|
"theme": {
|
|
@@ -1480,7 +1485,7 @@
|
|
|
1480
1485
|
"name": "layer-list",
|
|
1481
1486
|
"type": "registry:ui",
|
|
1482
1487
|
"title": "Layer List",
|
|
1483
|
-
"description": "
|
|
1488
|
+
"description": "Layer panel with selection, visibility and lock toggles, icons and inline rename. Compound component pattern; pair with use-drag-reorder to sort and context-menu for right-click actions.",
|
|
1484
1489
|
"categories": [
|
|
1485
1490
|
"substrate",
|
|
1486
1491
|
"ui",
|
|
@@ -1981,6 +1986,269 @@
|
|
|
1981
1986
|
}
|
|
1982
1987
|
],
|
|
1983
1988
|
"author": "George Drury <info@georgedrury.co.uk>"
|
|
1989
|
+
},
|
|
1990
|
+
{
|
|
1991
|
+
"name": "spring",
|
|
1992
|
+
"type": "registry:lib",
|
|
1993
|
+
"title": "Spring",
|
|
1994
|
+
"description": "Spring physics utilities: convert time-based springs (duration, bounce) to stiffness, damping and mass, and sample their progress over time.",
|
|
1995
|
+
"author": "George Drury <info@georgedrury.co.uk>",
|
|
1996
|
+
"categories": [
|
|
1997
|
+
"substrate",
|
|
1998
|
+
"lib",
|
|
1999
|
+
"animation"
|
|
2000
|
+
],
|
|
2001
|
+
"meta": {
|
|
2002
|
+
"lineage": [
|
|
2003
|
+
{
|
|
2004
|
+
"name": "Substrate"
|
|
2005
|
+
}
|
|
2006
|
+
]
|
|
2007
|
+
},
|
|
2008
|
+
"files": [
|
|
2009
|
+
{
|
|
2010
|
+
"path": "registry/substrate/lib/spring.ts",
|
|
2011
|
+
"type": "registry:lib",
|
|
2012
|
+
"target": "lib/substrate/spring.ts"
|
|
2013
|
+
}
|
|
2014
|
+
]
|
|
2015
|
+
},
|
|
2016
|
+
{
|
|
2017
|
+
"name": "spring-editor",
|
|
2018
|
+
"type": "registry:ui",
|
|
2019
|
+
"title": "Spring Editor",
|
|
2020
|
+
"description": "Spring curve preview with duration and bounce, or stiffness, damping and mass sliders. Used for spring transitions in animation tools.",
|
|
2021
|
+
"author": "George Drury <info@georgedrury.co.uk>",
|
|
2022
|
+
"categories": [
|
|
2023
|
+
"substrate",
|
|
2024
|
+
"ui",
|
|
2025
|
+
"animation"
|
|
2026
|
+
],
|
|
2027
|
+
"cssVars": {
|
|
2028
|
+
"theme": {
|
|
2029
|
+
"color-spring-curve": "var(--spring-curve, var(--color-primary))"
|
|
2030
|
+
},
|
|
2031
|
+
"light": {},
|
|
2032
|
+
"dark": {}
|
|
2033
|
+
},
|
|
2034
|
+
"meta": {
|
|
2035
|
+
"example": "<SpringEditor value={{ type: \"spring\", visualDuration: 0.3, bounce: 0.2 }} onChange={setSpring} />",
|
|
2036
|
+
"lineage": [
|
|
2037
|
+
{
|
|
2038
|
+
"name": "DialKit",
|
|
2039
|
+
"href": "https://github.com/joshpuckett/dialkit"
|
|
2040
|
+
},
|
|
2041
|
+
{
|
|
2042
|
+
"name": "Substrate"
|
|
2043
|
+
}
|
|
2044
|
+
]
|
|
2045
|
+
},
|
|
2046
|
+
"files": [
|
|
2047
|
+
{
|
|
2048
|
+
"path": "registry/substrate/components/spring-editor.tsx",
|
|
2049
|
+
"type": "registry:ui",
|
|
2050
|
+
"target": "components/substrate/spring-editor.tsx"
|
|
2051
|
+
}
|
|
2052
|
+
],
|
|
2053
|
+
"registryDependencies": [
|
|
2054
|
+
"https://substrate.georgedrury.co.uk/r/action",
|
|
2055
|
+
"https://substrate.georgedrury.co.uk/r/number-slider",
|
|
2056
|
+
"https://substrate.georgedrury.co.uk/r/toggle-group",
|
|
2057
|
+
"https://substrate.georgedrury.co.uk/r/spring"
|
|
2058
|
+
]
|
|
2059
|
+
},
|
|
2060
|
+
{
|
|
2061
|
+
"name": "xy-pad",
|
|
2062
|
+
"type": "registry:ui",
|
|
2063
|
+
"title": "XY Pad",
|
|
2064
|
+
"description": "Two-dimensional pad for setting two values at once by dragging or with the arrow keys. Used for offsets, positions and paired parameters.",
|
|
2065
|
+
"author": "George Drury <info@georgedrury.co.uk>",
|
|
2066
|
+
"categories": [
|
|
2067
|
+
"substrate",
|
|
2068
|
+
"ui",
|
|
2069
|
+
"form"
|
|
2070
|
+
],
|
|
2071
|
+
"cssVars": {
|
|
2072
|
+
"theme": {
|
|
2073
|
+
"color-xy-pad-handle": "var(--xy-pad-handle, var(--color-primary))"
|
|
2074
|
+
},
|
|
2075
|
+
"light": {},
|
|
2076
|
+
"dark": {}
|
|
2077
|
+
},
|
|
2078
|
+
"meta": {
|
|
2079
|
+
"example": "<XYPad value={offset} onChange={setOffset} x={{ min: -50, max: 50, step: 1 }} y={{ min: -50, max: 50, step: 1 }} />",
|
|
2080
|
+
"lineage": [
|
|
2081
|
+
{
|
|
2082
|
+
"name": "DialKit",
|
|
2083
|
+
"href": "https://github.com/joshpuckett/dialkit"
|
|
2084
|
+
},
|
|
2085
|
+
{
|
|
2086
|
+
"name": "Substrate"
|
|
2087
|
+
}
|
|
2088
|
+
]
|
|
2089
|
+
},
|
|
2090
|
+
"files": [
|
|
2091
|
+
{
|
|
2092
|
+
"path": "registry/substrate/components/xy-pad.tsx",
|
|
2093
|
+
"type": "registry:ui",
|
|
2094
|
+
"target": "components/substrate/xy-pad.tsx"
|
|
2095
|
+
}
|
|
2096
|
+
]
|
|
2097
|
+
},
|
|
2098
|
+
{
|
|
2099
|
+
"name": "image-picker",
|
|
2100
|
+
"type": "registry:ui",
|
|
2101
|
+
"title": "Image Picker",
|
|
2102
|
+
"description": "Thumbnail grid for choosing an image from a list, with upload and drag-and-drop. Uploads become data URLs.",
|
|
2103
|
+
"author": "George Drury <info@georgedrury.co.uk>",
|
|
2104
|
+
"categories": [
|
|
2105
|
+
"substrate",
|
|
2106
|
+
"ui",
|
|
2107
|
+
"form"
|
|
2108
|
+
],
|
|
2109
|
+
"cssVars": {
|
|
2110
|
+
"theme": {
|
|
2111
|
+
"color-image-picker-selection": "var(--image-picker-selection, var(--color-primary))"
|
|
2112
|
+
},
|
|
2113
|
+
"light": {},
|
|
2114
|
+
"dark": {}
|
|
2115
|
+
},
|
|
2116
|
+
"meta": {
|
|
2117
|
+
"example": "<ImagePicker value={image} onChange={setImage} options={[\"/a.jpg\", \"/b.jpg\"]} />",
|
|
2118
|
+
"lineage": [
|
|
2119
|
+
{
|
|
2120
|
+
"name": "DialKit",
|
|
2121
|
+
"href": "https://github.com/joshpuckett/dialkit"
|
|
2122
|
+
},
|
|
2123
|
+
{
|
|
2124
|
+
"name": "Substrate"
|
|
2125
|
+
}
|
|
2126
|
+
]
|
|
2127
|
+
},
|
|
2128
|
+
"files": [
|
|
2129
|
+
{
|
|
2130
|
+
"path": "registry/substrate/components/image-picker.tsx",
|
|
2131
|
+
"type": "registry:ui",
|
|
2132
|
+
"target": "components/substrate/image-picker.tsx"
|
|
2133
|
+
}
|
|
2134
|
+
],
|
|
2135
|
+
"dependencies": [
|
|
2136
|
+
"@remixicon/react"
|
|
2137
|
+
]
|
|
2138
|
+
},
|
|
2139
|
+
{
|
|
2140
|
+
"name": "controls",
|
|
2141
|
+
"type": "registry:ui",
|
|
2142
|
+
"title": "Controls",
|
|
2143
|
+
"description": "Config-driven control panels — describe parameters as an object with useControls and render them with Controls, built on DialKit's store.",
|
|
2144
|
+
"author": "George Drury <info@georgedrury.co.uk>",
|
|
2145
|
+
"categories": [
|
|
2146
|
+
"substrate",
|
|
2147
|
+
"ui",
|
|
2148
|
+
"form"
|
|
2149
|
+
],
|
|
2150
|
+
"dependencies": [
|
|
2151
|
+
"dialkit",
|
|
2152
|
+
"@remixicon/react"
|
|
2153
|
+
],
|
|
2154
|
+
"meta": {
|
|
2155
|
+
"example": "const values = useControls(\"Card\", { radius: [24, 0, 64], visible: true })\n<Panel><Controls /></Panel>",
|
|
2156
|
+
"lineage": [
|
|
2157
|
+
{
|
|
2158
|
+
"name": "DialKit",
|
|
2159
|
+
"href": "https://github.com/joshpuckett/dialkit"
|
|
2160
|
+
},
|
|
2161
|
+
{
|
|
2162
|
+
"name": "Substrate"
|
|
2163
|
+
}
|
|
2164
|
+
]
|
|
2165
|
+
},
|
|
2166
|
+
"files": [
|
|
2167
|
+
{
|
|
2168
|
+
"path": "registry/substrate/components/controls.tsx",
|
|
2169
|
+
"type": "registry:ui",
|
|
2170
|
+
"target": "components/substrate/controls.tsx"
|
|
2171
|
+
},
|
|
2172
|
+
{
|
|
2173
|
+
"path": "registry/substrate/hooks/use-controls.ts",
|
|
2174
|
+
"type": "registry:hook",
|
|
2175
|
+
"target": "hooks/substrate/use-controls.ts"
|
|
2176
|
+
},
|
|
2177
|
+
{
|
|
2178
|
+
"path": "registry/substrate/lib/controls-shortcuts.ts",
|
|
2179
|
+
"type": "registry:lib",
|
|
2180
|
+
"target": "lib/substrate/controls-shortcuts.ts"
|
|
2181
|
+
}
|
|
2182
|
+
],
|
|
2183
|
+
"registryDependencies": [
|
|
2184
|
+
"https://substrate.georgedrury.co.uk/r/pane",
|
|
2185
|
+
"https://substrate.georgedrury.co.uk/r/collapsible-pane",
|
|
2186
|
+
"https://substrate.georgedrury.co.uk/r/action",
|
|
2187
|
+
"https://substrate.georgedrury.co.uk/r/number-slider",
|
|
2188
|
+
"https://substrate.georgedrury.co.uk/r/number-input",
|
|
2189
|
+
"https://substrate.georgedrury.co.uk/r/toggle",
|
|
2190
|
+
"https://substrate.georgedrury.co.uk/r/select",
|
|
2191
|
+
"https://substrate.georgedrury.co.uk/r/colour-picker",
|
|
2192
|
+
"https://substrate.georgedrury.co.uk/r/text-area",
|
|
2193
|
+
"https://substrate.georgedrury.co.uk/r/easing-curve-editor",
|
|
2194
|
+
"https://substrate.georgedrury.co.uk/r/toggle-group",
|
|
2195
|
+
"https://substrate.georgedrury.co.uk/r/spring-editor",
|
|
2196
|
+
"https://substrate.georgedrury.co.uk/r/xy-pad",
|
|
2197
|
+
"https://substrate.georgedrury.co.uk/r/image-picker",
|
|
2198
|
+
"https://substrate.georgedrury.co.uk/r/spring",
|
|
2199
|
+
"https://substrate.georgedrury.co.uk/r/popover"
|
|
2200
|
+
]
|
|
2201
|
+
},
|
|
2202
|
+
{
|
|
2203
|
+
"name": "controls-timeline",
|
|
2204
|
+
"type": "registry:ui",
|
|
2205
|
+
"title": "Controls Timeline",
|
|
2206
|
+
"description": "Animation clips defined in code with useControlsTimeline, tuned in a timeline editor: scrub, move and resize clips, and edit their values. Built on DialKit's headless timeline.",
|
|
2207
|
+
"author": "George Drury <info@georgedrury.co.uk>",
|
|
2208
|
+
"categories": [
|
|
2209
|
+
"substrate",
|
|
2210
|
+
"ui",
|
|
2211
|
+
"animation"
|
|
2212
|
+
],
|
|
2213
|
+
"dependencies": [
|
|
2214
|
+
"dialkit",
|
|
2215
|
+
"@remixicon/react"
|
|
2216
|
+
],
|
|
2217
|
+
"cssVars": {
|
|
2218
|
+
"theme": {
|
|
2219
|
+
"color-timeline-clip": "var(--timeline-clip, var(--color-primary))"
|
|
2220
|
+
},
|
|
2221
|
+
"light": {},
|
|
2222
|
+
"dark": {}
|
|
2223
|
+
},
|
|
2224
|
+
"meta": {
|
|
2225
|
+
"example": "const timeline = useControlsTimeline(\"Card\", { enter: { at: 0, duration: 0.6, from: { y: 24 }, to: { y: 0 } } })\n<ControlsTimeline />",
|
|
2226
|
+
"lineage": [
|
|
2227
|
+
{
|
|
2228
|
+
"name": "DialKit",
|
|
2229
|
+
"href": "https://github.com/joshpuckett/dialkit"
|
|
2230
|
+
},
|
|
2231
|
+
{
|
|
2232
|
+
"name": "Substrate"
|
|
2233
|
+
}
|
|
2234
|
+
]
|
|
2235
|
+
},
|
|
2236
|
+
"files": [
|
|
2237
|
+
{
|
|
2238
|
+
"path": "registry/substrate/components/controls-timeline.tsx",
|
|
2239
|
+
"type": "registry:ui",
|
|
2240
|
+
"target": "components/substrate/controls-timeline.tsx"
|
|
2241
|
+
},
|
|
2242
|
+
{
|
|
2243
|
+
"path": "registry/substrate/hooks/use-controls-timeline.ts",
|
|
2244
|
+
"type": "registry:hook",
|
|
2245
|
+
"target": "hooks/substrate/use-controls-timeline.ts"
|
|
2246
|
+
}
|
|
2247
|
+
],
|
|
2248
|
+
"registryDependencies": [
|
|
2249
|
+
"https://substrate.georgedrury.co.uk/r/controls",
|
|
2250
|
+
"https://substrate.georgedrury.co.uk/r/popover"
|
|
2251
|
+
]
|
|
1984
2252
|
}
|
|
1985
2253
|
]
|
|
1986
2254
|
}
|
package/skills/3d-scene/SKILL.md
CHANGED
|
@@ -173,6 +173,7 @@ Some examples of what this surface enables:
|
|
|
173
173
|
|
|
174
174
|
## Related reference skills
|
|
175
175
|
|
|
176
|
+
- **scaffold-playground** — the craft rules and the checklist to run before you say it's done
|
|
176
177
|
- **substrate-scaffold** — Toolbar, Panel, StatusBar, ZoomControls for the app shell
|
|
177
|
-
- **substrate-controls** — NumberInput, Slider, ColourPicker, ActionControls for property panes
|
|
178
|
+
- **substrate-controls** — NumberInput, Slider, ColourPicker, ActionControls for property panes; `useControls` for tuning material, light and camera values from one config object
|
|
178
179
|
- **substrate-interaction** — useUndoable, useClipboard, createKeyboardShortcuts, TreeList for scene hierarchy
|
|
@@ -195,6 +195,7 @@ Some examples of what this surface enables:
|
|
|
195
195
|
|
|
196
196
|
## Related reference skills
|
|
197
197
|
|
|
198
|
+
- **scaffold-playground** — the craft rules and the checklist to run before you say it's done
|
|
198
199
|
- **substrate-scaffold** — Toolbar, Panel, StatusBar for the app shell
|
|
199
|
-
- **substrate-controls** — NumberInput, Slider, EasingCurveEditor, ActionControls for keyframe properties
|
|
200
|
+
- **substrate-controls** — NumberInput, Slider, EasingCurveEditor, ActionControls for keyframe properties. For tuning UI motion by eye (entrances, springs, choreography), use `useControlsTimeline` with `<ControlsTimeline />` instead of building a timeline: define clips in code, bind `clip.current` to style, then copy the tuned values back. The `timeline` component is for editing user-authored keyframes.
|
|
200
201
|
- **substrate-interaction** — useUndoable, createKeyboardShortcuts, LayerList for animation layers
|