@auraindustry/aurajs 0.1.1 → 0.1.5
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 +7 -0
- package/benchmarks/perf-thresholds.json +27 -0
- package/package.json +6 -1
- package/src/ai-guidance.mjs +302 -0
- package/src/asset-pack.mjs +2 -1
- package/src/authored-project.mjs +498 -2
- package/src/authored-runtime.mjs +14 -0
- package/src/bin-integrity.mjs +33 -26
- package/src/build-contract/capabilities.mjs +87 -1
- package/src/build-contract/constants.mjs +1 -0
- package/src/build-contract.mjs +2 -0
- package/src/bundler.mjs +143 -13
- package/src/cli.mjs +681 -13
- package/src/commands/packs.mjs +741 -0
- package/src/commands/project-authoring.mjs +128 -1
- package/src/conformance/cases/app-and-ui-runtime-cases.mjs +1 -2
- package/src/conformance/cases/core-runtime-cases.mjs +6 -2
- package/src/conformance/cases/scene3d-and-media-cases.mjs +238 -0
- package/src/conformance/cases/systems-and-gameplay-cases.mjs +1126 -10
- package/src/conformance-mobile.mjs +166 -0
- package/src/conformance.mjs +89 -30
- package/src/evidence-bundle.mjs +242 -0
- package/src/external-package-surface.mjs +1 -1
- package/src/headless-test/runtime-coordinator.mjs +186 -33
- package/src/headless-test.mjs +2 -0
- package/src/helpers/2d/index.mjs +183 -0
- package/src/helpers/index.mjs +26 -0
- package/src/helpers/starter-utils/adventure-objectives.js +102 -0
- package/src/helpers/starter-utils/adventure-world-2d.js +221 -0
- package/src/helpers/starter-utils/animation-2d.js +337 -0
- package/src/helpers/starter-utils/animation-packaging-2d.js +203 -0
- package/src/helpers/starter-utils/atlas-assets-2d.js +111 -0
- package/src/helpers/starter-utils/autoplay-debug-2d.js +215 -0
- package/src/helpers/starter-utils/avatar-3d.js +404 -0
- package/src/helpers/starter-utils/combat-feedback-2d.js +320 -0
- package/src/helpers/starter-utils/combat-runtime-2d.js +290 -0
- package/src/helpers/starter-utils/core.js +150 -0
- package/src/helpers/starter-utils/dialogue-2d.js +351 -0
- package/src/helpers/starter-utils/enemy-archetypes-2d.js +68 -0
- package/src/helpers/starter-utils/index.js +26 -0
- package/src/helpers/starter-utils/inventory-2d.js +268 -0
- package/src/helpers/starter-utils/journal-2d.js +267 -0
- package/src/helpers/starter-utils/platformer-3d.js +132 -0
- package/src/helpers/starter-utils/scene-audio-2d.js +236 -0
- package/src/helpers/starter-utils/streamed-world-2d.js +378 -0
- package/src/helpers/starter-utils/tilemap-nav-2d.js +499 -0
- package/src/helpers/starter-utils/tilemap-world-2d.js +205 -0
- package/src/helpers/starter-utils/triggers.js +662 -0
- package/src/helpers/starter-utils/tween-2d.js +615 -0
- package/src/helpers/starter-utils/wave-director.js +101 -0
- package/src/helpers/starter-utils/world-compositor-2d.js +253 -0
- package/src/helpers/starter-utils/world-persistence-2d.js +180 -0
- package/src/mobile/android/build.mjs +606 -0
- package/src/mobile/android/host-artifact.mjs +280 -0
- package/src/mobile/ios/build.mjs +1323 -0
- package/src/mobile/ios/host-artifact.mjs +819 -0
- package/src/mobile/shared/capabilities.mjs +174 -0
- package/src/package-integrity.mjs +18 -4
- package/src/packs/catalog.mjs +259 -0
- package/src/perf-benchmark-runner.mjs +17 -12
- package/src/perf-benchmark.mjs +408 -4
- package/src/publish-command.mjs +434 -17
- package/src/publish-validation.mjs +22 -11
- package/src/replay-runtime.mjs +257 -0
- package/src/scaffold/config.mjs +2 -0
- package/src/scaffold/fs.mjs +8 -1
- package/src/scaffold/project-docs.mjs +101 -41
- package/src/scaffold.mjs +4 -0
- package/src/session-runtime.mjs +4 -3
- package/src/web-conformance.mjs +0 -36
- package/templates/create/2d/src/runtime/app.js +4 -0
- package/templates/create/2d-adventure/config/gameplay/adventure.config.js +9 -6
- package/templates/create/2d-adventure/content/gameplay/dialogue.js +85 -0
- package/templates/create/2d-adventure/content/gameplay/world.js +32 -36
- package/templates/create/2d-adventure/content/gameplay/world.tilemap.json +273 -0
- package/templates/create/2d-adventure/docs/design/loop.md +4 -3
- package/templates/create/2d-adventure/prefabs/relic.prefab.js +10 -10
- package/templates/create/2d-adventure/prefabs/world.prefab.js +127 -74
- package/templates/create/2d-adventure/scenes/gameplay.scene.js +603 -112
- package/templates/create/2d-adventure/src/runtime/capabilities.js +16 -0
- package/templates/create/2d-adventure/ui/hud.screen.js +187 -4
- package/templates/create/2d-adventure/ui/journal.screen.js +183 -0
- package/templates/create/2d-survivor/src/runtime/app.js +4 -0
- package/templates/create/3d/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d/src/runtime/app.js +4 -0
- package/templates/create/3d/src/runtime/capabilities.js +5 -0
- package/templates/create/3d/src/runtime/materials.js +10 -0
- package/templates/create/3d-adventure/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-adventure/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-adventure/src/runtime/materials.js +11 -0
- package/templates/create/3d-collectathon/scenes/gameplay.scene.js +30 -3
- package/templates/create/3d-collectathon/src/runtime/app.js +4 -0
- package/templates/create/3d-collectathon/src/runtime/capabilities.js +5 -0
- package/templates/create/3d-collectathon/src/runtime/materials.js +10 -0
- package/templates/create/blank/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/create/blank/assets/splash/bg.webp +0 -0
- package/templates/create/blank/assets/splash/boot-loop.wav +0 -0
- package/templates/create/blank/assets/splash/boot-sting.wav +0 -0
- package/templates/create/blank/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/create/blank/assets/splash/logoholo.webp +0 -0
- package/templates/create/blank/src/main.js +5 -1
- package/templates/create/blank/src/runtime/splash.js +305 -0
- package/templates/create/local-multiplayer/scenes/gameplay.scene.js +186 -12
- package/templates/create/local-multiplayer/src/runtime/capabilities.js +8 -1
- package/templates/create/shared/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/create/shared/assets/splash/bg.webp +0 -0
- package/templates/create/shared/assets/splash/boot-loop.wav +0 -0
- package/templates/create/shared/assets/splash/boot-sting.wav +0 -0
- package/templates/create/shared/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/create/shared/assets/splash/logoholo.webp +0 -0
- package/templates/create/shared/src/runtime/splash.js +305 -0
- package/templates/create/shared/src/runtime/ui-forms.js +552 -0
- package/templates/create/shared/src/starter-utils/adventure-world-2d.js +221 -0
- package/templates/create/shared/src/starter-utils/animation-packaging-2d.js +203 -0
- package/templates/create/shared/src/starter-utils/atlas-assets-2d.js +111 -0
- package/templates/create/shared/src/starter-utils/autoplay-debug-2d.js +215 -0
- package/templates/create/shared/src/starter-utils/combat-runtime-2d.js +290 -0
- package/templates/create/shared/src/starter-utils/dialogue-2d.js +351 -0
- package/templates/create/shared/src/starter-utils/index.js +15 -1
- package/templates/create/shared/src/starter-utils/inventory-2d.js +268 -0
- package/templates/create/shared/src/starter-utils/journal-2d.js +267 -0
- package/templates/create/shared/src/starter-utils/scene-audio-2d.js +236 -0
- package/templates/create/shared/src/starter-utils/streamed-world-2d.js +378 -0
- package/templates/create/shared/src/starter-utils/tilemap-nav-2d.js +499 -0
- package/templates/create/shared/src/starter-utils/tilemap-world-2d.js +205 -0
- package/templates/create/shared/src/starter-utils/world-compositor-2d.js +253 -0
- package/templates/create/shared/src/starter-utils/world-persistence-2d.js +180 -0
- package/templates/create/video-cutscene/src/runtime/app.js +4 -0
- package/templates/create-bin/play.js +148 -7
- package/templates/skills/auramaxx/SKILL.md +46 -0
- package/templates/skills/auramaxx/project-requirements.md +68 -0
- package/templates/skills/auramaxx/starter-recipes.md +104 -0
- package/templates/skills/auramaxx/validation-checklist.md +49 -0
- package/templates/starter/assets/splash/aurajs-gg-wordmark.webp +0 -0
- package/templates/starter/assets/splash/bg.webp +0 -0
- package/templates/starter/assets/splash/boot-loop.wav +0 -0
- package/templates/starter/assets/splash/boot-sting.wav +0 -0
- package/templates/starter/assets/splash/logo-mascot-sheet.webp +0 -0
- package/templates/starter/assets/splash/logoholo.webp +0 -0
- package/templates/starter/src/main.js +4 -0
- package/templates/starter/src/runtime/splash.js +305 -0
- package/templates/skills/aurajs/SKILL.md +0 -96
- package/templates/skills/aurajs/api-contract-3d.md +0 -7
- package/templates/skills/aurajs/api-contract.md +0 -7
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { executeFrame } from './headless-test.mjs';
|
|
4
|
+
import {
|
|
5
|
+
applySessionState,
|
|
6
|
+
bootSessionRuntime,
|
|
7
|
+
exportSessionState,
|
|
8
|
+
} from './session-runtime.mjs';
|
|
9
|
+
|
|
10
|
+
export const GAME_REPLAY_SCHEMA_VERSION = 'aurajs.game-replay.v1';
|
|
11
|
+
export const GAME_REPLAY_REPORT_SCHEMA_VERSION = 'aurajs.game-replay-report.v1';
|
|
12
|
+
|
|
13
|
+
export class ReplayError extends Error {
|
|
14
|
+
constructor(reasonCode, message, details = {}) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = 'ReplayError';
|
|
17
|
+
this.reasonCode = reasonCode;
|
|
18
|
+
this.details = details;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function parseReplayFrames(value, fallback = 1) {
|
|
23
|
+
if (value == null) return fallback;
|
|
24
|
+
const numeric = Number(value);
|
|
25
|
+
if (!Number.isInteger(numeric) || numeric < 1) {
|
|
26
|
+
throw new ReplayError('invalid_replay_frames', 'Replay step frames must be a positive integer.');
|
|
27
|
+
}
|
|
28
|
+
return numeric;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function normalizeReplayPayload(payload) {
|
|
32
|
+
if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
|
|
33
|
+
throw new ReplayError('invalid_replay_payload', 'Replay payload must be an object.');
|
|
34
|
+
}
|
|
35
|
+
if (payload.schemaVersion !== GAME_REPLAY_SCHEMA_VERSION) {
|
|
36
|
+
throw new ReplayError(
|
|
37
|
+
'schema_version_mismatch',
|
|
38
|
+
`Unsupported replay schema "${payload.schemaVersion}". Expected "${GAME_REPLAY_SCHEMA_VERSION}".`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (!Array.isArray(payload.steps) || payload.steps.length === 0) {
|
|
42
|
+
throw new ReplayError('invalid_replay_payload', 'Replay payload requires a non-empty steps array.');
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
schemaVersion: GAME_REPLAY_SCHEMA_VERSION,
|
|
47
|
+
seed: payload.seed == null ? null : String(payload.seed),
|
|
48
|
+
stopOnDivergence: payload.stopOnDivergence !== false,
|
|
49
|
+
initialState: payload.initialState ?? null,
|
|
50
|
+
steps: payload.steps.map((step, index) => {
|
|
51
|
+
if (!step || typeof step !== 'object' || Array.isArray(step)) {
|
|
52
|
+
throw new ReplayError('invalid_replay_step', `Replay step at index ${index} must be an object.`);
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
label: typeof step.label === 'string' && step.label.trim().length > 0 ? step.label.trim() : null,
|
|
56
|
+
checkpointId: typeof step.checkpointId === 'string' && step.checkpointId.trim().length > 0 ? step.checkpointId.trim() : null,
|
|
57
|
+
expectFingerprint: typeof step.expectFingerprint === 'string' && step.expectFingerprint.trim().length > 0
|
|
58
|
+
? step.expectFingerprint.trim()
|
|
59
|
+
: null,
|
|
60
|
+
frames: parseReplayFrames(step.frames, 1),
|
|
61
|
+
input: step.input && typeof step.input === 'object' && !Array.isArray(step.input)
|
|
62
|
+
? step.input
|
|
63
|
+
: null,
|
|
64
|
+
};
|
|
65
|
+
}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function hashReplaySeed(seed) {
|
|
70
|
+
const text = String(seed || '');
|
|
71
|
+
let hash = 2166136261;
|
|
72
|
+
for (let index = 0; index < text.length; index += 1) {
|
|
73
|
+
hash ^= text.charCodeAt(index);
|
|
74
|
+
hash = Math.imul(hash, 16777619);
|
|
75
|
+
}
|
|
76
|
+
return hash >>> 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function createSeededMath(seed) {
|
|
80
|
+
if (seed == null) return Math;
|
|
81
|
+
let state = hashReplaySeed(seed);
|
|
82
|
+
if (state === 0) state = 0x6d2b79f5;
|
|
83
|
+
const nextRandom = () => {
|
|
84
|
+
state = (state + 0x6d2b79f5) >>> 0;
|
|
85
|
+
let t = state;
|
|
86
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
87
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
88
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
89
|
+
};
|
|
90
|
+
const math = Object.create(Math);
|
|
91
|
+
math.random = nextRandom;
|
|
92
|
+
return math;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function captureStateOrThrow(runtime, seed, capturedAt = null) {
|
|
96
|
+
const result = exportSessionState(runtime, {
|
|
97
|
+
mode: 'headless',
|
|
98
|
+
seed,
|
|
99
|
+
capturedAt,
|
|
100
|
+
});
|
|
101
|
+
if (!result || typeof result !== 'object' || result.ok !== true || !result.payload) {
|
|
102
|
+
throw new ReplayError(
|
|
103
|
+
typeof result?.reasonCode === 'string' ? result.reasonCode : 'replay_state_export_failed',
|
|
104
|
+
result?.detail
|
|
105
|
+
? `Replay state export failed: ${result.detail}`
|
|
106
|
+
: 'Replay state export failed.',
|
|
107
|
+
{ stateResult: result || null },
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
return result.payload;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function buildCheckpoint({ step, stepIndex, runtime, payload, matchedExpectation }) {
|
|
114
|
+
return {
|
|
115
|
+
checkpointId: step.checkpointId || null,
|
|
116
|
+
label: step.label || null,
|
|
117
|
+
stepIndex,
|
|
118
|
+
frameIndex: runtime.frameIndex,
|
|
119
|
+
elapsedSeconds: runtime.elapsedSeconds,
|
|
120
|
+
fingerprint: payload.export?.fingerprint || null,
|
|
121
|
+
matchedExpectation,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export async function runHeadlessReplay(options = {}) {
|
|
126
|
+
const projectRoot = resolve(options.projectRoot || process.cwd());
|
|
127
|
+
const replay = normalizeReplayPayload(options.payload);
|
|
128
|
+
const runtime = await bootSessionRuntime({
|
|
129
|
+
projectRoot,
|
|
130
|
+
file: options.file,
|
|
131
|
+
width: options.width,
|
|
132
|
+
height: options.height,
|
|
133
|
+
math: createSeededMath(replay.seed),
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
const inputController = runtime.aura?.input?.__headless;
|
|
137
|
+
if (!inputController || typeof inputController.applyFrame !== 'function' || typeof inputController.clearFrameTransitions !== 'function') {
|
|
138
|
+
throw new ReplayError(
|
|
139
|
+
'replay_input_unavailable',
|
|
140
|
+
'Headless replay requires the headless input controller.',
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
let initialStateApplied = false;
|
|
145
|
+
if (replay.initialState) {
|
|
146
|
+
const applyResult = applySessionState(runtime, replay.initialState);
|
|
147
|
+
if (!applyResult || typeof applyResult !== 'object' || applyResult.ok !== true) {
|
|
148
|
+
throw new ReplayError(
|
|
149
|
+
typeof applyResult?.reasonCode === 'string' ? applyResult.reasonCode : 'replay_initial_state_apply_failed',
|
|
150
|
+
applyResult?.detail
|
|
151
|
+
? `Replay initial state apply failed: ${applyResult.detail}`
|
|
152
|
+
: 'Replay initial state apply failed.',
|
|
153
|
+
{ applyResult: applyResult || null },
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
initialStateApplied = true;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
const checkpoints = [];
|
|
160
|
+
let divergence = null;
|
|
161
|
+
|
|
162
|
+
for (let index = 0; index < replay.steps.length; index += 1) {
|
|
163
|
+
const step = replay.steps[index];
|
|
164
|
+
if (step.input) {
|
|
165
|
+
inputController.applyFrame(step.input);
|
|
166
|
+
} else {
|
|
167
|
+
inputController.clearFrameTransitions();
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
for (let frame = 0; frame < step.frames; frame += 1) {
|
|
171
|
+
await executeFrame(runtime.aura, 1 / 60);
|
|
172
|
+
runtime.frameIndex += 1;
|
|
173
|
+
runtime.elapsedSeconds += 1 / 60;
|
|
174
|
+
if (frame < step.frames - 1) {
|
|
175
|
+
inputController.clearFrameTransitions();
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
const needsCheckpoint = step.checkpointId || step.expectFingerprint;
|
|
180
|
+
if (!needsCheckpoint) {
|
|
181
|
+
inputController.clearFrameTransitions();
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const payload = captureStateOrThrow(runtime, replay.seed, null);
|
|
186
|
+
const actualFingerprint = payload.export?.fingerprint || null;
|
|
187
|
+
const matchedExpectation = step.expectFingerprint == null || step.expectFingerprint === actualFingerprint;
|
|
188
|
+
checkpoints.push(buildCheckpoint({
|
|
189
|
+
step,
|
|
190
|
+
stepIndex: index,
|
|
191
|
+
runtime,
|
|
192
|
+
payload,
|
|
193
|
+
matchedExpectation,
|
|
194
|
+
}));
|
|
195
|
+
|
|
196
|
+
if (!matchedExpectation) {
|
|
197
|
+
divergence = {
|
|
198
|
+
stepIndex: index,
|
|
199
|
+
label: step.label || null,
|
|
200
|
+
checkpointId: step.checkpointId || null,
|
|
201
|
+
expectedFingerprint: step.expectFingerprint,
|
|
202
|
+
actualFingerprint,
|
|
203
|
+
frameIndex: runtime.frameIndex,
|
|
204
|
+
elapsedSeconds: runtime.elapsedSeconds,
|
|
205
|
+
};
|
|
206
|
+
if (replay.stopOnDivergence) {
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
inputController.clearFrameTransitions();
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
const finalState = captureStateOrThrow(runtime, replay.seed, null);
|
|
215
|
+
const completed = divergence == null;
|
|
216
|
+
const report = {
|
|
217
|
+
schemaVersion: GAME_REPLAY_REPORT_SCHEMA_VERSION,
|
|
218
|
+
ok: completed,
|
|
219
|
+
reasonCode: completed ? 'replay_ok' : 'replay_diverged',
|
|
220
|
+
replaySchemaVersion: GAME_REPLAY_SCHEMA_VERSION,
|
|
221
|
+
mode: 'headless',
|
|
222
|
+
projectRoot,
|
|
223
|
+
entryFile: runtime.entryFile,
|
|
224
|
+
seed: replay.seed,
|
|
225
|
+
initialStateApplied,
|
|
226
|
+
totalSteps: replay.steps.length,
|
|
227
|
+
executedFrames: runtime.frameIndex,
|
|
228
|
+
elapsedSeconds: runtime.elapsedSeconds,
|
|
229
|
+
finalFingerprint: finalState.export?.fingerprint || null,
|
|
230
|
+
checkpoints,
|
|
231
|
+
divergence,
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
return {
|
|
235
|
+
replay,
|
|
236
|
+
report,
|
|
237
|
+
finalState,
|
|
238
|
+
runtime,
|
|
239
|
+
runtimeSummary: {
|
|
240
|
+
width: runtime.width,
|
|
241
|
+
height: runtime.height,
|
|
242
|
+
framesExecuted: runtime.frameIndex,
|
|
243
|
+
elapsedSeconds: runtime.elapsedSeconds,
|
|
244
|
+
bundleOutFile: runtime.bundle.outFile,
|
|
245
|
+
moduleCount: runtime.bundle.moduleCount,
|
|
246
|
+
assertionsPassed: runtime.testState.passes,
|
|
247
|
+
drawCalls: runtime.testState.drawCalls,
|
|
248
|
+
audioCalls: runtime.testState.audioCalls,
|
|
249
|
+
},
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function serializeReplayReport(payload, compact = false) {
|
|
254
|
+
return compact
|
|
255
|
+
? `${JSON.stringify(payload)}\n`
|
|
256
|
+
: `${JSON.stringify(payload, null, 2)}\n`;
|
|
257
|
+
}
|
package/src/scaffold/config.mjs
CHANGED
|
@@ -4,9 +4,11 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
const SCAFFOLD_DIR = dirname(fileURLToPath(import.meta.url));
|
|
5
5
|
const CLI_SRC_DIR = resolve(SCAFFOLD_DIR, '..');
|
|
6
6
|
const CLI_PACKAGE = JSON.parse(readFileSync(resolve(CLI_SRC_DIR, '../package.json'), 'utf8'));
|
|
7
|
+
export const CLI_PACKAGE_NAME = CLI_PACKAGE.name;
|
|
7
8
|
const CLI_PACKAGE_VERSION = CLI_PACKAGE.version;
|
|
8
9
|
|
|
9
10
|
export const LEGACY_STARTER_TEMPLATE_DIR = resolve(CLI_SRC_DIR, '../templates/starter');
|
|
11
|
+
export const PACKAGED_STARTER_UTILS_DIR = resolve(CLI_SRC_DIR, './helpers/starter-utils');
|
|
10
12
|
|
|
11
13
|
export const CREATE_TEMPLATE_DIRS = {
|
|
12
14
|
'2d-adventure': resolve(CLI_SRC_DIR, '../templates/create/2d-adventure'),
|
package/src/scaffold/fs.mjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isUtf8 } from 'node:buffer';
|
|
1
2
|
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
2
3
|
import { dirname, join } from 'node:path';
|
|
3
4
|
|
|
@@ -33,7 +34,13 @@ export function copyTree(src, dest, replacements) {
|
|
|
33
34
|
continue;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
+
const sourceBytes = readFileSync(srcPath);
|
|
38
|
+
if (!isUtf8(sourceBytes)) {
|
|
39
|
+
writeFileSync(destPath, sourceBytes);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
let content = sourceBytes.toString('utf8');
|
|
37
44
|
for (const [key, value] of Object.entries(replacements)) {
|
|
38
45
|
content = content.replaceAll(`{{${key}}}`, value);
|
|
39
46
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { describeProjectAiGuidance } from '../ai-guidance.mjs';
|
|
2
|
+
|
|
1
3
|
export function renderProjectReadme({ name, projectTitle, template, templateMetadata }) {
|
|
2
4
|
if (templateMetadata?.runtimeFamily === 'retro') {
|
|
3
5
|
return renderRetroProjectReadme({ name, projectTitle, template, templateMetadata });
|
|
@@ -7,6 +9,7 @@ export function renderProjectReadme({ name, projectTitle, template, templateMeta
|
|
|
7
9
|
const workflowSection = renderTemplateWorkflowSection(templateMetadata);
|
|
8
10
|
const projectMap = renderProjectMapSection(template);
|
|
9
11
|
const generateFilesSection = renderGenerateFilesSection(template);
|
|
12
|
+
const aiWorkflowSection = renderAiWorkflowSection(template);
|
|
10
13
|
const stateOwnershipSection = renderStateOwnershipSection();
|
|
11
14
|
const continuityOwnershipSection = renderContinuityOwnershipSection();
|
|
12
15
|
const largeAssetSection = renderLargeAssetSection();
|
|
@@ -22,7 +25,7 @@ export function renderProjectReadme({ name, projectTitle, template, templateMeta
|
|
|
22
25
|
|
|
23
26
|
return `# ${projectTitle}
|
|
24
27
|
|
|
25
|
-
Scaffolded with \`
|
|
28
|
+
Scaffolded with \`auramaxx create ${name} --template ${template}\`.
|
|
26
29
|
|
|
27
30
|
## Quick Start
|
|
28
31
|
|
|
@@ -35,17 +38,18 @@ Optional commands:
|
|
|
35
38
|
|
|
36
39
|
\`\`\`bash
|
|
37
40
|
${optionalCommands}
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
auramaxx explain
|
|
42
|
+
auramaxx check
|
|
40
43
|
\`\`\`
|
|
41
44
|
|
|
42
45
|
${template === 'blank' ? '' : 'Press `F1` while the starter is running to toggle the development-only playtest HUD. Use the top scene strip to jump between scenes and the toolbar to record, capture screenshots, restart, pause, or minimize the HUD.\n\n'}
|
|
43
46
|
|
|
44
47
|
If you are publishing outside the \`@aurajs\` scope, update \`package.json -> name\`
|
|
45
|
-
before the first \`
|
|
48
|
+
before the first \`auramaxx publish\`.
|
|
46
49
|
|
|
47
50
|
${largeAssetSection}
|
|
48
51
|
${workflowSection}
|
|
52
|
+
${aiWorkflowSection}
|
|
49
53
|
${generateFilesSection}
|
|
50
54
|
${stateOwnershipSection}
|
|
51
55
|
${continuityOwnershipSection}
|
|
@@ -77,6 +81,7 @@ export function renderProjectRunbook({ projectTitle, template, templateMetadata
|
|
|
77
81
|
const workflowSection = renderTemplateWorkflowSection(templateMetadata);
|
|
78
82
|
const firstThirtyMinutes = renderFirstThirtyMinutesSteps(template);
|
|
79
83
|
const generateFilesSection = renderGenerateFilesSection(template);
|
|
84
|
+
const aiWorkflowSection = renderAiWorkflowSection(template);
|
|
80
85
|
const stateOwnershipSection = renderStateOwnershipSection();
|
|
81
86
|
const continuityOwnershipSection = renderContinuityOwnershipSection();
|
|
82
87
|
const largeAssetSection = renderLargeAssetSection();
|
|
@@ -93,6 +98,7 @@ ${stateOwnershipSection}
|
|
|
93
98
|
${continuityOwnershipSection}
|
|
94
99
|
|
|
95
100
|
${workflowSection}
|
|
101
|
+
${aiWorkflowSection}
|
|
96
102
|
${generateFilesSection}
|
|
97
103
|
|
|
98
104
|
## First-Hour Implementation Pass
|
|
@@ -112,7 +118,7 @@ If any are unavailable at runtime, fail fast and capture the reason code before
|
|
|
112
118
|
1. \`npm run build\` to emit native/web artifacts.
|
|
113
119
|
1. \`npm run play\` to sanity-check the packaged local wrapper path.
|
|
114
120
|
${templateMetadata?.optionalModules?.multiplayer === true ? '1. `npm run join -- AURA2P` to join a room-code multiplayer session through the generated wrapper.\n' : ''}1. \`npm run session -- start\` to open a persistent local developer session.
|
|
115
|
-
1. \`
|
|
121
|
+
1. \`auramaxx publish\` once metadata and binaries are ready.
|
|
116
122
|
1. If you are not publishing under \`@aurajs\`, update \`package.json -> name\` first.
|
|
117
123
|
|
|
118
124
|
${largeAssetSection}
|
|
@@ -131,13 +137,43 @@ ${steps.map((line) => `1. ${line}`).join('\n')}
|
|
|
131
137
|
`;
|
|
132
138
|
}
|
|
133
139
|
|
|
140
|
+
function renderAiWorkflowSection(template) {
|
|
141
|
+
const aiGuidance = describeProjectAiGuidance({
|
|
142
|
+
template,
|
|
143
|
+
starterUtils: template === 'blank'
|
|
144
|
+
? null
|
|
145
|
+
: {
|
|
146
|
+
available: true,
|
|
147
|
+
recommendedImportPath: './src/starter-utils/index.js',
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
const importHint = aiGuidance.recommendedImportPath || aiGuidance.preferredPackageSpecifier || '(none)';
|
|
152
|
+
const modules = Array.isArray(aiGuidance.recommendedModules) && aiGuidance.recommendedModules.length > 0
|
|
153
|
+
? aiGuidance.recommendedModules.map((entry) => `- \`${entry.id}\` via \`${importHint}\``).join('\n')
|
|
154
|
+
: '- no starter helper lane is preselected; build outward from `src/runtime/`, `scenes/`, and `content/`';
|
|
155
|
+
|
|
156
|
+
return `## AI Workflow
|
|
157
|
+
|
|
158
|
+
- run \`auramaxx explain --json\` before moving files so the current source boundary, starter helper lane, and paved-road guidance stay explicit
|
|
159
|
+
- run \`auramaxx check --json\` after edits when you want machine-readable import and registry validation
|
|
160
|
+
- keep authored gameplay code inside \`src/\`, \`scenes/\`, \`ui/\`, \`prefabs/\`, \`config/\`, and \`content/\`
|
|
161
|
+
- preferred helper import: \`${importHint}\`
|
|
162
|
+
- AI paved road lane: \`${aiGuidance.laneId}\`
|
|
163
|
+
|
|
164
|
+
Recommended starter modules:
|
|
165
|
+
|
|
166
|
+
${modules}
|
|
167
|
+
`;
|
|
168
|
+
}
|
|
169
|
+
|
|
134
170
|
function renderRetroProjectReadme({ name, projectTitle, template, templateMetadata }) {
|
|
135
171
|
const controls = templateMetadata.controls.map((line) => `- ${line}`).join('\n');
|
|
136
172
|
const firstEdits = templateMetadata.firstEdits.map((line) => `1. ${line}`).join('\n');
|
|
137
173
|
const workflowSection = renderTemplateWorkflowSection(templateMetadata);
|
|
138
174
|
return `# ${projectTitle}
|
|
139
175
|
|
|
140
|
-
Scaffolded with \`
|
|
176
|
+
Scaffolded with \`auramaxx create ${name} --template ${template}\`.
|
|
141
177
|
|
|
142
178
|
## Quick Start
|
|
143
179
|
|
|
@@ -156,8 +192,8 @@ npm run retro:explain
|
|
|
156
192
|
\`\`\`
|
|
157
193
|
|
|
158
194
|
Aura Retro projects build through the main AuraScript CLI, but they do not use
|
|
159
|
-
the default desktop play/dev wrapper flow. Treat \`
|
|
160
|
-
\`
|
|
195
|
+
the default desktop play/dev wrapper flow. Treat \`npm run retro:check\` and
|
|
196
|
+
\`auramaxx build --target <retro-target>\` as the primary development loop.
|
|
161
197
|
|
|
162
198
|
${workflowSection}
|
|
163
199
|
## Template Summary
|
|
@@ -225,6 +261,15 @@ export function renderStateOwnershipSection() {
|
|
|
225
261
|
- \`screenShell\` payloads are only the data passed into HUD, overlay, and modal screens.
|
|
226
262
|
- \`config/\` is for defaults and tuning.
|
|
227
263
|
- \`content/\` is for authored definitions and registries.
|
|
264
|
+
|
|
265
|
+
Example shared session state:
|
|
266
|
+
|
|
267
|
+
\`\`\`js
|
|
268
|
+
const runFlags = context.ensureSessionState('runFlags', { DID_START: false });
|
|
269
|
+
if (!runFlags.DID_START) {
|
|
270
|
+
runFlags.DID_START = true;
|
|
271
|
+
}
|
|
272
|
+
\`\`\`
|
|
228
273
|
`;
|
|
229
274
|
}
|
|
230
275
|
|
|
@@ -240,16 +285,16 @@ export function renderContinuityOwnershipSection() {
|
|
|
240
285
|
- \`scenes/*.scene.js\` should keep \`sceneState\` JSON-safe when it must survive restore.
|
|
241
286
|
- \`context.getCurrentScenePayload()\` is the read seam for payloads restored through \`sceneFlow\`.
|
|
242
287
|
- saved slots live under \`.aura/state/slots/\` and checkpoints live under \`.aura/state/checkpoints/\`.
|
|
243
|
-
- native dev restore hooks use \`
|
|
288
|
+
- native dev restore hooks use \`auramaxx dev --restore-slot <name>\` or \`auramaxx dev --restore-checkpoint <name>\`.
|
|
244
289
|
`;
|
|
245
290
|
}
|
|
246
291
|
|
|
247
292
|
export function renderLargeAssetSection() {
|
|
248
293
|
return `## Publish and Large Assets
|
|
249
294
|
|
|
250
|
-
- \`
|
|
295
|
+
- \`auramaxx publish\` is the public publish command inside an AuraJS project.
|
|
251
296
|
- AuraJS measures built asset payload size before publish. The default npm-first threshold is 50 MiB; operators can override it with \`AURA_PUBLISH_ASSET_THRESHOLD_BYTES\`.
|
|
252
|
-
- If the payload is too large, use your own HTTPS host for the heavy assets and run \`
|
|
297
|
+
- If the payload is too large, use your own HTTPS host for the heavy assets and run \`auramaxx external-assets generate --public-base-url <url>\`.
|
|
253
298
|
- That command writes \`aura.external-assets.json\` in the project root and stages manifests plus upload records under \`.aura/external-assets/\`.
|
|
254
299
|
- Packaged \`npx <game> play\` and \`join\` hydrate self-hosted assets into a local cache before launch.
|
|
255
300
|
- Cloudflare R2 and S3 are examples only. AuraPM and \`publishv2\` remain preview-only.
|
|
@@ -261,16 +306,16 @@ export function renderGenerateFilesSection(template) {
|
|
|
261
306
|
return `## Generate Files
|
|
262
307
|
|
|
263
308
|
\`\`\`bash
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
309
|
+
auramaxx make scene MainMenu
|
|
310
|
+
auramaxx make ui-screen PauseMenu
|
|
311
|
+
auramaxx make config EnemyTable
|
|
312
|
+
auramaxx make content SpawnTable
|
|
313
|
+
auramaxx explain
|
|
314
|
+
auramaxx check
|
|
270
315
|
\`\`\`
|
|
271
316
|
|
|
272
317
|
Blank now ships the same authored roots as the other starters. Use the seeded
|
|
273
|
-
files as the reference structure, then grow the project with \`
|
|
318
|
+
files as the reference structure, then grow the project with \`auramaxx make\`.
|
|
274
319
|
`;
|
|
275
320
|
}
|
|
276
321
|
|
|
@@ -278,12 +323,12 @@ files as the reference structure, then grow the project with \`npx aura make\`.
|
|
|
278
323
|
return `## Generate Files
|
|
279
324
|
|
|
280
325
|
\`\`\`bash
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
326
|
+
auramaxx make card StrikePlus
|
|
327
|
+
auramaxx make enemy JawWorm
|
|
328
|
+
auramaxx make relic BurningBlood
|
|
329
|
+
auramaxx make encounter Act1Hallway
|
|
330
|
+
auramaxx explain
|
|
331
|
+
auramaxx check
|
|
287
332
|
\`\`\`
|
|
288
333
|
`;
|
|
289
334
|
}
|
|
@@ -291,12 +336,12 @@ npx aura check
|
|
|
291
336
|
return `## Generate Files
|
|
292
337
|
|
|
293
338
|
\`\`\`bash
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
339
|
+
auramaxx make scene MainMenu
|
|
340
|
+
auramaxx make ui-screen PauseMenu
|
|
341
|
+
auramaxx make config EnemyTable
|
|
342
|
+
auramaxx make content SpawnTable
|
|
343
|
+
auramaxx explain
|
|
344
|
+
auramaxx check
|
|
300
345
|
\`\`\`
|
|
301
346
|
`;
|
|
302
347
|
}
|
|
@@ -309,8 +354,8 @@ export function renderProjectMapSection(template) {
|
|
|
309
354
|
- \`aura.config.json\` - identity/window/build/modules.
|
|
310
355
|
- \`aura.capabilities.json\` - canonical runtime API declaration for this scaffold.
|
|
311
356
|
- \`RUNBOOK.md\` - first-hour implementation and triage checklist.
|
|
312
|
-
- \`
|
|
313
|
-
- \`
|
|
357
|
+
- \`auramaxx explain\` - inspect how the current project is wired.
|
|
358
|
+
- \`auramaxx check\` - validate authored wiring before runtime.
|
|
314
359
|
- \`src/runtime/\` - runtime/bootstrap helpers plus the project and scene registries.
|
|
315
360
|
- \`src/runtime/project-registry.js\` - authored source of truth for scenes, screens, prefabs, \`configFiles\`, and \`contentFiles\`.
|
|
316
361
|
- \`src/runtime/scene-flow.js\` - active-scene continuity, stack state, and route payload handoff.
|
|
@@ -324,13 +369,13 @@ export function renderProjectMapSection(template) {
|
|
|
324
369
|
- \`config/\` - defaults and tunables.
|
|
325
370
|
- \`content/\` - authored game definitions, progression payloads, and starter-owned registries.
|
|
326
371
|
- \`content/registries/\` - starter-owned registries and future generator-owned indexes.
|
|
327
|
-
- \`src/runtime/app-state.js\` - shared mutable \`appState\` split into \`session\`, \`ui\`, and \`runtime\` buckets plus helper-backed access from scenes
|
|
372
|
+
- \`src/runtime/app-state.js\` - shared mutable \`appState\` split into \`session\`, \`ui\`, and \`runtime\` buckets plus helper-backed access from scenes. Starter example: \`context.ensureSessionState('runFlags', { DID_START: false })\`.`;
|
|
328
373
|
}
|
|
329
374
|
|
|
330
375
|
return `- \`src/main.js\` - stable bootstrap seam into the authored project layout.
|
|
331
376
|
- \`src/runtime/\` - runtime/bootstrap helpers plus the project and scene registries.
|
|
332
377
|
- \`src/runtime/project-registry.js\` - authored source of truth for scenes, screens, prefabs, \`configFiles\`, and \`contentFiles\`.
|
|
333
|
-
- \`src/runtime/app-state.js\` - shared mutable \`appState\` split into \`session\`, \`ui\`, and \`runtime\` buckets plus helper-backed access from scenes.
|
|
378
|
+
- \`src/runtime/app-state.js\` - shared mutable \`appState\` split into \`session\`, \`ui\`, and \`runtime\` buckets plus helper-backed access from scenes. Starter example: \`context.ensureSessionState('runFlags', { DID_START: false })\`.
|
|
334
379
|
- \`src/runtime/scene-flow.js\` - active-scene continuity, scene-stack restore ownership, and route payload handoff.
|
|
335
380
|
- \`src/runtime/screen-shell.js\` - HUD, overlay, and modal payload continuity ownership.
|
|
336
381
|
- \`src/runtime/ui-theme.js\` - shared theme presets plus \`appState.ui.preferences\` apply/reset helpers.
|
|
@@ -343,7 +388,13 @@ export function renderProjectMapSection(template) {
|
|
|
343
388
|
- \`config/\` - editable defaults and tuning payloads.
|
|
344
389
|
- \`content/\` - authored definitions, levels, registries, and progression content.
|
|
345
390
|
- \`content/registries/\` - starter-owned registry files for cards, enemies, relics, and encounters.
|
|
346
|
-
- \`src/starter-utils/\` -
|
|
391
|
+
- \`src/starter-utils/\` - local copies of reusable authored helper modules
|
|
392
|
+
shipped with AuraJS for non-blank templates. Keep imports local here for
|
|
393
|
+
starter-facing gameplay code; use the published
|
|
394
|
+
\`@auraindustry/aurajs/helpers\` lane only when you want the shared
|
|
395
|
+
package-backed helper surface directly. Run \`auramaxx vendor helpers\` when
|
|
396
|
+
you want to seed or resync the local helper lane in a project that does not
|
|
397
|
+
already have it.
|
|
347
398
|
- \`assets/starter/\` - starter asset pack and editable design payloads.
|
|
348
399
|
- \`aura.config.json\` - identity/window/build/modules.
|
|
349
400
|
- \`aura.capabilities.json\` - canonical runtime API declaration for this scaffold.
|
|
@@ -355,16 +406,16 @@ export function renderFirstThirtyMinutesSteps(template) {
|
|
|
355
406
|
return `1. Run \`npm install\` then \`npm run dev\` and confirm the starter loop is playable.
|
|
356
407
|
1. Read \`src/main.js\`, \`src/runtime/app.js\`, \`src/runtime/app-state.js\`, \`scenes/\`, \`config/\`, \`content/\`, and \`docs/design/\` once before adding new structure.
|
|
357
408
|
1. Decide whether your next change belongs in \`appState.session\`, \`appState.ui\`, \`appState.runtime\`, \`sceneState\`, \`config/\`, or \`content/\`, and whether it must survive save or restart continuity.
|
|
358
|
-
1. Run \`
|
|
359
|
-
1. Use \`
|
|
409
|
+
1. Run \`auramaxx explain\` once so the bootstrap stays obvious before the project grows.
|
|
410
|
+
1. Use \`auramaxx make\` when you want more authored files without inventing paths.`;
|
|
360
411
|
}
|
|
361
412
|
|
|
362
413
|
if (template === 'deckbuilder-2d') {
|
|
363
414
|
return `1. Run \`npm install\` then \`npm run dev\` and finish one starter battle end to end.
|
|
364
415
|
1. Read \`content/registries/\`, \`content/cards/\`, \`content/enemies/\`, and \`content/encounters/\` before changing scene flow.
|
|
365
416
|
1. Open \`src/runtime/ui-theme.js\`, \`src/runtime/ui-settings.js\`, and \`src/runtime/ui-forms.js\` before adding pause/settings or form glue of your own.
|
|
366
|
-
1. Generate one extra card or encounter with \`
|
|
367
|
-
1. Run \`
|
|
417
|
+
1. Generate one extra card or encounter with \`auramaxx make\` instead of hand-creating files.
|
|
418
|
+
1. Run \`auramaxx explain\` or \`auramaxx check\` once so the starter-owned registries stay obvious as the project grows.
|
|
368
419
|
1. Only then move into battle polish, rewards, or meta-progression.`;
|
|
369
420
|
}
|
|
370
421
|
|
|
@@ -373,9 +424,9 @@ export function renderFirstThirtyMinutesSteps(template) {
|
|
|
373
424
|
1. Open \`src/runtime/ui-theme.js\`, \`src/runtime/ui-settings.js\`, and \`src/runtime/ui-forms.js\` before inventing starter-local theme, settings, or form plumbing.
|
|
374
425
|
1. Review \`assets/starter/\`, \`config/gameplay/\`, \`content/gameplay/\`, and \`docs/design/\` and rewrite the seed content so it matches your game's nouns, tuning, and milestone goals.
|
|
375
426
|
1. Keep shared state in \`appState.session\` / \`appState.ui\`, keep route payloads in \`sceneFlow\`, and keep scene-only state inside \`sceneState\`.
|
|
376
|
-
1. Run \`
|
|
427
|
+
1. Run \`auramaxx explain\` or \`auramaxx check\` when you want a fast map of the authored project wiring.
|
|
377
428
|
1. Press \`F1\` in the running starter to open the playtest HUD, jump between authored scenes, and use the compact capture/restart toolbar.
|
|
378
|
-
1. Use \`
|
|
429
|
+
1. Use \`auramaxx make scene MainMenu\` or \`auramaxx make ui-screen PauseMenu\` instead of hand-making new authored file paths.`;
|
|
379
430
|
}
|
|
380
431
|
|
|
381
432
|
export function renderContentMapDoc({ template }) {
|
|
@@ -403,6 +454,15 @@ Template: \`${template}\`
|
|
|
403
454
|
- \`src/runtime/project-inspector.js\` exposes the live F1 playtest HUD.
|
|
404
455
|
- authored scenes read shared state with \`ensureSessionState\`, \`ensureUiState\`, and \`getCurrentScenePayload()\`.
|
|
405
456
|
|
|
457
|
+
## Shared State Example
|
|
458
|
+
|
|
459
|
+
\`\`\`js
|
|
460
|
+
const runFlags = context.ensureSessionState('runFlags', { DID_START: false });
|
|
461
|
+
if (!runFlags.DID_START) {
|
|
462
|
+
runFlags.DID_START = true;
|
|
463
|
+
}
|
|
464
|
+
\`\`\`
|
|
465
|
+
|
|
406
466
|
## Current Starter Inventory
|
|
407
467
|
|
|
408
468
|
- \`scenes/boot.scene.js\`
|
package/src/scaffold.mjs
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
CREATE_TEMPLATE_DIRS,
|
|
8
8
|
GITIGNORE_TEMPLATE,
|
|
9
9
|
LEGACY_STARTER_TEMPLATE_DIR,
|
|
10
|
+
PACKAGED_STARTER_UTILS_DIR,
|
|
10
11
|
PLAY_BIN_TEMPLATE,
|
|
11
12
|
applyTemplateConfigOverrides,
|
|
12
13
|
buildCapabilitiesDeclaration,
|
|
@@ -106,6 +107,9 @@ export function scaffoldGame(options) {
|
|
|
106
107
|
copyTree(templateDir, dest, replacements);
|
|
107
108
|
if (shouldCopyCreateSharedTemplate(normalizedTemplate, templateMetadata) && existsSync(CREATE_SHARED_TEMPLATE_DIR)) {
|
|
108
109
|
copyTree(CREATE_SHARED_TEMPLATE_DIR, dest, replacements);
|
|
110
|
+
if (existsSync(PACKAGED_STARTER_UTILS_DIR)) {
|
|
111
|
+
copyTree(PACKAGED_STARTER_UTILS_DIR, join(dest, 'src', 'starter-utils'), replacements);
|
|
112
|
+
}
|
|
109
113
|
}
|
|
110
114
|
|
|
111
115
|
mkdirSync(join(dest, 'assets'), { recursive: true });
|
package/src/session-runtime.mjs
CHANGED
|
@@ -74,8 +74,10 @@ export async function bootSessionRuntime(options = {}) {
|
|
|
74
74
|
});
|
|
75
75
|
|
|
76
76
|
const testState = createSessionTestState();
|
|
77
|
-
const aura = createHeadlessAura({ width, height, testState });
|
|
78
|
-
const context = vm.createContext(createRuntimeContext(aura, testState
|
|
77
|
+
const aura = createHeadlessAura({ width, height, testState, projectRoot });
|
|
78
|
+
const context = vm.createContext(createRuntimeContext(aura, testState, {
|
|
79
|
+
math: options.math,
|
|
80
|
+
}));
|
|
79
81
|
|
|
80
82
|
const source = readFileSync(bundle.outFile, 'utf8');
|
|
81
83
|
const script = new vm.Script(source, {
|
|
@@ -318,4 +320,3 @@ export async function exportSessionInspect(runtime, options = {}) {
|
|
|
318
320
|
};
|
|
319
321
|
}
|
|
320
322
|
}
|
|
321
|
-
|