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 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/surfaces/types.ts"],"names":[],"mappings":"AAeA,MAAM,CAAC,MAAM,eAAe,GAAoB;IAC9C,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,2CAA2C,EAAE;IACpG,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,0DAA0D,EAAE;IACjH,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,qDAAqD,EAAE;IAC9G,EAAE,KAAK,EAAE,aAAa,EAAE,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,mDAAmD,EAAE;IAChH,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,yCAAyC,EAAE;IAChG,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAAE,yCAAyC,EAAE;IACzG,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,wCAAwC,EAAE;CAC1F,CAAA"}
@@ -0,0 +1,5 @@
1
+ export type PackageManager = "npm" | "pnpm" | "bun";
2
+ export declare function detectPackageManager(cwd: string): PackageManager;
3
+ export declare function getInstallCommand(pm: PackageManager): string;
4
+ export declare function getRunCommand(pm: PackageManager, script: string): string;
5
+ //# sourceMappingURL=detect-pm.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,20 @@
1
+ import { existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ export function detectPackageManager(cwd) {
4
+ if (existsSync(join(cwd, "bun.lockb")) || existsSync(join(cwd, "bun.lock"))) {
5
+ return "bun";
6
+ }
7
+ if (existsSync(join(cwd, "pnpm-lock.yaml"))) {
8
+ return "pnpm";
9
+ }
10
+ return "npm";
11
+ }
12
+ export function getInstallCommand(pm) {
13
+ return `${pm} install`;
14
+ }
15
+ export function getRunCommand(pm, script) {
16
+ if (pm === "npm")
17
+ return `npm run ${script}`;
18
+ return `${pm} ${script}`;
19
+ }
20
+ //# sourceMappingURL=detect-pm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"detect-pm.js","sourceRoot":"","sources":["../../src/utils/detect-pm.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAIhC,MAAM,UAAU,oBAAoB,CAAC,GAAW;IAC9C,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,CAAC,EAAE,CAAC;QAC5E,OAAO,KAAK,CAAA;IACd,CAAC;IACD,IAAI,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,CAAC,EAAE,CAAC;QAC5C,OAAO,MAAM,CAAA;IACf,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,EAAkB;IAClD,OAAO,GAAG,EAAE,UAAU,CAAA;AACxB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,EAAkB,EAAE,MAAc;IAC9D,IAAI,EAAE,KAAK,KAAK;QAAE,OAAO,WAAW,MAAM,EAAE,CAAA;IAC5C,OAAO,GAAG,EAAE,IAAI,MAAM,EAAE,CAAA;AAC1B,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare function ensureDir(dir: string): void;
2
+ export declare function writeFile(filePath: string, content: string): void;
3
+ export declare function copyDir(src: string, dest: string): void;
4
+ export declare function exists(path: string): boolean;
5
+ export declare function listDirs(dir: string): string[];
6
+ export declare function resolveSkillsDir(): string;
7
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAGA,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAI3C;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAGjE;AAED,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBvD;AAED,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAE5C;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAK9C;AAED,wBAAgB,gBAAgB,IAAI,MAAM,CAUzC"}
@@ -0,0 +1,52 @@
1
+ import { existsSync, mkdirSync, writeFileSync, readdirSync, readFileSync } from "node:fs";
2
+ import { join, dirname } from "node:path";
3
+ export function ensureDir(dir) {
4
+ if (!existsSync(dir)) {
5
+ mkdirSync(dir, { recursive: true });
6
+ }
7
+ }
8
+ export function writeFile(filePath, content) {
9
+ ensureDir(dirname(filePath));
10
+ writeFileSync(filePath, content, "utf-8");
11
+ }
12
+ export function copyDir(src, dest) {
13
+ ensureDir(dest);
14
+ const entries = readdirSync(src, { withFileTypes: true });
15
+ for (const entry of entries) {
16
+ const srcPath = join(src, entry.name);
17
+ const destPath = join(dest, entry.name);
18
+ try {
19
+ if (entry.isDirectory()) {
20
+ copyDir(srcPath, destPath);
21
+ }
22
+ else {
23
+ writeFileSync(destPath, readFileSync(srcPath));
24
+ }
25
+ }
26
+ catch {
27
+ // Skip files that can't be read
28
+ }
29
+ }
30
+ }
31
+ export function exists(path) {
32
+ return existsSync(path);
33
+ }
34
+ export function listDirs(dir) {
35
+ if (!existsSync(dir))
36
+ return [];
37
+ return readdirSync(dir, { withFileTypes: true })
38
+ .filter((d) => d.isDirectory())
39
+ .map((d) => d.name);
40
+ }
41
+ export function resolveSkillsDir() {
42
+ const distDir = dirname(dirname(new URL(import.meta.url).pathname));
43
+ const skillsDir = join(distDir, "skills");
44
+ if (existsSync(skillsDir))
45
+ return skillsDir;
46
+ const pkgRoot = join(distDir, "..");
47
+ const fallback = join(pkgRoot, "skills");
48
+ if (existsSync(fallback))
49
+ return fallback;
50
+ throw new Error("Could not locate bundled skills directory");
51
+ }
52
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAA;AACzF,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEzC,MAAM,UAAU,SAAS,CAAC,GAAW;IACnC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACrB,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACrC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB,EAAE,OAAe;IACzD,SAAS,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAA;IAC5B,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,OAAO,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,IAAY;IAC/C,SAAS,CAAC,IAAI,CAAC,CAAA;IACf,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAA;IACzD,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAA;QACvC,IAAI,CAAC;YACH,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;gBACxB,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;YAC5B,CAAC;iBAAM,CAAC;gBACN,aAAa,CAAC,QAAQ,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC,CAAA;YAChD,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gCAAgC;QAClC,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,IAAY;IACjC,OAAO,UAAU,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAA;IAC/B,OAAO,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC;SAC7C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;SAC9B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;AACvB,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IACnE,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACzC,IAAI,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAA;IAE3C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,CAAA;IACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAA;IACxC,IAAI,UAAU,CAAC,QAAQ,CAAC;QAAE,OAAO,QAAQ,CAAA;IAEzC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;AAC9D,CAAC"}
@@ -0,0 +1,10 @@
1
+ export declare const log: {
2
+ info: (msg: string) => void;
3
+ success: (msg: string) => void;
4
+ warn: (msg: string) => void;
5
+ error: (msg: string) => void;
6
+ step: (msg: string) => void;
7
+ blank: () => void;
8
+ title: (msg: string) => void;
9
+ };
10
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,GAAG;gBACF,MAAM;mBACH,MAAM;gBACT,MAAM;iBACL,MAAM;gBACP,MAAM;;iBAEL,MAAM;CAKpB,CAAA"}
@@ -0,0 +1,15 @@
1
+ import chalk from "chalk";
2
+ export const log = {
3
+ info: (msg) => console.log(chalk.cyan("ℹ"), msg),
4
+ success: (msg) => console.log(chalk.green("✓"), msg),
5
+ warn: (msg) => console.log(chalk.yellow("⚠"), msg),
6
+ error: (msg) => console.error(chalk.red("✗"), msg),
7
+ step: (msg) => console.log(chalk.dim("→"), msg),
8
+ blank: () => console.log(),
9
+ title: (msg) => {
10
+ log.blank();
11
+ console.log(chalk.bold(msg));
12
+ log.blank();
13
+ },
14
+ };
15
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/utils/logger.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,MAAM,CAAC,MAAM,GAAG,GAAG;IACjB,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACxD,OAAO,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC5D,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC1D,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IAC1D,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC;IACvD,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE;IAC1B,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE;QACrB,GAAG,CAAC,KAAK,EAAE,CAAA;QACX,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAA;QAC5B,GAAG,CAAC,KAAK,EAAE,CAAA;IACb,CAAC;CACF,CAAA"}
@@ -0,0 +1,7 @@
1
+ export interface ExecOptions {
2
+ cwd?: string;
3
+ silent?: boolean;
4
+ }
5
+ export declare function exec(command: string, options?: ExecOptions): string;
6
+ export declare function execSilent(command: string, cwd?: string): string | null;
7
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,MAAM,CAevE;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAMvE"}
@@ -0,0 +1,28 @@
1
+ import { execSync } from "node:child_process";
2
+ import { log } from "./logger.js";
3
+ export function exec(command, options = {}) {
4
+ const { cwd, silent = false } = options;
5
+ try {
6
+ const result = execSync(command, {
7
+ cwd,
8
+ encoding: "utf-8",
9
+ stdio: silent ? "pipe" : "inherit",
10
+ });
11
+ return typeof result === "string" ? result.trim() : "";
12
+ }
13
+ catch (error) {
14
+ if (!silent) {
15
+ log.error(`Command failed: ${command}`);
16
+ }
17
+ throw error;
18
+ }
19
+ }
20
+ export function execSilent(command, cwd) {
21
+ try {
22
+ return exec(command, { cwd, silent: true });
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../src/utils/shell.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAC7C,OAAO,EAAE,GAAG,EAAE,MAAM,aAAa,CAAA;AAOjC,MAAM,UAAU,IAAI,CAAC,OAAe,EAAE,UAAuB,EAAE;IAC7D,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,KAAK,EAAE,GAAG,OAAO,CAAA;IACvC,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,EAAE;YAC/B,GAAG;YACH,QAAQ,EAAE,OAAO;YACjB,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;SACnC,CAAC,CAAA;QACF,OAAO,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAA;IACxD,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,GAAG,CAAC,KAAK,CAAC,mBAAmB,OAAO,EAAE,CAAC,CAAA;QACzC,CAAC;QACD,MAAM,KAAK,CAAA;IACb,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe,EAAE,GAAY;IACtD,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC"}
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "create-substrate",
3
+ "version": "0.1.0",
4
+ "description": "Scaffold a Substrate creative tool playground",
5
+ "type": "module",
6
+ "bin": {
7
+ "create-substrate": "./dist/index.js"
8
+ },
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsx src/index.ts"
12
+ },
13
+ "dependencies": {
14
+ "chalk": "^5.4.0",
15
+ "commander": "^13.0.0"
16
+ },
17
+ "devDependencies": {
18
+ "@types/node": "^20.0.0",
19
+ "tsx": "^4.0.0",
20
+ "typescript": "^5.0.0"
21
+ },
22
+ "files": [
23
+ "dist",
24
+ "skills"
25
+ ],
26
+ "keywords": [
27
+ "substrate",
28
+ "canvas",
29
+ "design-tool",
30
+ "vite",
31
+ "react",
32
+ "scaffold"
33
+ ],
34
+ "license": "MIT"
35
+ }
@@ -0,0 +1,172 @@
1
+ # 3D scene
2
+
3
+ Guide to building interactive 3D viewports with Substrate — object placement, orbit cameras, material editors, and lighting controls.
4
+
5
+ ## When to use this surface
6
+
7
+ Use a 3D scene when the app involves spatial objects in three dimensions: product viewers, architectural walkthroughs, particle systems, shader playgrounds, or any tool where users orbit, zoom, and interact with a scene graph.
8
+
9
+ ## Surface setup
10
+
11
+ The 3D viewport lives inside the Substrate layout where the canvas would normally go. Use Three.js (via `@react-three/fiber` and `@react-three/drei`) as the rendering engine.
12
+
13
+ ### Dependencies
14
+
15
+ ```bash
16
+ npm install three @react-three/fiber @react-three/drei
17
+ npm install -D @types/three
18
+ ```
19
+
20
+ ### Mount the viewport
21
+
22
+ Create a surface component that fills the available space between panels:
23
+
24
+ ```tsx
25
+ "use client"
26
+
27
+ import { Canvas } from "@react-three/fiber"
28
+ import { OrbitControls, Grid, Environment } from "@react-three/drei"
29
+
30
+ export function SceneViewport() {
31
+ return (
32
+ <div className="absolute inset-0 bg-canvas">
33
+ <Canvas camera={{ position: [5, 5, 5], fov: 50 }}>
34
+ <OrbitControls makeDefault />
35
+ <Grid infiniteGrid fadeDistance={50} />
36
+ <Environment preset="studio" />
37
+ <ambientLight intensity={0.4} />
38
+ <directionalLight position={[10, 10, 5]} intensity={1} />
39
+ {/* Scene objects render here */}
40
+ </Canvas>
41
+ </div>
42
+ )
43
+ }
44
+ ```
45
+
46
+ Drop this into the playground layout in place of `<DesignCanvas />`.
47
+
48
+ ## Store architecture
49
+
50
+ Create a Zustand scene store to manage the 3D scene graph. This follows the same pattern as `document-store` but for 3D objects:
51
+
52
+ ```ts
53
+ interface SceneObject {
54
+ id: string
55
+ name: string
56
+ type: "mesh" | "light" | "group" | "camera"
57
+ position: [number, number, number]
58
+ rotation: [number, number, number]
59
+ scale: [number, number, number]
60
+ geometry?: "box" | "sphere" | "cylinder" | "plane" | "torus" | "custom"
61
+ material?: MaterialConfig
62
+ visible: boolean
63
+ locked: boolean
64
+ children?: string[]
65
+ }
66
+ ```
67
+
68
+ Store actions should include: `addObject`, `removeObject`, `updateObject`, `selectObject`, `pushSnapshot` (for undo/redo). Use the same snapshot-based undo pattern as the 2D canvas.
69
+
70
+ ## Wiring to Substrate chrome
71
+
72
+ ### Toolbar
73
+
74
+ Map toolbar toggles to 3D-specific modes:
75
+
76
+ | Tool | Purpose | Shortcut |
77
+ |---|---|---|
78
+ | Select | Click objects in the viewport | V |
79
+ | Move | Translate selected object(s) | G |
80
+ | Rotate | Rotate selected object(s) | R |
81
+ | Scale | Scale selected object(s) | S |
82
+ | Add | Open an add menu (cube, sphere, light, etc.) | Shift+A |
83
+
84
+ Use `useToolStore` — the same store the 2D canvas uses. The tool type union can be extended with 3D-specific modes.
85
+
86
+ ### Panels
87
+
88
+ **Left panel — scene hierarchy:**
89
+
90
+ A tree view of the scene graph. Each node shows name, type icon, and visibility toggle. Clicking selects the object in the viewport. This follows the same pattern as the layers panel but supports nesting (groups/parent-child).
91
+
92
+ **Right panel — properties inspector:**
93
+
94
+ Use the Pane/Action/Slider compound components to expose:
95
+
96
+ - **Transform pane** — X/Y/Z position, rotation (degrees), scale with number inputs
97
+ - **Geometry pane** — type-specific properties (radius, segments, width/height/depth)
98
+ - **Material pane** — colour picker, metalness/roughness sliders, texture upload
99
+ - **Light pane** (when a light is selected) — intensity slider, colour, shadow toggle
100
+
101
+ ### Keyboard shortcuts
102
+
103
+ Extend `useKeyboardShortcuts` or create a `use3DShortcuts` hook:
104
+
105
+ - Delete — remove selected object
106
+ - Cmd+Z / Cmd+Shift+Z — undo/redo via snapshot store
107
+ - Cmd+D — duplicate selected
108
+ - H — toggle visibility of selected
109
+ - Numpad shortcuts for camera views (front/top/right) if desired
110
+
111
+ ## Interaction patterns
112
+
113
+ ### Object selection
114
+
115
+ `@react-three/fiber` provides `onPointerDown` on mesh components. Use raycasting (built into R3F) rather than manual hit-testing:
116
+
117
+ ```tsx
118
+ <mesh
119
+ onClick={(e) => {
120
+ e.stopPropagation()
121
+ sceneStore.selectObject(object.id, e.shiftKey)
122
+ }}
123
+ >
124
+ {/* geometry + material */}
125
+ </mesh>
126
+ ```
127
+
128
+ ### Transform gizmos
129
+
130
+ Use `@react-three/drei`'s `TransformControls` for move/rotate/scale. Wire the active mode to `useToolStore`:
131
+
132
+ ```tsx
133
+ {selectedId && (
134
+ <TransformControls
135
+ object={selectedRef}
136
+ mode={activeTool === "rotate" ? "rotate" : activeTool === "scale" ? "scale" : "translate"}
137
+ onObjectChange={() => sceneStore.updateFromRef(selectedId, selectedRef)}
138
+ />
139
+ )}
140
+ ```
141
+
142
+ ### Camera
143
+
144
+ `OrbitControls` handles orbit/zoom/pan. Disable it when a transform gizmo is active to prevent conflicts. The hand tool can temporarily enable a fly/walk camera mode.
145
+
146
+ ## Theming
147
+
148
+ The 3D viewport background can read `--canvas` via CSS on the container div. For the Three.js scene background, read it from the DOM:
149
+
150
+ ```ts
151
+ const style = getComputedStyle(document.documentElement)
152
+ const bg = style.getPropertyValue("--canvas").trim()
153
+ // Convert to Three.js colour and set scene.background
154
+ ```
155
+
156
+ Grid, gizmo, and selection highlight colours can be configured as constants or driven by additional CSS variables.
157
+
158
+ ## What to build
159
+
160
+ Some examples of what this surface enables:
161
+
162
+ - **Product configurator** — load a 3D model, expose material/colour options in panes, orbit to inspect
163
+ - **Scene builder** — add primitives, position them, set up lighting, export as glTF
164
+ - **Shader playground** — custom `ShaderMaterial` with uniforms exposed as sliders in the properties panel
165
+ - **Particle system editor** — particle emitter properties as pane controls, real-time preview in the viewport
166
+ - **Architectural viewer** — import a model, add measurement tools, annotate with text labels
167
+
168
+ ## Related reference skills
169
+
170
+ - **substrate-scaffold** — Toolbar, Panel, StatusBar, ZoomControls for the app shell
171
+ - **substrate-controls** — NumberInput, Slider, ColourPicker, ActionControls for property panes
172
+ - **substrate-interaction** — useUndoable, useClipboard, createKeyboardShortcuts, TreeList for scene hierarchy
@@ -0,0 +1,194 @@
1
+ # Animation
2
+
3
+ Guide to building timeline-based motion tools with Substrate — keyframe editing, easing controls, playback, and animated previews.
4
+
5
+ ## When to use this surface
6
+
7
+ Use an animation surface when the app involves motion over time: UI animation prototyping, motion graphics editors, sprite animation, easing explorers, or any tool where users define how things change across a timeline.
8
+
9
+ ## Surface setup
10
+
11
+ Animation tools combine a **preview stage** (where the animation plays) with a **timeline** (where keyframes are edited). The preview can be DOM-based (GSAP animating real elements) or canvas-based, depending on what's being animated.
12
+
13
+ ### Dependencies
14
+
15
+ ```bash
16
+ npm install gsap
17
+ ```
18
+
19
+ GSAP handles the animation engine — tweening, easing, timeline sequencing. For simpler cases, CSS animations or the Web Animations API may suffice, but GSAP provides the most control for a creative tool.
20
+
21
+ ### Layout
22
+
23
+ Animation tools typically use a vertical split — preview on top, timeline on the bottom:
24
+
25
+ ```
26
+ ┌──────────┬────────────────────────┬──────────┐
27
+ │ │ │ │
28
+ │ Left │ Preview stage │ Right │
29
+ │ panel │ (animated elements) │ panel │
30
+ │ │ │ │
31
+ │ Layers │ │ Props │
32
+ │ │ │ │
33
+ ├──────────┴────────────────────────┴──────────┤
34
+ │ Timeline │
35
+ │ ──●────────●──────────●─────── ▶ 0:00 / 2:00│
36
+ │ [tracks with keyframe diamonds] │
37
+ └───────────────────────────────────────────────┘
38
+ [ Toolbar ]
39
+ ```
40
+
41
+ ## Store architecture
42
+
43
+ ### Animation store
44
+
45
+ ```ts
46
+ interface AnimationState {
47
+ duration: number // Total duration in seconds
48
+ currentTime: number // Playhead position
49
+ isPlaying: boolean
50
+ fps: number // Preview framerate (default 60)
51
+ layers: AnimationLayer[]
52
+ selectedKeyframes: string[]
53
+ }
54
+
55
+ interface AnimationLayer {
56
+ id: string
57
+ name: string
58
+ targetId: string // Which element this layer animates
59
+ property: string // "x" | "y" | "opacity" | "scale" | "rotation" | ...
60
+ keyframes: Keyframe[]
61
+ visible: boolean
62
+ locked: boolean
63
+ }
64
+
65
+ interface Keyframe {
66
+ id: string
67
+ time: number // Position in seconds
68
+ value: number
69
+ easing: EasingType // "linear" | "ease-in" | "ease-out" | "ease-in-out" | "cubic-bezier" | ...
70
+ bezierHandles?: [number, number, number, number] // For custom cubic-bezier
71
+ }
72
+ ```
73
+
74
+ ### Element store
75
+
76
+ Reuse the same pattern as the 2D canvas document store, but elements here represent animated objects on the stage rather than static shapes. Each element has base properties that keyframes override at specific times.
77
+
78
+ ## Timeline component
79
+
80
+ The timeline is the core component that's unique to animation surfaces. It needs:
81
+
82
+ - **Playhead** — a draggable vertical line showing current time, scrubbable
83
+ - **Tracks** — one row per animated property, showing keyframe diamonds
84
+ - **Keyframe diamonds** — draggable markers at specific times, selectable
85
+ - **Zoom** — horizontal zoom to see more or fewer seconds
86
+ - **Rulers** — time markings along the top (seconds/frames)
87
+ - **Playback controls** — play/pause, jump to start/end, loop toggle
88
+
89
+ ### Interaction model
90
+
91
+ The timeline uses horizontal dragging extensively:
92
+
93
+ - Drag the playhead to scrub through time
94
+ - Drag a keyframe diamond to move it in time
95
+ - Shift-click keyframes to multi-select
96
+ - Double-click a track to add a keyframe at that time
97
+ - Right-click a keyframe for easing options
98
+
99
+ This is pointer-event-driven, similar to the 2D canvas interaction model but on a 1D (time) axis rather than 2D space. Consider a dedicated `useTimelineInteraction` hook following the same state machine pattern as `useCanvasInteraction`.
100
+
101
+ ## Wiring to Substrate chrome
102
+
103
+ ### Toolbar
104
+
105
+ | Tool | Purpose | Shortcut |
106
+ |---|---|---|
107
+ | Select | Select keyframes on timeline | V |
108
+ | Add keyframe | Click on timeline to add | K |
109
+ | Play/Pause | Toggle playback | Space |
110
+ | Jump to start | Move playhead to 0 | Home |
111
+ | Jump to end | Move playhead to duration | End |
112
+ | Loop | Toggle loop playback | L |
113
+
114
+ ### Left panel — layers
115
+
116
+ List animation layers (one per animated property per element). Show: element name, property name, visibility toggle, lock toggle. Group layers by element.
117
+
118
+ ### Right panel — keyframe properties
119
+
120
+ When a keyframe is selected, show:
121
+
122
+ - **Time pane** — exact time position (number input)
123
+ - **Value pane** — the property value at this keyframe
124
+ - **Easing pane** — easing type dropdown plus a visual curve editor for cubic-bezier
125
+ - **Interpolation** — linear vs smooth vs step
126
+
127
+ The easing curve editor is a specialised pane — a small canvas showing the bezier curve with draggable control points.
128
+
129
+ ## Preview stage
130
+
131
+ The preview stage renders the current state of the animation at `currentTime`. On each frame:
132
+
133
+ 1. Read `currentTime` from the animation store
134
+ 2. For each layer, interpolate between the surrounding keyframes using the specified easing
135
+ 3. Apply interpolated values to the corresponding elements
136
+ 4. Render the stage
137
+
138
+ During playback, a `requestAnimationFrame` loop advances `currentTime` at the configured FPS.
139
+
140
+ ### Using GSAP
141
+
142
+ GSAP's timeline can be built from the keyframe data and scrubbed to `currentTime`:
143
+
144
+ ```ts
145
+ // Build a GSAP timeline from store data
146
+ const tl = gsap.timeline({ paused: true })
147
+
148
+ for (const layer of layers) {
149
+ for (let i = 0; i < layer.keyframes.length - 1; i++) {
150
+ const from = layer.keyframes[i]
151
+ const to = layer.keyframes[i + 1]
152
+ tl.to(targetRef, {
153
+ [layer.property]: to.value,
154
+ duration: to.time - from.time,
155
+ ease: to.easing,
156
+ }, from.time)
157
+ }
158
+ }
159
+
160
+ // Scrub to current time
161
+ tl.seek(currentTime)
162
+ ```
163
+
164
+ Rebuild the GSAP timeline when keyframes change. Seek to `currentTime` on every frame during playback and when the user scrubs.
165
+
166
+ ## Keyboard shortcuts
167
+
168
+ - Space — play/pause
169
+ - K — add keyframe at current time for selected property
170
+ - Delete — remove selected keyframes
171
+ - Cmd+Z / Cmd+Shift+Z — undo/redo
172
+ - Left/Right arrows — step forward/back one frame
173
+ - Shift+Left/Right — step forward/back 10 frames
174
+ - Home/End — jump to start/end
175
+
176
+ ## Theming
177
+
178
+ The preview stage uses `bg-canvas`. The timeline area can use `bg-panel` or a slightly different shade. Keyframe diamonds, playhead, and track colours should be configurable — consider additional CSS variables like `--timeline-playhead`, `--timeline-keyframe`, `--timeline-track`.
179
+
180
+ ## What to build
181
+
182
+ Some examples of what this surface enables:
183
+
184
+ - **UI animation prototyper** — animate component properties (opacity, position, scale), export CSS/GSAP code
185
+ - **Easing explorer** — visual comparison of different easing functions, interactive curve editor
186
+ - **Sprite animator** — frame-by-frame sprite animation with onion skinning
187
+ - **Motion graphics tool** — animate text and shapes along paths with timing controls
188
+ - **Transition builder** — design page/component transitions, preview at different speeds
189
+
190
+ ## Related reference skills
191
+
192
+ - **substrate-scaffold** — Toolbar, Panel, StatusBar for the app shell
193
+ - **substrate-controls** — NumberInput, Slider, EasingCurveEditor, ActionControls for keyframe properties
194
+ - **substrate-interaction** — useUndoable, createKeyboardShortcuts, LayerList for animation layers