@maccesar/titools 4.6.1 → 4.7.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.
- package/README.md +44 -8
- package/commands/ti-audit.md +1 -0
- package/commands/ti-check.md +3 -2
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/skills/ti-game/SKILL.md +179 -0
- package/skills/ti-game/references/api.md +333 -0
- package/skills/ti-game/references/project-setup.md +280 -0
- package/skills/ti-game/references/recipes.md +1220 -0
- package/skills/ti-game/references/roadmap.md +55 -0
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
</div>
|
|
8
8
|
|
|
9
|
-
TiTools is a Titanium SDK toolkit for AI coding assistants. It ships
|
|
9
|
+
TiTools is a Titanium SDK toolkit for AI coding assistants. It ships 9 skills — 4 opinionated (`ti-expert`, `purgetss`, `ti-ui`, `ti-game`) plus 5 documentation-mirror skills (`ti-api`, `ti-guides`, `ti-howtos`, `alloy-guides`, `alloy-howtos`) — a research agent, and reference files covering Titanium architecture, API reference, native how-tos, Alloy MVC, PurgeTSS styling, UI/UX patterns, and 2D game development with the `ti.game` module.
|
|
10
10
|
|
|
11
11
|
The reference files are maintained against official documentation whenever an official source exists, so the assistant can retrieve current framework behavior instead of guessing from generic training data.
|
|
12
12
|
|
|
@@ -36,9 +36,9 @@ The fastest way to get started with Claude Code. One command to add the marketpl
|
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
What you get:
|
|
39
|
-
- All
|
|
39
|
+
- All 9 TiTools skills (`ti-expert`, `purgetss`, `ti-ui`, `ti-game`, `ti-api`, `ti-guides`, `ti-howtos`, `alloy-guides`, `alloy-howtos`)
|
|
40
40
|
- ti-pro research agent
|
|
41
|
-
- Session hook that auto-detects Titanium projects (`tiapp.xml`, Alloy, PurgeTSS)
|
|
41
|
+
- Session hook that auto-detects Titanium projects (`tiapp.xml`, Alloy, PurgeTSS, `ti.game`)
|
|
42
42
|
- Slash commands: `/ti-check`, `/ti-new-screen`, `/ti-audit`
|
|
43
43
|
- Auto-updates via marketplace (opt-in — see note below)
|
|
44
44
|
|
|
@@ -70,7 +70,7 @@ claude # or gemini, or codex
|
|
|
70
70
|
```
|
|
71
71
|
|
|
72
72
|
What gets installed:
|
|
73
|
-
- The
|
|
73
|
+
- The 9 TiTools skills to `~/.agents/skills/`
|
|
74
74
|
- ti-pro agent for Claude Code
|
|
75
75
|
- Platform symlinks for Claude Code (Gemini CLI and Codex CLI auto-discover from `~/.agents/skills/` — no symlinks needed)
|
|
76
76
|
- Knowledge index in your project's `AGENTS.md`/`CLAUDE.md`/`GEMINI.md`
|
|
@@ -91,7 +91,7 @@ Why NPM?
|
|
|
91
91
|
| **Knowledge Index** | Not included | Included (`titools sync`) |
|
|
92
92
|
| **Auto-updates** | Marketplace (opt-in, enable in `/plugin`) | SessionStart hook (daily) |
|
|
93
93
|
| **Slash commands** | `/ti-check`, `/ti-new-screen`, `/ti-audit` | Same three (`~/.claude/commands/`) |
|
|
94
|
-
| **Session hook** | Auto-detects Titanium projects
|
|
94
|
+
| **Session hook** | Auto-detects Titanium projects (Alloy/Classic, PurgeTSS, `ti.game`) | Auto-update only |
|
|
95
95
|
|
|
96
96
|
Having both installed is fine: the CLI detects an enabled marketplace plugin and skips its own skill symlinks and command copies, so nothing shows up twice. `titools doctor` reports which channel is serving Claude Code.
|
|
97
97
|
|
|
@@ -177,6 +177,7 @@ The knowledge index is based on the latest Titanium SDK documentation. If your p
|
|
|
177
177
|
| ti-expert | Architecture and implementation | Starting point for most tasks |
|
|
178
178
|
| purgetss | Utility-first styling | UI styling and animations |
|
|
179
179
|
| ti-ui | UI/UX patterns | Complex layouts, ListViews, platform UI |
|
|
180
|
+
| ti-game | 2D games with the `ti.game` module | Sprites, physics, collisions, particles, camera |
|
|
180
181
|
| ti-api | Complete Titanium API reference | Looking up properties, methods, events |
|
|
181
182
|
| ti-guides | SDK fundamentals | tiapp.xml, Hyperloop, distribution, JDK/Xcode compatibility, release notes |
|
|
182
183
|
| ti-howtos | Native feature integration | Location, push, media, platform APIs |
|
|
@@ -184,7 +185,8 @@ The knowledge index is based on the latest Titanium SDK documentation. If your p
|
|
|
184
185
|
| alloy-howtos | Alloy CLI, configuration, debugging | alloy.jmk, config.json, custom XML tags |
|
|
185
186
|
|
|
186
187
|
Notes:
|
|
187
|
-
- The first
|
|
188
|
+
- The first four (`ti-expert`, `purgetss`, `ti-ui`, `ti-game`) are opinionated workflow skills reflecting TiTools' Titanium conventions.
|
|
189
|
+
- `ti-game` documents the `ti.game` native module (2D sprite engine on OpenGL ES 2.0, Android and iOS). Its API reference was verified against the module source; it applies to Alloy and Classic projects alike and does not depend on PurgeTSS.
|
|
188
190
|
- The latter five are documentation-mirror skills sourced from the official Titanium SDK docs (`tidev/titanium-docs`) and audited against them via the internal `titools-skill-auditor`.
|
|
189
191
|
- `purgetss` reference files are audited against the official PurgeTSS documentation, but its workflow conventions are opinionated.
|
|
190
192
|
|
|
@@ -254,9 +256,11 @@ These commands automatically invoke the relevant skills:
|
|
|
254
256
|
The plugin includes a session start hook that auto-detects Titanium projects. When you open Claude Code in a directory with `tiapp.xml`, it automatically reports:
|
|
255
257
|
|
|
256
258
|
```
|
|
257
|
-
Titanium Alloy + PurgeTSS project detected. TiTools skills are available and MUST be used...
|
|
259
|
+
Titanium Alloy + PurgeTSS + ti.game project detected. TiTools skills are available and MUST be used...
|
|
258
260
|
```
|
|
259
261
|
|
|
262
|
+
It reports Alloy vs Classic, whether PurgeTSS is configured, and whether the project declares the `ti.game` module — a game project also gets a line pointing at the `ti-game` skill.
|
|
263
|
+
|
|
260
264
|
This ensures Claude knows it's a Titanium project from the first prompt, preventing it from writing generic code.
|
|
261
265
|
|
|
262
266
|
---
|
|
@@ -285,6 +289,7 @@ All skills include automatic project detection to ensure compatibility:
|
|
|
285
289
|
| purgetss | PurgeTSS installation | Checks for `purgetss/` folder, `config.cjs`, `utilities.tss` |
|
|
286
290
|
| ti-expert | Alloy vs Classic | Checks for `app/` (Alloy) vs `Resources/` (Classic) structure |
|
|
287
291
|
| ti-ui | Titanium projects | Checks for `tiapp.xml` (both Alloy and Classic) |
|
|
292
|
+
| ti-game | ti.game module | Checks for `<module>ti.game</module>` in `tiapp.xml` or `require('ti.game')` |
|
|
288
293
|
|
|
289
294
|
Why this matters:
|
|
290
295
|
- PurgeTSS suggestions are only provided if PurgeTSS is installed
|
|
@@ -422,6 +427,37 @@ Key rules:
|
|
|
422
427
|
|
|
423
428
|
---
|
|
424
429
|
|
|
430
|
+
### ti-game
|
|
431
|
+
|
|
432
|
+
2D game development with the `ti.game` native module — a sprite engine rendered with OpenGL ES 2.0, same JS API on Android and iOS. Works in Alloy and Classic projects.
|
|
433
|
+
|
|
434
|
+
When it activates:
|
|
435
|
+
- `tiapp.xml` declares `ti.game`, or any file calls `require('ti.game')`
|
|
436
|
+
- Sprites, sprite sheets, TexturePacker atlases, frame animations, native tweens
|
|
437
|
+
- Physics: gravity and velocity, solid platforms, one-way floors, bouncing, the arcade car model, Newtonian thrust
|
|
438
|
+
- Collision groups, invisible trigger zones, hitbox tuning
|
|
439
|
+
- Particle emitters, Verlet ropes, camera follow/zoom/shake/effects, low-latency sound
|
|
440
|
+
- Drag & drop, pinch, rotate, multitouch controls
|
|
441
|
+
|
|
442
|
+
Example prompts:
|
|
443
|
+
```
|
|
444
|
+
"Build a flappy-bird style game with ti.game."
|
|
445
|
+
"My sprites won't collide — collisionGroup is set on both."
|
|
446
|
+
"Add a camera that follows the player with a dead zone."
|
|
447
|
+
"How do I make a top-down racer that drifts?"
|
|
448
|
+
"Why does my game stutter when I move sprites from setInterval?"
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
Key rules:
|
|
452
|
+
- JS describes the scene and reacts to events; the engine runs every frame. Never move a sprite from a timer — use velocity, gravity, a tween, `carMode` or `thrust`
|
|
453
|
+
- Build the level inside a guarded `resize` handler, never from `Ti.Platform.displayCaps`
|
|
454
|
+
- `solidWith` blocks, `collidesWith` reports — they are independent
|
|
455
|
+
- A sprite with size but no sheet is an invisible trigger (scores, goals, walls)
|
|
456
|
+
- Add a whole level with one `gameView.add([...])` call
|
|
457
|
+
- There is no text in the engine: HUDs are `Ti.UI.Label` overlays
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
425
461
|
## Usage examples and best practices
|
|
426
462
|
|
|
427
463
|
### Example prompts
|
|
@@ -517,7 +553,7 @@ Behavior depends on where you run it:
|
|
|
517
553
|
| With `--local` flag | Installs skills locally to `./.agents/skills/` in the current project |
|
|
518
554
|
|
|
519
555
|
What it does:
|
|
520
|
-
- Installs the
|
|
556
|
+
- Installs the 9 TiTools skills (global or local depending on context)
|
|
521
557
|
- Installs ti-pro agent for Claude Code
|
|
522
558
|
- Installs the `/ti-check`, `/ti-new-screen` and `/ti-audit` slash commands into `~/.claude/commands/`
|
|
523
559
|
- Detects installed AI platforms and lets you choose which to link (only Claude Code needs platform symlinks; Gemini CLI and Codex CLI auto-discover from `~/.agents/skills/`)
|
package/commands/ti-audit.md
CHANGED
|
@@ -9,5 +9,6 @@ Audit the current Titanium project by invoking the relevant TiTools skills:
|
|
|
9
9
|
2. Invoke `ti-ui` — check for UI anti-patterns (Ti.UI.SIZE in ListViews, WebView inside TableView, missing accessibility)
|
|
10
10
|
3. If PurgeTSS project, invoke `purgetss` — check for custom TSS that should be utility classes, unsupported classes, padding on Views
|
|
11
11
|
4. Invoke `alloy-guides` — check for proper Alloy patterns (model usage, widget structure)
|
|
12
|
+
5. If the project declares `ti.game`, invoke `ti-game` — check for sprites moved from timers instead of native properties, levels sized from `Ti.Platform.displayCaps` instead of the `resize` event, sprites added one by one instead of in one array, and timers or sounds left running when the window closes
|
|
12
13
|
|
|
13
14
|
Report findings grouped by severity: critical, warning, info.
|
package/commands/ti-check.md
CHANGED
|
@@ -8,8 +8,9 @@ Check the current Titanium project and report:
|
|
|
8
8
|
1. Read `tiapp.xml` — report SDK version, app ID, deployment targets
|
|
9
9
|
2. Check if Alloy project (app/views + app/controllers exist)
|
|
10
10
|
3. Check if PurgeTSS is configured (purgetss/config.cjs exists)
|
|
11
|
-
4. Check
|
|
11
|
+
4. Check whether the `ti.game` module is declared in `tiapp.xml` — report its version and whether the module is actually present under `modules/<platform>/ti.game/<version>/` or installed globally
|
|
12
|
+
5. Check for common issues:
|
|
12
13
|
- Missing icon files (DefaultIcon.png)
|
|
13
14
|
- Empty modules section in tiapp.xml
|
|
14
15
|
- Outdated SDK version
|
|
15
|
-
|
|
16
|
+
6. Report a summary of findings
|
package/lib/config.js
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ti-game
|
|
3
|
+
description: "Use when building or reviewing 2D games with the ti.game module for Titanium SDK (Android and iOS) — sprites, sprite sheets, frame animations, tweens, physics (gravity, solid platforms, carMode drifting, thrust), collision groups, particles, Verlet ropes, camera follow/zoom/shake, low-latency sound, drag & drop, multitouch. AUTO-DETECT: if tiapp.xml declares ti.game or any file calls require('ti.game'), invoke BEFORE writing ANY game code. Also trigger on: game, juego, sprite, spritesheet, platformer, endless runner, top-down, shooter, racer, flappy, breakout, rhythm game, card game, puzzle, collision, hitbox, parallax, particles, game loop, 60 fps, GameView. ti.game is NOT Phaser, Godot or Box2D: you never write a game loop, never move a sprite from setInterval, and several familiar features (bitmap text, tilemap layer, sprite parenting, raycast) do not exist yet — check references/roadmap.md before inventing an API."
|
|
4
|
+
argument-hint: "[genre or feature]"
|
|
5
|
+
allowed-tools: Read, Grep, Glob, Edit, Write, Bash(node *)
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# ti.game — 2D game engine for Titanium SDK
|
|
9
|
+
|
|
10
|
+
`ti.game` is a native OpenGL ES 2.0 sprite engine exposed to JavaScript, written and maintained by **Michael Gangolf (m1ga)** — upstream is https://github.com/m1ga/ti.game. This skill was written against version 0.3.0 as it stands in the `macCesar/ti.game` contribution fork; when upstream and the fork disagree, upstream wins. Same JS API on Android and iOS — the iOS side is a class-per-class Obj-C twin of the Android engine.
|
|
11
|
+
|
|
12
|
+
Works in **both Classic and Alloy** projects. Nothing here depends on PurgeTSS.
|
|
13
|
+
|
|
14
|
+
## The one rule everything follows
|
|
15
|
+
|
|
16
|
+
**JS describes the scene and reacts to events. The engine runs every frame.**
|
|
17
|
+
|
|
18
|
+
The Kroll bridge (JS ↔ native) is far too slow for per-frame work, so the API is a *scene description*: setting `sprite.x`, `sprite.velocityY` or `car.throttle` writes a volatile field the render thread reads on the next tick. Events flow back only when something discrete happens — `tap`, `collision`, `land`, `complete`. Nothing fires per frame by design.
|
|
19
|
+
|
|
20
|
+
The practical consequence, and the single biggest mistake to avoid:
|
|
21
|
+
|
|
22
|
+
> If you are about to move a sprite from a `setInterval` or a `requestAnimationFrame`, stop and find the native property that does it. Coarse timers for *decisions* (an AI picking a direction every 80–150 ms, an autofire cadence, a spawn schedule) are fine and the official demos use them. Timers for *motion* are not.
|
|
23
|
+
|
|
24
|
+
| You want | Do NOT write | Use |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| A sprite that falls | `setInterval(() => s.y += 5)` | `s.gravity = 2000` |
|
|
27
|
+
| A sprite that moves at constant speed | timer updating `x` | `s.velocityX = 300` |
|
|
28
|
+
| Move from A to B over time | manual easing loop | `s.animate({ x, y, duration, easing })` |
|
|
29
|
+
| A car that drives and drifts | your own physics | `carMode: true` + `throttle`/`steering` |
|
|
30
|
+
| A ship with inertia | vector math per frame | `thrust` + `angularVelocity` |
|
|
31
|
+
| Drag a sprite with the finger | `touchmove` handler | `draggable: true` |
|
|
32
|
+
| Scrolling background | timer repositioning copies | `wrapX` / `wrapShift` + `velocityX` |
|
|
33
|
+
| Camera that follows the player | timer writing `cameraX` | `gameView.follow(sprite, options)` |
|
|
34
|
+
| Smoke, sparks, explosions | pooled sprites in JS | `Game.createEmitter(...)` |
|
|
35
|
+
| A swinging chain or cape | verlet solver in JS | `Game.createRope(...)` |
|
|
36
|
+
| Slow motion or a pause that still draws | pausing your own timers | `gameView.timeScale = 0.5` / `0` |
|
|
37
|
+
|
|
38
|
+
## Minimal scene
|
|
39
|
+
|
|
40
|
+
```javascript
|
|
41
|
+
const Game = require('ti.game');
|
|
42
|
+
|
|
43
|
+
const win = Ti.UI.createWindow({
|
|
44
|
+
backgroundColor: '#000',
|
|
45
|
+
navBarHidden: true, // iOS: no nav bar
|
|
46
|
+
theme: 'Theme.Titanium.DayNight.NoTitleBar' // Android: no title bar
|
|
47
|
+
});
|
|
48
|
+
const gameView = Game.createGameView({ backgroundColor: '#8ed8f8' });
|
|
49
|
+
|
|
50
|
+
const sheet = Game.createSpriteSheet({
|
|
51
|
+
image: 'assets/hero.png',
|
|
52
|
+
frameWidth: 32,
|
|
53
|
+
frameHeight: 48,
|
|
54
|
+
smoothing: false // nearest-neighbor — crisp pixel art
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
let initialized = false;
|
|
58
|
+
gameView.addEventListener('resize', (e) => {
|
|
59
|
+
if (initialized) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
initialized = true;
|
|
63
|
+
buildLevel(e.width, e.height);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
function buildLevel(W, H) {
|
|
67
|
+
const hero = Game.createSprite({
|
|
68
|
+
sheet: sheet,
|
|
69
|
+
x: W / 2,
|
|
70
|
+
y: H / 2,
|
|
71
|
+
width: 96,
|
|
72
|
+
height: 144,
|
|
73
|
+
animations: {
|
|
74
|
+
idle: { frames: [0], fps: 1, loop: true },
|
|
75
|
+
walk: { frames: [1, 2], fps: 6, loop: true }
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
hero.play('idle');
|
|
79
|
+
gameView.add(hero);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
win.add(gameView);
|
|
83
|
+
win.open();
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Build the level on `resize`, never from `displayCaps`
|
|
87
|
+
|
|
88
|
+
`Ti.Platform.displayCaps` includes the system bars and reports **points** on iOS, while the scene lives in surface **pixels**. Sizing a level from it puts bottom-anchored sprites below the visible area. The GameView fires `resize` with the real surface size — that is the coordinate space. The guard flag matters: `resize` fires again on rotation and on some lifecycle transitions, and rebuilding the level there would duplicate every sprite.
|
|
89
|
+
|
|
90
|
+
When you genuinely need dp→scene units (to keep a floor above 80dp on-screen buttons), measure the surface rather than trusting the density factor, because the iOS Simulator renders at 1x while still reporting the device scale:
|
|
91
|
+
|
|
92
|
+
```javascript
|
|
93
|
+
const density = Ti.Platform.osname === 'android'
|
|
94
|
+
? Ti.Platform.displayCaps.logicalDensityFactor
|
|
95
|
+
: H / Ti.Platform.displayCaps.platformHeight;
|
|
96
|
+
const buttonZone = Math.round(130 * density);
|
|
97
|
+
const groundTop = H - buttonZone;
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Coordinates
|
|
101
|
+
|
|
102
|
+
Top-left origin, y-down, surface pixels. Touch coordinates map 1:1. `(x, y)` is the sprite's **anchor** (default `0.5/0.5` = center, so `y` is the middle of the sprite, not its top). Rotation in degrees, positive clockwise. All JS durations are milliseconds.
|
|
103
|
+
|
|
104
|
+
## Pick a movement model
|
|
105
|
+
|
|
106
|
+
| Model | Properties | Fits |
|
|
107
|
+
| --- | --- | --- |
|
|
108
|
+
| Plain velocity | `velocityX/Y` (px/s), `gravity` (px/s²) | Flappy, projectiles, falling objects, notes |
|
|
109
|
+
| Platformer | velocity + `solidWith`, read-only `onGround`, `land` event | Mario-style run & jump |
|
|
110
|
+
| Bouncing body | `restitution` (0..1) on top of `solidWith` | Balls, pinball, breakout |
|
|
111
|
+
| Car | `carMode: true`, `throttle`, `steering` (-1..1) | Top-down racer with emergent drift |
|
|
112
|
+
| Newtonian flight | `thrust` (px/s² along heading), `angularVelocity` (deg/s), `maxSpeed` | Asteroids, lunar lander |
|
|
113
|
+
| Tween | `animate({ x, y, duration, easing })` | Point-and-click walking, UI cards, patrols |
|
|
114
|
+
|
|
115
|
+
Gravity is per sprite, not global — set it on each body that should fall. A sprite with no `gravity` and no velocity simply stays put.
|
|
116
|
+
|
|
117
|
+
## Block versus react: `solidWith` and `collidesWith` are independent
|
|
118
|
+
|
|
119
|
+
- `solidWith: ['ground']` **blocks** movement against sprites tagged `collisionGroup: 'ground'`. The engine pushes the sprite out along the axis of least penetration, sets read-only `onGround` and fires `land`.
|
|
120
|
+
- `collidesWith: ['coin', 'enemy']` **reports** overlap. Fires `collision` once per overlap-enter (payload `group`, `other`, `x`, `y`), re-arming after separation. Nothing is blocked.
|
|
121
|
+
|
|
122
|
+
A sprite can use both — a player that stands on platforms (`solidWith`) and dies on spikes (`collidesWith`).
|
|
123
|
+
|
|
124
|
+
**A sprite with `width`/`height` but no `sheet` renders nothing and works as an invisible trigger.** Score zones, goals, checkpoints, ceilings, kill floors and walls are all built this way in the official demos. This is the idiomatic way to add logic to a scene without art.
|
|
125
|
+
|
|
126
|
+
Tune fairness with `hitboxScale` (art rarely fills its frame; slightly small hitboxes feel better) and `hitboxShape: 'circle'` for balls and rocks — circles also resolve against solids along the contact normal, so they bounce off corners diagonally instead of like a box. Turn on `debug: true` per sprite, or on the GameView for everything, to see green collision AABBs, blue touch bounds and the orange anchor dot.
|
|
127
|
+
|
|
128
|
+
## Performance rules that actually matter
|
|
129
|
+
|
|
130
|
+
- **One texture = one draw call.** The batcher accumulates up to 1000 quads and flushes on texture switch. A scene whose sprites all share one sheet renders in a single draw call regardless of sprite count. Pack art into as few sheets as possible; reuse one white particle texture and tint it at runtime.
|
|
131
|
+
- **Bulk-add a level.** `gameView.add([spriteA, spriteB, emitter, rope])` crosses the bridge once and commits under one scene lock. Collect a level's objects in an array and add them in one call; `add(object)` still works for single objects.
|
|
132
|
+
- **Keep collision group lists targeted.** Cost is O(colliders × candidates) per frame. A bullet checking `['asteroid']` tests 5 sprites, not the whole scene.
|
|
133
|
+
- **Pool, don't create.** Bullets, notes, obstacles and enemies are created once (usually 3–10 of them), then recycled by setting `visible = false` and zeroing velocity. Creating sprites mid-game costs a bridge hop and a scene lock.
|
|
134
|
+
- **Read properties in handlers, not in loops.** `ball.x` is a synchronous snapshot of the live native value — perfect inside a `collision` handler or an 80 ms AI tick, wasteful in a tight loop.
|
|
135
|
+
- **`maxFps: 60`** on the GameView keeps 120 Hz ProMotion displays from doubling render work. `0` (default) follows the display refresh rate.
|
|
136
|
+
- **Judge performance on device.** The iOS Simulator's OpenGL translation layer is disproportionately slow and renders at a 1x drawable; real devices keep native screen scale and run far smoother.
|
|
137
|
+
|
|
138
|
+
## There is no text in the engine
|
|
139
|
+
|
|
140
|
+
The engine draws sprites, particles and ropes — **not text**. HUDs, scores and labels are ordinary `Ti.UI.Label` views overlaid on the window, on top of the GameView. That is how every official demo does it. Consequences worth knowing before designing a HUD: overlaid Titanium views are screen-fixed, so they do not scroll with the camera, do not z-sort against sprites and cannot be tweened by the engine. Bitmap-font text sprites are planned but do not exist — see [roadmap.md](references/roadmap.md).
|
|
141
|
+
|
|
142
|
+
Standard Titanium touch events do not reach the GameView, but ordinary Titanium buttons and views layered on top work normally, and sibling views receive simultaneous pointers — which is how the demos build multitouch d-pads (hold ▶ and press jump at the same time). One caveat from the demos: Android's `touchFeedback` ripple cannot animate over this canvas and spams `RippleDrawable` errors, so on-screen buttons set their own `backgroundColor` on `touchstart`/`touchend`.
|
|
143
|
+
|
|
144
|
+
## Clean up what you created
|
|
145
|
+
|
|
146
|
+
The render loop follows the activity lifecycle automatically, but **your timers and sounds do not**. Every demo that starts an interval or plays looping music stops it on window close. In Alloy, wire this into the controller's `cleanup()`.
|
|
147
|
+
|
|
148
|
+
```javascript
|
|
149
|
+
win.addEventListener('close', () => {
|
|
150
|
+
clearInterval(aiTimer);
|
|
151
|
+
clearTimeout(spawnTimer);
|
|
152
|
+
music.stop(); // a looping track outlives the window otherwise
|
|
153
|
+
gameView.pause();
|
|
154
|
+
gameView.removeAllSprites();
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
## Reference files
|
|
159
|
+
|
|
160
|
+
Read the one that matches the task instead of guessing — the API surface below was verified against the module source, not reconstructed from memory.
|
|
161
|
+
|
|
162
|
+
| Need | Reference |
|
|
163
|
+
| --- | --- |
|
|
164
|
+
| Exact properties, methods, events, defaults for every object | [api.md](references/api.md) |
|
|
165
|
+
| Working code per genre: flappy, platformer, top-down, racer, asteroids, endless runner, rhythm, cards, point & click, particles, ropes, camera | [recipes.md](references/recipes.md) |
|
|
166
|
+
| Install the module, tiapp.xml, Alloy vs Classic wiring, assets, sprite sheets, atlases, lifecycle, testing | [project-setup.md](references/project-setup.md) |
|
|
167
|
+
| What does NOT exist yet, what is coming, and how to work around it today | [roadmap.md](references/roadmap.md) |
|
|
168
|
+
|
|
169
|
+
## Before writing game code, check these
|
|
170
|
+
|
|
171
|
+
1. Is the level built inside a guarded `resize` handler, using `e.width`/`e.height`?
|
|
172
|
+
2. Does any timer move a sprite? Replace it with velocity, gravity, a tween, `carMode` or `thrust`.
|
|
173
|
+
3. Are all the level's objects added in one `gameView.add([...])` call?
|
|
174
|
+
4. Does every moving body have the right model — `solidWith` to be blocked, `collidesWith` to be notified?
|
|
175
|
+
5. Is `hitboxScale` set on sprites whose art does not fill the frame?
|
|
176
|
+
6. Do triggers (scores, goals, kill zones) use sheet-less sprites instead of visible art?
|
|
177
|
+
7. Is every `createSound`, `setInterval` and `setTimeout` stopped when the window closes?
|
|
178
|
+
8. Is the HUD a `Ti.UI.Label` overlay, not an imagined engine text API?
|
|
179
|
+
9. Are you using an API that actually exists? Anything involving text, tilemaps, sprite parenting, raycasting, joysticks or `blend: 'multiply'` — check [roadmap.md](references/roadmap.md) first.
|