auramaxx 0.1.0 → 0.1.1
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 +30 -11
- package/bin/auramaxx.js +1 -1
- package/package.json +1 -1
- package/src/server/cli/commands/create.ts +20 -24
- package/src/server/cli/commands/play.ts +13 -2
- package/src/server/cli/lib/theme.ts +58 -0
package/README.md
CHANGED
|
@@ -27,15 +27,34 @@ npx auramaxx
|
|
|
27
27
|
Inside a scaffolded game, use the shorter `auramaxx` alias or the generated
|
|
28
28
|
`npm run ...` scripts for local engine commands.
|
|
29
29
|
|
|
30
|
-
Play an
|
|
30
|
+
## Play an Example
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
|
-
|
|
33
|
+
npm install -g auramaxx
|
|
34
|
+
auramaxx play auracraft
|
|
34
35
|
|
|
35
36
|
# or run a published game wrapper directly
|
|
36
|
-
npx
|
|
37
|
+
npx auracraft play
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Fork a Game
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npm install -g auramaxx
|
|
44
|
+
auramaxx fork auramon
|
|
37
45
|
```
|
|
38
46
|
|
|
47
|
+
## Working With AI Agent
|
|
48
|
+
|
|
49
|
+
Inside your codebase:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
cd <your-codebase>
|
|
53
|
+
npx -y skills add Aura-Industry/auramaxx
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
Then use <https://www.aurajs.gg/docs> for engine docs and API references.
|
|
57
|
+
|
|
39
58
|
## Multiplayer TL;DR
|
|
40
59
|
|
|
41
60
|
```bash
|
|
@@ -52,7 +71,7 @@ Keep that same flow and add internet-backed rooms with either:
|
|
|
52
71
|
- `aura.config.json -> multiplayer.relay = "relay.aurajs.gg"`
|
|
53
72
|
- or `AURA_MULTIPLAYER_RELAY_HOST=relay.aurajs.gg`
|
|
54
73
|
|
|
55
|
-
Use [
|
|
74
|
+
Use [Multiplayer Quickstart](https://www.aurajs.gg/docs/multiplayer-quickstart) for the short multiplayer doc, or [Multiplayer Party Example](./packages/aurascript/examples/multiplayer-party/README.md) for the same-project example with diagnostics and room chat.
|
|
56
75
|
|
|
57
76
|
## Feature Set
|
|
58
77
|
|
|
@@ -80,13 +99,13 @@ Use [`packages/aurascript/docs/external/game-dev-api/multiplayer-quickstart.md`]
|
|
|
80
99
|
|
|
81
100
|
## Docs
|
|
82
101
|
|
|
83
|
-
- [
|
|
84
|
-
- [
|
|
85
|
-
- [
|
|
86
|
-
- [
|
|
87
|
-
- [
|
|
88
|
-
- [
|
|
89
|
-
- [
|
|
102
|
+
- [AuraJS README](https://www.aurajs.gg/docs) - AuraJS overview and public docs entrypoint
|
|
103
|
+
- [Game Developer Handbook](https://www.aurajs.gg/docs/handbook) - game developer handbook
|
|
104
|
+
- [Multiplayer Quickstart](https://www.aurajs.gg/docs/multiplayer-quickstart) - shortest multiplayer setup path
|
|
105
|
+
- [Core API Contract](https://www.aurajs.gg/docs/api-contract) - frozen core API contract
|
|
106
|
+
- [3D API Contract](https://www.aurajs.gg/docs/api-contract-3d) - frozen 3D API contract
|
|
107
|
+
- [Exact Reference Index](https://www.aurajs.gg/docs/reference) - exact reference index
|
|
108
|
+
- [Combined Public Reference](https://www.aurajs.gg/docs/reference) - combined public reference
|
|
90
109
|
|
|
91
110
|
Live docs:
|
|
92
111
|
|
package/bin/auramaxx.js
CHANGED
|
@@ -48,7 +48,7 @@ const COMMANDS = {
|
|
|
48
48
|
'shell-hook': 'Auto-load .aura env vars on cd (like direnv)',
|
|
49
49
|
play: 'Play an AuraJS game from npm (auramaxx play <game>)',
|
|
50
50
|
fork: 'Fork a published AuraJS game into a local editable project (auramaxx fork <game>)',
|
|
51
|
-
create: 'Scaffold a new AuraJS game (2d/3d/
|
|
51
|
+
create: 'Scaffold a new AuraJS game (2d/3d/multiplayer) via AuraJS CLI',
|
|
52
52
|
make: 'Generate authored AuraJS project files via AuraJS CLI',
|
|
53
53
|
publish: 'Publish current AuraJS game package to npm with guided prompts',
|
|
54
54
|
// diary: 'Append daily diary entries via authenticated CLI path', // Temporarily disabled at root CLI.
|
package/package.json
CHANGED
|
@@ -6,23 +6,21 @@ import { printBanner, printSection, paint, ANSI } from '../lib/theme';
|
|
|
6
6
|
import { promptInput, promptSelect } from '../lib/prompt';
|
|
7
7
|
|
|
8
8
|
const TEMPLATE_OPTIONS = [
|
|
9
|
-
{ value: '2d
|
|
10
|
-
{ value: '3d
|
|
11
|
-
{ value: '
|
|
9
|
+
{ value: '2d', label: '[2D] Adventure', aliases: ['1', '2', '2d', '2d-adventure', 'adventure-2d'] },
|
|
10
|
+
{ value: '3d', label: '[3D] Adventure', aliases: ['3', '3d', '3d-adventure', 'adventure-3d'] },
|
|
11
|
+
{ value: 'multiplayer', label: '[MP] Multiplayer', aliases: ['4', 'mp', 'multiplayer', 'room', 'room-code', 'local-multiplayer'] },
|
|
12
12
|
];
|
|
13
|
-
|
|
14
|
-
const VALID_TEMPLATES = new Set(TEMPLATE_OPTIONS.map((option) => option.value));
|
|
15
13
|
const TEMPLATE_ALIASES: Record<string, string> = {
|
|
16
|
-
'2d': '2d
|
|
17
|
-
'
|
|
18
|
-
'2d
|
|
19
|
-
'
|
|
20
|
-
'3d': '3d
|
|
21
|
-
'
|
|
22
|
-
'
|
|
23
|
-
'
|
|
24
|
-
'
|
|
25
|
-
'
|
|
14
|
+
'2d': '2d',
|
|
15
|
+
'2d-adventure': '2d',
|
|
16
|
+
'adventure-2d': '2d',
|
|
17
|
+
'3d': '3d',
|
|
18
|
+
'3d-adventure': '3d',
|
|
19
|
+
'adventure-3d': '3d',
|
|
20
|
+
'multiplayer': 'multiplayer',
|
|
21
|
+
'local-multiplayer': 'multiplayer',
|
|
22
|
+
'room-code': 'multiplayer',
|
|
23
|
+
'room': 'multiplayer',
|
|
26
24
|
};
|
|
27
25
|
const COMMAND_DIR = path.dirname(fileURLToPath(import.meta.url));
|
|
28
26
|
const LOCAL_AURAJS_CLI = path.resolve(
|
|
@@ -98,15 +96,10 @@ async function resolveGameName(initialName: string | null): Promise<string> {
|
|
|
98
96
|
|
|
99
97
|
async function resolveTemplate(initialTemplate: string | null): Promise<string> {
|
|
100
98
|
const normalized = normalizeTemplate(initialTemplate);
|
|
101
|
-
if (normalized
|
|
99
|
+
if (normalized) {
|
|
102
100
|
return normalized;
|
|
103
101
|
}
|
|
104
|
-
|
|
105
|
-
if (normalized && !VALID_TEMPLATES.has(normalized)) {
|
|
106
|
-
console.log(` Unknown template "${normalized}"; choose one below.`);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return promptSelect(' Starter template', TEMPLATE_OPTIONS, '2d-shooter');
|
|
102
|
+
return promptSelect(' Starter template', TEMPLATE_OPTIONS, '2d');
|
|
110
103
|
}
|
|
111
104
|
|
|
112
105
|
async function main() {
|
|
@@ -114,10 +107,13 @@ async function main() {
|
|
|
114
107
|
|
|
115
108
|
if (parsed.help) {
|
|
116
109
|
printBanner('CREATE');
|
|
117
|
-
console.log(` ${paint('Usage:', ANSI.bold)} auramaxx create [name] [--template <2d
|
|
110
|
+
console.log(` ${paint('Usage:', ANSI.bold)} auramaxx create [name] [--template <2d|3d|multiplayer>] [--skip-install]`);
|
|
118
111
|
console.log('');
|
|
119
112
|
console.log(' Styled wrapper around AuraJS create scaffolding.');
|
|
120
|
-
console.log(` ${paint('
|
|
113
|
+
console.log(` ${paint('Examples:', ANSI.dim)}`);
|
|
114
|
+
console.log(' auramaxx create my-game --template 2d');
|
|
115
|
+
console.log(' auramaxx create my-game --template 3d');
|
|
116
|
+
console.log(' auramaxx create my-room-game --template multiplayer');
|
|
121
117
|
console.log('');
|
|
122
118
|
return;
|
|
123
119
|
}
|
|
@@ -3,7 +3,7 @@ import { existsSync, mkdtempSync, readFileSync, rmSync } from 'fs';
|
|
|
3
3
|
import { homedir, tmpdir } from 'os';
|
|
4
4
|
import { join, resolve } from 'path';
|
|
5
5
|
import { pathToFileURL } from 'url';
|
|
6
|
-
import { printBanner, printSection, paint, ANSI } from '../lib/theme';
|
|
6
|
+
import { printBanner, printSection, paint, ANSI, createProgressDisplay } from '../lib/theme';
|
|
7
7
|
import {
|
|
8
8
|
assertPublishedGameBinIntegrity,
|
|
9
9
|
buildPublishedGameLaunchEnv,
|
|
@@ -185,17 +185,21 @@ export async function installVerifiedGamePackage(
|
|
|
185
185
|
{
|
|
186
186
|
execFileSyncImpl = execFileSync,
|
|
187
187
|
env = process.env,
|
|
188
|
+
onProgress,
|
|
188
189
|
}: {
|
|
189
190
|
execFileSyncImpl?: typeof execFileSync;
|
|
190
191
|
env?: NodeJS.ProcessEnv;
|
|
192
|
+
onProgress?: (step: number, label: string, detail?: string) => void;
|
|
191
193
|
} = {},
|
|
192
194
|
) {
|
|
193
195
|
if (!plan.name || !plan.packageName) {
|
|
194
196
|
throw new Error('installVerifiedGamePackage requires a resolved package spec.');
|
|
195
197
|
}
|
|
196
198
|
|
|
199
|
+
onProgress?.(1, 'Resolving package', plan.packageName);
|
|
197
200
|
const installRoot = mkdtempSync(join(tmpdir(), 'auramaxx-play-'));
|
|
198
201
|
try {
|
|
202
|
+
onProgress?.(2, 'Installing verified wrapper', plan.name);
|
|
199
203
|
execFileSyncImpl(resolveNpmCommand(), buildSecureInstallArgs(plan.name, installRoot), {
|
|
200
204
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
201
205
|
env: {
|
|
@@ -212,6 +216,7 @@ export async function installVerifiedGamePackage(
|
|
|
212
216
|
|
|
213
217
|
const gamePackage = readInstalledPackageJson(packageRoot);
|
|
214
218
|
const dependencySpec = String(gamePackage?.dependencies?.['@auraindustry/aurajs'] || '').trim();
|
|
219
|
+
onProgress?.(3, 'Verifying package integrity', dependencySpec || plan.packageName);
|
|
215
220
|
const integrity = assertPublishedGameBinIntegrity({
|
|
216
221
|
packageRoot,
|
|
217
222
|
projectPackage: gamePackage,
|
|
@@ -296,14 +301,20 @@ export async function main(argv: string[] = process.argv.slice(2)) {
|
|
|
296
301
|
|
|
297
302
|
printBanner(plan.name.toUpperCase());
|
|
298
303
|
printSection(plan.name, describeForwardedCommand(plan.forwardedArgs[0] || 'play'));
|
|
304
|
+
const progress = createProgressDisplay(4);
|
|
299
305
|
|
|
300
306
|
let install: Awaited<ReturnType<typeof installVerifiedGamePackage>> | null = null;
|
|
301
307
|
try {
|
|
302
|
-
install = await installVerifiedGamePackage(plan
|
|
308
|
+
install = await installVerifiedGamePackage(plan, {
|
|
309
|
+
onProgress(step, label, detail) {
|
|
310
|
+
progress.update(step, label, detail);
|
|
311
|
+
},
|
|
312
|
+
});
|
|
303
313
|
const env = buildPublishedGameLaunchEnv(
|
|
304
314
|
process.env,
|
|
305
315
|
plan.forwardedArgs[0] === 'join' ? { AURA_GAME_JOIN_MODE: 'play' } : {},
|
|
306
316
|
);
|
|
317
|
+
progress.update(4, 'Launching game', plan.forwardedArgs[0] || 'play');
|
|
307
318
|
execFileSync(process.execPath, [install.binAbsolutePath, ...plan.forwardedArgs], {
|
|
308
319
|
stdio: 'inherit',
|
|
309
320
|
cwd: install.packageRoot,
|
|
@@ -221,6 +221,64 @@ export function printComplete(message: string): void {
|
|
|
221
221
|
console.log('');
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
+
function stripAnsi(text: string): string {
|
|
225
|
+
return text.replace(/\x1b\[[0-9;]*m/g, '');
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function formatProgressBar(current: number, total: number, width: number): string {
|
|
229
|
+
const safeTotal = Math.max(1, total);
|
|
230
|
+
const clamped = Math.max(0, Math.min(current, safeTotal));
|
|
231
|
+
const filled = Math.round((clamped / safeTotal) * width);
|
|
232
|
+
const active = paint('/'.repeat(filled), ANSI.fgAccent, ANSI.bold);
|
|
233
|
+
const pending = paint('-'.repeat(Math.max(0, width - filled)), ANSI.dim);
|
|
234
|
+
return `[${active}${pending}]`;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface ProgressDisplay {
|
|
238
|
+
update(step: number, label: string, detail?: string): void;
|
|
239
|
+
complete(label?: string, detail?: string): void;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
export function createProgressDisplay(totalSteps: number, width = 24): ProgressDisplay {
|
|
243
|
+
const stdout = process.stdout;
|
|
244
|
+
const interactive = stdout.isTTY;
|
|
245
|
+
let renderedLineCount = 0;
|
|
246
|
+
|
|
247
|
+
function draw(step: number, label: string, detail?: string) {
|
|
248
|
+
const safeStep = Math.max(0, Math.min(step, totalSteps));
|
|
249
|
+
const titleLine = ` ${paint('//', ANSI.fgAccent, ANSI.bold)} ${paint(label, ANSI.bold)} ${paint(`${safeStep}/${totalSteps}`, ANSI.dim)} ${formatProgressBar(safeStep, totalSteps, width)}`;
|
|
250
|
+
const lines = detail ? [titleLine, ` ${paint(detail, ANSI.dim)}`] : [titleLine];
|
|
251
|
+
|
|
252
|
+
if (interactive && renderedLineCount > 0) {
|
|
253
|
+
stdout.write(`\u001b[${renderedLineCount}A`);
|
|
254
|
+
for (let index = 0; index < renderedLineCount; index += 1) {
|
|
255
|
+
stdout.write('\u001b[2K');
|
|
256
|
+
stdout.write('\u001b[1B');
|
|
257
|
+
}
|
|
258
|
+
stdout.write(`\u001b[${renderedLineCount}A`);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
for (const line of lines) {
|
|
262
|
+
if (interactive) {
|
|
263
|
+
stdout.write('\u001b[2K');
|
|
264
|
+
stdout.write(`${line}\n`);
|
|
265
|
+
} else {
|
|
266
|
+
console.log(stripAnsi(line));
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
renderedLineCount = lines.length;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
return {
|
|
273
|
+
update(step: number, label: string, detail?: string) {
|
|
274
|
+
draw(step, label, detail);
|
|
275
|
+
},
|
|
276
|
+
complete(label = 'Ready', detail?: string) {
|
|
277
|
+
draw(totalSteps, label, detail);
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
224
282
|
// ── Seed phrase box (security-critical) ──────────────────────
|
|
225
283
|
|
|
226
284
|
/**
|