@silkweaver/build 1.3.1 → 1.3.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.
Files changed (33) hide show
  1. package/dist/build.js +16 -6
  2. package/dist/object_format.d.ts +7 -6
  3. package/dist/object_format.js +18 -33
  4. package/dist/templates.js +1 -0
  5. package/package.json +1 -1
  6. package/templates/empty/.engine/engine.mjs +17557 -0
  7. package/templates/empty/.engine/version.json +4 -0
  8. package/templates/empty/project.json +2 -2
  9. package/templates/physics_ball/.engine/engine.mjs +17557 -0
  10. package/templates/physics_ball/.engine/version.json +4 -0
  11. package/templates/physics_ball/objects/obj_ball.ts +24 -0
  12. package/templates/physics_ball/objects/obj_paddle.ts +25 -0
  13. package/templates/physics_ball/objects/obj_tracker.ts +7 -0
  14. package/templates/physics_ball/objects/obj_wall.ts +8 -0
  15. package/templates/physics_ball/project.json +53 -0
  16. package/templates/physics_ball/rooms/room_main/room.json +77 -0
  17. package/templates/physics_ball/sprites/spr_ball/0.png +0 -0
  18. package/templates/physics_ball/sprites/spr_ball/meta.json +22 -0
  19. package/templates/physics_ball/sprites/spr_paddle/0.png +0 -0
  20. package/templates/physics_ball/sprites/spr_paddle/meta.json +17 -0
  21. package/templates/physics_ball/sprites/spr_tracker/0.png +0 -0
  22. package/templates/physics_ball/sprites/spr_tracker/meta.json +22 -0
  23. package/templates/physics_ball/sprites/spr_wall/0.png +0 -0
  24. package/templates/physics_ball/sprites/spr_wall/meta.json +22 -0
  25. package/templates/platformer/.engine/engine.mjs +17557 -0
  26. package/templates/platformer/.engine/version.json +4 -0
  27. package/templates/platformer/objects/obj_platform.ts +0 -2
  28. package/templates/platformer/objects/obj_player.ts +33 -23
  29. package/templates/platformer/project.json +2 -2
  30. package/templates/topdown/.engine/engine.mjs +17557 -0
  31. package/templates/topdown/.engine/version.json +4 -0
  32. package/templates/topdown/objects/obj_player.ts +35 -37
  33. package/templates/topdown/project.json +2 -2
package/dist/build.js CHANGED
@@ -218,10 +218,13 @@ async function generate_entry_code(project_folder, proj, asset_mode, engine_path
218
218
  if ((inst.rotation ?? 0) !== 0)
219
219
  lines.push(` ${v}.image_angle = ${inst.rotation}`);
220
220
  lines.push(` ${v}.register_events()`);
221
- lines.push(` game_loop.register(EVENT_TYPE.create, ${v}.on_create.bind(${v}))`);
222
- // Per-instance creation code runs after the object's Create event (bound: this = instance).
221
+ // Queue the Create event (+ optional per-instance creation code) via the engine helper,
222
+ // which runs them under the active-instance context so `sw`/`inst` resolve inside.
223
223
  if (inst.creation_code && inst.creation_code.trim()) {
224
- lines.push(` game_loop.register(EVENT_TYPE.create, (function(this: any){\n${inst.creation_code}\n}).bind(${v}))`);
224
+ lines.push(` instance_queue_create(${v}, (function(this: any){\n${inst.creation_code}\n}).bind(${v}))`);
225
+ }
226
+ else {
227
+ lines.push(` instance_queue_create(${v})`);
225
228
  }
226
229
  return lines.join('\n');
227
230
  }).filter(Boolean).join('\n');
@@ -277,7 +280,9 @@ async function generate_entry_code(project_folder, proj, asset_mode, engine_path
277
280
  ${var_name}.room_width = ${rm_data.width ?? 640}
278
281
  ${var_name}.room_height = ${rm_data.height ?? 480}
279
282
  ${var_name}.room_speed = ${rm_data.room_speed ?? 60}
280
- ${var_name}.room_persistent = ${rm_data.persistent ?? false}
283
+ ${var_name}.room_persistent = ${rm_data.persistent ?? false}${room_physics[room_name]
284
+ ? `\n${var_name}.physics_world = true\n${var_name}.physics_gravity_x = ${room_physics[room_name].gx}\n${var_name}.physics_gravity_y = ${room_physics[room_name].gy}`
285
+ : ''}
281
286
  ${var_name}.background_show_color = ${rm_data.bg_show_color ?? true}
282
287
  ${var_name}.background_solid_color = ${hex_to_bgr(rm_data.bg_color ?? '#000000')}${rm_data.creation_code && rm_data.creation_code.trim()
283
288
  ? `\n${var_name}.creation_code = () => {\n${rm_data.creation_code}\n}`
@@ -510,7 +515,7 @@ async function _load_sound(name: string, meta_url: string, base: string): Promis
510
515
  // ── Bootstrap ───────────────────────────────────────────────────────────────
511
516
  export default async function init(canvas: HTMLCanvasElement): Promise<void> {
512
517
  renderer.init(canvas, ${proj.settings.windowWidth ?? 640}, ${proj.settings.windowHeight ?? 480})
513
- // Background clear color: ${proj.settings.displayColor ?? '#000000'}
518
+ renderer.set_clear_color(${JSON.stringify(proj.settings.displayColor ?? '#000000')}) // window/clear color (Game Settings)
514
519
  game_loop.init_input(canvas)
515
520
 
516
521
  // Load sprites
@@ -534,6 +539,9 @@ export default async function init(canvas: HTMLCanvasElement): Promise<void> {
534
539
  // Set up rooms
535
540
  ${room_setups.join('\n')}
536
541
 
542
+ // Register rooms by name (room_goto('rm_x') / room_get('rm_x') / room_exists('rm_x'))
543
+ ${room_names.map(n => `room_register_name('${n}', _room_${n})`).join('\n ')}
544
+
537
545
  // Link room order
538
546
  ${room_var_names.map((v, i) => {
539
547
  const prev = room_var_names[i - 1];
@@ -546,7 +554,9 @@ export default async function init(canvas: HTMLCanvasElement): Promise<void> {
546
554
 
547
555
  const start = ${start_var}
548
556
  if (!start) { console.error('[Game] No rooms defined.'); return }
549
- ${room_physics[start_room] ? ` physics_world_create(${room_physics[start_room].gx}, ${room_physics[start_room].gy})\n` : ''} game_loop.start(start)
557
+ // The physics world is (re)created per-room in room.build_for_entry() from the room's
558
+ // physics_world/gravity fields — so it's fresh on every entry AND every restart.
559
+ game_loop.start(start)
550
560
  }
551
561
  `;
552
562
  return entry_code;
@@ -33,13 +33,14 @@ export interface object_model {
33
33
  /** Extracts the object model from a class-file source. */
34
34
  export declare function parse_object(src: string): object_model;
35
35
  /**
36
- * Collects every instance member reachable through `this.` in a class: declared instance fields
37
- * *plus* members created/assigned at runtime inside any event (e.g. `this.velocity = 0` in on_create,
38
- * read in on_step). This drives `this.` autocomplete, so a variable made in one event surfaces in all
39
- * the others matching the usual split of constants on the object, runtime state in Create. Static
40
- * fields and method/event names are excluded (engine members are merged in separately).
36
+ * Collects the object's OWN variables: declared instance fields *plus* members created/assigned at
37
+ * runtime via the `inst.` namespace inside any event (e.g. `inst.velocity = 0` in on_create, read in
38
+ * on_step). This drives `inst.` autocomplete, so a variable made in one event surfaces in all the
39
+ * others. Static fields (object metadata) and method/event names are excluded. The engine's built-in
40
+ * instance API is NOT collected here — it lives on `sw.` and is typed from the engine directly so
41
+ * `this.x`/`sw.x` style writes never leak into the author's own-variable list.
41
42
  */
42
- export declare function this_members(src: string): string[];
43
+ export declare function object_vars(src: string): string[];
43
44
  /**
44
45
  * Sets (adds or updates) a static metadata field. `expr` is the raw initializer
45
46
  * text (e.g. `'spr_player'`, `true`, `-5`, `obj_base`).
@@ -46,7 +46,7 @@ var __importStar = (this && this.__importStar) || (function () {
46
46
  Object.defineProperty(exports, "__esModule", { value: true });
47
47
  exports.EVENT_ORDER = exports.META_ORDER = void 0;
48
48
  exports.parse_object = parse_object;
49
- exports.this_members = this_members;
49
+ exports.object_vars = object_vars;
50
50
  exports.set_static = set_static;
51
51
  exports.remove_static = remove_static;
52
52
  exports.set_field = set_field;
@@ -63,19 +63,6 @@ exports.META_ORDER = [
63
63
  'sprite', 'parent', 'solid', 'visible', 'persistent', 'depth',
64
64
  'physics', 'physics_shape', 'physics_density', 'physics_restitution', 'physics_friction', 'physics_sensor',
65
65
  ];
66
- /**
67
- * Explicit type annotations for static fields whose base-class type is narrower than what TypeScript
68
- * would infer from the literal initializer. Without this, `static physics_shape = 'box'` widens to
69
- * `string`, which doesn't satisfy the base's `'box' | 'circle'` and the subclass fails to compile.
70
- */
71
- const META_TYPES = {
72
- physics_shape: `'box' | 'circle'`,
73
- };
74
- /** Renders a `static <name>[: <type>] = <expr>;` declaration, adding an annotation where one is needed. */
75
- function _static_decl(name, expr) {
76
- const ann = META_TYPES[name];
77
- return `static ${name}${ann ? `: ${ann}` : ''} = ${expr};`;
78
- }
79
66
  /** Canonical GMS-style order of `on_*` event methods (used to keep events ordered in code). */
80
67
  exports.EVENT_ORDER = [
81
68
  'on_create', 'on_destroy',
@@ -164,13 +151,14 @@ function _string_literal(node) {
164
151
  return null;
165
152
  }
166
153
  /**
167
- * Collects every instance member reachable through `this.` in a class: declared instance fields
168
- * *plus* members created/assigned at runtime inside any event (e.g. `this.velocity = 0` in on_create,
169
- * read in on_step). This drives `this.` autocomplete, so a variable made in one event surfaces in all
170
- * the others matching the usual split of constants on the object, runtime state in Create. Static
171
- * fields and method/event names are excluded (engine members are merged in separately).
154
+ * Collects the object's OWN variables: declared instance fields *plus* members created/assigned at
155
+ * runtime via the `inst.` namespace inside any event (e.g. `inst.velocity = 0` in on_create, read in
156
+ * on_step). This drives `inst.` autocomplete, so a variable made in one event surfaces in all the
157
+ * others. Static fields (object metadata) and method/event names are excluded. The engine's built-in
158
+ * instance API is NOT collected here — it lives on `sw.` and is typed from the engine directly so
159
+ * `this.x`/`sw.x` style writes never leak into the author's own-variable list.
172
160
  */
173
- function this_members(src) {
161
+ function object_vars(src) {
174
162
  const sf = _source(src);
175
163
  const cls = _find_class(sf);
176
164
  if (!cls)
@@ -183,14 +171,14 @@ function this_members(src) {
183
171
  names.add(n);
184
172
  }
185
173
  }
186
- // Any `this.<name> = …` (or compound assignment) anywhere in the class body — including nested
187
- // blocks/closures — counts as an instance member the user can reference elsewhere.
174
+ // Any `inst.<name> = …` (or compound assignment) anywhere in the class body — including nested
175
+ // blocks/closures — counts as an author variable the user can reference elsewhere.
188
176
  const visit = (node) => {
189
177
  if (ts.isBinaryExpression(node)
190
178
  && node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment
191
179
  && node.operatorToken.kind <= ts.SyntaxKind.LastAssignment
192
180
  && ts.isPropertyAccessExpression(node.left)
193
- && node.left.expression.kind === ts.SyntaxKind.ThisKeyword
181
+ && ts.isIdentifier(node.left.expression) && node.left.expression.text === 'inst'
194
182
  && ts.isIdentifier(node.left.name)) {
195
183
  names.add(node.left.name.text);
196
184
  }
@@ -239,19 +227,16 @@ function set_static(src, name, expr) {
239
227
  if (!cls)
240
228
  return src;
241
229
  const existing = _find_member(cls, m => ts.isPropertyDeclaration(m) && _is_static(m) && _name_of(m) === name);
230
+ if (existing?.initializer) {
231
+ return _apply(src, { start: existing.initializer.getStart(sf), end: existing.initializer.getEnd(), text: expr });
232
+ }
242
233
  if (existing) {
243
- // For annotated fields (e.g. physics_shape) replace the whole member so the type annotation is
244
- // always present/correct updating just the initializer could leave it un-annotated (→ widens
245
- // to string and fails to compile). For plain fields, the cheaper initializer-only edit is fine.
246
- if (META_TYPES[name])
247
- return _apply(src, { start: existing.getStart(sf), end: existing.getEnd(), text: _static_decl(name, expr) });
248
- if (existing.initializer)
249
- return _apply(src, { start: existing.initializer.getStart(sf), end: existing.initializer.getEnd(), text: expr });
250
- return _apply(src, { start: existing.getStart(sf), end: existing.getEnd(), text: _static_decl(name, expr) });
234
+ // declared without initializer replace the whole member
235
+ return _apply(src, { start: existing.getStart(sf), end: existing.getEnd(), text: `static ${name} = ${expr};` });
251
236
  }
252
237
  // New static: metadata lives at the TOP, ordered by META_ORDER. Insert before the first static
253
238
  // that sorts after it; else before the first non-static member (so statics stay grouped up top).
254
- const stub = ` ${_static_decl(name, expr)}\n`;
239
+ const stub = ` static ${name} = ${expr};\n`;
255
240
  const order = exports.META_ORDER.indexOf(name);
256
241
  if (order >= 0) {
257
242
  const after = cls.members.find(m => {
@@ -584,7 +569,7 @@ function scaffold_object(class_name, kind = 'normal') {
584
569
  if (kind === 'physics') {
585
570
  return `export class ${class_name} extends gm_object {
586
571
  static physics = true;
587
- static physics_shape: 'box' | 'circle' = 'box';
572
+ static physics_shape = 'box';
588
573
  static physics_density = 0.5;
589
574
  static physics_restitution = 0.1;
590
575
  static physics_friction = 0.2;
package/dist/templates.js CHANGED
@@ -51,6 +51,7 @@ const TEMPLATE_REGISTRY = [
51
51
  { id: 'empty', label: 'Empty', description: 'A blank project with a single empty room.' },
52
52
  { id: 'platformer', label: 'Platformer', description: 'A/D to move, Space to jump — gravity, solid platforms, parent-based collision.' },
53
53
  { id: 'topdown', label: 'Top-down', description: 'WASD movement with parent-based wall collision (place_meeting + a _col parent).' },
54
+ { id: 'physics_ball', label: 'Physics Ball', description: 'Bounce a ball on a mouse paddle for score — matter.js physics (circle/box bodies, restitution, instance_nearest).' },
54
55
  ];
55
56
  /** Absolute path to the bundled templates directory (sibling of dist/). */
56
57
  function templates_dir() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@silkweaver/build",
3
- "version": "1.3.1",
3
+ "version": "1.3.3",
4
4
  "description": "Silkweaver toolchain — compiles a project folder into a runnable game (HTML5 / desktop executable). Usable from a CLI or the IDE.",
5
5
  "type": "commonjs",
6
6
  "license": "GPL-3.0",