@maccesar/titools 4.14.0 → 4.16.0

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.
@@ -1,6 +1,6 @@
1
1
  # Setting up a ti.game project
2
2
 
3
- Installing the module, wiring it into Classic and Alloy projects, organizing art and sound, and the lifecycle work the engine does not do for you.
3
+ Installing the module, wiring it into Classic and Alloy projects, organizing art and sound, and the lifecycle work the engine does not do for you. Verified against `ti.game@d587081` (2026-08-28).
4
4
 
5
5
  <!-- TOC-START -->
6
6
  ## Contents
@@ -25,8 +25,8 @@ There is no registry and no `ti module install` command — Titanium modules are
25
25
 
26
26
  ```
27
27
  modules/
28
- ├── android/ti.game/0.4.0/
29
- └── iphone/ti.game/0.4.0/
28
+ ├── android/ti.game/0.5.0/
29
+ └── iphone/ti.game/0.5.0/
30
30
  ```
31
31
 
32
32
  Unzipping the module zip at the project root creates exactly that layout.
@@ -37,14 +37,14 @@ Then declare it in `tiapp.xml`. The iOS platform key is `iphone`, not `ios`:
37
37
 
38
38
  ```xml
39
39
  <modules>
40
- <module platform="android" version="0.4.0">ti.game</module>
41
- <module platform="iphone" version="0.4.0">ti.game</module>
40
+ <module platform="android" version="0.5.0">ti.game</module>
41
+ <module platform="iphone" version="0.5.0">ti.game</module>
42
42
  </modules>
43
43
  ```
44
44
 
45
45
  Pinning `version` is worth the extra attribute: with two module versions installed side by side, an unpinned entry silently picks the highest one.
46
46
 
47
- **The version string does not identify a feature set — the build date does.** The manifest went `0.3.0` → **`0.4.0`** on 2026-08-20, after months of feature landings under the old number, and then kept accepting features without moving again. So both numbers cover several incompatible builds:
47
+ **The version string does not identify a feature set — the build date does.** The manifest went `0.3.0` → **`0.4.0`** on 2026-08-20 and **`0.5.0`** on 2026-08-27, and in between each number kept accepting features without moving. So every one of them covers several incompatible builds:
48
48
 
49
49
  | A build from | Missing, compared to what this skill documents |
50
50
  | --- | --- |
@@ -55,8 +55,11 @@ Pinning `version` is worth the extra attribute: with two module versions install
55
55
  | `0.4.0` built before 2026-08-24 | additionally rocks side to side through a multi-frame animation on a `smoothing: true` grid sheet — the half-texel inset was one-sided, so the end frames came out slightly wider and off-centre |
56
56
  | `0.4.0` built before 2026-08-26 | additionally `sprite.attachTo()` / `detach()` / `attachedTo`, and `gameView.follow()` still aborts the app on Android if it is handed anything that is not a sprite |
57
57
  | `0.4.0` built on 2026-08-26 but before `83b7863` | additionally the opacity an attachment inherits from its target, the `anchor` property, and percentage strings on every ratio — a build in this window has `attachTo` but treats `'55%'` as a number it cannot read |
58
+ | `0.4.0` at its last commit (`b780051`) | additionally everything the `0.5.0` bump carries: `hitboxShape: 'rotatedRect'`, circular solids resolved as circles, `solidMode`, `gravityX`, `linearDamping`, and `restitution` read off both sides of a contact. It also still pulls a swept sprite back to where its frame started when it begins the frame already touching a solid, so a `swept: true` body parked on a slope creeps and then breaks loose as if launched |
59
+ | `0.5.0` built before `d042060` | the performance HUD object form (`debug: { hud, hitbox, hudFont }`) and the `performance` event |
60
+ | `0.5.0` built before `10a046e` | additionally `Game.createTileLayer()`, native visible-cell tile rendering, tile collision/live edits, and TileLayer participation in `findPath` |
58
61
 
59
- The published releases are pre-releases and lag `main`: the newest one is `0.4.0` (2026-08-20). If a call that this skill documents is `undefined` at runtime, check the manifest version *and the build date* before hunting for a typo, and rebuild from upstream `main`. More reliable than either is feature-detecting in code: read the property **before** ever writing it (`typeof sprite.hitboxScaleX === 'undefined'` means the build predates it). Write-then-read always says yes, because an unknown property is stored on the Kroll proxy and reads back exactly as it was set. A method has no such trap — `typeof sprite.attachTo === 'function'` is a clean probe whatever the app did earlier.
62
+ The newest local release tag is still `0.4.0` (2026-08-20), so tagged artifacts lag one manifest bump plus the HUD and TileLayer work that landed after `0.5.0` was introduced. If a documented call is `undefined`, check the manifest and build commit before hunting for a typo, and rebuild from upstream `main`. More reliable than either is feature detection: read a property **before** writing it (`typeof sprite.hitboxScaleX === 'undefined'`) or probe a method/factory (`typeof Game.createTileLayer === 'function'`). Write-then-read is not proof because Kroll can retain an unknown property on the proxy.
60
63
 
61
64
  Building the module from source:
62
65
 
@@ -68,7 +71,7 @@ ti build -p ios --build-only # macOS only → ios/dist/ti.game-iphone-<ve
68
71
 
69
72
  ## Classic projects
70
73
 
71
- `require('ti.game')` anywhere and add the GameView to a window. The 26 demos in the module's `example/` folder are Classic, each one a CommonJS module exporting a start function (`app.js` is the launcher, not a demo):
74
+ `require('ti.game')` anywhere and add the GameView to a window. The 33 demos in the module's `example/` folder are Classic, each one a CommonJS module exporting a start function (`app.js` is the launcher, not a demo):
72
75
 
73
76
  ```javascript
74
77
  // Resources/flappy.js
@@ -269,6 +272,8 @@ The engine handles what it owns: the render loop pauses and resumes with the act
269
272
  A leaked `setInterval` keeps running after the window closes, keeps reading sprite properties from a dead scene and keeps the whole closure alive. A looping `createSound` keeps playing over the next screen.
270
273
 
271
274
  ```javascript
275
+ const levelObjects = []; // keep emitters, ropes, and TileLayers here
276
+
272
277
  function cleanup() {
273
278
  clearInterval(aiTimer);
274
279
  clearTimeout(spawnTimer);
@@ -279,7 +284,10 @@ function cleanup() {
279
284
  target.removeEventListener(eventName, handler);
280
285
  });
281
286
  gameView.pause();
282
- gameView.removeAllSprites();
287
+ gameView.removeAllSprites(); // Sprite/Text only
288
+ levelObjects.forEach((object) => { // emitters, ropes, tile layers
289
+ gameView.remove(object);
290
+ });
283
291
  }
284
292
 
285
293
  // Classic
@@ -300,7 +308,7 @@ function listen(target, eventName, handler) {
300
308
  }
301
309
  ```
302
310
 
303
- For restart-without-teardown (a retry button), `removeAllSprites()` plus rebuilding is simplest, but pooling and repositioning is cheaper: reset positions, zero velocities, `clearTweens()`, and re-`play()` the animations.
311
+ `removeAllSprites()` is named literally: it clears Sprite/Text objects and their attachment state, but leaves emitters, ropes, and tile layers in the scene. Track non-sprite scene objects in `levelObjects` and remove them explicitly. For restart-without-teardown, pooling and repositioning is cheaper than rebuilding: reset positions, zero velocities, `clearTweens()`, and re-`play()` animations.
304
312
 
305
313
  ### GPU textures: `unload()`
306
314
 
@@ -327,7 +335,7 @@ Since 2026-08-23 the module retires the previous generation itself: stale render
327
335
 
328
336
  ## Debugging and tuning
329
337
 
330
- - **`debug: true` on the GameView** draws collision shapes for the whole scene; on a single sprite, only that one. Green = collision AABB with `hitboxScale` and the per-axis `hitboxScaleX`/`hitboxScaleY` applied, blue = sprite/touch bounds (the full drawn frame, which is also the touch area), orange dot = anchor. This is the fastest way to explain a hit that should not have registered.
338
+ - **`debug: true` on the GameView** draws collision shapes for the whole scene; object form separates hitboxes from the performance HUD: `debug: { hitbox: true, hud: 'topRight' }`. On a sprite or TileLayer, `debug` remains a boolean. See [debugging-performance.md](debugging-performance.md) for colors, telemetry payloads, platform-only keys, and a tuning workflow.
331
339
  - **Physics that feels wrong is usually a units problem.** Speeds are px/s and accelerations px/s², both in surface pixels — which is why the demos express them as fractions of `W` and `H`. A gravity of `20` is imperceptible; `H * 2.2` is a snappy platformer.
332
340
  - **Sprite is invisible?** Check in order: was it added to the GameView, does it have a sheet, is `width`/`height` non-zero, is it inside the surface bounds, and is its `zIndex` below a background sprite.
333
341
  - **Collision never fires?** `collisionGroup` goes on the *target*, `collidesWith` on the *mover*. Both need to be set, and `visible: false` disables collision entirely.
@@ -343,4 +351,6 @@ The JS API is identical on Android and iOS. What differs is around it:
343
351
  - **`logicalDensityFactor` lies in the iOS Simulator** — it reports the device scale while the surface renders at 1x. Derive dp→scene units from the surface instead: `H / Ti.Platform.displayCaps.platformHeight`.
344
352
  - **Android's `touchFeedback` ripple** cannot animate over the GL canvas and logs `RippleDrawable` errors; give on-screen buttons manual `backgroundColor` feedback on `touchstart`/`touchend`.
345
353
  - **Sound formats**: WAV, MP3 and OGG on Android; WAV, MP3 and M4A on iOS. WAV for effects, MP3 for music covers both.
354
+ - **TileLayer grid configuration**: assign `legend`, `firstGid`, `cols`, and `rows` in `createTileLayer()`. iOS accepts later writes; Android treats them as creation-time inputs.
355
+ - **Performance telemetry**: `averagePresentMs` and `presentFailures` exist only on iOS and are omitted on Android.
346
356
  - **`theme: 'Theme.Titanium.DayNight.NoTitleBar'`** on the window is the Android idiom for a fullscreen game surface; on iOS use `navBarHidden`/`statusBarHidden` (or the Alloy XML equivalents).