@doodle-engine/cli 0.0.21 → 0.0.22

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/dist/cli.js CHANGED
@@ -9,73 +9,73 @@ import { join as h, extname as f, relative as E, dirname as U } from "path";
9
9
  import { parse as y } from "yaml";
10
10
  import { extractAssetPaths as W, getAssetType as R, parseDialogue as k } from "@doodle-engine/core";
11
11
  import J from "prompts";
12
- function C(n, o) {
12
+ function C(t, o) {
13
13
  const s = [];
14
- for (const r of Object.values(n.dialogues)) {
15
- const t = o.get(r.id) || `dialogue:${r.id}`;
16
- s.push(...Q(r, t));
14
+ for (const r of Object.values(t.dialogues)) {
15
+ const n = o.get(r.id) || `dialogue:${r.id}`;
16
+ s.push(...Q(r, n));
17
17
  }
18
- for (const r of Object.values(n.characters))
19
- if (r.dialogue && !n.dialogues[r.dialogue]) {
20
- const t = o.get(r.id) || `character:${r.id}`;
18
+ for (const r of Object.values(t.characters))
19
+ if (r.dialogue && !t.dialogues[r.dialogue]) {
20
+ const n = o.get(r.id) || `character:${r.id}`;
21
21
  s.push({
22
- file: t,
22
+ file: n,
23
23
  message: `Character "${r.id}" references non-existent dialogue "${r.dialogue}"`,
24
24
  suggestion: `Create dialogue "${r.dialogue}" or fix the reference`
25
25
  });
26
26
  }
27
- return s.push(...K(n, o)), s;
27
+ return s.push(...K(t, o)), s;
28
28
  }
29
- function Q(n, o) {
29
+ function Q(t, o) {
30
30
  const s = [], r = /* @__PURE__ */ new Set();
31
- for (const t of n.nodes)
32
- r.has(t.id) && s.push({
31
+ for (const n of t.nodes)
32
+ r.has(n.id) && s.push({
33
33
  file: o,
34
- message: `Duplicate node ID "${t.id}"`,
34
+ message: `Duplicate node ID "${n.id}"`,
35
35
  suggestion: "Node IDs must be unique within a dialogue"
36
- }), r.add(t.id);
37
- r.has(n.startNode) || s.push({
36
+ }), r.add(n.id);
37
+ r.has(t.startNode) || s.push({
38
38
  file: o,
39
- message: `Start node "${n.startNode}" not found`,
40
- suggestion: `Add a NODE ${n.startNode} or fix the startNode reference`
39
+ message: `Start node "${t.startNode}" not found`,
40
+ suggestion: `Add a NODE ${t.startNode} or fix the startNode reference`
41
41
  });
42
- for (const t of n.nodes)
43
- s.push(...Y(t, r, o));
42
+ for (const n of t.nodes)
43
+ s.push(...Y(n, r, o));
44
44
  return s;
45
45
  }
46
- function Y(n, o, s) {
46
+ function Y(t, o, s) {
47
47
  const r = [];
48
- if (n.next && !o.has(n.next) && r.push({
48
+ if (t.next && !o.has(t.next) && r.push({
49
49
  file: s,
50
- message: `Node "${n.id}" GOTO "${n.next}" points to non-existent node`,
51
- suggestion: `Add NODE ${n.next} or fix the GOTO target`
52
- }), n.conditionalNext)
53
- for (const t of n.conditionalNext)
54
- o.has(t.next) || r.push({
50
+ message: `Node "${t.id}" GOTO "${t.next}" points to non-existent node`,
51
+ suggestion: `Add NODE ${t.next} or fix the GOTO target`
52
+ }), t.conditionalNext)
53
+ for (const n of t.conditionalNext)
54
+ o.has(n.next) || r.push({
55
55
  file: s,
56
- message: `Node "${n.id}" IF block GOTO "${t.next}" points to non-existent node`,
57
- suggestion: `Add NODE ${t.next} or fix the GOTO target`
58
- }), r.push(...O(t.condition, n.id, s));
59
- for (const t of n.choices) {
60
- if (!t.effects?.some(
56
+ message: `Node "${t.id}" IF block GOTO "${n.next}" points to non-existent node`,
57
+ suggestion: `Add NODE ${n.next} or fix the GOTO target`
58
+ }), r.push(...O(n.condition, t.id, s));
59
+ for (const n of t.choices) {
60
+ if (!n.effects?.some(
61
61
  (e) => e.type === "endDialogue" || e.type === "goToLocation" || e.type === "startDialogue"
62
- ) && t.next && !o.has(t.next) && r.push({
62
+ ) && n.next && !o.has(n.next) && r.push({
63
63
  file: s,
64
- message: `Node "${n.id}" choice "${t.id}" GOTO "${t.next}" points to non-existent node`,
65
- suggestion: `Add NODE ${t.next} or fix the GOTO target`
66
- }), t.conditions)
67
- for (const e of t.conditions)
68
- r.push(...O(e, n.id, s));
69
- if (t.effects)
70
- for (const e of t.effects)
71
- r.push(...A(e, n.id, s));
64
+ message: `Node "${t.id}" choice "${n.id}" GOTO "${n.next}" points to non-existent node`,
65
+ suggestion: `Add NODE ${n.next} or fix the GOTO target`
66
+ }), n.conditions)
67
+ for (const e of n.conditions)
68
+ r.push(...O(e, t.id, s));
69
+ if (n.effects)
70
+ for (const e of n.effects)
71
+ r.push(...A(e, t.id, s));
72
72
  }
73
- if (n.conditions)
74
- for (const t of n.conditions)
75
- r.push(...O(t, n.id, s));
76
- if (n.effects)
77
- for (const t of n.effects)
78
- r.push(...A(t, n.id, s));
73
+ if (t.conditions)
74
+ for (const n of t.conditions)
75
+ r.push(...O(n, t.id, s));
76
+ if (t.effects)
77
+ for (const n of t.effects)
78
+ r.push(...A(n, t.id, s));
79
79
  return r;
80
80
  }
81
81
  const z = {
@@ -123,51 +123,51 @@ const z = {
123
123
  showInterlude: ["interludeId"],
124
124
  roll: ["variable", "min", "max"]
125
125
  };
126
- function O(n, o, s) {
126
+ function O(t, o, s) {
127
127
  const r = [];
128
- if (!n.type)
128
+ if (!t.type)
129
129
  return r.push({
130
130
  file: s,
131
131
  message: `Node "${o}" has condition with missing type`
132
132
  }), r;
133
- if (n.type === "timeIs")
134
- return n.hour === void 0 && n.day === void 0 && r.push({
133
+ if (t.type === "timeIs")
134
+ return t.hour === void 0 && t.day === void 0 && r.push({
135
135
  file: s,
136
136
  message: `Node "${o}" condition "timeIs" must have at least one of "hour" or "day" argument`
137
137
  }), r;
138
- const t = z[n.type];
139
- if (!t)
138
+ const n = z[t.type];
139
+ if (!n)
140
140
  return r;
141
- for (const a of t)
142
- (n[a] === void 0 || n[a] === null || n[a] === "") && r.push({
141
+ for (const a of n)
142
+ (t[a] === void 0 || t[a] === null || t[a] === "") && r.push({
143
143
  file: s,
144
- message: `Node "${o}" condition "${n.type}" missing required "${a}" argument`
144
+ message: `Node "${o}" condition "${t.type}" missing required "${a}" argument`
145
145
  });
146
146
  return r;
147
147
  }
148
- function A(n, o, s) {
148
+ function A(t, o, s) {
149
149
  const r = [];
150
- if (!n.type)
150
+ if (!t.type)
151
151
  return r.push({
152
152
  file: s,
153
153
  message: `Node "${o}" has effect with missing type`
154
154
  }), r;
155
- const t = V[n.type];
156
- if (!t)
155
+ const n = V[t.type];
156
+ if (!n)
157
157
  return r;
158
- for (const a of t)
159
- (n[a] === void 0 || n[a] === null || n[a] === "") && r.push({
158
+ for (const a of n)
159
+ (t[a] === void 0 || t[a] === null || t[a] === "") && r.push({
160
160
  file: s,
161
- message: `Node "${o}" effect "${n.type}" missing required "${a}" argument`
161
+ message: `Node "${o}" effect "${t.type}" missing required "${a}" argument`
162
162
  });
163
163
  return r;
164
164
  }
165
- function K(n, o) {
165
+ function K(t, o) {
166
166
  const s = [], r = /* @__PURE__ */ new Set();
167
- for (const e of Object.values(n.locales))
167
+ for (const e of Object.values(t.locales))
168
168
  for (const i of Object.keys(e))
169
169
  r.add(i);
170
- const t = (e) => e.startsWith("@"), a = (e, i, l) => {
170
+ const n = (e) => e.startsWith("@"), a = (e, i, l) => {
171
171
  const d = e.slice(1);
172
172
  if (!r.has(d)) {
173
173
  const u = o.get(i) || `${l}:${i}`;
@@ -178,45 +178,47 @@ function K(n, o) {
178
178
  });
179
179
  }
180
180
  };
181
- for (const e of Object.values(n.locations))
182
- t(e.name) && a(e.name, e.id, "location"), t(e.description) && a(e.description, e.id, "location");
183
- for (const e of Object.values(n.characters))
184
- t(e.name) && a(e.name, e.id, "character"), t(e.biography) && a(e.biography, e.id, "character");
185
- for (const e of Object.values(n.items))
186
- t(e.name) && a(e.name, e.id, "item"), t(e.description) && a(e.description, e.id, "item");
187
- for (const e of Object.values(n.quests)) {
188
- t(e.name) && a(e.name, e.id, "quest"), t(e.description) && a(e.description, e.id, "quest");
181
+ for (const e of Object.values(t.locations))
182
+ n(e.name) && a(e.name, e.id, "location"), n(e.description) && a(e.description, e.id, "location");
183
+ for (const e of Object.values(t.characters))
184
+ n(e.name) && a(e.name, e.id, "character"), n(e.biography) && a(e.biography, e.id, "character");
185
+ for (const e of Object.values(t.items))
186
+ n(e.name) && a(e.name, e.id, "item"), n(e.description) && a(e.description, e.id, "item");
187
+ for (const e of Object.values(t.quests)) {
188
+ n(e.name) && a(e.name, e.id, "quest"), n(e.description) && a(e.description, e.id, "quest");
189
189
  for (const i of e.stages)
190
- t(i.description) && a(i.description, e.id, "quest");
190
+ n(i.description) && a(i.description, e.id, "quest");
191
191
  }
192
- for (const e of Object.values(n.journalEntries))
193
- t(e.title) && a(e.title, e.id, "journal"), t(e.text) && a(e.text, e.id, "journal");
194
- for (const e of Object.values(n.dialogues))
192
+ for (const e of Object.values(t.journalEntries))
193
+ n(e.title) && a(e.title, e.id, "journal"), n(e.text) && a(e.text, e.id, "journal");
194
+ for (const e of Object.values(t.dialogues))
195
195
  for (const i of e.nodes) {
196
- t(i.text) && a(i.text, e.id, "dialogue");
196
+ n(i.text) && a(i.text, e.id, "dialogue");
197
197
  for (const l of i.choices)
198
- t(l.text) && a(l.text, e.id, "dialogue");
198
+ n(l.text) && a(l.text, e.id, "dialogue");
199
199
  }
200
- for (const e of Object.values(n.interludes))
201
- t(e.text) && a(e.text, e.id, "interlude");
200
+ for (const e of Object.values(t.interludes))
201
+ n(e.text) && a(e.text, e.id, "interlude");
202
202
  return s;
203
203
  }
204
- function I(n) {
205
- if (n.length === 0) {
204
+ function I(t) {
205
+ if (t.length === 0) {
206
206
  console.log(c.green("✓ No validation errors"));
207
207
  return;
208
208
  }
209
209
  console.log(
210
210
  c.red(
211
211
  `
212
- ✗ Found ${n.length} validation error${n.length === 1 ? "" : "s"}:
212
+ ✗ Found ${t.length} validation error${t.length === 1 ? "" : "s"}:
213
213
  `
214
214
  )
215
215
  );
216
- for (const o of n)
217
- console.log(c.bold(o.file) + (o.line ? `:${o.line}` : "")), console.log(" " + c.red(o.message)), o.suggestion && console.log(" " + c.dim(o.suggestion)), console.log();
216
+ for (const o of t)
217
+ console.log(
218
+ c.bold(o.file) + (o.line ? `:${o.line}` : "")
219
+ ), console.log(" " + c.red(o.message)), o.suggestion && console.log(" " + c.dim(o.suggestion)), console.log();
218
220
  }
219
- async function q(n, o, s, r, t = Date.now().toString()) {
221
+ async function q(t, o, s, r, n = Date.now().toString()) {
220
222
  const { shell: a, game: e } = W(
221
223
  s,
222
224
  r
@@ -252,7 +254,7 @@ async function q(n, o, s, r, t = Date.now().toString()) {
252
254
  )
253
255
  ), u = l.reduce((g, _) => g + (_.size ?? 0), 0), m = d.reduce((g, _) => g + (_.size ?? 0), 0);
254
256
  return {
255
- version: t,
257
+ version: n,
256
258
  shell: l,
257
259
  game: d,
258
260
  shellSize: u,
@@ -260,31 +262,43 @@ async function q(n, o, s, r, t = Date.now().toString()) {
260
262
  };
261
263
  }
262
264
  const S = "🐾", X = "✨", Z = "✏️", ee = "➕";
263
- async function ne() {
264
- const n = process.cwd(), o = h(n, "content");
265
- console.log(""), console.log(c.bold.magenta(` ${S} Doodle Engine Dev Server ${S}`)), console.log("");
265
+ async function te() {
266
+ const t = process.cwd(), o = h(t, "content");
267
+ console.log(""), console.log(
268
+ c.bold.magenta(` ${S} Doodle Engine Dev Server ${S}`)
269
+ ), console.log("");
266
270
  const s = {
267
271
  name: "doodle-content-loader",
268
- configureServer(t) {
269
- t.middlewares.use("/api/content", async (d, u) => {
272
+ configureServer(n) {
273
+ n.middlewares.use("/api/content", async (d, u) => {
270
274
  try {
271
275
  const m = await j(o);
272
276
  u.setHeader("Content-Type", "application/json"), u.end(JSON.stringify(m));
273
277
  } catch (m) {
274
- console.error(c.red(" Error loading content:"), m), u.statusCode = 500, u.end(JSON.stringify({ error: "Failed to load content" }));
278
+ console.error(
279
+ c.red(" Error loading content:"),
280
+ m
281
+ ), u.statusCode = 500, u.end(
282
+ JSON.stringify({ error: "Failed to load content" })
283
+ );
275
284
  }
276
- }), t.middlewares.use("/api/manifest", async (d, u) => {
285
+ }), n.middlewares.use("/api/manifest", async (d, u) => {
277
286
  try {
278
287
  const { registry: m, config: g } = await j(o), _ = await q(
279
- h(n, "assets"),
280
- n,
288
+ h(t, "assets"),
289
+ t,
281
290
  m,
282
291
  g,
283
292
  "dev"
284
293
  );
285
294
  u.setHeader("Content-Type", "application/json"), u.end(JSON.stringify(_));
286
295
  } catch (m) {
287
- console.error(c.red(" Error generating manifest:"), m), u.statusCode = 500, u.end(JSON.stringify({ error: "Failed to generate manifest" }));
296
+ console.error(
297
+ c.red(" Error generating manifest:"),
298
+ m
299
+ ), u.statusCode = 500, u.end(
300
+ JSON.stringify({ error: "Failed to generate manifest" })
301
+ );
288
302
  }
289
303
  });
290
304
  const a = L(o, {
@@ -298,26 +312,32 @@ async function ne() {
298
312
  let i = null;
299
313
  const l = (d) => {
300
314
  i && clearTimeout(i), i = setTimeout(async () => {
301
- i = null, console.log(d), await te(o), t.ws.send({ type: "full-reload", path: "*" });
315
+ i = null, console.log(d), await ne(o), n.ws.send({ type: "full-reload", path: "*" });
302
316
  }, 50);
303
317
  };
304
318
  a.on("change", (d) => {
305
- l(c.yellow(` ${Z} Content changed: ${d}`));
319
+ l(
320
+ c.yellow(` ${Z} Content changed: ${d}`)
321
+ );
306
322
  }), a.on("add", (d) => {
307
- e && l(c.green(` ${ee} Content added: ${d}`));
323
+ e && l(
324
+ c.green(` ${ee} Content added: ${d}`)
325
+ );
308
326
  });
309
327
  }
310
328
  }, r = await F({
311
- root: n,
329
+ root: t,
312
330
  plugins: [G(), s],
313
331
  server: {
314
332
  port: 3e3,
315
333
  open: !0
316
334
  }
317
335
  });
318
- await r.listen(), r.printUrls(), console.log(""), console.log(c.dim(` ${X} Watching content files for changes...`)), console.log("");
336
+ await r.listen(), r.printUrls(), console.log(""), console.log(
337
+ c.dim(` ${X} Watching content files for changes...`)
338
+ ), console.log("");
319
339
  }
320
- async function j(n) {
340
+ async function j(t) {
321
341
  const o = {
322
342
  locations: {},
323
343
  characters: {},
@@ -339,8 +359,8 @@ async function j(n) {
339
359
  { dir: "journal", key: "journalEntries" },
340
360
  { dir: "interludes", key: "interludes" }
341
361
  ];
342
- for (const { dir: t, key: a } of r) {
343
- const e = h(n, t);
362
+ for (const { dir: n, key: a } of r) {
363
+ const e = h(t, n);
344
364
  try {
345
365
  const i = await b(e);
346
366
  for (const l of i)
@@ -352,25 +372,25 @@ async function j(n) {
352
372
  }
353
373
  }
354
374
  try {
355
- const t = h(n, "locales"), a = await b(t);
375
+ const n = h(t, "locales"), a = await b(n);
356
376
  for (const e of a)
357
377
  if (f(e) === ".yaml" || f(e) === ".yml") {
358
- const i = h(t, e), l = await p(i, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
378
+ const i = h(n, e), l = await p(i, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
359
379
  o.locales[u] = d ?? {};
360
380
  }
361
381
  } catch {
362
382
  }
363
383
  try {
364
- const t = h(n, "dialogues"), a = await b(t);
384
+ const n = h(t, "dialogues"), a = await b(n);
365
385
  for (const e of a)
366
386
  if (f(e) === ".dlg") {
367
- const i = h(t, e), l = await p(i, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
387
+ const i = h(n, e), l = await p(i, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
368
388
  o.dialogues[u.id] = u;
369
389
  }
370
390
  } catch {
371
391
  }
372
392
  try {
373
- const t = h(n, "game.yaml"), a = await p(t, "utf-8");
393
+ const n = h(t, "game.yaml"), a = await p(n, "utf-8");
374
394
  s = y(a);
375
395
  } catch {
376
396
  console.warn(c.yellow(" No game.yaml found, using defaults")), s = {
@@ -383,15 +403,15 @@ async function j(n) {
383
403
  }
384
404
  return { registry: o, config: s };
385
405
  }
386
- async function te(n) {
406
+ async function ne(t) {
387
407
  try {
388
- const { registry: o, fileMap: s } = await oe(n), r = C(o, s);
408
+ const { registry: o, fileMap: s } = await oe(t), r = C(o, s);
389
409
  r.length > 0 && (console.log(""), I(r), console.log(""));
390
410
  } catch (o) {
391
411
  console.error(c.red(" Error running validation:"), o);
392
412
  }
393
413
  }
394
- async function oe(n) {
414
+ async function oe(t) {
395
415
  const o = {
396
416
  locations: {},
397
417
  characters: {},
@@ -411,8 +431,8 @@ async function oe(n) {
411
431
  { dir: "journal", key: "journalEntries" },
412
432
  { dir: "interludes", key: "interludes" }
413
433
  ];
414
- for (const { dir: t, key: a } of r) {
415
- const e = h(n, t);
434
+ for (const { dir: n, key: a } of r) {
435
+ const e = h(t, n);
416
436
  try {
417
437
  const i = await b(e);
418
438
  for (const l of i)
@@ -424,34 +444,34 @@ async function oe(n) {
424
444
  }
425
445
  }
426
446
  try {
427
- const t = h(n, "locales"), a = await b(t);
447
+ const n = h(t, "locales"), a = await b(n);
428
448
  for (const e of a)
429
449
  if (f(e) === ".yaml" || f(e) === ".yml") {
430
- const i = h(t, e), l = await p(i, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
450
+ const i = h(n, e), l = await p(i, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
431
451
  o.locales[u] = d ?? {};
432
452
  }
433
453
  } catch {
434
454
  }
435
455
  try {
436
- const t = h(n, "dialogues"), a = await b(t);
456
+ const n = h(t, "dialogues"), a = await b(n);
437
457
  for (const e of a)
438
458
  if (f(e) === ".dlg") {
439
- const i = h(t, e), l = await p(i, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
459
+ const i = h(n, e), l = await p(i, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
440
460
  o.dialogues[u.id] = u, s.set(u.id, E(process.cwd(), i));
441
461
  }
442
462
  } catch {
443
463
  }
444
464
  return { registry: o, fileMap: s };
445
465
  }
446
- function ae(n) {
447
- const o = `doodle-engine-assets-${n.version}`, s = [
448
- ...n.shell.map((t) => t.path),
449
- ...n.game.map((t) => t.path)
466
+ function ae(t) {
467
+ const o = `doodle-engine-assets-${t.version}`, s = [
468
+ ...t.shell.map((n) => n.path),
469
+ ...t.game.map((n) => n.path)
450
470
  ], r = JSON.stringify(s, null, 2);
451
471
  return `/**
452
472
  * Doodle Engine Service Worker
453
473
  * Generated at build time — do not edit manually.
454
- * Cache version: ${n.version}
474
+ * Cache version: ${t.version}
455
475
  */
456
476
 
457
477
  const CACHE_NAME = ${JSON.stringify(o)};
@@ -519,34 +539,34 @@ self.addEventListener('fetch', (event) => {
519
539
  `;
520
540
  }
521
541
  async function re() {
522
- const n = process.cwd(), o = h(n, "content");
542
+ const t = process.cwd(), o = h(t, "content");
523
543
  console.log(""), console.log(c.bold.magenta("🐕 Building Doodle Engine game...")), console.log(""), console.log(c.dim("Validating content..."));
524
- let s, r, t;
544
+ let s, r, n;
525
545
  try {
526
546
  const a = await se(o);
527
- r = a.registry, t = a.config;
547
+ r = a.registry, n = a.config;
528
548
  const { fileMap: e } = a, i = C(r, e);
529
- I(i), i.length > 0 && (console.log(c.red("Build failed due to validation errors.")), console.log(""), process.exit(1)), s = { registry: r, config: t };
549
+ I(i), i.length > 0 && (console.log(c.red("Build failed due to validation errors.")), console.log(""), process.exit(1)), s = { registry: r, config: n };
530
550
  } catch (a) {
531
551
  console.error(c.red("Error loading content:"), a), process.exit(1);
532
552
  }
533
553
  console.log("");
534
554
  try {
535
555
  await P({
536
- root: n,
556
+ root: t,
537
557
  plugins: [G()],
538
558
  build: {
539
559
  outDir: "dist",
540
560
  emptyOutDir: !0
541
561
  }
542
562
  });
543
- const a = h(n, "dist"), e = n;
563
+ const a = h(t, "dist"), e = t;
544
564
  console.log(c.dim("Generating asset manifest..."));
545
565
  const i = await q(
546
- h(n, "assets"),
566
+ h(t, "assets"),
547
567
  e,
548
568
  r,
549
- t,
569
+ n,
550
570
  Date.now().toString()
551
571
  ), l = h(a, "api");
552
572
  await T(l, { recursive: !0 }), await w(h(l, "content"), JSON.stringify(s)), await w(h(l, "manifest"), JSON.stringify(i)), await w(
@@ -559,7 +579,7 @@ async function re() {
559
579
  console.error(c.red("Build failed:"), a), process.exit(1);
560
580
  }
561
581
  }
562
- async function se(n) {
582
+ async function se(t) {
563
583
  const o = {
564
584
  locations: {},
565
585
  characters: {},
@@ -580,7 +600,7 @@ async function se(n) {
580
600
  { dir: "interludes", key: "interludes" }
581
601
  ];
582
602
  for (const { dir: a, key: e } of r) {
583
- const i = h(n, a);
603
+ const i = h(t, a);
584
604
  try {
585
605
  const l = await b(i);
586
606
  for (const d of l)
@@ -592,7 +612,7 @@ async function se(n) {
592
612
  }
593
613
  }
594
614
  try {
595
- const a = h(n, "locales"), e = await b(a);
615
+ const a = h(t, "locales"), e = await b(a);
596
616
  for (const i of e)
597
617
  if (f(i) === ".yaml" || f(i) === ".yml") {
598
618
  const l = h(a, i), d = await p(l, "utf-8"), u = y(d), m = i.replace(/\.(yaml|yml)$/, "");
@@ -601,7 +621,7 @@ async function se(n) {
601
621
  } catch {
602
622
  }
603
623
  try {
604
- const a = h(n, "dialogues"), e = await b(a);
624
+ const a = h(t, "dialogues"), e = await b(a);
605
625
  for (const i of e)
606
626
  if (f(i) === ".dlg") {
607
627
  const l = h(a, i), d = await p(l, "utf-8"), u = i.replace(".dlg", ""), m = k(d, u);
@@ -609,12 +629,12 @@ async function se(n) {
609
629
  }
610
630
  } catch {
611
631
  }
612
- let t = null;
632
+ let n = null;
613
633
  try {
614
- const a = h(n, "game.yaml"), e = await p(a, "utf-8");
615
- t = y(e);
634
+ const a = h(t, "game.yaml"), e = await p(a, "utf-8");
635
+ n = y(e);
616
636
  } catch {
617
- t = {
637
+ n = {
618
638
  id: "game",
619
639
  startLocation: "",
620
640
  startTime: { day: 1, hour: 8 },
@@ -623,19 +643,19 @@ async function se(n) {
623
643
  startInventory: []
624
644
  };
625
645
  }
626
- return { registry: o, fileMap: s, config: t };
646
+ return { registry: o, fileMap: s, config: n };
627
647
  }
628
648
  async function ie() {
629
- const n = process.cwd(), o = h(n, "content");
649
+ const t = process.cwd(), o = h(t, "content");
630
650
  console.log(""), console.log(c.bold.magenta("🐾 Validating Doodle Engine content...")), console.log("");
631
651
  try {
632
- const { registry: s, fileMap: r } = await ce(o), t = C(s, r);
633
- I(t), t.length > 0 && process.exit(1);
652
+ const { registry: s, fileMap: r } = await ce(o), n = C(s, r);
653
+ I(n), n.length > 0 && process.exit(1);
634
654
  } catch (s) {
635
655
  console.error(c.red("Error loading content:"), s), process.exit(1);
636
656
  }
637
657
  }
638
- async function ce(n) {
658
+ async function ce(t) {
639
659
  const o = {
640
660
  locations: {},
641
661
  characters: {},
@@ -653,8 +673,8 @@ async function ce(n) {
653
673
  { dir: "quests", key: "quests" },
654
674
  { dir: "journal", key: "journalEntries" }
655
675
  ];
656
- for (const { dir: t, key: a } of r) {
657
- const e = h(n, t);
676
+ for (const { dir: n, key: a } of r) {
677
+ const e = h(t, n);
658
678
  try {
659
679
  const i = await b(e);
660
680
  for (const l of i)
@@ -666,19 +686,19 @@ async function ce(n) {
666
686
  }
667
687
  }
668
688
  try {
669
- const t = h(n, "locales"), a = await b(t);
689
+ const n = h(t, "locales"), a = await b(n);
670
690
  for (const e of a)
671
691
  if (f(e) === ".yaml" || f(e) === ".yml") {
672
- const i = h(t, e), l = await p(i, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
692
+ const i = h(n, e), l = await p(i, "utf-8"), d = y(l), u = e.replace(/\.(yaml|yml)$/, "");
673
693
  o.locales[u] = d ?? {};
674
694
  }
675
695
  } catch {
676
696
  }
677
697
  try {
678
- const t = h(n, "dialogues"), a = await b(t);
698
+ const n = h(t, "dialogues"), a = await b(n);
679
699
  for (const e of a)
680
700
  if (f(e) === ".dlg") {
681
- const i = h(t, e), l = await p(i, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
701
+ const i = h(n, e), l = await p(i, "utf-8"), d = e.replace(".dlg", ""), u = k(l, d);
682
702
  o.dialogues[u.id] = u, s.set(u.id, E(process.cwd(), i));
683
703
  }
684
704
  } catch {
@@ -691,33 +711,33 @@ dist
691
711
  *.log
692
712
  `, de = `<!doctype html>
693
713
  <html lang="en">
694
- <head>
695
- <meta charset="UTF-8" />
696
- <meta name="viewport" content="width=device-width, initial-scale=1.0" />
697
- <title>Doodle Engine Game</title>
698
- </head>
699
- <body>
700
- <div id="root"></div>
701
- <script type="module" src="/src/main.tsx"><\/script>
702
- </body>
714
+ <head>
715
+ <meta charset="UTF-8" />
716
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
717
+ <title>Doodle Engine Game</title>
718
+ </head>
719
+ <body>
720
+ <div id="root"></div>
721
+ <script type="module" src="/src/main.tsx"><\/script>
722
+ </body>
703
723
  </html>
704
724
  `, ue = `{
705
- "compilerOptions": {
706
- "target": "ES2024",
707
- "lib": ["ES2024", "DOM", "DOM.Iterable"],
708
- "module": "ESNext",
709
- "moduleResolution": "bundler",
710
- "jsx": "react-jsx",
711
- "strict": true,
712
- "skipLibCheck": true,
713
- "esModuleInterop": true,
714
- "forceConsistentCasingInFileNames": true,
715
- "resolveJsonModule": true,
716
- "isolatedModules": true,
717
- "noEmit": true,
718
- "types": ["vite/client"]
719
- },
720
- "include": ["src"]
725
+ "compilerOptions": {
726
+ "target": "ES2024",
727
+ "lib": ["ES2024", "DOM", "DOM.Iterable"],
728
+ "module": "ESNext",
729
+ "moduleResolution": "bundler",
730
+ "jsx": "react-jsx",
731
+ "strict": true,
732
+ "skipLibCheck": true,
733
+ "esModuleInterop": true,
734
+ "forceConsistentCasingInFileNames": true,
735
+ "resolveJsonModule": true,
736
+ "isolatedModules": true,
737
+ "noEmit": true,
738
+ "types": ["vite/client"]
739
+ },
740
+ "include": ["src"]
721
741
  }
722
742
  `, he = `id: bartender
723
743
  name: "@character.bartender.name"
@@ -1388,189 +1408,190 @@ stages:
1388
1408
  description: "@quest.odd_jobs.stage.talked_to_merchant"
1389
1409
  - id: complete
1390
1410
  description: "@quest.odd_jobs.stage.complete"
1391
- `, Re = `import { useEffect, useState } from "react";
1392
- import { Engine } from "@doodle-engine/core";
1393
- import type { GameState, Snapshot } from "@doodle-engine/core";
1394
- import { GameProvider, useGame } from "@doodle-engine/react";
1411
+ `, Re = `import { useEffect, useState } from 'react';
1412
+ import { Engine } from '@doodle-engine/core';
1413
+ import type { GameState, Snapshot } from '@doodle-engine/core';
1414
+ import { GameProvider, useGame } from '@doodle-engine/react';
1395
1415
 
1396
1416
  export function App() {
1397
- const [game, setGame] = useState<{
1398
- engine: Engine;
1399
- snapshot: Snapshot;
1400
- } | null>(null);
1401
-
1402
- useEffect(() => {
1403
- fetch("/api/content")
1404
- .then((res) => res.json())
1405
- .then((data) => {
1406
- const engine = new Engine(data.registry, createEmptyState());
1407
- const snapshot = engine.newGame(data.config);
1408
- setGame({ engine, snapshot });
1409
- });
1410
- }, []);
1417
+ const [game, setGame] = useState<{
1418
+ engine: Engine;
1419
+ snapshot: Snapshot;
1420
+ } | null>(null);
1421
+
1422
+ useEffect(() => {
1423
+ fetch('/api/content')
1424
+ .then((res) => res.json())
1425
+ .then((data) => {
1426
+ const engine = new Engine(data.registry, createEmptyState());
1427
+ const snapshot = engine.newGame(data.config);
1428
+ setGame({ engine, snapshot });
1429
+ });
1430
+ }, []);
1431
+
1432
+ if (!game) {
1433
+ return (
1434
+ <div className="app-bootstrap">
1435
+ <div className="spinner" />
1436
+ </div>
1437
+ );
1438
+ }
1411
1439
 
1412
- if (!game) {
1413
1440
  return (
1414
- <div className="app-bootstrap">
1415
- <div className="spinner" />
1416
- </div>
1441
+ <GameProvider
1442
+ engine={game.engine}
1443
+ initialSnapshot={game.snapshot}
1444
+ devTools={import.meta.env.DEV}
1445
+ >
1446
+ <GameUI />
1447
+ </GameProvider>
1417
1448
  );
1418
- }
1419
-
1420
- return (
1421
- <GameProvider
1422
- engine={game.engine}
1423
- initialSnapshot={game.snapshot}
1424
- devTools={import.meta.env.DEV}
1425
- >
1426
- <GameUI />
1427
- </GameProvider>
1428
- );
1429
1449
  }
1430
1450
 
1431
1451
  function GameUI() {
1432
- const { snapshot, actions } = useGame();
1433
-
1434
- return (
1435
- <div
1436
- style={{
1437
- padding: "2rem",
1438
- fontFamily: "sans-serif",
1439
- maxWidth: "800px",
1440
- margin: "0 auto",
1441
- }}
1442
- >
1443
- <h1>{snapshot.location.name}</h1>
1444
- <p>{snapshot.location.description}</p>
1445
-
1446
- {snapshot.dialogue && (
1452
+ const { snapshot, actions } = useGame();
1453
+
1454
+ return (
1447
1455
  <div
1448
- style={{
1449
- background: "#f0f0f0",
1450
- padding: "1rem",
1451
- borderRadius: "8px",
1452
- margin: "1rem 0",
1453
- }}
1456
+ style={{
1457
+ padding: '2rem',
1458
+ fontFamily: 'sans-serif',
1459
+ maxWidth: '800px',
1460
+ margin: '0 auto',
1461
+ }}
1454
1462
  >
1455
- <strong>{snapshot.dialogue.speakerName}:</strong>
1456
- <p>{snapshot.dialogue.text}</p>
1457
- {snapshot.choices.map((choice) => (
1458
- <button
1459
- key={choice.id}
1460
- onClick={() => actions.selectChoice(choice.id)}
1461
- style={{
1462
- display: "block",
1463
- margin: "0.5rem 0",
1464
- padding: "0.5rem 1rem",
1465
- cursor: "pointer",
1466
- }}
1467
- >
1468
- {choice.text}
1469
- </button>
1470
- ))}
1471
- </div>
1472
- )}
1473
-
1474
- {!snapshot.dialogue && snapshot.charactersHere.length > 0 && (
1475
- <div>
1476
- <h2>Characters here</h2>
1477
- {snapshot.charactersHere.map((char) => (
1478
- <button
1479
- key={char.id}
1480
- onClick={() => actions.talkTo(char.id)}
1481
- style={{
1482
- display: "block",
1483
- margin: "0.5rem 0",
1484
- padding: "0.5rem 1rem",
1485
- cursor: "pointer",
1486
- }}
1487
- >
1488
- Talk to {char.name}
1489
- </button>
1490
- ))}
1463
+ <h1>{snapshot.location.name}</h1>
1464
+ <p>{snapshot.location.description}</p>
1465
+
1466
+ {snapshot.dialogue && (
1467
+ <div
1468
+ style={{
1469
+ background: '#f0f0f0',
1470
+ padding: '1rem',
1471
+ borderRadius: '8px',
1472
+ margin: '1rem 0',
1473
+ }}
1474
+ >
1475
+ <strong>{snapshot.dialogue.speakerName}:</strong>
1476
+ <p>{snapshot.dialogue.text}</p>
1477
+ {snapshot.choices.map((choice) => (
1478
+ <button
1479
+ key={choice.id}
1480
+ onClick={() => actions.selectChoice(choice.id)}
1481
+ style={{
1482
+ display: 'block',
1483
+ margin: '0.5rem 0',
1484
+ padding: '0.5rem 1rem',
1485
+ cursor: 'pointer',
1486
+ }}
1487
+ >
1488
+ {choice.text}
1489
+ </button>
1490
+ ))}
1491
+ </div>
1492
+ )}
1493
+
1494
+ {!snapshot.dialogue && snapshot.charactersHere.length > 0 && (
1495
+ <div>
1496
+ <h2>Characters here</h2>
1497
+ {snapshot.charactersHere.map((char) => (
1498
+ <button
1499
+ key={char.id}
1500
+ onClick={() => actions.talkTo(char.id)}
1501
+ style={{
1502
+ display: 'block',
1503
+ margin: '0.5rem 0',
1504
+ padding: '0.5rem 1rem',
1505
+ cursor: 'pointer',
1506
+ }}
1507
+ >
1508
+ Talk to {char.name}
1509
+ </button>
1510
+ ))}
1511
+ </div>
1512
+ )}
1491
1513
  </div>
1492
- )}
1493
- </div>
1494
- );
1514
+ );
1495
1515
  }
1496
1516
 
1497
1517
  function createEmptyState(): GameState {
1498
- return {
1499
- currentLocation: "",
1500
- currentTime: { day: 1, hour: 0 },
1501
- flags: {},
1502
- variables: {},
1503
- inventory: [],
1504
- questProgress: {},
1505
- unlockedJournalEntries: [],
1506
- playerNotes: [],
1507
- dialogueState: null,
1508
- characterState: {},
1509
- itemLocations: {},
1510
- mapEnabled: true,
1511
- notifications: [],
1512
- pendingSounds: [],
1513
- pendingVideo: null,
1514
- pendingInterlude: null,
1515
- currentLocale: "en",
1516
- };
1518
+ return {
1519
+ currentLocation: '',
1520
+ currentTime: { day: 1, hour: 0 },
1521
+ flags: {},
1522
+ variables: {},
1523
+ inventory: [],
1524
+ questProgress: {},
1525
+ unlockedJournalEntries: [],
1526
+ playerNotes: [],
1527
+ dialogueState: null,
1528
+ characterState: {},
1529
+ itemLocations: {},
1530
+ mapEnabled: true,
1531
+ notifications: [],
1532
+ pendingSounds: [],
1533
+ pendingVideo: null,
1534
+ pendingInterlude: null,
1535
+ currentLocale: 'en',
1536
+ };
1517
1537
  }
1518
- `, Ae = `import { useEffect, useState } from "react";
1538
+ `, Ae = `import { useEffect, useState } from 'react';
1519
1539
  import type {
1520
- ContentRegistry,
1521
- GameConfig,
1522
- AssetManifest,
1523
- } from "@doodle-engine/core";
1524
- import { GameShell } from "@doodle-engine/react";
1540
+ ContentRegistry,
1541
+ GameConfig,
1542
+ AssetManifest,
1543
+ } from '@doodle-engine/core';
1544
+ import { GameShell } from '@doodle-engine/react';
1525
1545
 
1526
1546
  export function App() {
1527
- const [content, setContent] = useState<{
1528
- registry: ContentRegistry;
1529
- config: GameConfig;
1530
- } | null>(null);
1531
- const [manifest, setManifest] = useState<AssetManifest | null>(null);
1532
-
1533
- useEffect(() => {
1534
- Promise.all([
1535
- fetch("/api/content").then((res) => res.json()),
1536
- fetch("/api/manifest").then((res) => res.json()),
1537
- ]).then(([contentData, manifestData]) => {
1538
- setContent({
1539
- registry: contentData.registry,
1540
- config: contentData.config,
1541
- });
1542
- setManifest(manifestData);
1543
- });
1544
- }, []);
1547
+ const [content, setContent] = useState<{
1548
+ registry: ContentRegistry;
1549
+ config: GameConfig;
1550
+ } | null>(null);
1551
+ const [manifest, setManifest] = useState<AssetManifest | null>(null);
1552
+
1553
+ useEffect(() => {
1554
+ Promise.all([
1555
+ fetch('/api/content').then((res) => res.json()),
1556
+ fetch('/api/manifest').then((res) => res.json()),
1557
+ ]).then(([contentData, manifestData]) => {
1558
+ setContent({
1559
+ registry: contentData.registry,
1560
+ config: contentData.config,
1561
+ });
1562
+ setManifest(manifestData);
1563
+ });
1564
+ }, []);
1565
+
1566
+ // Minimal bootstrap state while fetching manifest/content
1567
+ if (!content || !manifest) {
1568
+ return (
1569
+ <div className="app-bootstrap">
1570
+ <div className="spinner" />
1571
+ </div>
1572
+ );
1573
+ }
1545
1574
 
1546
- // Minimal bootstrap state while fetching manifest/content
1547
- if (!content || !manifest) {
1548
1575
  return (
1549
- <div className="app-bootstrap">
1550
- <div className="spinner" />
1551
- </div>
1576
+ <GameShell
1577
+ registry={content.registry}
1578
+ config={content.config}
1579
+ manifest={manifest}
1580
+ title="My Doodle Game"
1581
+ subtitle="A text-based adventure"
1582
+ availableLocales={[{ code: 'en', label: 'English' }]}
1583
+ devTools={import.meta.env.DEV}
1584
+ />
1552
1585
  );
1553
- }
1554
-
1555
- return (
1556
- <GameShell
1557
- registry={content.registry}
1558
- config={content.config}
1559
- manifest={manifest}
1560
- title="My Doodle Game"
1561
- subtitle="A text-based adventure"
1562
- availableLocales={[{ code: "en", label: "English" }]}
1563
- devTools={import.meta.env.DEV}
1564
- />
1565
- );
1566
1586
  }
1567
1587
  `, Se = `body {
1568
- margin: 0;
1569
- font-family:
1570
- -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu",
1571
- "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
1572
- -webkit-font-smoothing: antialiased;
1573
- -moz-osx-font-smoothing: grayscale;
1588
+ margin: 0;
1589
+ font-family:
1590
+ -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
1591
+ 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
1592
+ sans-serif;
1593
+ -webkit-font-smoothing: antialiased;
1594
+ -moz-osx-font-smoothing: grayscale;
1574
1595
  }
1575
1596
 
1576
1597
  /* ── Theme overrides ──────────────────────────────────────────────── */
@@ -1584,23 +1605,23 @@ export function App() {
1584
1605
  --doodle-accent: #6366f1;
1585
1606
  }
1586
1607
  */
1587
- `, je = `import { StrictMode } from "react";
1588
- import { createRoot } from "react-dom/client";
1589
- import "@doodle-engine/react/style.css";
1590
- import { App } from "./App";
1591
- import "./index.css";
1608
+ `, je = `import { StrictMode } from 'react';
1609
+ import { createRoot } from 'react-dom/client';
1610
+ import '@doodle-engine/react/style.css';
1611
+ import { App } from './App';
1612
+ import './index.css';
1592
1613
 
1593
1614
  // Register service worker in production for offline asset caching
1594
- if ("serviceWorker" in navigator && import.meta.env.PROD) {
1595
- navigator.serviceWorker.register("/sw.js").catch(() => {
1596
- // SW registration failure is non-fatal
1597
- });
1615
+ if ('serviceWorker' in navigator && import.meta.env.PROD) {
1616
+ navigator.serviceWorker.register('/sw.js').catch(() => {
1617
+ // SW registration failure is non-fatal
1618
+ });
1598
1619
  }
1599
1620
 
1600
- createRoot(document.getElementById("root")!).render(
1601
- <StrictMode>
1602
- <App />
1603
- </StrictMode>,
1621
+ createRoot(document.getElementById('root')!).render(
1622
+ <StrictMode>
1623
+ <App />
1624
+ </StrictMode>
1604
1625
  );
1605
1626
  `, D = "🐾", xe = "🐕", H = "🦴", Ge = "✨", $ = "📁", N = "✅", qe = "🚀", x = /* @__PURE__ */ Object.assign({
1606
1627
  "./templates/_root/_gitignore": le,
@@ -1629,8 +1650,8 @@ createRoot(document.getElementById("root")!).render(
1629
1650
  "./templates/src/index.css": Se,
1630
1651
  "./templates/src/main.tsx": je
1631
1652
  });
1632
- function He(n) {
1633
- const o = n.replace("./templates/", "");
1653
+ function He(t) {
1654
+ const o = t.replace("./templates/", "");
1634
1655
  if (o === "src/App.default.tsx" || o === "src/App.custom.tsx")
1635
1656
  return null;
1636
1657
  if (o.startsWith("_root/")) {
@@ -1639,9 +1660,9 @@ function He(n) {
1639
1660
  }
1640
1661
  return o;
1641
1662
  }
1642
- async function $e(n) {
1643
- const o = h(process.cwd(), n);
1644
- console.log(""), console.log(c.bold.magenta(` ${D} Doodle Engine ${D}`)), console.log(c.dim(" Text-based RPG and Adventure Game Scaffolder")), console.log(""), console.log(` ${xe} Creating new game: ${c.bold.cyan(n)}`), console.log("");
1663
+ async function $e(t) {
1664
+ const o = h(process.cwd(), t);
1665
+ console.log(""), console.log(c.bold.magenta(` ${D} Doodle Engine ${D}`)), console.log(c.dim(" Text-based RPG and Adventure Game Scaffolder")), console.log(""), console.log(` ${xe} Creating new game: ${c.bold.cyan(t)}`), console.log("");
1645
1666
  const { useDefaultRenderer: s } = await J({
1646
1667
  type: "confirm",
1647
1668
  name: "useDefaultRenderer",
@@ -1651,13 +1672,13 @@ async function $e(n) {
1651
1672
  s === void 0 && (console.log(
1652
1673
  c.yellow(`
1653
1674
  ${H} No worries, maybe next time! Woof!`)
1654
- ), process.exit(0)), console.log(""), await Me(o, n, s), console.log(""), console.log(c.bold.green(` ${N} Project created successfully!`)), console.log(""), console.log(c.dim(` ${$} ${o}`)), console.log(""), console.log(c.bold(" Next steps:")), console.log(c.cyan(` cd ${n}`)), console.log(
1675
+ ), process.exit(0)), console.log(""), await Me(o, t, s), console.log(""), console.log(c.bold.green(` ${N} Project created successfully!`)), console.log(""), console.log(c.dim(` ${$} ${o}`)), console.log(""), console.log(c.bold(" Next steps:")), console.log(c.cyan(` cd ${t}`)), console.log(
1655
1676
  c.cyan(" npm install ") + c.dim("# or: yarn install / pnpm install")
1656
1677
  ), console.log(
1657
1678
  c.cyan(" npm run dev ") + c.dim("# or: yarn dev / pnpm dev")
1658
1679
  ), console.log(""), console.log(c.dim(` ${qe} Happy game making! ${D}`)), console.log("");
1659
1680
  }
1660
- async function Me(n, o, s) {
1681
+ async function Me(t, o, s) {
1661
1682
  const r = [
1662
1683
  "content/locations",
1663
1684
  "content/characters",
@@ -1679,9 +1700,9 @@ async function Me(n, o, s) {
1679
1700
  ];
1680
1701
  console.log(` ${$} ${c.bold("Creating directories...")}`);
1681
1702
  for (const e of r)
1682
- await T(h(n, e), { recursive: !0 });
1703
+ await T(h(t, e), { recursive: !0 });
1683
1704
  console.log(c.green(` ${N} Directories created`)), console.log("");
1684
- const t = {
1705
+ const n = {
1685
1706
  name: o,
1686
1707
  version: "0.1.0",
1687
1708
  type: "module",
@@ -1706,17 +1727,17 @@ async function Me(n, o, s) {
1706
1727
  }
1707
1728
  };
1708
1729
  console.log(` ${Ge} ${c.bold("Writing project files...")}`), await w(
1709
- h(n, "package.json"),
1710
- JSON.stringify(t, null, 2)
1730
+ h(t, "package.json"),
1731
+ JSON.stringify(n, null, 2)
1711
1732
  );
1712
1733
  for (const [e, i] of Object.entries(x)) {
1713
1734
  const l = He(e);
1714
1735
  if (l === null) continue;
1715
- const d = h(n, l);
1736
+ const d = h(t, l);
1716
1737
  await T(U(d), { recursive: !0 }), await w(d, i);
1717
1738
  }
1718
1739
  const a = s ? "./templates/src/App.default.tsx" : "./templates/src/App.custom.tsx";
1719
- await w(h(n, "src/App.tsx"), x[a]), console.log(c.green(` ${N} Source files created`)), console.log(""), console.log(` ${H} ${c.bold("Starter content written")}`), console.log(""), console.log(c.dim(" Content includes:")), console.log(c.dim(" 2 locations (tavern, market)")), console.log(c.dim(" 2 characters (bartender, merchant)")), console.log(c.dim(" 1 item (old coin)")), console.log(c.dim(" 1 map (town with 2 locations)")), console.log(c.dim(" 1 quest (odd jobs, 3 stages)")), console.log(c.dim(" 3 journal entries")), console.log(
1740
+ await w(h(t, "src/App.tsx"), x[a]), console.log(c.green(` ${N} Source files created`)), console.log(""), console.log(` ${H} ${c.bold("Starter content written")}`), console.log(""), console.log(c.dim(" Content includes:")), console.log(c.dim(" 2 locations (tavern, market)")), console.log(c.dim(" 2 characters (bartender, merchant)")), console.log(c.dim(" 1 item (old coin)")), console.log(c.dim(" 1 map (town with 2 locations)")), console.log(c.dim(" 1 quest (odd jobs, 3 stages)")), console.log(c.dim(" 3 journal entries")), console.log(
1720
1741
  c.dim(" 1 interlude (chapter one, auto-triggers at tavern)")
1721
1742
  ), console.log(
1722
1743
  c.dim(
@@ -1728,11 +1749,11 @@ const v = new M();
1728
1749
  v.name("doodle").description(
1729
1750
  c.magenta("🐾 Doodle Engine") + c.dim(" — Narrative RPG development tools")
1730
1751
  ).version("0.0.1");
1731
- v.command("create <project-name>").description("Scaffold a new Doodle Engine game project").action(async (n) => {
1732
- await $e(n);
1752
+ v.command("create <project-name>").description("Scaffold a new Doodle Engine game project").action(async (t) => {
1753
+ await $e(t);
1733
1754
  });
1734
1755
  v.command("dev").description("Start development server with hot reload").action(async () => {
1735
- await ne();
1756
+ await te();
1736
1757
  });
1737
1758
  v.command("build").description("Build game for production").action(async () => {
1738
1759
  await re();