@substrate-kit/cli 0.1.1 → 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.
Files changed (146) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/LICENSE +21 -0
  3. package/README.md +25 -8
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +10 -60
  6. package/dist/cli.js.map +1 -1
  7. package/dist/commands/add.d.ts +1 -0
  8. package/dist/commands/add.d.ts.map +1 -1
  9. package/dist/commands/add.js +51 -106
  10. package/dist/commands/add.js.map +1 -1
  11. package/dist/commands/docs.d.ts +4 -2
  12. package/dist/commands/docs.d.ts.map +1 -1
  13. package/dist/commands/docs.js +33 -54
  14. package/dist/commands/docs.js.map +1 -1
  15. package/dist/commands/init.d.ts.map +1 -1
  16. package/dist/commands/init.js +158 -122
  17. package/dist/commands/init.js.map +1 -1
  18. package/dist/index.js +0 -0
  19. package/dist/mcp/server.d.ts.map +1 -1
  20. package/dist/mcp/server.js +8 -7
  21. package/dist/mcp/server.js.map +1 -1
  22. package/dist/mcp/tools/get-component.d.ts +1 -1
  23. package/dist/mcp/tools/get-component.d.ts.map +1 -1
  24. package/dist/mcp/tools/get-component.js +10 -6
  25. package/dist/mcp/tools/get-component.js.map +1 -1
  26. package/dist/mcp/tools/get-docs.d.ts +17 -0
  27. package/dist/mcp/tools/get-docs.d.ts.map +1 -0
  28. package/dist/mcp/tools/get-docs.js +23 -0
  29. package/dist/mcp/tools/get-docs.js.map +1 -0
  30. package/dist/mcp/tools/install.d.ts +2 -1
  31. package/dist/mcp/tools/install.d.ts.map +1 -1
  32. package/dist/mcp/tools/install.js +19 -30
  33. package/dist/mcp/tools/install.js.map +1 -1
  34. package/dist/mcp/tools/search.d.ts +1 -1
  35. package/dist/mcp/tools/search.d.ts.map +1 -1
  36. package/dist/mcp/tools/search.js +2 -4
  37. package/dist/mcp/tools/search.js.map +1 -1
  38. package/dist/{mcp/types.d.ts → registry.d.ts} +6 -1
  39. package/dist/registry.d.ts.map +1 -0
  40. package/dist/registry.js +48 -0
  41. package/dist/registry.js.map +1 -0
  42. package/dist/utils/agents-file.d.ts +4 -0
  43. package/dist/utils/agents-file.d.ts.map +1 -0
  44. package/dist/utils/agents-file.js +36 -0
  45. package/dist/utils/agents-file.js.map +1 -0
  46. package/dist/utils/docs.d.ts +7 -0
  47. package/dist/utils/docs.d.ts.map +1 -0
  48. package/dist/utils/docs.js +28 -0
  49. package/dist/utils/docs.js.map +1 -0
  50. package/dist/utils/shadcn.d.ts +12 -0
  51. package/dist/utils/shadcn.d.ts.map +1 -0
  52. package/dist/utils/shadcn.js +29 -0
  53. package/dist/utils/shadcn.js.map +1 -0
  54. package/dist/utils/version.d.ts +3 -0
  55. package/dist/utils/version.d.ts.map +1 -0
  56. package/dist/utils/version.js +8 -0
  57. package/dist/utils/version.js.map +1 -0
  58. package/docs/components/action.mdx +30 -0
  59. package/docs/components/alignment-controls.mdx +30 -0
  60. package/docs/components/badge.mdx +22 -0
  61. package/docs/components/breadcrumbs.mdx +25 -0
  62. package/docs/components/collapsible-pane.mdx +35 -0
  63. package/docs/components/colour-picker.mdx +66 -0
  64. package/docs/components/command-palette.mdx +36 -0
  65. package/docs/components/context-menu.mdx +31 -0
  66. package/docs/components/controls-timeline.mdx +107 -0
  67. package/docs/components/controls.mdx +168 -0
  68. package/docs/components/design-canvas.mdx +51 -0
  69. package/docs/components/document-tabs.mdx +25 -0
  70. package/docs/components/easing-curve-editor.mdx +85 -0
  71. package/docs/components/empty-state.mdx +26 -0
  72. package/docs/components/gallery.mdx +60 -0
  73. package/docs/components/history-controls.mdx +47 -0
  74. package/docs/components/image-picker.mdx +50 -0
  75. package/docs/components/layer-list.mdx +36 -0
  76. package/docs/components/node.mdx +85 -0
  77. package/docs/components/number-input.mdx +44 -0
  78. package/docs/components/number-slider.mdx +32 -0
  79. package/docs/components/pane.mdx +39 -0
  80. package/docs/components/panel.mdx +28 -0
  81. package/docs/components/popover.mdx +32 -0
  82. package/docs/components/progress-bar.mdx +24 -0
  83. package/docs/components/resizer.mdx +24 -0
  84. package/docs/components/select.mdx +31 -0
  85. package/docs/components/shortcut-overlay.mdx +43 -0
  86. package/docs/components/slider.mdx +20 -0
  87. package/docs/components/spring-editor.mdx +85 -0
  88. package/docs/components/status-bar.mdx +42 -0
  89. package/docs/components/surface.mdx +47 -0
  90. package/docs/components/swatch-palette.mdx +36 -0
  91. package/docs/components/text-area.mdx +26 -0
  92. package/docs/components/timeline.mdx +96 -0
  93. package/docs/components/toast.mdx +42 -0
  94. package/docs/components/toggle-group.mdx +40 -0
  95. package/docs/components/toggle.mdx +27 -0
  96. package/docs/components/toolbar.mdx +24 -0
  97. package/docs/components/tree-list.mdx +46 -0
  98. package/docs/components/xy-pad.mdx +49 -0
  99. package/docs/hooks/use-clipboard.mdx +70 -0
  100. package/docs/hooks/use-drag-reorder.mdx +60 -0
  101. package/docs/hooks/use-selection.mdx +68 -0
  102. package/docs/hooks/use-undoable.mdx +83 -0
  103. package/docs/hooks/use-viewport.mdx +75 -0
  104. package/docs/utilities/bounding-box.mdx +76 -0
  105. package/docs/utilities/keyboard-shortcuts.mdx +64 -0
  106. package/docs/utilities/snap.mdx +73 -0
  107. package/package.json +6 -3
  108. package/registry.json +331 -16
  109. package/skills/3d-scene/SKILL.md +2 -1
  110. package/skills/animation/SKILL.md +2 -1
  111. package/skills/canvas-2d/SKILL.md +68 -6
  112. package/skills/composing-panels/SKILL.md +9 -12
  113. package/skills/data-visualisation/SKILL.md +2 -1
  114. package/skills/image-generation/SKILL.md +2 -1
  115. package/skills/install-components/SKILL.md +22 -16
  116. package/skills/scaffold-playground/SKILL.md +42 -22
  117. package/skills/substrate-canvas/SKILL.md +5 -0
  118. package/skills/substrate-controls/SKILL.md +57 -2
  119. package/skills/substrate-interaction/SKILL.md +19 -10
  120. package/skills/substrate-scaffold/SKILL.md +4 -4
  121. package/skills/theming/SKILL.md +8 -2
  122. package/skills/wire-interactions/SKILL.md +6 -3
  123. package/templates/agents-section.md +41 -0
  124. package/dist/commands/browse.d.ts +0 -2
  125. package/dist/commands/browse.d.ts.map +0 -1
  126. package/dist/commands/browse.js +0 -25
  127. package/dist/commands/browse.js.map +0 -1
  128. package/dist/commands/create.d.ts +0 -9
  129. package/dist/commands/create.d.ts.map +0 -1
  130. package/dist/commands/create.js +0 -415
  131. package/dist/commands/create.js.map +0 -1
  132. package/dist/commands/variables.d.ts +0 -4
  133. package/dist/commands/variables.d.ts.map +0 -1
  134. package/dist/commands/variables.js +0 -111
  135. package/dist/commands/variables.js.map +0 -1
  136. package/dist/mcp/registry.d.ts +0 -3
  137. package/dist/mcp/registry.d.ts.map +0 -1
  138. package/dist/mcp/registry.js +0 -43
  139. package/dist/mcp/registry.js.map +0 -1
  140. package/dist/mcp/tools/theme.d.ts +0 -10
  141. package/dist/mcp/tools/theme.d.ts.map +0 -1
  142. package/dist/mcp/tools/theme.js +0 -37
  143. package/dist/mcp/tools/theme.js.map +0 -1
  144. package/dist/mcp/types.d.ts.map +0 -1
  145. package/dist/mcp/types.js +0 -2
  146. package/dist/mcp/types.js.map +0 -1
@@ -0,0 +1,75 @@
1
+ ---
2
+ title: useViewport
3
+ description: Pan and zoom state management for canvas surfaces.
4
+ ---
5
+
6
+ ## Install
7
+
8
+ ```bash
9
+ npx shadcn@latest add https://substrate.georgedrury.co.uk/r/use-viewport
10
+ ```
11
+
12
+ ## Usage
13
+
14
+ ```tsx
15
+ import { useViewport } from "@/hooks/substrate/use-viewport"
16
+
17
+ function Canvas() {
18
+ const {
19
+ viewport,
20
+ handleWheel,
21
+ toWorld,
22
+ toScreen,
23
+ zoomIn,
24
+ zoomOut,
25
+ resetZoom,
26
+ zoomToFit,
27
+ } = useViewport({ minZoom: 0.1, maxZoom: 10 })
28
+
29
+ return (
30
+ <div onWheel={handleWheel} style={{ overflow: "hidden" }}>
31
+ <div
32
+ style={{
33
+ transform: `translate(${viewport.x}px, ${viewport.y}px) scale(${viewport.zoom})`,
34
+ transformOrigin: "0 0",
35
+ }}
36
+ >
37
+ {/* Canvas content */}
38
+ </div>
39
+ </div>
40
+ )
41
+ }
42
+ ```
43
+
44
+ ## Features
45
+
46
+ This is a surface-agnostic extraction of pan/zoom logic. It manages `{ x, y, zoom }` state and provides coordinate transforms between screen and world space. The `handleWheel` callback supports two modes – plain scroll for panning and Ctrl/⌘ + scroll for pinch-zoom – keeping the world point under the cursor stationary during zoom.
47
+
48
+ The hook uses refs internally so that callbacks like `toWorld` and `toScreen` remain referentially stable across renders.
49
+
50
+ ## API
51
+
52
+ ### Options
53
+
54
+ | Option | Type | Default | Description |
55
+ | --- | --- | --- | --- |
56
+ | `initial` | `Partial<Viewport>` | `{ x: 0, y: 0, zoom: 1 }` | Initial viewport state |
57
+ | `minZoom` | `number` | `0.1` | Minimum zoom level |
58
+ | `maxZoom` | `number` | `10` | Maximum zoom level |
59
+ | `zoomFactor` | `number` | `1.2` | Multiplier for `zoomIn` / `zoomOut` |
60
+
61
+ ### Returns
62
+
63
+ | Property | Type | Description |
64
+ | --- | --- | --- |
65
+ | `viewport` | `Viewport` | Current `{ x, y, zoom }` state |
66
+ | `setViewport` | `(v: Viewport) => void` | Set viewport directly |
67
+ | `toWorld` | `(screenX, screenY) => Point` | Convert screen coordinates to world |
68
+ | `toScreen` | `(worldX, worldY) => Point` | Convert world coordinates to screen |
69
+ | `pan` | `(dx, dy) => void` | Pan by a screen-space delta |
70
+ | `zoomToPoint` | `(screenX, screenY, zoom) => void` | Zoom keeping a screen point stationary |
71
+ | `zoomIn` | `(screenX?, screenY?) => void` | Zoom in by `zoomFactor` |
72
+ | `zoomOut` | `(screenX?, screenY?) => void` | Zoom out by `zoomFactor` |
73
+ | `resetZoom` | `() => void` | Reset to `{ x: 0, y: 0, zoom: 1 }` |
74
+ | `zoomToFit` | `(bounds, padding?) => void` | Fit a bounding box into the viewport |
75
+ | `handleWheel` | `(e: WheelEvent) => void` | Attach to your container's `onWheel` |
@@ -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.1.1",
4
- "description": "Scaffold interactive canvas playgrounds with Substrate primitives",
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,7 +9,8 @@
9
9
  "scripts": {
10
10
  "build": "tsc",
11
11
  "dev": "tsx src/index.ts",
12
- "prepack": "npm run build"
12
+ "prepack": "node ../../scripts/bundle-cli-assets.mjs && npm run build",
13
+ "prepublishOnly": "node ../../scripts/release-stamp.mjs verify"
13
14
  },
14
15
  "dependencies": {
15
16
  "@modelcontextprotocol/sdk": "^1.28.0",
@@ -25,6 +26,8 @@
25
26
  "files": [
26
27
  "dist",
27
28
  "skills",
29
+ "templates",
30
+ "docs",
28
31
  "registry.json",
29
32
  ".claude-plugin"
30
33
  ],