@playcraft/cli 0.0.53 → 0.0.56
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/README.md +21 -0
- package/REMIX.md +103 -19
- package/dist/atom-tree/fusion-hints.js +8 -3
- package/dist/atom-tree/fusion-intent.js +62 -0
- package/dist/atom-tree/selection.js +3 -1
- package/dist/commands/create.js +439 -159
- package/dist/commands/image.js +79 -69
- package/dist/commands/levels.js +29 -0
- package/dist/commands/patterns.js +75 -0
- package/dist/commands/remix.js +47 -0
- package/dist/commands/skills.js +48 -17
- package/dist/index.js +13 -6
- package/dist/remix/clone-source.js +208 -0
- package/dist/remix/clone.js +255 -0
- package/dist/scaffold/templates.js +35 -0
- package/dist/utils/agent-api-client.js +10 -3
- package/dist/utils/remix-image-attachments.js +4 -32
- package/dist/utils/sandbox-path.js +20 -0
- package/package.json +3 -3
- package/project-template/.claude/agents/creative-director.md +114 -0
- package/project-template/.claude/agents/developer.md +5 -2
- package/project-template/.claude/agents/game-designer.md +41 -20
- package/project-template/.claude/agents/refs/README.md +8 -0
- package/project-template/.claude/agents/refs/creative-director-guide.md +35 -0
- package/project-template/.claude/agents/refs/creative-director-kickoff-guide.md +52 -0
- package/project-template/.claude/agents/refs/creative-discovery-guide.md +76 -0
- package/project-template/.claude/agents/refs/creative-north-star-examples.md +82 -0
- package/project-template/.claude/agents/refs/developer-dev-handoff.md +1 -1
- package/project-template/.claude/agents/refs/game-designer-fusion-depth-playbook.md +28 -0
- package/project-template/.claude/agents/refs/game-designer-gameplay-sufficiency.md +4 -4
- package/project-template/.claude/agents/reviewer.md +11 -0
- package/project-template/.claude/hooks/README.md +12 -12
- package/project-template/.claude/hooks/block-developer-preflight.mjs +49 -13
- package/project-template/.claude/hooks/block-ring1-tasklist.mjs +1 -1
- package/project-template/.claude/hooks/user-prompt.mjs +3 -13
- package/project-template/.claude/hooks/validate-workflow-stop.mjs +209 -12
- package/project-template/.claude/settings.json +2 -2
- package/project-template/.claude/skills/playcraft-playable-optimization/SKILL.md +20 -20
- package/project-template/.claude/skills/session-analyzer/scripts/resolve-session.mjs +0 -1
- package/project-template/.claude/snapshot.mjs +0 -1
- package/project-template/.codebuddy/settings.json +1 -1
- package/project-template/.cursor/rules/playcraft-orchestrator.mdc +1 -1
- package/project-template/CLAUDE.md +9 -9
- package/project-template/docs/project-state.md +1 -1
- package/project-template/docs/team/agent-conduct.md +18 -18
- package/project-template/docs/team/collaboration.md +19 -7
- package/project-template/docs/team/workflow-changelog.md +15 -0
- package/project-template/fusion-patterns/catalog.json +77 -0
- package/project-template/package.json +2 -0
- package/project-template/skills/_shared/scripts/create-playable.mjs +31 -11
- package/project-template/skills/_shared/scripts/dev-start.mjs +3 -3
- package/project-template/skills/_shared/scripts/disclosure-config.mjs +65 -39
- package/project-template/skills/_shared/scripts/harness-smoke.mjs +3 -1
- package/project-template/skills/_shared/scripts/lib/fusion-intent.mjs +88 -0
- package/project-template/skills/_shared/scripts/lib/skill-fidelity.mjs +185 -0
- package/project-template/skills/_shared/scripts/slice-set.mjs +29 -2
- package/project-template/skills/_shared/scripts/state-get.mjs +124 -7
- package/project-template/skills/_shared/scripts/state-store.mjs +25 -2
- package/project-template/skills/_shared/scripts/validate-level-sketch.mjs +444 -0
- package/project-template/skills/_shared/scripts/verify-design-consistency.mjs +728 -0
- package/project-template/skills/playable-record/scripts/lib/dev-server.mjs +46 -11
- package/project-template/skills/playable-record/scripts/record-playable.mjs +2 -1
- package/project-template/skills/playable-record/scripts/verify-contract.mjs +4 -4
- package/project-template/skills/playable-record/scripts/verify-firstwin.mjs +3 -3
- package/project-template/skills/playable-record/scripts/verify-fusion.mjs +37 -2
- package/project-template/skills/playable-record/scripts/verify-slice.mjs +2 -2
- package/project-template/templates/design-brief.template.md +34 -0
- package/project-template/templates/design-methodology.md +1 -2
- package/project-template/templates/design.template.md +65 -0
- package/project-template/templates/developer-log.template.md +12 -1
- package/project-template/templates/five-axis-framework.md +12 -0
- package/project-template/templates/game-designer-creative-process.template.md +99 -0
- package/project-template/templates/level-sketch.template.json +56 -0
- package/project-template/templates/north-star.template.md +43 -0
- package/project-template/templates/project-state.template.md +1 -1
- package/project-template/vite.config.ts +4 -5
- package/project-templates/phaser/.claude/agents/creative-director.md +114 -0
- package/project-templates/phaser/.claude/agents/game-designer.md +41 -20
- package/project-templates/phaser/.claude/agents/refs/creative-director-guide.md +35 -0
- package/project-templates/phaser/.claude/agents/refs/creative-director-kickoff-guide.md +52 -0
- package/project-templates/phaser/.claude/agents/refs/creative-discovery-guide.md +76 -0
- package/project-templates/phaser/.claude/agents/refs/creative-north-star-examples.md +82 -0
- package/project-templates/phaser/.claude/agents/refs/developer-dev-handoff.md +1 -1
- package/project-templates/phaser/.claude/agents/refs/game-designer-fusion-depth-playbook.md +28 -0
- package/project-templates/phaser/.claude/agents/reviewer.md +11 -0
- package/project-templates/phaser/.claude/hooks/block-ring1-tasklist.mjs +2 -2
- package/project-templates/phaser/.claude/hooks/user-prompt.mjs +17 -18
- package/project-templates/phaser/.claude/hooks/validate-workflow-stop.mjs +209 -12
- package/project-templates/phaser/.claude/skills/playcraft-playable-optimization/SKILL.md +20 -20
- package/project-templates/phaser/.cursor/rules/playcraft-orchestrator.mdc +1 -1
- package/project-templates/phaser/CLAUDE.md +88 -54
- package/project-templates/phaser/docs/DESIGN.md +25 -0
- package/project-templates/phaser/docs/project-state.md +1 -1
- package/project-templates/phaser/docs/team/collaboration.md +19 -7
- package/project-templates/phaser/docs/team/workflow-changelog.md +14 -0
- package/project-templates/phaser/fusion-patterns/catalog.json +77 -0
- package/project-templates/phaser/package.json +3 -1
- package/project-templates/phaser/skills/_shared/scripts/dev-start.mjs +3 -3
- package/project-templates/phaser/skills/_shared/scripts/disclosure-config.mjs +65 -39
- package/project-templates/phaser/skills/_shared/scripts/harness-smoke.mjs +3 -1
- package/project-templates/phaser/skills/_shared/scripts/lib/fusion-intent.mjs +88 -0
- package/project-templates/phaser/skills/_shared/scripts/lib/skill-fidelity.mjs +185 -0
- package/project-templates/phaser/skills/_shared/scripts/state-get.mjs +124 -7
- package/project-templates/phaser/skills/_shared/scripts/state-store.mjs +25 -2
- package/project-templates/phaser/skills/_shared/scripts/validate-level-sketch.mjs +444 -0
- package/project-templates/phaser/skills/_shared/scripts/verify-design-consistency.mjs +728 -0
- package/project-templates/phaser/skills/playable-record/scripts/lib/dev-server.mjs +46 -11
- package/project-templates/phaser/skills/playable-record/scripts/record-playable.mjs +2 -1
- package/project-templates/phaser/skills/playable-record/scripts/verify-contract.mjs +4 -4
- package/project-templates/phaser/skills/playable-record/scripts/verify-firstwin.mjs +3 -3
- package/project-templates/phaser/skills/playable-record/scripts/verify-fusion.mjs +37 -2
- package/project-templates/phaser/skills/playable-record/scripts/verify-slice.mjs +2 -2
- package/project-templates/phaser/templates/design-brief.template.md +42 -11
- package/project-templates/phaser/templates/design-methodology.md +1 -2
- package/project-templates/phaser/templates/design.template.md +77 -0
- package/project-templates/phaser/templates/five-axis-framework.md +50 -1
- package/project-templates/phaser/templates/game-designer-creative-process.template.md +99 -0
- package/project-templates/phaser/templates/level-sketch.template.json +56 -0
- package/project-templates/phaser/templates/north-star.template.md +43 -0
- package/project-templates/phaser/templates/project-state.template.md +1 -1
- package/project-templates/phaser/vite.config.ts +4 -5
- package/project-templates/playable-template-phaser/.playcraftignore +10 -0
- package/project-templates/playable-template-phaser/CLAUDE.md +178 -0
- package/project-templates/playable-template-phaser/PLAYCRAFT-MIGRATION.md +328 -0
- package/project-templates/playable-template-phaser/README.md +381 -0
- package/project-templates/playable-template-phaser/assets/brain.png +0 -0
- package/project-templates/playable-template-phaser/assets/button.png +0 -0
- package/project-templates/playable-template-phaser/assets/interact.png +0 -0
- package/project-templates/playable-template-phaser/assets/logo.webp +0 -0
- package/project-templates/playable-template-phaser/assets/warn_brain.png +0 -0
- package/project-templates/playable-template-phaser/builds.config.js +12 -0
- package/project-templates/playable-template-phaser/globals.d.ts +2 -0
- package/project-templates/playable-template-phaser/index.html +12 -0
- package/project-templates/playable-template-phaser/package.json +45 -0
- package/project-templates/playable-template-phaser/scripts/base64-to-mp3.js +340 -0
- package/project-templates/playable-template-phaser/scripts/convert-to-webp.js +370 -0
- package/project-templates/playable-template-phaser/src/Game.ts +154 -0
- package/project-templates/playable-template-phaser/src/config/LoadingConfig.ts +40 -0
- package/project-templates/playable-template-phaser/src/config/ThemeConfig.ts +81 -0
- package/project-templates/playable-template-phaser/src/index.css +18 -0
- package/project-templates/playable-template-phaser/src/index.html +9 -0
- package/project-templates/playable-template-phaser/src/index.ts +30 -0
- package/project-templates/playable-template-phaser/src/json5.d.ts +4 -0
- package/project-templates/playable-template-phaser/src/managers/AudioManager.ts +559 -0
- package/project-templates/playable-template-phaser/src/scenes/MainScene.ts +301 -0
- package/project-templates/playable-template-phaser/src/scenes/PreloadScene.ts +256 -0
- package/project-templates/playable-template-phaser/src/theme/README.md +194 -0
- package/project-templates/playable-template-phaser/src/theme/blue-theme/assets/.gitkeep +24 -0
- package/project-templates/playable-template-phaser/src/theme/blue-theme/index.ts +27 -0
- package/project-templates/playable-template-phaser/src/theme/blue-theme/theme.data.json5 +19 -0
- package/project-templates/playable-template-phaser/src/theme/green-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-phaser/src/theme/green-theme/index.ts +20 -0
- package/project-templates/playable-template-phaser/src/theme/green-theme/theme.data.json5 +19 -0
- package/project-templates/playable-template-phaser/src/theme/index.ts +1 -0
- package/project-templates/playable-template-phaser/src/theme/red-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-phaser/src/theme/red-theme/index.ts +20 -0
- package/project-templates/playable-template-phaser/src/theme/red-theme/theme.data.json5 +19 -0
- package/project-templates/playable-template-phaser/src/theme/theme.metadata.md +60 -0
- package/project-templates/playable-template-phaser/src/theme/theme.schema.json5 +149 -0
- package/project-templates/playable-template-phaser/src/ui/BrainAgeUI.ts +681 -0
- package/project-templates/playable-template-phaser/src/ui/CountdownUI.ts +565 -0
- package/project-templates/playable-template-phaser/src/ui/PlayButton.ts +51 -0
- package/project-templates/playable-template-phaser/src/ui/ScoreUI.ts +207 -0
- package/project-templates/playable-template-phaser/src/ui/SuccessUI.ts +43 -0
- package/project-templates/playable-template-phaser/src/ui/index.ts +15 -0
- package/project-templates/playable-template-phaser/tsconfig.json +26 -0
- package/project-templates/playable-template-phaser/vite.config.ts +64 -0
- package/project-templates/playable-template-phaser//346/226/260/346/211/213/345/274/200/345/217/221/346/214/207/345/215/227.md +209 -0
- package/project-templates/playable-template-three/README.md +795 -0
- package/project-templates/playable-template-three/assets/Stork.glb +0 -0
- package/project-templates/playable-template-three/assets/button.png +0 -0
- package/project-templates/playable-template-three/assets/logo.webp +0 -0
- package/project-templates/playable-template-three/build.json +7 -0
- package/project-templates/playable-template-three/builds.config.example.js +151 -0
- package/project-templates/playable-template-three/builds.config.js +158 -0
- package/project-templates/playable-template-three/package.json +36 -0
- package/project-templates/playable-template-three/scripts/convert-to-webp.js +370 -0
- package/project-templates/playable-template-three/scripts/theme-builds.js +514 -0
- package/project-templates/playable-template-three/src/Game.ts +215 -0
- package/project-templates/playable-template-three/src/config/LoadingConfig.ts +27 -0
- package/project-templates/playable-template-three/src/config/ThemeConfig.ts +36 -0
- package/project-templates/playable-template-three/src/global.d.ts +108 -0
- package/project-templates/playable-template-three/src/index.css +18 -0
- package/project-templates/playable-template-three/src/index.html +9 -0
- package/project-templates/playable-template-three/src/index.ts +20 -0
- package/project-templates/playable-template-three/src/managers/AudioManager.ts +538 -0
- package/project-templates/playable-template-three/src/scenes/PreloadScene.ts +305 -0
- package/project-templates/playable-template-three/src/theme/README.md +225 -0
- package/project-templates/playable-template-three/src/theme/blue-theme/assets/.gitkeep +28 -0
- package/project-templates/playable-template-three/src/theme/blue-theme/index.ts +45 -0
- package/project-templates/playable-template-three/src/theme/current.ts +12 -0
- package/project-templates/playable-template-three/src/theme/green-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-three/src/theme/green-theme/index.ts +34 -0
- package/project-templates/playable-template-three/src/theme/red-theme/assets/.gitkeep +3 -0
- package/project-templates/playable-template-three/src/theme/red-theme/index.ts +34 -0
- package/project-templates/playable-template-three/tsconfig.json +24 -0
- package/project-templates/threejs/.claude/agents/creative-director.md +114 -0
- package/project-templates/threejs/.claude/agents/game-designer.md +41 -20
- package/project-templates/threejs/.claude/agents/refs/creative-director-guide.md +35 -0
- package/project-templates/threejs/.claude/agents/refs/creative-director-kickoff-guide.md +52 -0
- package/project-templates/threejs/.claude/agents/refs/creative-discovery-guide.md +76 -0
- package/project-templates/threejs/.claude/agents/refs/creative-north-star-examples.md +82 -0
- package/project-templates/threejs/.claude/agents/refs/developer-dev-handoff.md +1 -1
- package/project-templates/threejs/.claude/agents/refs/game-designer-fusion-depth-playbook.md +28 -0
- package/project-templates/threejs/.claude/agents/reviewer.md +11 -0
- package/project-templates/threejs/.claude/hooks/block-ring1-tasklist.mjs +2 -2
- package/project-templates/threejs/.claude/hooks/user-prompt.mjs +17 -18
- package/project-templates/threejs/.claude/hooks/validate-workflow-stop.mjs +209 -12
- package/project-templates/threejs/.claude/skills/playcraft-playable-optimization/SKILL.md +20 -20
- package/project-templates/threejs/.cursor/rules/playcraft-orchestrator.mdc +1 -1
- package/project-templates/threejs/CLAUDE.md +88 -54
- package/project-templates/threejs/docs/DESIGN.md +25 -0
- package/project-templates/threejs/docs/project-state.md +1 -1
- package/project-templates/threejs/docs/team/collaboration.md +19 -7
- package/project-templates/threejs/docs/team/workflow-changelog.md +14 -0
- package/project-templates/threejs/fusion-patterns/catalog.json +77 -0
- package/project-templates/threejs/package.json +3 -1
- package/project-templates/threejs/skills/_shared/scripts/dev-start.mjs +3 -3
- package/project-templates/threejs/skills/_shared/scripts/disclosure-config.mjs +65 -39
- package/project-templates/threejs/skills/_shared/scripts/harness-smoke.mjs +3 -1
- package/project-templates/threejs/skills/_shared/scripts/lib/fusion-intent.mjs +88 -0
- package/project-templates/threejs/skills/_shared/scripts/lib/skill-fidelity.mjs +185 -0
- package/project-templates/threejs/skills/_shared/scripts/state-get.mjs +124 -7
- package/project-templates/threejs/skills/_shared/scripts/state-store.mjs +25 -2
- package/project-templates/threejs/skills/_shared/scripts/validate-level-sketch.mjs +444 -0
- package/project-templates/threejs/skills/_shared/scripts/verify-design-consistency.mjs +728 -0
- package/project-templates/threejs/skills/playable-record/scripts/lib/dev-server.mjs +46 -11
- package/project-templates/threejs/skills/playable-record/scripts/record-playable.mjs +2 -1
- package/project-templates/threejs/skills/playable-record/scripts/verify-contract.mjs +4 -4
- package/project-templates/threejs/skills/playable-record/scripts/verify-firstwin.mjs +3 -3
- package/project-templates/threejs/skills/playable-record/scripts/verify-fusion.mjs +37 -2
- package/project-templates/threejs/skills/playable-record/scripts/verify-slice.mjs +2 -2
- package/project-templates/threejs/templates/design-brief.template.md +42 -11
- package/project-templates/threejs/templates/design-methodology.md +1 -2
- package/project-templates/threejs/templates/design.template.md +77 -0
- package/project-templates/threejs/templates/five-axis-framework.md +50 -1
- package/project-templates/threejs/templates/game-designer-creative-process.template.md +99 -0
- package/project-templates/threejs/templates/level-sketch.template.json +56 -0
- package/project-templates/threejs/templates/north-star.template.md +43 -0
- package/project-templates/threejs/templates/project-state.template.md +1 -1
- package/project-templates/threejs/vite.config.ts +4 -5
- package/project-template/docs/DESIGN.md +0 -65
|
@@ -5,36 +5,61 @@
|
|
|
5
5
|
* real listening URL. Previously these were copy-pasted into verify-contract,
|
|
6
6
|
* verify-firstwin and record-playable, which let the port-detection logic drift.
|
|
7
7
|
*
|
|
8
|
-
* Vite runs with strictPort:false, so when the preferred port (
|
|
8
|
+
* Vite runs with strictPort:false, so when the preferred port (5173) is taken it
|
|
9
9
|
* auto-increments. `detectDevUrl` parses Vite's `Local:` stdout line to recover
|
|
10
10
|
* the actual port instead of guessing — this is what keeps devUrl correct under
|
|
11
11
|
* port drift (see docs/harness/experiment-lessons.md §9.2).
|
|
12
|
+
* Do not use 6000: Chromium treats it as an unsafe port (ERR_UNSAFE_PORT).
|
|
12
13
|
*/
|
|
13
14
|
|
|
14
15
|
import { spawn } from 'node:child_process';
|
|
16
|
+
import http from 'node:http';
|
|
17
|
+
|
|
18
|
+
/** Preferred Vite dev port — avoids PlayCraft frontend (:3000) and backend (:3001). */
|
|
19
|
+
export const DEFAULT_DEV_PORT = 5173;
|
|
20
|
+
export const DEFAULT_DEV_URL = `http://127.0.0.1:${DEFAULT_DEV_PORT}/`;
|
|
15
21
|
|
|
16
22
|
const LOCAL_URL_RE = /Local:\s+(http:\/\/(?:localhost|127\.0\.0\.1):\d+\/)/;
|
|
23
|
+
const ANSI_RE = /\x1b\[[0-9;]*m/g;
|
|
24
|
+
|
|
25
|
+
/** Probe a URL with node:http (undici `fetch` can fail on 127.0.0.1 in some runtimes). */
|
|
26
|
+
function probeHttp(url) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
const req = http.get(url, (res) => {
|
|
29
|
+
res.resume();
|
|
30
|
+
resolve(res.statusCode ?? 0);
|
|
31
|
+
});
|
|
32
|
+
req.setTimeout(2000, () => {
|
|
33
|
+
req.destroy();
|
|
34
|
+
reject(new Error('probe timeout'));
|
|
35
|
+
});
|
|
36
|
+
req.on('error', reject);
|
|
37
|
+
});
|
|
38
|
+
}
|
|
17
39
|
|
|
18
|
-
/** Poll a URL
|
|
40
|
+
/** Poll a URL until any non-5xx response arrives. */
|
|
19
41
|
export async function waitForHttp(url, timeoutMs = 30000) {
|
|
20
42
|
const start = Date.now();
|
|
43
|
+
let lastErr = '';
|
|
21
44
|
while (Date.now() - start < timeoutMs) {
|
|
22
45
|
try {
|
|
23
|
-
const
|
|
24
|
-
if (
|
|
25
|
-
|
|
26
|
-
|
|
46
|
+
const status = await probeHttp(url);
|
|
47
|
+
if (status < 500) return;
|
|
48
|
+
lastErr = `HTTP ${status}`;
|
|
49
|
+
} catch (err) {
|
|
50
|
+
lastErr = err instanceof Error ? err.message : String(err);
|
|
27
51
|
}
|
|
28
52
|
await new Promise((r) => setTimeout(r, 250));
|
|
29
53
|
}
|
|
30
|
-
throw new Error(`Server not ready: ${url}`);
|
|
54
|
+
throw new Error(`Server not ready: ${url}${lastErr ? ` (${lastErr})` : ''}`);
|
|
31
55
|
}
|
|
32
56
|
|
|
33
57
|
/** Spawn `npm run dev` (Vite) bound to 127.0.0.1 with piped stdio for URL detection. */
|
|
34
58
|
export function startDevServer(cwd) {
|
|
35
|
-
return spawn('npm', ['run', 'dev', '--', '--host', '127.0.0.1'], {
|
|
59
|
+
return spawn('npm', ['run', 'dev', '--', '--host', '127.0.0.1', '--port', String(DEFAULT_DEV_PORT), '--no-open'], {
|
|
36
60
|
cwd,
|
|
37
61
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
62
|
+
env: { ...process.env, BROWSER: 'none' },
|
|
38
63
|
});
|
|
39
64
|
}
|
|
40
65
|
|
|
@@ -53,7 +78,7 @@ export function startHttpServer(port, cwd) {
|
|
|
53
78
|
* @returns {string | null}
|
|
54
79
|
*/
|
|
55
80
|
export function parseLocalUrl(text) {
|
|
56
|
-
const m = String(text).match(LOCAL_URL_RE);
|
|
81
|
+
const m = String(text).replace(ANSI_RE, '').match(LOCAL_URL_RE);
|
|
57
82
|
return m ? m[1] : null;
|
|
58
83
|
}
|
|
59
84
|
|
|
@@ -66,25 +91,35 @@ export function parseLocalUrl(text) {
|
|
|
66
91
|
* @returns {Promise<string>}
|
|
67
92
|
*/
|
|
68
93
|
export function detectDevUrl(child, preferredUrl, timeoutMs = 30000) {
|
|
69
|
-
return new Promise((res) => {
|
|
94
|
+
return new Promise((res, rej) => {
|
|
95
|
+
let buf = '';
|
|
70
96
|
const timer = setTimeout(() => {
|
|
71
97
|
cleanup();
|
|
72
98
|
res(preferredUrl);
|
|
73
99
|
}, timeoutMs);
|
|
74
100
|
const onData = (data) => {
|
|
75
|
-
|
|
101
|
+
buf += String(data);
|
|
102
|
+
const url = parseLocalUrl(buf);
|
|
76
103
|
if (url) {
|
|
77
104
|
clearTimeout(timer);
|
|
78
105
|
cleanup();
|
|
79
106
|
res(url);
|
|
80
107
|
}
|
|
81
108
|
};
|
|
109
|
+
const onExit = (code) => {
|
|
110
|
+
clearTimeout(timer);
|
|
111
|
+
cleanup();
|
|
112
|
+
const tail = buf.trim().slice(-1500);
|
|
113
|
+
rej(new Error(`dev server exited ${code} before publishing a Local URL${tail ? `\n${tail}` : ''}`));
|
|
114
|
+
};
|
|
82
115
|
const cleanup = () => {
|
|
83
116
|
child.stdout?.off('data', onData);
|
|
84
117
|
child.stderr?.off('data', onData);
|
|
118
|
+
child.off('exit', onExit);
|
|
85
119
|
};
|
|
86
120
|
child.stdout?.on('data', onData);
|
|
87
121
|
child.stderr?.on('data', onData);
|
|
122
|
+
child.once('exit', onExit);
|
|
88
123
|
});
|
|
89
124
|
}
|
|
90
125
|
|
|
@@ -11,6 +11,7 @@ import { chromium } from 'playwright';
|
|
|
11
11
|
import { evaluateContract, snapshotContractInPage } from './verify-contract.mjs';
|
|
12
12
|
import {
|
|
13
13
|
detectDevUrl,
|
|
14
|
+
DEFAULT_DEV_URL,
|
|
14
15
|
pickServerPort,
|
|
15
16
|
startDevServer,
|
|
16
17
|
startHttpServer,
|
|
@@ -314,7 +315,7 @@ async function main() {
|
|
|
314
315
|
externalServer = true;
|
|
315
316
|
} else if (opts.useDev) {
|
|
316
317
|
server = startDevServer(projectRoot);
|
|
317
|
-
const preferredUrl = opts.url ||
|
|
318
|
+
const preferredUrl = opts.url || DEFAULT_DEV_URL;
|
|
318
319
|
console.log(`[record] Starting dev server, waiting for ${preferredUrl}`);
|
|
319
320
|
const detectedUrl = await detectDevUrl(server, preferredUrl, 30000);
|
|
320
321
|
opts.url = detectedUrl;
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
* Exit 0 = contract satisfied, 2 = contract broken, 1 = unexpected error.
|
|
20
20
|
*
|
|
21
21
|
* Usage:
|
|
22
|
-
* node skills/playable-record/scripts/verify-contract.mjs --root=. --use-dev --url=http://localhost:
|
|
22
|
+
* node skills/playable-record/scripts/verify-contract.mjs --root=. --use-dev --url=http://localhost:5173/
|
|
23
23
|
* node skills/playable-record/scripts/verify-contract.mjs --root=. # standalone http-server
|
|
24
|
-
* node skills/playable-record/scripts/verify-contract.mjs --url=http://localhost:
|
|
24
|
+
* node skills/playable-record/scripts/verify-contract.mjs --url=http://localhost:5173/ --json
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import { resolve } from 'node:path';
|
|
28
28
|
import { fileURLToPath } from 'node:url';
|
|
29
|
-
import { detectDevUrl, startDevServer, startHttpServer, waitForHttp } from './lib/dev-server.mjs';
|
|
29
|
+
import { detectDevUrl, startDevServer, startHttpServer, waitForHttp, DEFAULT_DEV_URL } from './lib/dev-server.mjs';
|
|
30
30
|
import { writeValidatorArtifact } from '../../_shared/scripts/lib/validator-artifacts.mjs';
|
|
31
31
|
|
|
32
32
|
const DEFAULT_SCENE = 'MainScene';
|
|
@@ -178,7 +178,7 @@ export async function runContractProbe(opts) {
|
|
|
178
178
|
external = true;
|
|
179
179
|
} else if (opts.useDev) {
|
|
180
180
|
server = startDevServer(projectRoot);
|
|
181
|
-
url = await detectDevUrl(server, opts.url ||
|
|
181
|
+
url = await detectDevUrl(server, opts.url || DEFAULT_DEV_URL, 30000);
|
|
182
182
|
} else {
|
|
183
183
|
server = startHttpServer(opts.port, projectRoot);
|
|
184
184
|
url = `http://127.0.0.1:${opts.port}/game/index.html`;
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* polls getState() until isGameOver && currentPhase === 'ENDCARD', then exits 0.
|
|
7
7
|
*
|
|
8
8
|
* Usage:
|
|
9
|
-
* node skills/playable-record/scripts/verify-firstwin.mjs --root=. --use-dev --url=http://localhost:
|
|
9
|
+
* node skills/playable-record/scripts/verify-firstwin.mjs --root=. --use-dev --url=http://localhost:5173/
|
|
10
10
|
* npm run verify:firstwin
|
|
11
11
|
*
|
|
12
12
|
* Exit 0 = first level winnable (ENDCARD reached)
|
|
@@ -18,7 +18,7 @@ import { readdir, readFile } from 'node:fs/promises';
|
|
|
18
18
|
import { resolve } from 'node:path';
|
|
19
19
|
import { fileURLToPath } from 'node:url';
|
|
20
20
|
import { evaluateContract, snapshotContractInPage } from './verify-contract.mjs';
|
|
21
|
-
import { detectDevUrl, startDevServer, startHttpServer, waitForHttp } from './lib/dev-server.mjs';
|
|
21
|
+
import { detectDevUrl, startDevServer, startHttpServer, waitForHttp, DEFAULT_DEV_URL } from './lib/dev-server.mjs';
|
|
22
22
|
import { writeValidatorArtifact } from '../../_shared/scripts/lib/validator-artifacts.mjs';
|
|
23
23
|
|
|
24
24
|
const DEFAULT_SCENE = 'MainScene';
|
|
@@ -198,7 +198,7 @@ export async function runFirstWinProbe(opts) {
|
|
|
198
198
|
/* external server */
|
|
199
199
|
} else if (opts.useDev) {
|
|
200
200
|
server = startDevServer(projectRoot);
|
|
201
|
-
url = await detectDevUrl(server, opts.url ||
|
|
201
|
+
url = await detectDevUrl(server, opts.url || DEFAULT_DEV_URL, 30000);
|
|
202
202
|
} else {
|
|
203
203
|
server = startHttpServer(opts.port, projectRoot);
|
|
204
204
|
url = `http://127.0.0.1:${opts.port}/game/index.html`;
|
|
@@ -19,8 +19,14 @@ import { readFile, readdir } from 'node:fs/promises';
|
|
|
19
19
|
import { existsSync } from 'node:fs';
|
|
20
20
|
import { join, resolve, basename } from 'node:path';
|
|
21
21
|
import { writeValidatorArtifact } from '../../_shared/scripts/lib/validator-artifacts.mjs';
|
|
22
|
+
import {
|
|
23
|
+
detectFusionIntent,
|
|
24
|
+
readFusionIntentFromProject,
|
|
25
|
+
} from '../../_shared/scripts/lib/fusion-intent.mjs';
|
|
22
26
|
|
|
23
27
|
// `[*_\s]*` tolerates markdown emphasis in the §6 template form `- **Fusion type**:`.
|
|
28
|
+
const FUSION_COMPOSITE_ATOMS = new Set(['arrow_pick_match_rules.aigameplay']);
|
|
29
|
+
|
|
24
30
|
const FUSION_TYPE_RE =
|
|
25
31
|
/Fusion\s+type[*_\s]*:\s*(Single|A-Visual|B1-Passive|B2-Active|C-Sequential|D-Parallel)/i;
|
|
26
32
|
const REAL_FUSION_TYPES = new Set(['A-Visual', 'B1-Passive', 'B2-Active', 'C-Sequential', 'D-Parallel']);
|
|
@@ -56,6 +62,19 @@ export const GAMEPLAY_SIGNATURES = {
|
|
|
56
62
|
'escape_core',
|
|
57
63
|
'canMoveArrow',
|
|
58
64
|
],
|
|
65
|
+
'path_elimination_rules.aigameplay': [
|
|
66
|
+
'path_elimination',
|
|
67
|
+
'canPathExitBoard',
|
|
68
|
+
'removedPaths',
|
|
69
|
+
'findFirstRemovablePath',
|
|
70
|
+
],
|
|
71
|
+
'arrow_pick_match_rules.aigameplay': [
|
|
72
|
+
'arrow_pick_match',
|
|
73
|
+
'slideOutToTray',
|
|
74
|
+
'trayCapacity',
|
|
75
|
+
'LevelValidator',
|
|
76
|
+
'pick_and_match',
|
|
77
|
+
],
|
|
59
78
|
};
|
|
60
79
|
|
|
61
80
|
function parseArgs(argv) {
|
|
@@ -212,7 +231,23 @@ export async function verifyFusion(root, overrides = {}) {
|
|
|
212
231
|
gameplayAtoms = readSelectedGameplayAtoms(tree);
|
|
213
232
|
}
|
|
214
233
|
|
|
215
|
-
|
|
234
|
+
const singleCompositeFusion =
|
|
235
|
+
gameplayAtoms.length === 1 && FUSION_COMPOSITE_ATOMS.has(gameplayAtoms[0] ?? '');
|
|
236
|
+
|
|
237
|
+
if (gameplayAtoms.length < 2 && !singleCompositeFusion) {
|
|
238
|
+
const { intentTags, rawIntent } = readFusionIntentFromProject(root);
|
|
239
|
+
if (detectFusionIntent(intentTags, rawIntent)) {
|
|
240
|
+
const selected = gameplayAtoms[0] ?? '(none)';
|
|
241
|
+
return {
|
|
242
|
+
ok: false,
|
|
243
|
+
skipped: false,
|
|
244
|
+
problems: [
|
|
245
|
+
`fusion intent detected but only one gameplay atom selected (${selected}) — pick a fusion skill (e.g. arrow_pick_match_rules.aigameplay) or document Single + downgrade reason in DESIGN.md ## 6`,
|
|
246
|
+
],
|
|
247
|
+
gameplayAtoms,
|
|
248
|
+
fusionIntent: true,
|
|
249
|
+
};
|
|
250
|
+
}
|
|
216
251
|
return { ok: true, skipped: true, reason: 'single gameplay atom — fusion no-op PASS' };
|
|
217
252
|
}
|
|
218
253
|
|
|
@@ -224,7 +259,7 @@ export async function verifyFusion(root, overrides = {}) {
|
|
|
224
259
|
|
|
225
260
|
if (!type) {
|
|
226
261
|
problems.push('DESIGN.md missing Fusion type: — classify fusion in ## 6. Gameplay Fusion');
|
|
227
|
-
} else if (type === 'Single' && !isPseudoFusion) {
|
|
262
|
+
} else if (type === 'Single' && !isPseudoFusion && !singleCompositeFusion) {
|
|
228
263
|
problems.push(
|
|
229
264
|
`DESIGN.md Fusion type is Single but atom-tree selected ${gameplayAtoms.length} gameplay atoms — use a real fusion type or document pseudo-fusion`,
|
|
230
265
|
);
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
import fs from 'node:fs';
|
|
22
22
|
import path from 'node:path';
|
|
23
23
|
import { fileURLToPath } from 'node:url';
|
|
24
|
-
import { detectDevUrl, startDevServer, startHttpServer, waitForHttp } from './lib/dev-server.mjs';
|
|
24
|
+
import { detectDevUrl, startDevServer, startHttpServer, waitForHttp, DEFAULT_DEV_URL } from './lib/dev-server.mjs';
|
|
25
25
|
import { getActiveSlice, readState } from '../../_shared/scripts/state-store.mjs';
|
|
26
26
|
|
|
27
27
|
function parseArgs(argv) {
|
|
@@ -57,7 +57,7 @@ export async function runSliceProbe(opts) {
|
|
|
57
57
|
/* external server */
|
|
58
58
|
} else if (opts.useDev) {
|
|
59
59
|
server = startDevServer(root);
|
|
60
|
-
url = await detectDevUrl(server, opts.url ||
|
|
60
|
+
url = await detectDevUrl(server, opts.url || DEFAULT_DEV_URL, 30000);
|
|
61
61
|
} else {
|
|
62
62
|
server = startHttpServer(opts.port, root);
|
|
63
63
|
url = `http://127.0.0.1:${opts.port}/game/index.html`;
|
|
@@ -56,6 +56,40 @@ Append-only evidence (newest first or chronological — pick one and stay consis
|
|
|
56
56
|
|
|
57
57
|
## Brainstorm Log
|
|
58
58
|
|
|
59
|
+
### Creative Angle
|
|
60
|
+
|
|
61
|
+
- **Idea hook**: {If only one core moment survives — from Phase 1 candidates}
|
|
62
|
+
- **Emotional payoff**: {What the player should feel after the first win}
|
|
63
|
+
- **Anti-generic**: {Why this is not "ordinary arrow + tray match-3"}
|
|
64
|
+
|
|
65
|
+
### Pattern picked
|
|
66
|
+
|
|
67
|
+
- Pattern: {id from `playcraft patterns match`} [{SOURCE}]
|
|
68
|
+
- Why this over alternatives: {one line}
|
|
69
|
+
|
|
70
|
+
### Reference insight
|
|
71
|
+
|
|
72
|
+
- {3–5 bullets from patterns match or `playcraft tools research --focus gameplay`} [{WEB|SKILL}]
|
|
73
|
+
- researchSkippedReason: {only if no research/patterns — explain why}
|
|
74
|
+
|
|
75
|
+
### Motion moments (Ring 1)
|
|
76
|
+
|
|
77
|
+
- First tap: {slide_out visual — what moves, how long}
|
|
78
|
+
- First blocked: {blocked shake/tint — teach dependency}
|
|
79
|
+
- First match-3: {match_clear in tray — payoff moment}
|
|
80
|
+
- Rejected motion: {why not swap/gravity cascade / board match3 — e.g. "主手势是 path tap,三消仅在托盘"}
|
|
81
|
+
|
|
82
|
+
### Mechanic variation
|
|
83
|
+
|
|
84
|
+
- {One axis beyond stitching two skills: e.g. tray pressure curve / blocked dependency layers / board phase unlock}
|
|
85
|
+
- rejectedShallowFusion: {why not all-free opening or ≤4 paths on 8×8}
|
|
86
|
+
|
|
87
|
+
### Gameplay Lens (3 questions)
|
|
88
|
+
|
|
89
|
+
1. Core action in one verb: {…}
|
|
90
|
+
2. After 3–5 steps the player gets: {…}
|
|
91
|
+
3. With sound off for 10s, gameplay guessable? {yes/no + why}
|
|
92
|
+
|
|
59
93
|
### Round 1
|
|
60
94
|
|
|
61
95
|
- Asked: {question and why it mattered for core action / feedback}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Design Methodology Foundations
|
|
2
2
|
|
|
3
|
-
> **When to read**:
|
|
4
|
-
> Artist and Reviewer may also reference this for context on emotional intent.
|
|
3
|
+
> **When to read**: `@creative-director` and `@game-designer` during Ring 1 creative/spec (via `npm run state:get` → `referenceReads`). Ground Narrative Level and Emotional Arc before writing north-star or DESIGN §0.
|
|
5
4
|
|
|
6
5
|
---
|
|
7
6
|
|
|
@@ -13,6 +13,32 @@
|
|
|
13
13
|
|
|
14
14
|
---
|
|
15
15
|
|
|
16
|
+
## 0. Creative North Star
|
|
17
|
+
|
|
18
|
+
> Ring 1 reader entry. Write this **before** mechanics tables. Copy from `docs/north-star.md`: **One-liner** verbatim; **Micro-Story Spine** field-value match (trim per field).
|
|
19
|
+
|
|
20
|
+
### Micro-Story Spine
|
|
21
|
+
|
|
22
|
+
**Narrative level**: {L0 | L1 | L2}
|
|
23
|
+
**Who**: {from north-star}
|
|
24
|
+
**Situation**: {from north-star}
|
|
25
|
+
**Stakes**: {from north-star}
|
|
26
|
+
**Payoff image**: {from north-star}
|
|
27
|
+
**Emotional arc**: {from north-star}
|
|
28
|
+
|
|
29
|
+
**One-liner**: {One vivid sentence — what feeling/tension the player is playing with, not a mechanic checklist.}
|
|
30
|
+
|
|
31
|
+
**System Dynamic**: {One sentence — what system tension keeps the player acting.}
|
|
32
|
+
|
|
33
|
+
**Why this fusion**: {2–3 sentences — how arrow / elimination / tray **serve** the idea above, not "because the user asked for fusion". Start with: "This fusion serves §0 because…"}
|
|
34
|
+
|
|
35
|
+
**Rejected vibe**:
|
|
36
|
+
|
|
37
|
+
- {Not this — e.g. not a casual match-3 binge}
|
|
38
|
+
- {Not this — e.g. not a pure arrow logic puzzle with no payoff}
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
16
42
|
## Player Action
|
|
17
43
|
|
|
18
44
|
{What the player can do first: tap / drag / aim / choose. Name the visible target and why the action is obvious.}
|
|
@@ -48,3 +74,42 @@
|
|
|
48
74
|
## Open Assumptions
|
|
49
75
|
|
|
50
76
|
{Only list assumptions that materially affect Ring 1. Use "none" if clear.}
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 6. Gameplay Fusion
|
|
81
|
+
|
|
82
|
+
Fusion type: {Single | A-Visual | B1-Passive | B2-Active | C-Sequential | D-Parallel}
|
|
83
|
+
|
|
84
|
+
This fusion serves §0 because {link back to One-liner / System Dynamic keywords}.
|
|
85
|
+
|
|
86
|
+
{One paragraph: which parent mechanics combine, interaction contract (not just skill names), and why this fusion is playable first.}
|
|
87
|
+
|
|
88
|
+
## 7. Gameplay Seed
|
|
89
|
+
|
|
90
|
+
First Level Scenario: {8×8 board, path count, blocked vs opening moves, tray pressure — must match docs/level-sketch.json}
|
|
91
|
+
|
|
92
|
+
Player Fantasy: {2–3 sentences from the player's POV. **Expand from Micro-Story Who + Situation** — not a generic "solve puzzle + match-3" line.}
|
|
93
|
+
|
|
94
|
+
Decision Moment: {One aha or mis-tap moment — e.g. blocked path feedback → find unlock order.}
|
|
95
|
+
|
|
96
|
+
## 8. Feedback & Animation Spine
|
|
97
|
+
|
|
98
|
+
### 8.1 Event Catalog(必填)
|
|
99
|
+
|
|
100
|
+
| Event | Trigger | Visual (Ring 1) | Audio placeholder | Duration budget | Blocks input? |
|
|
101
|
+
| ----------- | --------------------------- | --------------------------------------- | ----------------- | --------------- | ------------- |
|
|
102
|
+
| slide_out | valid tap on free path | path container tween along direction | sfx_slide | 300–400ms | yes |
|
|
103
|
+
| blocked | invalid tap on blocked path | board shake + path red tint | sfx_blocked | ~300ms | no |
|
|
104
|
+
| fly_to_tray | after slide_out | head bezier to tray slot | sfx_land | 350–450ms | yes |
|
|
105
|
+
| match_clear | 3 same color in tray | tray burst + scale pop | sfx_match | 200–300ms | yes |
|
|
106
|
+
| win | board empty + tray clear | overlay + optional confetti placeholder | sfx_win | ≤800ms | yes |
|
|
107
|
+
|
|
108
|
+
### 8.2 Atom / Skill refs
|
|
109
|
+
|
|
110
|
+
- Primary: `slide_out_to_tray_animation.aicomponent` (defaults: slide 350ms, fly 400ms)
|
|
111
|
+
- Secondary: `path_animation.aicomponent` (blocked shake)
|
|
112
|
+
|
|
113
|
+
### 8.3 Juice escalation (Ring 1 minimal)
|
|
114
|
+
|
|
115
|
+
- Combo/streak: optional; if n/a, state "flat feedback, escalate in Ring 2"
|
|
@@ -18,6 +18,17 @@
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Dispatch Context
|
|
22
|
+
|
|
23
|
+
> **Source of disclosure**: `dispatchPacket.requiredContext.mustRead` is the only authority for this run's required reading set.
|
|
24
|
+
|
|
25
|
+
- **mustRead loaded**: {{yes/no — list every path from dispatchPacket.requiredContext.mustRead}}
|
|
26
|
+
- **atomTreeFocus readFields**: {{meta.engineDecision / meta.selectedAtoms / meta.skillsMatch.mediaGroups / meta.rings}}
|
|
27
|
+
- **selectedAtomsPolicy**: {{read-all-selected-skills-before-game-edit / n-a}}
|
|
28
|
+
- **slice skillRefs focus**: {{current slice skillRefs or fromScratchReason}}
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
21
32
|
## Spec Quick-Check
|
|
22
33
|
|
|
23
34
|
> **Before coding**, confirm the spec is actually implementable in the current project.
|
|
@@ -31,7 +42,7 @@
|
|
|
31
42
|
|
|
32
43
|
## Skill Preflight
|
|
33
44
|
|
|
34
|
-
> **Before coding**, read
|
|
45
|
+
> **Before coding**, read every selected atom Skill disclosed by `dispatchPacket.requiredContext.mustRead`. Add one row per `docs/atom-tree.json → meta.selectedAtoms[]` item; `skillRefs` only narrows current implementation focus.
|
|
35
46
|
|
|
36
47
|
| selectedAtomRef | Read path / source | 提供了什么 | 怎么用 | 注意 |
|
|
37
48
|
| ---------------------- | -------------------------------------- | ------------------------ | ----------------------------------------- | ------------ |
|
|
@@ -65,6 +65,18 @@ For every non-`Single` option, answer:
|
|
|
65
65
|
|
|
66
66
|
If these answers are weak, the fusion is probably decorative complexity.
|
|
67
67
|
|
|
68
|
+
### Mechanic Depth beyond Stitching
|
|
69
|
+
|
|
70
|
+
| Pattern | When to use | Depth signal |
|
|
71
|
+
| --------------------------------------------- | ------------------------------------------ | ---------------------------------------------------------- |
|
|
72
|
+
| **Composite atom** (`arrow_pick_match_rules`) | Path + tray match already fused in one PGS | Single interaction contract; prefer over stitching parents |
|
|
73
|
+
| **Pseudo-fusion B1** | Visual dual system, single reducer | Secondary mechanic auto-triggers — document reducer |
|
|
74
|
+
| **Board phase B1** | Same 8×8 grid, mask unlock | Board "changes" via phase, not resize |
|
|
75
|
+
|
|
76
|
+
**Forbidden in DESIGN:** listing two parent skill names without **interaction contract** (who acts, where match happens, what blocked teaches).
|
|
77
|
+
|
|
78
|
+
See also: `.claude/agents/refs/game-designer-fusion-depth-playbook.md`
|
|
79
|
+
|
|
68
80
|
### Decision Rules
|
|
69
81
|
|
|
70
82
|
```
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# Creative Process — {Game Name}
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
Ring 1 clarify audit trail. Fill phases 1–4 BEFORE finalizing DESIGN.md.
|
|
5
|
+
Source: templates/game-designer-creative-process.template.md
|
|
6
|
+
-->
|
|
7
|
+
|
|
8
|
+
**Created**: {YYYY-MM-DD}
|
|
9
|
+
**Creative arm**: {A1 | A2 | A3 — from GD_CREATIVE_ARM env if harness}
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## Phase 1 — Radical Diverge
|
|
14
|
+
|
|
15
|
+
List ≥3 **gameplay core-moment** candidates. Do not write DESIGN.md yet.
|
|
16
|
+
|
|
17
|
+
### Candidate A
|
|
18
|
+
|
|
19
|
+
- **Core moment**: {one sentence}
|
|
20
|
+
- **Story hook**: {15s filmable Hook frame}
|
|
21
|
+
- **Who / Stakes**: {one line each}
|
|
22
|
+
- **Why interesting**: {…}
|
|
23
|
+
- **Core challenge**: {…}
|
|
24
|
+
- **Worst case**: {what breaks if player ignores rules}
|
|
25
|
+
|
|
26
|
+
### Candidate B
|
|
27
|
+
|
|
28
|
+
- **Core moment**: {…}
|
|
29
|
+
- **Story hook**: {…}
|
|
30
|
+
- **Who / Stakes**: {…}
|
|
31
|
+
- **Why interesting**: {…}
|
|
32
|
+
- **Core challenge**: {…}
|
|
33
|
+
- **Worst case**: {…}
|
|
34
|
+
|
|
35
|
+
### Candidate C
|
|
36
|
+
|
|
37
|
+
- **Core moment**: {…}
|
|
38
|
+
- **Story hook**: {…}
|
|
39
|
+
- **Who / Stakes**: {…}
|
|
40
|
+
- **Why interesting**: {…}
|
|
41
|
+
- **Core challenge**: {…}
|
|
42
|
+
- **Worst case**: {…}
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Phase 2 — Adversarial Review (five questions)
|
|
47
|
+
|
|
48
|
+
For each candidate, answer **evidence-based** questions — not aesthetic veto.
|
|
49
|
+
|
|
50
|
+
| Candidate | Q1 Second tap? | Q2 Ignore mechanism? | Q3 White-box fun? | Q4 Depth ceiling? | Q5 Strip story — still care? |
|
|
51
|
+
| --------- | -------------- | -------------------- | ----------------- | ----------------- | ---------------------------- |
|
|
52
|
+
| A | {…} | {…} | {…} | {…} | {…} |
|
|
53
|
+
| B | {…} | {…} | {…} | {…} | {…} |
|
|
54
|
+
| C | {…} | {…} | {…} | {…} | {…} |
|
|
55
|
+
|
|
56
|
+
**Vulnerability list** (falsifiable, not "not fun"):
|
|
57
|
+
|
|
58
|
+
- {bullet}
|
|
59
|
+
- {bullet}
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## Phase 3 — Commitment
|
|
64
|
+
|
|
65
|
+
**Chosen candidate**: {A | B | C}
|
|
66
|
+
|
|
67
|
+
**Narrative level**: {L0 | L1 | L2} — {CD decides; if L0, quote user's explicit opt-out request here}
|
|
68
|
+
|
|
69
|
+
**Patch promises** (how this design addresses vulnerabilities):
|
|
70
|
+
|
|
71
|
+
- {…}
|
|
72
|
+
|
|
73
|
+
**Rejected alternatives**:
|
|
74
|
+
|
|
75
|
+
- {B}: deferred because {…}
|
|
76
|
+
- {C}: deferred because {…}
|
|
77
|
+
|
|
78
|
+
**Pressure test memo** (≤30 lines):
|
|
79
|
+
|
|
80
|
+
- White-box: {…}
|
|
81
|
+
- 1-minute test: {…}
|
|
82
|
+
- Depth test: {…}
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
## Phase 4 — Design Intent
|
|
87
|
+
|
|
88
|
+
**Design Intent**: {e.g. "Player aha at move 3 when blocked path unlocks tray combo"}
|
|
89
|
+
|
|
90
|
+
> **Mandatory sync**: Copy **Design Intent verbatim** into `docs/DESIGN.md` §0 **One-liner**. Copy **System Dynamic** into §0 second field. Copy **Micro-Story Spine** fields field-for-field from `docs/north-star.md`.
|
|
91
|
+
|
|
92
|
+
**Mechanic variation** (vs pure stitch): {one axis — tray pressure / phase unlock / segment density}
|
|
93
|
+
|
|
94
|
+
**Rejected shallow fusion**: {e.g. all-free 4 paths on 8×8}
|
|
95
|
+
|
|
96
|
+
**Pattern / skills locked after commitment**:
|
|
97
|
+
|
|
98
|
+
- Pattern: {from playcraft patterns match}
|
|
99
|
+
- Primary skill: {e.g. arrow_pick_match_rules.aigameplay}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": 1,
|
|
3
|
+
"row": 8,
|
|
4
|
+
"col": 8,
|
|
5
|
+
"levelTime": 0,
|
|
6
|
+
"trayCapacity": 7,
|
|
7
|
+
"matchCount": 3,
|
|
8
|
+
"colors": ["red", "red", "red", "blue", "blue", "blue"],
|
|
9
|
+
"arrows": [
|
|
10
|
+
[
|
|
11
|
+
[0, 0],
|
|
12
|
+
[1, 0],
|
|
13
|
+
[2, 0],
|
|
14
|
+
[3, 0],
|
|
15
|
+
[4, 0],
|
|
16
|
+
[5, 0]
|
|
17
|
+
],
|
|
18
|
+
[
|
|
19
|
+
[7, 1],
|
|
20
|
+
[6, 1],
|
|
21
|
+
[5, 1],
|
|
22
|
+
[4, 1],
|
|
23
|
+
[3, 1],
|
|
24
|
+
[2, 1]
|
|
25
|
+
],
|
|
26
|
+
[
|
|
27
|
+
[2, 2],
|
|
28
|
+
[2, 3],
|
|
29
|
+
[2, 4],
|
|
30
|
+
[2, 5],
|
|
31
|
+
[2, 6]
|
|
32
|
+
],
|
|
33
|
+
[
|
|
34
|
+
[0, 7],
|
|
35
|
+
[1, 7],
|
|
36
|
+
[2, 7],
|
|
37
|
+
[3, 7],
|
|
38
|
+
[4, 7]
|
|
39
|
+
],
|
|
40
|
+
[
|
|
41
|
+
[7, 6],
|
|
42
|
+
[6, 6],
|
|
43
|
+
[5, 6],
|
|
44
|
+
[4, 6],
|
|
45
|
+
[3, 6]
|
|
46
|
+
],
|
|
47
|
+
[
|
|
48
|
+
[6, 3],
|
|
49
|
+
[6, 4],
|
|
50
|
+
[6, 5],
|
|
51
|
+
[5, 5],
|
|
52
|
+
[4, 5],
|
|
53
|
+
[3, 5]
|
|
54
|
+
]
|
|
55
|
+
]
|
|
56
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Creative North Star — {Game Name}
|
|
2
|
+
|
|
3
|
+
<!--
|
|
4
|
+
Ring 1 creative discovery output (written by @creative-director).
|
|
5
|
+
@game-designer-spec copies §0 fields from this file into docs/DESIGN.md §0.
|
|
6
|
+
One-liner: verbatim. Micro-Story Spine: field-value match (trimmed per field).
|
|
7
|
+
Source: templates/north-star.template.md
|
|
8
|
+
-->
|
|
9
|
+
|
|
10
|
+
**Date**: {YYYY-MM-DD}
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## Micro-Story Spine
|
|
15
|
+
|
|
16
|
+
**Narrative level**: L1 | L2 <!-- default L1; L0 only when user explicitly opts out of story; L3 forbidden -->
|
|
17
|
+
**Who**: {player identity; L0 may use n/a — pure mechanic showcase}
|
|
18
|
+
**Situation**: {opening Hook frame — one glance readable scene/situation}
|
|
19
|
+
**Stakes**: {what core pressure means in the player's world — not abstract game over}
|
|
20
|
+
**Payoff image**: {first core payoff moment — must film a PGS beat: path slide out, fly to tray, or tray match burst}
|
|
21
|
+
**Emotional arc**: {Urgency | Challenge | Competence | Curiosity | Relaxation}
|
|
22
|
+
|
|
23
|
+
## One-liner
|
|
24
|
+
|
|
25
|
+
{L1/L2: one vivid pitch — must name Who or Situation; no pure debt/bet abstract stacking.}
|
|
26
|
+
{L0: Hook spectacle + mechanic payoff; Who optional.}
|
|
27
|
+
|
|
28
|
+
## System Dynamic
|
|
29
|
+
|
|
30
|
+
{One sentence — what system tension keeps the player acting.}
|
|
31
|
+
|
|
32
|
+
## Why this fusion
|
|
33
|
+
|
|
34
|
+
{2–3 sentences — how parent mechanics **serve** the idea above. Start with intent, not grid sizes.}
|
|
35
|
+
|
|
36
|
+
## Rejected vibe
|
|
37
|
+
|
|
38
|
+
- {Not this — e.g. not a casual match-3 binge}
|
|
39
|
+
- {Not this — e.g. not a pure arrow logic puzzle with no payoff}
|
|
40
|
+
|
|
41
|
+
## Design Intent
|
|
42
|
+
|
|
43
|
+
{Phase 4 single line — must match One-liner verbatim when copied to DESIGN §0.}
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
|
|
56
56
|
Each iteration runs inner loops: `clarify` → `build` → `verify` → **Ring Gate** (user acceptance) → next iteration.
|
|
57
57
|
|
|
58
|
-
<!-- Iteration definitions: see
|
|
58
|
+
<!-- Iteration definitions: see docs/team/collaboration.md (growth-rings-v1) -->
|
|
59
59
|
|
|
60
60
|
## Ring DoD (current iteration)
|
|
61
61
|
|