@auraindustry/aurajs 0.1.1 → 0.1.3
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/package.json +1 -1
- package/src/asset-pack.mjs +2 -1
- package/src/authored-runtime.mjs +14 -0
- package/src/bin-integrity.mjs +33 -26
- package/src/conformance/cases/systems-and-gameplay-cases.mjs +861 -6
- package/src/external-package-surface.mjs +1 -1
- package/src/package-integrity.mjs +18 -4
- package/src/publish-command.mjs +133 -13
- package/src/publish-validation.mjs +22 -11
- package/src/scaffold/project-docs.mjs +58 -40
- package/templates/create/2d/src/runtime/app.js +4 -0
- package/templates/create/2d-survivor/src/runtime/app.js +4 -0
- package/templates/create/3d/src/runtime/app.js +4 -0
- package/templates/create/3d-collectathon/src/runtime/app.js +4 -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/video-cutscene/src/runtime/app.js +4 -0
- package/templates/create-bin/play.js +114 -2
- 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
|
@@ -36,7 +36,7 @@ function shouldCopyPath(sourcePath, {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
const topLevel = relativePath.split('/')[0];
|
|
39
|
-
if (topLevel === '.aura' || topLevel === '.git' || topLevel === 'node_modules') {
|
|
39
|
+
if (topLevel === '.aura' || topLevel === '.git' || topLevel === '.logs' || topLevel === 'node_modules') {
|
|
40
40
|
return false;
|
|
41
41
|
}
|
|
42
42
|
|
|
@@ -72,7 +72,7 @@ function readJsonFile(path) {
|
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
function listHashedPackageFiles(root, current = root, acc = []) {
|
|
75
|
+
function listHashedPackageFiles(root, current = root, acc = [], includedPaths = null) {
|
|
76
76
|
for (const entry of readdirSync(current, { withFileTypes: true })) {
|
|
77
77
|
const fullPath = join(current, entry.name);
|
|
78
78
|
const relativePath = normalizeRelativePath(relative(root, fullPath));
|
|
@@ -92,7 +92,7 @@ function listHashedPackageFiles(root, current = root, acc = []) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
if (entry.isDirectory()) {
|
|
95
|
-
listHashedPackageFiles(root, fullPath, acc);
|
|
95
|
+
listHashedPackageFiles(root, fullPath, acc, includedPaths);
|
|
96
96
|
continue;
|
|
97
97
|
}
|
|
98
98
|
|
|
@@ -100,6 +100,10 @@ function listHashedPackageFiles(root, current = root, acc = []) {
|
|
|
100
100
|
continue;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
if (includedPaths && !includedPaths.has(relativePath)) {
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
103
107
|
const buffer = readFileSync(fullPath);
|
|
104
108
|
acc.push({
|
|
105
109
|
path: relativePath,
|
|
@@ -198,8 +202,16 @@ function normalizeBuildMetadata(buildMetadata = {}) {
|
|
|
198
202
|
};
|
|
199
203
|
}
|
|
200
204
|
|
|
201
|
-
function buildManifestBody({ packageRoot, projectPackage, buildMetadata = null, signer }) {
|
|
205
|
+
function buildManifestBody({ packageRoot, projectPackage, buildMetadata = null, signer, includedRelativePaths = null }) {
|
|
202
206
|
const resolvedPackage = projectPackage || readJsonFile(resolve(packageRoot, 'package.json'));
|
|
207
|
+
const normalizedIncludedPaths = Array.isArray(includedRelativePaths)
|
|
208
|
+
? new Set(
|
|
209
|
+
includedRelativePaths
|
|
210
|
+
.map((entry) => normalizeRelativePath(entry))
|
|
211
|
+
.filter(Boolean)
|
|
212
|
+
.filter((entry) => entry !== PACKAGE_INTEGRITY_MANIFEST_PATH && entry !== PACKAGE_INTEGRITY_SIGNATURE_PATH),
|
|
213
|
+
)
|
|
214
|
+
: null;
|
|
203
215
|
return {
|
|
204
216
|
schema: PACKAGE_INTEGRITY_SCHEMA,
|
|
205
217
|
package: {
|
|
@@ -219,7 +231,7 @@ function buildManifestBody({ packageRoot, projectPackage, buildMetadata = null,
|
|
|
219
231
|
publicKeyPem: signer.publicKeyPem,
|
|
220
232
|
fingerprint: signer.fingerprint,
|
|
221
233
|
},
|
|
222
|
-
files: listHashedPackageFiles(packageRoot),
|
|
234
|
+
files: listHashedPackageFiles(packageRoot, packageRoot, [], normalizedIncludedPaths),
|
|
223
235
|
};
|
|
224
236
|
}
|
|
225
237
|
|
|
@@ -512,6 +524,7 @@ export function writeSignedPackageIntegrityArtifacts({
|
|
|
512
524
|
signerProjectRoot = packageRoot,
|
|
513
525
|
buildMetadata = null,
|
|
514
526
|
projectPackage = null,
|
|
527
|
+
includedRelativePaths = null,
|
|
515
528
|
} = {}) {
|
|
516
529
|
const resolvedPackageRoot = resolve(packageRoot || process.cwd());
|
|
517
530
|
const signer = ensureSignerKeyPair(resolve(signerProjectRoot || resolvedPackageRoot));
|
|
@@ -520,6 +533,7 @@ export function writeSignedPackageIntegrityArtifacts({
|
|
|
520
533
|
projectPackage,
|
|
521
534
|
buildMetadata,
|
|
522
535
|
signer,
|
|
536
|
+
includedRelativePaths,
|
|
523
537
|
});
|
|
524
538
|
const signature = sign(
|
|
525
539
|
null,
|
package/src/publish-command.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
3
|
-
import {
|
|
2
|
+
import { existsSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { tmpdir } from 'node:os';
|
|
4
|
+
import { join, resolve } from 'node:path';
|
|
4
5
|
|
|
5
6
|
import { preparePublishPackageSurface } from './external-package-surface.mjs';
|
|
6
7
|
import {
|
|
@@ -9,6 +10,7 @@ import {
|
|
|
9
10
|
} from './package-integrity.mjs';
|
|
10
11
|
import { resolvePublishEnvExampleSurface } from './publish-env-example.mjs';
|
|
11
12
|
import { validatePublishProject } from './publish-validation.mjs';
|
|
13
|
+
import { formatBytes } from './external-asset-policy.mjs';
|
|
12
14
|
|
|
13
15
|
export function isNpmPublishLifecycleInvocation(env = process.env) {
|
|
14
16
|
return env.npm_lifecycle_event === 'publish' && env.npm_command === 'publish';
|
|
@@ -18,6 +20,116 @@ export function hasOption(commandArgs, optionName) {
|
|
|
18
20
|
return commandArgs.some((arg) => arg === optionName || arg.startsWith(`${optionName}=`));
|
|
19
21
|
}
|
|
20
22
|
|
|
23
|
+
function stripOption(commandArgs, optionName) {
|
|
24
|
+
const nextArgs = [];
|
|
25
|
+
for (let index = 0; index < commandArgs.length; index += 1) {
|
|
26
|
+
const current = commandArgs[index];
|
|
27
|
+
if (current === optionName) {
|
|
28
|
+
index += 1;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (current.startsWith(`${optionName}=`)) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
nextArgs.push(current);
|
|
35
|
+
}
|
|
36
|
+
return nextArgs;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function extractPublishToken(commandArgs, env = process.env) {
|
|
40
|
+
let explicitToken = null;
|
|
41
|
+
|
|
42
|
+
for (let index = 0; index < commandArgs.length; index += 1) {
|
|
43
|
+
const current = commandArgs[index];
|
|
44
|
+
if (current === '--token') {
|
|
45
|
+
explicitToken = commandArgs[index + 1] || '';
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
if (current.startsWith('--token=')) {
|
|
49
|
+
explicitToken = current.slice('--token='.length);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const envToken = typeof env.NODE_AUTH_TOKEN === 'string' && env.NODE_AUTH_TOKEN.trim().length > 0
|
|
55
|
+
? env.NODE_AUTH_TOKEN.trim()
|
|
56
|
+
: null;
|
|
57
|
+
const normalizedToken = typeof explicitToken === 'string' && explicitToken.trim().length > 0
|
|
58
|
+
? explicitToken.trim()
|
|
59
|
+
: envToken;
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
publishArgs: stripOption(commandArgs, '--token'),
|
|
63
|
+
publishEnv: normalizedToken
|
|
64
|
+
? {
|
|
65
|
+
...env,
|
|
66
|
+
NODE_AUTH_TOKEN: normalizedToken,
|
|
67
|
+
}
|
|
68
|
+
: env,
|
|
69
|
+
publishToken: normalizedToken,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function normalizeRegistryUrl(registryValue) {
|
|
74
|
+
const normalizedValue = String(registryValue || '').trim();
|
|
75
|
+
if (!normalizedValue) {
|
|
76
|
+
return 'https://registry.npmjs.org/';
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const registryUrl = new URL(normalizedValue);
|
|
81
|
+
if (!registryUrl.pathname.endsWith('/')) {
|
|
82
|
+
registryUrl.pathname = `${registryUrl.pathname}/`;
|
|
83
|
+
}
|
|
84
|
+
return registryUrl.toString();
|
|
85
|
+
} catch {
|
|
86
|
+
return 'https://registry.npmjs.org/';
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function buildRegistryAuthLine(token, registryUrl) {
|
|
91
|
+
const parsedUrl = new URL(registryUrl);
|
|
92
|
+
const registryPath = parsedUrl.pathname === '/' ? '' : parsedUrl.pathname.replace(/\/$/, '');
|
|
93
|
+
return `//${parsedUrl.host}${registryPath}/:_authToken=${token}`;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function createPublishTokenEnv(token, env = process.env) {
|
|
97
|
+
if (!token) {
|
|
98
|
+
return {
|
|
99
|
+
env,
|
|
100
|
+
cleanup() {},
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const registryUrl = normalizeRegistryUrl(env.npm_config_registry || env.NPM_CONFIG_REGISTRY);
|
|
105
|
+
const userConfigDir = mkdtempSync(join(tmpdir(), 'aurajs-npm-auth-'));
|
|
106
|
+
const userConfigPath = join(userConfigDir, '.npmrc');
|
|
107
|
+
writeFileSync(
|
|
108
|
+
userConfigPath,
|
|
109
|
+
[
|
|
110
|
+
`registry=${registryUrl}`,
|
|
111
|
+
'always-auth=true',
|
|
112
|
+
buildRegistryAuthLine(token, registryUrl),
|
|
113
|
+
'',
|
|
114
|
+
].join('\n'),
|
|
115
|
+
'utf8',
|
|
116
|
+
);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
env: {
|
|
120
|
+
...env,
|
|
121
|
+
NODE_AUTH_TOKEN: token,
|
|
122
|
+
NPM_CONFIG_USERCONFIG: userConfigPath,
|
|
123
|
+
npm_config_userconfig: userConfigPath,
|
|
124
|
+
NPM_CONFIG_REGISTRY: registryUrl,
|
|
125
|
+
npm_config_registry: registryUrl,
|
|
126
|
+
},
|
|
127
|
+
cleanup() {
|
|
128
|
+
rmSync(userConfigDir, { recursive: true, force: true });
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
21
133
|
export function readProjectPackage(projectRoot = process.cwd()) {
|
|
22
134
|
const packagePath = resolve(projectRoot, 'package.json');
|
|
23
135
|
if (!existsSync(packagePath)) {
|
|
@@ -46,8 +158,9 @@ export function readProjectPackage(projectRoot = process.cwd()) {
|
|
|
46
158
|
}
|
|
47
159
|
|
|
48
160
|
export function buildPublishArgs(commandArgs, { packageName } = {}) {
|
|
49
|
-
const
|
|
50
|
-
|
|
161
|
+
const sanitizedArgs = stripOption(commandArgs, '--token');
|
|
162
|
+
const publishArgs = ['publish', ...sanitizedArgs];
|
|
163
|
+
if (String(packageName || '').startsWith('@') && !hasOption(sanitizedArgs, '--access')) {
|
|
51
164
|
publishArgs.push('--access', 'public');
|
|
52
165
|
}
|
|
53
166
|
return publishArgs;
|
|
@@ -68,13 +181,10 @@ function spawnPublish(commandArgs, { projectRoot, env, stdout, stderr }) {
|
|
|
68
181
|
return new Promise((resolveRun, rejectRun) => {
|
|
69
182
|
const child = spawn(resolveNpmCommand(), commandArgs, {
|
|
70
183
|
cwd: projectRoot,
|
|
71
|
-
stdio:
|
|
184
|
+
stdio: 'inherit',
|
|
72
185
|
env,
|
|
73
186
|
});
|
|
74
187
|
|
|
75
|
-
pipeChildStream(child.stdout, stdout);
|
|
76
|
-
pipeChildStream(child.stderr, stderr);
|
|
77
|
-
|
|
78
188
|
child.on('error', (error) => {
|
|
79
189
|
rejectRun(error);
|
|
80
190
|
});
|
|
@@ -134,9 +244,13 @@ export async function runPublishCommand(
|
|
|
134
244
|
const assetBytes = Number.isFinite(error?.details?.assetBytes) ? error.details.assetBytes : null;
|
|
135
245
|
const thresholdBytes = Number.isFinite(error?.details?.thresholdBytes) ? error.details.thresholdBytes : null;
|
|
136
246
|
if (assetBytes !== null && thresholdBytes !== null) {
|
|
137
|
-
stdout?.write(` Asset payload: ${assetBytes}
|
|
247
|
+
stdout?.write(` Asset payload: ${formatBytes(assetBytes)} (${assetBytes} bytes)\n`);
|
|
248
|
+
stdout?.write(` Threshold: ${formatBytes(thresholdBytes)} (${thresholdBytes} bytes)\n`);
|
|
138
249
|
}
|
|
139
|
-
stdout?.write('
|
|
250
|
+
stdout?.write(' This package is too large for npm-first publish.\n');
|
|
251
|
+
stdout?.write(' Self-host for now: upload the heavy assets to your own public HTTPS host, then generate the external asset config.\n');
|
|
252
|
+
stdout?.write(' Command: auramaxx external-assets generate --public-base-url https://cdn.example.com/my-game\n');
|
|
253
|
+
stdout?.write(' Docs: https://www.aurajs.gg/docs/publishing-and-large-assets\n');
|
|
140
254
|
}
|
|
141
255
|
if (error?.reportPath) {
|
|
142
256
|
stdout?.write(` Validation report: ${error.reportPath}\n\n`);
|
|
@@ -146,8 +260,10 @@ export async function runPublishCommand(
|
|
|
146
260
|
|
|
147
261
|
const packageName = validation.packageName;
|
|
148
262
|
const { projectPackage } = readProjectPackage(projectRoot);
|
|
149
|
-
const publishArgs =
|
|
150
|
-
const
|
|
263
|
+
const { publishArgs: sanitizedCommandArgs, publishEnv, publishToken } = extractPublishToken(commandArgs, env);
|
|
264
|
+
const publishArgs = buildPublishArgs(sanitizedCommandArgs, { packageName });
|
|
265
|
+
const publishTokenEnv = createPublishTokenEnv(publishToken, publishEnv);
|
|
266
|
+
const dryRun = hasOption(sanitizedCommandArgs, '--dry-run');
|
|
151
267
|
const envExampleSurface = resolvePublishEnvExampleSurface({ projectRoot });
|
|
152
268
|
const packageSurface = preparePublishPackageSurface({
|
|
153
269
|
projectRoot,
|
|
@@ -162,6 +278,9 @@ export async function runPublishCommand(
|
|
|
162
278
|
packageRoot: packageSurface.publishRoot,
|
|
163
279
|
signerProjectRoot: projectRoot,
|
|
164
280
|
buildMetadata: validation?.report?.validation?.build || null,
|
|
281
|
+
includedRelativePaths: Array.isArray(validation?.report?.validation?.pack?.files)
|
|
282
|
+
? validation.report.validation.pack.files.map((entry) => entry?.path).filter(Boolean)
|
|
283
|
+
: null,
|
|
165
284
|
});
|
|
166
285
|
stdout?.write(`\n aura publish: ${dryRun ? 'dry-run' : 'npm-first publish'}\n`);
|
|
167
286
|
stdout?.write(` Package: ${packageName}\n`);
|
|
@@ -176,11 +295,12 @@ export async function runPublishCommand(
|
|
|
176
295
|
try {
|
|
177
296
|
await spawnPublish(publishArgs, {
|
|
178
297
|
projectRoot: packageSurface.publishRoot,
|
|
179
|
-
env,
|
|
298
|
+
env: publishTokenEnv.env,
|
|
180
299
|
stdout,
|
|
181
300
|
stderr,
|
|
182
301
|
});
|
|
183
302
|
} finally {
|
|
303
|
+
publishTokenEnv.cleanup();
|
|
184
304
|
packageSurface.cleanup();
|
|
185
305
|
}
|
|
186
306
|
|
|
@@ -401,12 +401,16 @@ export async function validatePublishProject(
|
|
|
401
401
|
);
|
|
402
402
|
}
|
|
403
403
|
|
|
404
|
+
const expectedAurajsVersion = typeof projectPackage?.dependencies?.['@auraindustry/aurajs'] === 'string'
|
|
405
|
+
? projectPackage.dependencies['@auraindustry/aurajs'].trim()
|
|
406
|
+
: null;
|
|
407
|
+
|
|
404
408
|
const binIntegrity = assertProjectBinIntegrity({
|
|
405
409
|
projectRoot,
|
|
406
410
|
projectPackage,
|
|
407
411
|
packageName,
|
|
408
412
|
aurajsPackageRoot: DEFAULT_AURAJS_PACKAGE_ROOT,
|
|
409
|
-
expectedAurajsVersion
|
|
413
|
+
expectedAurajsVersion,
|
|
410
414
|
enforceExactAurajsDependency: true,
|
|
411
415
|
});
|
|
412
416
|
report.validation.binIntegrity = {
|
|
@@ -566,20 +570,11 @@ export async function validatePublishProject(
|
|
|
566
570
|
);
|
|
567
571
|
}
|
|
568
572
|
|
|
569
|
-
|
|
573
|
+
let packageIntegrity = writeSignedPackageIntegrityArtifacts({
|
|
570
574
|
packageRoot: packageSurface.publishRoot,
|
|
571
575
|
signerProjectRoot: projectRoot,
|
|
572
576
|
buildMetadata,
|
|
573
577
|
});
|
|
574
|
-
report.validation.packageIntegrity = {
|
|
575
|
-
reasonCode: 'publish_package_integrity_ok',
|
|
576
|
-
manifestPath: packageIntegrity.manifestPath,
|
|
577
|
-
signaturePath: packageIntegrity.signaturePath,
|
|
578
|
-
schema: packageIntegrity.schema,
|
|
579
|
-
fileCount: packageIntegrity.fileCount,
|
|
580
|
-
signerFingerprint: packageIntegrity.signerFingerprint,
|
|
581
|
-
publishedMetadata: packageIntegrity.publishedMetadata,
|
|
582
|
-
};
|
|
583
578
|
|
|
584
579
|
assetThresholdRecord.packageSurfaceMode = packageSurface.mode;
|
|
585
580
|
assetThresholdRecord.assetPackaging = packageSurface.mode === SELF_HOSTED_PACKAGE_SURFACE_MODE
|
|
@@ -664,6 +659,22 @@ export async function validatePublishProject(
|
|
|
664
659
|
files: packFiles,
|
|
665
660
|
};
|
|
666
661
|
|
|
662
|
+
packageIntegrity = writeSignedPackageIntegrityArtifacts({
|
|
663
|
+
packageRoot: packageSurface.publishRoot,
|
|
664
|
+
signerProjectRoot: projectRoot,
|
|
665
|
+
buildMetadata,
|
|
666
|
+
includedRelativePaths: packFiles.map((entry) => entry.path),
|
|
667
|
+
});
|
|
668
|
+
report.validation.packageIntegrity = {
|
|
669
|
+
reasonCode: 'publish_package_integrity_ok',
|
|
670
|
+
manifestPath: packageIntegrity.manifestPath,
|
|
671
|
+
signaturePath: packageIntegrity.signaturePath,
|
|
672
|
+
schema: packageIntegrity.schema,
|
|
673
|
+
fileCount: packageIntegrity.fileCount,
|
|
674
|
+
signerFingerprint: packageIntegrity.signerFingerprint,
|
|
675
|
+
publishedMetadata: packageIntegrity.publishedMetadata,
|
|
676
|
+
};
|
|
677
|
+
|
|
667
678
|
report.summary = {
|
|
668
679
|
pass: true,
|
|
669
680
|
reasonCode: 'publish_validation_ok',
|
|
@@ -22,7 +22,7 @@ export function renderProjectReadme({ name, projectTitle, template, templateMeta
|
|
|
22
22
|
|
|
23
23
|
return `# ${projectTitle}
|
|
24
24
|
|
|
25
|
-
Scaffolded with \`
|
|
25
|
+
Scaffolded with \`auramaxx create ${name} --template ${template}\`.
|
|
26
26
|
|
|
27
27
|
## Quick Start
|
|
28
28
|
|
|
@@ -35,14 +35,14 @@ Optional commands:
|
|
|
35
35
|
|
|
36
36
|
\`\`\`bash
|
|
37
37
|
${optionalCommands}
|
|
38
|
-
|
|
39
|
-
|
|
38
|
+
auramaxx explain
|
|
39
|
+
auramaxx check
|
|
40
40
|
\`\`\`
|
|
41
41
|
|
|
42
42
|
${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
43
|
|
|
44
44
|
If you are publishing outside the \`@aurajs\` scope, update \`package.json -> name\`
|
|
45
|
-
before the first \`
|
|
45
|
+
before the first \`auramaxx publish\`.
|
|
46
46
|
|
|
47
47
|
${largeAssetSection}
|
|
48
48
|
${workflowSection}
|
|
@@ -112,7 +112,7 @@ If any are unavailable at runtime, fail fast and capture the reason code before
|
|
|
112
112
|
1. \`npm run build\` to emit native/web artifacts.
|
|
113
113
|
1. \`npm run play\` to sanity-check the packaged local wrapper path.
|
|
114
114
|
${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. \`
|
|
115
|
+
1. \`auramaxx publish\` once metadata and binaries are ready.
|
|
116
116
|
1. If you are not publishing under \`@aurajs\`, update \`package.json -> name\` first.
|
|
117
117
|
|
|
118
118
|
${largeAssetSection}
|
|
@@ -137,7 +137,7 @@ function renderRetroProjectReadme({ name, projectTitle, template, templateMetada
|
|
|
137
137
|
const workflowSection = renderTemplateWorkflowSection(templateMetadata);
|
|
138
138
|
return `# ${projectTitle}
|
|
139
139
|
|
|
140
|
-
Scaffolded with \`
|
|
140
|
+
Scaffolded with \`auramaxx create ${name} --template ${template}\`.
|
|
141
141
|
|
|
142
142
|
## Quick Start
|
|
143
143
|
|
|
@@ -156,8 +156,8 @@ npm run retro:explain
|
|
|
156
156
|
\`\`\`
|
|
157
157
|
|
|
158
158
|
Aura Retro projects build through the main AuraScript CLI, but they do not use
|
|
159
|
-
the default desktop play/dev wrapper flow. Treat \`
|
|
160
|
-
\`
|
|
159
|
+
the default desktop play/dev wrapper flow. Treat \`npm run retro:check\` and
|
|
160
|
+
\`auramaxx build --target <retro-target>\` as the primary development loop.
|
|
161
161
|
|
|
162
162
|
${workflowSection}
|
|
163
163
|
## Template Summary
|
|
@@ -225,6 +225,15 @@ export function renderStateOwnershipSection() {
|
|
|
225
225
|
- \`screenShell\` payloads are only the data passed into HUD, overlay, and modal screens.
|
|
226
226
|
- \`config/\` is for defaults and tuning.
|
|
227
227
|
- \`content/\` is for authored definitions and registries.
|
|
228
|
+
|
|
229
|
+
Example shared session state:
|
|
230
|
+
|
|
231
|
+
\`\`\`js
|
|
232
|
+
const runFlags = context.ensureSessionState('runFlags', { DID_START: false });
|
|
233
|
+
if (!runFlags.DID_START) {
|
|
234
|
+
runFlags.DID_START = true;
|
|
235
|
+
}
|
|
236
|
+
\`\`\`
|
|
228
237
|
`;
|
|
229
238
|
}
|
|
230
239
|
|
|
@@ -240,16 +249,16 @@ export function renderContinuityOwnershipSection() {
|
|
|
240
249
|
- \`scenes/*.scene.js\` should keep \`sceneState\` JSON-safe when it must survive restore.
|
|
241
250
|
- \`context.getCurrentScenePayload()\` is the read seam for payloads restored through \`sceneFlow\`.
|
|
242
251
|
- saved slots live under \`.aura/state/slots/\` and checkpoints live under \`.aura/state/checkpoints/\`.
|
|
243
|
-
- native dev restore hooks use \`
|
|
252
|
+
- native dev restore hooks use \`auramaxx dev --restore-slot <name>\` or \`auramaxx dev --restore-checkpoint <name>\`.
|
|
244
253
|
`;
|
|
245
254
|
}
|
|
246
255
|
|
|
247
256
|
export function renderLargeAssetSection() {
|
|
248
257
|
return `## Publish and Large Assets
|
|
249
258
|
|
|
250
|
-
- \`
|
|
259
|
+
- \`auramaxx publish\` is the public publish command inside an AuraJS project.
|
|
251
260
|
- 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 \`
|
|
261
|
+
- 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
262
|
- That command writes \`aura.external-assets.json\` in the project root and stages manifests plus upload records under \`.aura/external-assets/\`.
|
|
254
263
|
- Packaged \`npx <game> play\` and \`join\` hydrate self-hosted assets into a local cache before launch.
|
|
255
264
|
- Cloudflare R2 and S3 are examples only. AuraPM and \`publishv2\` remain preview-only.
|
|
@@ -261,16 +270,16 @@ export function renderGenerateFilesSection(template) {
|
|
|
261
270
|
return `## Generate Files
|
|
262
271
|
|
|
263
272
|
\`\`\`bash
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
273
|
+
auramaxx make scene MainMenu
|
|
274
|
+
auramaxx make ui-screen PauseMenu
|
|
275
|
+
auramaxx make config EnemyTable
|
|
276
|
+
auramaxx make content SpawnTable
|
|
277
|
+
auramaxx explain
|
|
278
|
+
auramaxx check
|
|
270
279
|
\`\`\`
|
|
271
280
|
|
|
272
281
|
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 \`
|
|
282
|
+
files as the reference structure, then grow the project with \`auramaxx make\`.
|
|
274
283
|
`;
|
|
275
284
|
}
|
|
276
285
|
|
|
@@ -278,12 +287,12 @@ files as the reference structure, then grow the project with \`npx aura make\`.
|
|
|
278
287
|
return `## Generate Files
|
|
279
288
|
|
|
280
289
|
\`\`\`bash
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
290
|
+
auramaxx make card StrikePlus
|
|
291
|
+
auramaxx make enemy JawWorm
|
|
292
|
+
auramaxx make relic BurningBlood
|
|
293
|
+
auramaxx make encounter Act1Hallway
|
|
294
|
+
auramaxx explain
|
|
295
|
+
auramaxx check
|
|
287
296
|
\`\`\`
|
|
288
297
|
`;
|
|
289
298
|
}
|
|
@@ -291,12 +300,12 @@ npx aura check
|
|
|
291
300
|
return `## Generate Files
|
|
292
301
|
|
|
293
302
|
\`\`\`bash
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
303
|
+
auramaxx make scene MainMenu
|
|
304
|
+
auramaxx make ui-screen PauseMenu
|
|
305
|
+
auramaxx make config EnemyTable
|
|
306
|
+
auramaxx make content SpawnTable
|
|
307
|
+
auramaxx explain
|
|
308
|
+
auramaxx check
|
|
300
309
|
\`\`\`
|
|
301
310
|
`;
|
|
302
311
|
}
|
|
@@ -309,8 +318,8 @@ export function renderProjectMapSection(template) {
|
|
|
309
318
|
- \`aura.config.json\` - identity/window/build/modules.
|
|
310
319
|
- \`aura.capabilities.json\` - canonical runtime API declaration for this scaffold.
|
|
311
320
|
- \`RUNBOOK.md\` - first-hour implementation and triage checklist.
|
|
312
|
-
- \`
|
|
313
|
-
- \`
|
|
321
|
+
- \`auramaxx explain\` - inspect how the current project is wired.
|
|
322
|
+
- \`auramaxx check\` - validate authored wiring before runtime.
|
|
314
323
|
- \`src/runtime/\` - runtime/bootstrap helpers plus the project and scene registries.
|
|
315
324
|
- \`src/runtime/project-registry.js\` - authored source of truth for scenes, screens, prefabs, \`configFiles\`, and \`contentFiles\`.
|
|
316
325
|
- \`src/runtime/scene-flow.js\` - active-scene continuity, stack state, and route payload handoff.
|
|
@@ -324,13 +333,13 @@ export function renderProjectMapSection(template) {
|
|
|
324
333
|
- \`config/\` - defaults and tunables.
|
|
325
334
|
- \`content/\` - authored game definitions, progression payloads, and starter-owned registries.
|
|
326
335
|
- \`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
|
|
336
|
+
- \`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
337
|
}
|
|
329
338
|
|
|
330
339
|
return `- \`src/main.js\` - stable bootstrap seam into the authored project layout.
|
|
331
340
|
- \`src/runtime/\` - runtime/bootstrap helpers plus the project and scene registries.
|
|
332
341
|
- \`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.
|
|
342
|
+
- \`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
343
|
- \`src/runtime/scene-flow.js\` - active-scene continuity, scene-stack restore ownership, and route payload handoff.
|
|
335
344
|
- \`src/runtime/screen-shell.js\` - HUD, overlay, and modal payload continuity ownership.
|
|
336
345
|
- \`src/runtime/ui-theme.js\` - shared theme presets plus \`appState.ui.preferences\` apply/reset helpers.
|
|
@@ -355,16 +364,16 @@ export function renderFirstThirtyMinutesSteps(template) {
|
|
|
355
364
|
return `1. Run \`npm install\` then \`npm run dev\` and confirm the starter loop is playable.
|
|
356
365
|
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
366
|
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 \`
|
|
367
|
+
1. Run \`auramaxx explain\` once so the bootstrap stays obvious before the project grows.
|
|
368
|
+
1. Use \`auramaxx make\` when you want more authored files without inventing paths.`;
|
|
360
369
|
}
|
|
361
370
|
|
|
362
371
|
if (template === 'deckbuilder-2d') {
|
|
363
372
|
return `1. Run \`npm install\` then \`npm run dev\` and finish one starter battle end to end.
|
|
364
373
|
1. Read \`content/registries/\`, \`content/cards/\`, \`content/enemies/\`, and \`content/encounters/\` before changing scene flow.
|
|
365
374
|
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 \`
|
|
375
|
+
1. Generate one extra card or encounter with \`auramaxx make\` instead of hand-creating files.
|
|
376
|
+
1. Run \`auramaxx explain\` or \`auramaxx check\` once so the starter-owned registries stay obvious as the project grows.
|
|
368
377
|
1. Only then move into battle polish, rewards, or meta-progression.`;
|
|
369
378
|
}
|
|
370
379
|
|
|
@@ -373,9 +382,9 @@ export function renderFirstThirtyMinutesSteps(template) {
|
|
|
373
382
|
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
383
|
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
384
|
1. Keep shared state in \`appState.session\` / \`appState.ui\`, keep route payloads in \`sceneFlow\`, and keep scene-only state inside \`sceneState\`.
|
|
376
|
-
1. Run \`
|
|
385
|
+
1. Run \`auramaxx explain\` or \`auramaxx check\` when you want a fast map of the authored project wiring.
|
|
377
386
|
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 \`
|
|
387
|
+
1. Use \`auramaxx make scene MainMenu\` or \`auramaxx make ui-screen PauseMenu\` instead of hand-making new authored file paths.`;
|
|
379
388
|
}
|
|
380
389
|
|
|
381
390
|
export function renderContentMapDoc({ template }) {
|
|
@@ -403,6 +412,15 @@ Template: \`${template}\`
|
|
|
403
412
|
- \`src/runtime/project-inspector.js\` exposes the live F1 playtest HUD.
|
|
404
413
|
- authored scenes read shared state with \`ensureSessionState\`, \`ensureUiState\`, and \`getCurrentScenePayload()\`.
|
|
405
414
|
|
|
415
|
+
## Shared State Example
|
|
416
|
+
|
|
417
|
+
\`\`\`js
|
|
418
|
+
const runFlags = context.ensureSessionState('runFlags', { DID_START: false });
|
|
419
|
+
if (!runFlags.DID_START) {
|
|
420
|
+
runFlags.DID_START = true;
|
|
421
|
+
}
|
|
422
|
+
\`\`\`
|
|
423
|
+
|
|
406
424
|
## Current Starter Inventory
|
|
407
425
|
|
|
408
426
|
- \`scenes/boot.scene.js\`
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createSceneRegistry } from './scene-registry.js';
|
|
2
2
|
import { createProjectInspector } from './project-inspector.js';
|
|
3
3
|
import { assertRuntimeCapabilities } from './capabilities.js';
|
|
4
|
+
import { initSplash, updateSplash, drawSplash, isSplashActive } from './splash.js';
|
|
4
5
|
|
|
5
6
|
export function createApp() {
|
|
6
7
|
const sceneRegistry = createSceneRegistry({
|
|
@@ -26,13 +27,16 @@ export function createApp() {
|
|
|
26
27
|
},
|
|
27
28
|
setup() {
|
|
28
29
|
assertRuntimeCapabilities();
|
|
30
|
+
initSplash();
|
|
29
31
|
activeScene()?.setup?.();
|
|
30
32
|
},
|
|
31
33
|
update(dt) {
|
|
34
|
+
if (isSplashActive()) { updateSplash(dt); return; }
|
|
32
35
|
projectInspector.syncInput(globalThis.aura?.input || null);
|
|
33
36
|
activeScene()?.update?.(dt);
|
|
34
37
|
},
|
|
35
38
|
draw() {
|
|
39
|
+
if (isSplashActive()) { drawSplash(); return; }
|
|
36
40
|
activeScene()?.draw?.();
|
|
37
41
|
projectInspector.draw({ activeSceneId });
|
|
38
42
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createSceneRegistry } from './scene-registry.js';
|
|
2
2
|
import { createProjectInspector } from './project-inspector.js';
|
|
3
3
|
import { assertRuntimeCapabilities } from './capabilities.js';
|
|
4
|
+
import { initSplash, updateSplash, drawSplash, isSplashActive } from './splash.js';
|
|
4
5
|
|
|
5
6
|
export function createApp() {
|
|
6
7
|
const sceneRegistry = createSceneRegistry({
|
|
@@ -26,13 +27,16 @@ export function createApp() {
|
|
|
26
27
|
},
|
|
27
28
|
setup() {
|
|
28
29
|
assertRuntimeCapabilities();
|
|
30
|
+
initSplash();
|
|
29
31
|
activeScene()?.setup?.();
|
|
30
32
|
},
|
|
31
33
|
update(dt) {
|
|
34
|
+
if (isSplashActive()) { updateSplash(dt); return; }
|
|
32
35
|
projectInspector.syncInput(globalThis.aura?.input || null);
|
|
33
36
|
activeScene()?.update?.(dt);
|
|
34
37
|
},
|
|
35
38
|
draw() {
|
|
39
|
+
if (isSplashActive()) { drawSplash(); return; }
|
|
36
40
|
activeScene()?.draw?.();
|
|
37
41
|
projectInspector.draw({ activeSceneId });
|
|
38
42
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createSceneRegistry } from './scene-registry.js';
|
|
2
2
|
import { createProjectInspector } from './project-inspector.js';
|
|
3
3
|
import { assertRuntimeCapabilities } from './capabilities.js';
|
|
4
|
+
import { initSplash, updateSplash, drawSplash, isSplashActive } from './splash.js';
|
|
4
5
|
|
|
5
6
|
export function createApp() {
|
|
6
7
|
const sceneRegistry = createSceneRegistry({
|
|
@@ -26,13 +27,16 @@ export function createApp() {
|
|
|
26
27
|
},
|
|
27
28
|
setup() {
|
|
28
29
|
assertRuntimeCapabilities();
|
|
30
|
+
initSplash();
|
|
29
31
|
activeScene()?.setup?.();
|
|
30
32
|
},
|
|
31
33
|
update(dt) {
|
|
34
|
+
if (isSplashActive()) { updateSplash(dt); return; }
|
|
32
35
|
projectInspector.syncInput(globalThis.aura?.input || null);
|
|
33
36
|
activeScene()?.update?.(dt);
|
|
34
37
|
},
|
|
35
38
|
draw() {
|
|
39
|
+
if (isSplashActive()) { drawSplash(); return; }
|
|
36
40
|
activeScene()?.draw?.();
|
|
37
41
|
projectInspector.draw({ activeSceneId });
|
|
38
42
|
},
|