@maccesar/titools 5.0.0 → 5.1.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.
Files changed (41) hide show
  1. package/README.md +26 -3
  2. package/package.json +1 -1
  3. package/skills/purgetss/SKILL.md +27 -24
  4. package/skills/purgetss/references/EXAMPLES.md +52 -41
  5. package/skills/purgetss/references/adopting-purgetss.md +137 -0
  6. package/skills/purgetss/references/animation-advanced.md +18 -5
  7. package/skills/purgetss/references/animation-system.md +21 -9
  8. package/skills/purgetss/references/app-branding.md +36 -97
  9. package/skills/purgetss/references/appearance-module.md +70 -5
  10. package/skills/purgetss/references/apply-directive.md +14 -6
  11. package/skills/purgetss/references/arbitrary-values.md +59 -23
  12. package/skills/purgetss/references/brand-padding-geometry.md +105 -0
  13. package/skills/purgetss/references/class-categories.md +684 -272
  14. package/skills/purgetss/references/class-index-properties.md +713 -607
  15. package/skills/purgetss/references/class-index.md +149 -84
  16. package/skills/purgetss/references/classic-projects.md +3 -3
  17. package/skills/purgetss/references/cli-commands.md +27 -213
  18. package/skills/purgetss/references/color-commands.md +218 -0
  19. package/skills/purgetss/references/configurable-properties.md +17 -2
  20. package/skills/purgetss/references/custom-fonts.md +21 -16
  21. package/skills/purgetss/references/custom-rules.md +7 -7
  22. package/skills/purgetss/references/customization-deep-dive.md +14 -11
  23. package/skills/purgetss/references/dynamic-component-creation.md +104 -61
  24. package/skills/purgetss/references/grid-layout.md +21 -24
  25. package/skills/purgetss/references/icon-fonts.md +37 -20
  26. package/skills/purgetss/references/installation-setup.md +1 -1
  27. package/skills/purgetss/references/ios-large-titles.md +12 -11
  28. package/skills/purgetss/references/migration-guide.md +101 -10
  29. package/skills/purgetss/references/multi-density-images.md +44 -24
  30. package/skills/purgetss/references/opacity-modifier.md +1 -1
  31. package/skills/purgetss/references/performance-tips.md +5 -4
  32. package/skills/purgetss/references/platform-modifiers.md +2 -2
  33. package/skills/purgetss/references/purgetss-ui-classic.md +21 -5
  34. package/skills/purgetss/references/semantic-colors.md +20 -13
  35. package/skills/purgetss/references/smart-mappings.md +8 -7
  36. package/skills/purgetss/references/svg-pipeline.md +21 -13
  37. package/skills/purgetss/references/tikit-components.md +2 -2
  38. package/skills/purgetss/references/titanium-resets.md +27 -17
  39. package/skills/purgetss/references/ui-ux-design.md +38 -26
  40. package/skills/purgetss/references/values-and-units.md +1 -2
  41. package/skills/purgetss/references/version-history.md +32 -4
package/README.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  TiTools is a Titanium SDK toolkit for AI coding assistants. It ships 11 skills — 6 specialist skills (`ti-reuse-first`, `ti-expert`, `purgetss`, `ti-ui`, `ti-game`, `ti-synthengine`) plus 5 documentation-mirror skills (`ti-api`, `ti-guides`, `ti-howtos`, `alloy-guides`, `alloy-howtos`) — a research agent, and reference files covering reuse and simplification, Titanium architecture, API reference, native how-tos, Alloy MVC, PurgeTSS styling and resource automation, UI/UX patterns, 2D games, and native sound synthesis.
10
10
 
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.
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. As of v5.0.0 those sources are the Titanium SDK's own API definitions and the rewritten guides at [titaniumsdk.com](https://titaniumsdk.com). [Where the references come from](#where-the-references-come-from) has the detail.
12
12
 
13
13
  Without TiTools, assistants rely on general training data. That data can be outdated or too generic for Titanium work. With TiTools, the assistant can look up Alloy architecture, memory cleanup patterns, PurgeTSS utility classes, and platform-specific APIs.
14
14
 
@@ -191,8 +191,31 @@ Notes:
191
191
  - `ti-reuse-first` runs before the others. It asks whether a thing needs to exist and what already does it — a search order that stops at the first rung that holds — and sweeps an existing `app/` for near-identical controllers, single-listener events, wrappers around one call, and layout recomputed in JavaScript. It is deliberately two-sided: it says when adding a module or a Widget is the right answer, so the bias does not simply invert.
192
192
  - `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 and tracks upstream `main` (the module ships features ahead of its manifest version); it applies to Alloy and Classic projects alike and does not depend on PurgeTSS.
193
193
  - `ti-synthengine` translates aesthetic sound requests into strict, production-ready JavaScript for the cross-platform `ti.synthengine` 1.0.0 module. Seven references preserve the official documentation and an eighth adds curated retro, xylophone, memory-pad, polyphony and timer-ownership recipes; the API contract was cross-checked against both native implementations.
194
- - The latter five are documentation-mirror skills, audited via the internal `titools-skill-auditor` against three sources: `ti-api` against the API definitions in `tidev/titanium-sdk` (`apidoc/`, anchored to the newest GA tag), the guide skills against the rewritten guides in `tidev/titaniumsdk.com` (`content/docs/`), and both against the frozen `tidev/titanium-docs` corpus as an archive. The archive is additive: TiDev condensed 336 legacy pages into 62, and the material it left behind is kept here rather than deleted.
195
- - `purgetss` reference files are audited against the official PurgeTSS documentation, but its workflow conventions are opinionated.
194
+ - The latter five are documentation-mirror skills, audited against official sources via the internal `titools-skill-auditor`. See [Where the references come from](#where-the-references-come-from).
195
+ - `purgetss` reference files are audited against the official PurgeTSS documentation and against the package source (the CLI and the generated `utilities.tss`), but its workflow conventions are opinionated.
196
+
197
+ ---
198
+
199
+ ## Where the references come from
200
+
201
+ The Titanium documentation was rewritten during 2026, and v5.0.0 moved TiTools onto the new sources. No skill, command or flag was renamed and the references answer the same questions. What changed is what they are checked against.
202
+
203
+ | Source | Feeds | Why it is the one |
204
+ |---|---|---|
205
+ | [`tidev/titanium-sdk`](https://github.com/tidev/titanium-sdk) → `apidoc/*.yml` | `ti-api` | The API definitions the SDK team edits. Every other copy of the API is compiled from these. |
206
+ | [`tidev/titaniumsdk.com`](https://github.com/tidev/titaniumsdk.com) → `content/docs/` | `ti-guides`, `ti-howtos`, `alloy-guides`, `alloy-howtos` | The rewritten guides, and what [titaniumsdk.com](https://titaniumsdk.com) serves. |
207
+ | `tidev/titaniumsdk.com` → `registry/sdk/<version>/` | `ti-api`, as a cross-check | The API compiled per published release. It answers which version actually shipped an API, which the YAML alone cannot. |
208
+ | [`tidev/titanium-docs`](https://github.com/tidev/titanium-docs) | all five, as an archive | The previous corpus, now frozen. Kept for what the rewrite left out. |
209
+
210
+ ### Why the API comes from the SDK
211
+
212
+ The website does not write API documentation. It compiles it from `apidoc/*.yml` and commits the result, so it trails the SDK by construction. `ti-api` reads the YAML for what exists and the compiled registry for which release shipped it, and documents the newest GA rather than `main`. An API merged into the SDK today reaches these references when the release carrying it ships, because until then you cannot call it.
213
+
214
+ ### The archive is additive
215
+
216
+ `tidev/titanium-docs` is frozen and being archived upstream. TiDev's own migration audit classifies its 336 guide pages as 121 rewritten, 121 merged, 2 kept and 92 archived. Of those 92, 91 are release notes and the last is the discontinued Atom package, so no guide topic was dropped. The difference is density: 1390 KB of legacy prose became 219 KB.
217
+
218
+ TiTools keeps the full corpus. The archive never overrides a live source on a question of fact, and nothing is deleted from a reference merely because the rewritten site no longer covers it. These skills still answer questions the official guides have not been rewritten to cover yet, such as the conditional `if=` attribute in Alloy XML and TSS, custom XML tags via `app/lib/`, and `alloy compile`.
196
219
 
197
220
  ---
198
221
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@maccesar/titools",
3
- "version": "5.0.0",
3
+ "version": "5.1.0",
4
4
  "description": "Titanium SDK skills and agents for AI coding assistants, including native game and sound synthesis modules",
5
5
  "main": "lib/index.js",
6
6
  "type": "module",
@@ -44,7 +44,7 @@ Every utility class you suggest and every styling pattern you describe MUST be b
44
44
 
45
45
  `[source: references/<file>.md]`
46
46
 
47
- Example: *"Use `wh-12` to set width and height to 48px [source: references/class-index.md]"*
47
+ Example: *"Use `wh-12` to set width and height to 48 [source: references/class-index.md]"*
48
48
 
49
49
  ### Step 4 — If you must answer from memory
50
50
 
@@ -205,7 +205,7 @@ purgetss create 'MyApp' -d -v fa
205
205
  ### 🚨 RESPECT USER FILES
206
206
  **NEVER delete any existing `.tss` files** (like `index.tss`, `detail.tss`) or other project files without explicit user consent.
207
207
 
208
- **How to handle migration to PurgeTSS:**
208
+ **How to handle migration to PurgeTSS** (full workflow and translation tables in [adopting-purgetss.md](references/adopting-purgetss.md)):
209
209
  1. **ONLY** replace custom classes with PurgeTSS utility classes if the user explicitly requests it.
210
210
  2. When requested:
211
211
  - Analyze the definitions in the existing `.tss` files.
@@ -241,17 +241,16 @@ purgetss create 'MyApp' -d -v fa
241
241
  > **`horizontal`** - Arrange elements left to right:
242
242
  > ```xml
243
243
  > <View class="horizontal w-screen">
244
- > <Label text="Left" />
245
- > <View class="w-screen" /> <!-- Spacer -->
246
- > <Label text="Right" />
244
+ > <Label text="First" />
245
+ > <Label class="ml-4" text="Second" /> <!-- ml-4 = 16 after the previous sibling -->
247
246
  > </View>
248
247
  > ```
249
248
  >
250
- > **`composite`** (default) - Absolute positioning with `top`, `left`, etc.:
249
+ > **`composite`** (default) - Absolute positioning with `top`, `left`, etc. (to pin one child left and another right, use a composite parent with `left-0` / `right-0`):
251
250
  > ```xml
252
251
  > <View class="h-screen w-screen">
253
- > <View class="wh-12 absolute left-0 top-0 bg-red-500" />
254
- > <View class="wh-12 absolute bottom-0 right-0 bg-blue-500" />
252
+ > <View class="wh-12 left-0 top-0 bg-red-500" />
253
+ > <View class="wh-12 bottom-0 right-0 bg-blue-500" />
255
254
  > </View>
256
255
  > ```
257
256
  >
@@ -280,8 +279,11 @@ purgetss create 'MyApp' -d -v fa
280
279
  >
281
280
  > **OR use PurgeTSS platform modifier classes:**
282
281
  > ```xml
283
- > <!-- ✅ GOOD - Platform-specific classes -->
284
- > <Window class="ios:status-bar-light android:status-bar-dark">
282
+ > <!-- ✅ GOOD - status-bar-* classes are already emitted as [platform=ios] -->
283
+ > <Window class="status-bar-light">
284
+ >
285
+ > <!-- ✅ GOOD - ios: / android: scope any other class to one platform -->
286
+ > <Window class="ios:bg-white android:bg-gray-100">
285
287
  > ```
286
288
  >
287
289
  > **Properties that ALWAYS require platform modifiers:**
@@ -300,7 +302,7 @@ purgetss create 'MyApp' -d -v fa
300
302
 
301
303
  - **NO `p-` padding classes**: Titanium does NOT support a native `padding` property on `View`, `Window`, `ScrollView`, or `TableView`. Always use **margins on children** (`m-`) to simulate internal spacing.
302
304
  - **View defaults to `SIZE`**: Use `w-screen`/`h-screen` to fill space when needed.
303
- - **`rounded-full`**: To get a perfect circle, use `rounded-full-XX` (where XX is the width/height of the square element).
305
+ - **`rounded-full`**: On its own it is a fixed 8×8 circle (`width: 8, height: 8, borderRadius: 4`). For any other size, use `rounded-full-XX` (where XX is the spacing-scale size of the square element).
304
306
  - **`rounded-full-XX` includes size**: These classes already set `width`, `height`, and `borderRadius`. Do **not** add `w-XX h-XX`/`wh-XX` unless you need to override.
305
307
  - **`m-xx` on FILL elements**: Adding `m-4` to a `w-screen` element pins it to all four edges (top, bottom, left, right). This will **stretch the component vertically** to fill the parent unless you explicitly add `h-auto` (`Ti.UI.SIZE`) to constrain it to its content.
306
308
  - **`w-XX` + `h-XX` → `wh-XX`**: If both width and height use the same scale value, prefer a single `wh-XX` (order doesn't matter: `w-10 h-10` and `h-10 w-10` are equivalent).
@@ -327,7 +329,7 @@ purgetss create 'MyApp' -d -v fa
327
329
  > ```
328
330
 
329
331
  - **NEVER add `composite` class explicitly** - That's the default, use `horizontal`/`vertical` when needed
330
- - **Arbitrary values use parentheses**: `w-(100px)`, `bg-(#ff0000)` - NO square brackets
332
+ - **Arbitrary values use parentheses**: `w-(100)`, `bg-(#ff0000)` - NO square brackets, and no `px` unit (unitless values are pixels; since v7.8.0 `w-(100px)` stops the build with a `Class Syntax Error`)
331
333
  - **`mode: 'all'` required** in `config.cjs` for Ti Elements styling
332
334
  - **Classes use `kebab-case`**: `.my-class`, IDs use `camelCase`: `#myId`
333
335
 
@@ -400,12 +402,12 @@ PurgeTSS shares naming with some CSS Frameworks but has DIFFERENT classes for Ti
400
402
  | ----------------------- | ------------------------------------- |
401
403
  | `keyboard-type-email` | `hintText` (use attribute) |
402
404
  | `return-key-type-next` | `passwordMask` (use attribute) |
403
- | `text-center` | `autocorrect` (use attribute) |
404
- | `bg-blue-500` | `autocapitalization` (use attribute) |
405
- | `w-screen` | `flex-row` → use `horizontal` |
406
- | `wh-16` | `justify-between` → use margins |
407
- | `rounded-lg` | `w-full` → use `w-screen` |
408
- | `m-4`, `gap-4` | `p-4` on View → use `m-4` on children |
405
+ | `text-center` | `flex-row` → use `horizontal` |
406
+ | `bg-blue-500` | `justify-between` → use positioning |
407
+ | `w-screen` (`Ti.UI.FILL`), `w-full` (`'100%'`) | `p-4` on View → use `m-4` on children |
408
+ | `wh-16`, `rounded-lg`, `m-4`, `gap-4` | |
409
+ | `autocorrect`, `autocorrect-false` | |
410
+ | `autocapitalization-text-none` (also `normal-case`, `uppercase`, `capitalize`, `sentences`) | |
409
411
 
410
412
  > **💡 TIP**
411
413
  > When in doubt, prefer using the search command above to verify. It's better to spend 5 seconds verifying than suggesting a class that doesn't exist and will appear in the "unused classes" warning.
@@ -416,16 +418,16 @@ Load these only when needed:
416
418
 
417
419
  ### Essential References
418
420
  - **[Class Index](references/class-index.md)** - Naming conventions, prohibited classes, prefix inventory, verification commands (LOAD FIRST when unsure about a class)
419
- - **[Class Index — Properties (A–Z)](references/class-index-properties.md)** - Full A–Z table of every Titanium property and its PurgeTSS class prefix
420
- - **[Class Categories](references/class-categories.md)** - Complete prefix inventory by category (layout, colors, typography, states, etc.)
421
+ - **[Class Index — Properties (A–Z)](references/class-index-properties.md)** - Every Titanium property with the class families that set it, generated from `utilities.tss`
422
+ - **[Class Categories](references/class-categories.md)** - Every class family grouped by kind of value: colors, dimensions, constants, booleans
421
423
  - **[Dynamic Component Creation](references/dynamic-component-creation.md)** - `$.UI.create()` and `Alloy.createStyle()` for creating components in Controllers (READ FIRST for dynamic components)
422
- - **[Appearance Module](references/appearance-module.md)** - Light/Dark/System mode switching with persistence (v7.5.3)
423
- - **[Semantic Colors](references/semantic-colors.md)** - Titanium semantic colors for Light/Dark mode via `semantic` command (v7.6.0)
424
424
 
425
425
  ### Setup & Configuration
426
426
  - [Installation & Setup](references/installation-setup.md) - First run, VS Code, LiveView
427
427
  - [CLI Commands](references/cli-commands.md) - All `purgetss` commands
428
- - [Migration Guide](references/migration-guide.md) - Migrating existing apps from manual TSS to PurgeTSS
428
+ - [Color Commands](references/color-commands.md) - `semantic`, `shades` and `color-module`: Light/Dark semantic colors, palettes in `config.cjs`, and the CommonJS color module
429
+ - [Adopting PurgeTSS](references/adopting-purgetss.md) - Moving an existing Alloy app from hand-written `.tss` files to utility classes: the style-priority trap, view-by-view workflow, and property-to-class translation tables
430
+ - [Migration Guide](references/migration-guide.md) - Upgrading between PurgeTSS versions (v7.2.6 → v7.17.1): breaking changes and what to review after each upgrade
429
431
  - **[Values and Units](references/values-and-units.md)** - How `ti.ui.defaultunit` in `tiapp.xml` interprets the unitless numeric values PurgeTSS writes (foundational concept for spacing, sizes, typography)
430
432
 
431
433
  ### Customization
@@ -449,7 +451,8 @@ Load these only when needed:
449
451
  - [iOS Large Titles](references/ios-large-titles.md) - Best practice for iOS Large Title navigation
450
452
 
451
453
  ### App Assets
452
- - [App Branding](references/app-branding.md) - `brand` command: 14 pieces, per-piece config, selection, optimization, appicon padding, and rounded non-icon artwork (v7.16.0)
454
+ - [App Branding](references/app-branding.md) - `brand` command: 14 pieces, per-piece config, selection, optimization, launch assets, FCM notification icon, and troubleshooting
455
+ - [Brand Padding & Geometry](references/brand-padding-geometry.md) - Per-piece padding, master sizing, splash sizing rule, rounded non-icon artwork (v7.16.0), and adaptive-mask math for `brand`
453
456
  - [Launch Background](references/launch-background.md) - Carrying `brand.background` into the iOS LaunchScreen and a launcher-only Android theme (`--notes` output)
454
457
  - [Multi-Density Images](references/multi-density-images.md) - `images` command for Android res-*dpi + iPhone @1x/@2x/@3x UI images (v7.6.0)
455
458
  - [SVG Pipeline](references/svg-pipeline.md) - SVG-aware compile-time image pipeline: `.svg` refs + numeric `w-*`/`h-*` classes compile to 8 density PNGs; `images.files`/`images.autoSync` (v7.11.0–v7.11.1)
@@ -17,11 +17,11 @@ Complete examples of common patterns with anti-patterns and correct implementati
17
17
  - [Gap Usage](#gap-usage)
18
18
  - [Padding on Container Views](#padding-on-container-views)
19
19
  - [`w-full` vs `w-screen`](#w-full-vs-w-screen)
20
- - [`rounded-full` Without Size](#rounded-full-without-size)
20
+ - [`rounded-full` Is a Fixed 8×8 Circle](#rounded-full-is-a-fixed-88-circle)
21
21
  - [Square Brackets for Arbitrary Values](#square-brackets-for-arbitrary-values)
22
22
  - [Layout Defaults](#layout-defaults)
23
23
  - [ScrollView Without `content-w-screen` / `content-h-auto`](#scrollview-without-content-w-screen--content-h-auto)
24
- - [Deprecated `theme.View.DEFAULT` vs `theme.extend.View`](#deprecated-themeviewdefault-vs-themeextendview)
24
+ - [`theme.View` (Replace) vs `theme.extend.View` (Merge)](#themeview-replace-vs-themeextendview-merge)
25
25
  - [Quick Reference Table](#quick-reference-table)
26
26
 
27
27
  <!-- TOC-END -->
@@ -45,18 +45,19 @@ The examples below catalog anti-patterns observed in real Titanium + PurgeTSS pr
45
45
  </View>
46
46
  ```
47
47
 
48
- **✅ CORRECT (Use horizontal layout + spacer):**
48
+ **✅ CORRECT (Composite parent + edge positioning):**
49
49
  ```xml
50
- <View class="horizontal w-screen">
51
- <Label text="Left" />
52
- <View class="w-screen" /> <!-- Spacer -->
53
- <Label text="Right" />
50
+ <!-- Parent defaults to composite; each child is pinned to one edge -->
51
+ <View class="w-screen">
52
+ <Label text="Left" class="left-0" />
53
+ <Label text="Right" class="right-0" />
54
54
  </View>
55
55
  ```
56
56
 
57
57
  **✅ ALTERNATIVE (Use margins):**
58
58
  ```xml
59
- <View class="horizontal w-screen">
59
+ <!-- In a composite parent, ml-4 emits left: 16 and mr-4 emits right: 16 -->
60
+ <View class="w-screen">
60
61
  <Label text="Left" class="ml-4" />
61
62
  <Label text="Right" class="mr-4" />
62
63
  </View>
@@ -172,8 +173,8 @@ The examples below catalog anti-patterns observed in real Titanium + PurgeTSS pr
172
173
  ```
173
174
 
174
175
  ```bash
175
- # Then run:
176
- purgetss build
176
+ # Then run (bare command = purge; `purgetss build` only regenerates utilities.tss):
177
+ purgetss
177
178
  # OR just compile:
178
179
  alloy compile
179
180
  ```
@@ -193,8 +194,8 @@ alloy compile
193
194
  **❌ WRONG (Children with % widths, parent without w-screen):**
194
195
  ```xml
195
196
  <View class="horizontal m-4">
196
- <View class="w-(48%)">...</view>
197
- <View class="w-(48%)">...</view>
197
+ <View class="w-(48%)">...</View>
198
+ <View class="w-(48%)">...</View>
198
199
  </View>
199
200
  <!-- Parent doesn't have w-screen, % calculations may fail -->
200
201
  ```
@@ -202,8 +203,8 @@ alloy compile
202
203
  **✅ CORRECT (Parent has w-screen):**
203
204
  ```xml
204
205
  <View class="horizontal m-4 w-screen">
205
- <View class="w-(48%)">...</view>
206
- <View class="w-(48%)">...</view>
206
+ <View class="w-(48%)">...</View>
207
+ <View class="w-(48%)">...</View>
207
208
  </View>
208
209
  ```
209
210
 
@@ -211,20 +212,32 @@ alloy compile
211
212
 
212
213
  ### Gap Usage
213
214
 
214
- **❌ WRONG (gap adds margin all around, breaks % widths):**
215
+ **❌ WRONG (gap on the column itself: margins add to the % width):**
215
216
  ```xml
216
- <View class="grid grid-cols-2 gap-4">
217
- <View class="col-span-6">...</view> <!-- 50% + 16px margins -->
218
- <View class="col-span-6">...</view> <!-- 50% + 16px margins -->
217
+ <View class="grid">
218
+ <View class="grid-cols-2 gap-4">...</View> <!-- 50% + 16 left + 16 right -->
219
+ <View class="grid-cols-2 gap-4">...</View> <!-- 50% + 16 left + 16 right -->
219
220
  </View>
220
221
  <!-- Total > 100%, elements wrap or overflow -->
221
222
  ```
222
223
 
223
- **✅ CORRECT (Use explicit margins):**
224
+ **✅ CORRECT (Official grid pattern: gap on an inner View inside each column):**
225
+ ```xml
226
+ <View class="grid">
227
+ <View class="grid-cols-2">
228
+ <View class="gap-4">...</View>
229
+ </View>
230
+ <View class="grid-cols-2">
231
+ <View class="gap-4">...</View>
232
+ </View>
233
+ </View>
234
+ ```
235
+
236
+ **✅ ALTERNATIVE (Use explicit margins):**
224
237
  ```xml
225
238
  <View class="horizontal mb-4 w-screen">
226
- <View class="w-(48%) mr-2">...</view>
227
- <View class="w-(48%) ml-2">...</view>
239
+ <View class="w-(48%) mr-2">...</View>
240
+ <View class="w-(48%) ml-2">...</View>
228
241
  </View>
229
242
  ```
230
243
 
@@ -274,9 +287,9 @@ alloy compile
274
287
 
275
288
  ---
276
289
 
277
- ### `rounded-full` Without Size
290
+ ### `rounded-full` Is a Fixed 8×8 Circle
278
291
 
279
- **❌ WRONG (rounded-full alone doesn't exist):**
292
+ **❌ WRONG (`rounded-full` emits `width: 8, height: 8, borderRadius: 4`, which conflicts with `w-12 h-12`; at 48×48 a radius of 4 is not a circle):**
280
293
  ```xml
281
294
  <View class="h-12 w-12 rounded-full" />
282
295
  ```
@@ -300,25 +313,25 @@ alloy compile
300
313
 
301
314
  **❌ WRONG (Square brackets are not supported):**
302
315
  ```xml
303
- <View class="w-[100px] bg-[#ff0000]" />
316
+ <View class="w-[100] bg-[#ff0000]" />
304
317
  ```
305
318
 
306
319
  **✅ CORRECT (PurgeTSS uses parentheses):**
307
320
  ```xml
308
- <View class="w-(100px) bg-(#ff0000)" />
321
+ <View class="w-(100) bg-(#ff0000)" />
309
322
  ```
310
323
 
311
- **PurgeTSS syntax for arbitrary values uses `()` not `[]`.**
324
+ **PurgeTSS syntax for arbitrary values uses `()` not `[]`, and pixel values are written without a unit: `w-(100px)` also stops the build (`Explicit "px" unit is redundant`).**
312
325
 
313
326
  > **🚨 v7.8.0+ HARD-FAILS THE BUILD ON SQUARE BRACKETS**
314
327
  > Since v7.8.0, the build stops with a structured `Class Syntax Error` block (file path + line number + `Fix:` suggestion) the moment it spots `top-[10px]`, `wh-[12]`, or any other square-bracket utility. Pre-v7.8.0, those classes silently dropped into the `// Unused or unsupported classes` block of `app.tss` — easy to miss. Now they're loud and actionable.
315
328
  >
316
329
  > v7.10.1 reworded the error message from `'Tailwind-style brackets "[ ]" are not supported'` to `'Square brackets "[ ]" are not supported'`. Same enforcement, less framing.
317
330
  >
318
- > See [Arbitrary Values → Class syntax pre-validation](arbitrary-values.md#class-syntax-pre-validation) for the full list of patterns the pre-validator catches (5 total, including inverted negative sign and whitespace inside parentheses).
331
+ > See [Arbitrary Values → Class syntax pre-validation](arbitrary-values.md#class-syntax-pre-validation) for the full list of patterns the pre-validator catches (5 total, including inverted negative sign, whitespace inside parentheses, and redundant `px` units).
319
332
 
320
333
  **Examples:**
321
- - `w-(100px)` - Custom width
334
+ - `w-(100)` - Custom width
322
335
  - `bg-(#ff0000)` - Custom background color
323
336
  - `mt-(20dp)` - Custom margin top
324
337
  - `text-(#333333)` - Custom text color
@@ -381,33 +394,31 @@ alloy compile
381
394
 
382
395
  ---
383
396
 
384
- ### Deprecated `theme.View.DEFAULT` vs `theme.extend.View`
397
+ ### `theme.View` (Replace) vs `theme.extend.View` (Merge)
385
398
 
386
- **WRONG (old shape — deprecated in recent PurgeTSS):**
399
+ **Replace mode (`theme.View`, no `extend`) — the framework default `Ti.UI.SIZE` for View is dropped:**
387
400
  ```javascript
388
401
  // purgetss/config.cjs
389
402
  module.exports = {
390
403
  theme: {
391
- View: {
392
- DEFAULT: { backgroundColor: '#ffffff' }
393
- }
404
+ View: { apply: 'bg-white' }
394
405
  }
395
406
  }
396
407
  ```
397
408
 
398
- **CORRECT (new `extend` shape):**
409
+ **Extend mode (`theme.extend.View`) — merges with the built-in defaults:**
399
410
  ```javascript
400
411
  // purgetss/config.cjs
401
412
  module.exports = {
402
413
  theme: {
403
414
  extend: {
404
- View: { backgroundColor: '#ffffff' }
415
+ View: { apply: 'bg-white' }
405
416
  }
406
417
  }
407
418
  }
408
419
  ```
409
420
 
410
- **Why:** The nested `DEFAULT` key is a legacy artifact. Component-level theme overrides now live directly under `theme.extend.<Component>` and are merged with built-in defaults. Using the old shape silently produces unexpected styles on newer PurgeTSS versions.
421
+ **Why:** `Window`, `View`, and `ImageView` have built-in defaults (white Window background, `Ti.UI.SIZE` on View, iOS `hires: true` on ImageView). Under `theme.extend` your customization merges with them; at the top level of `theme` your config replaces them. The `DEFAULT` / `default` wrapper is not deprecated: `View: { apply: '...' }` and `View: { default: { apply: '...' } }` produce the same TSS, and the explicit wrapper is how you add `ios:` / `android:` blocks next to it.
411
422
 
412
423
  ---
413
424
 
@@ -421,10 +432,10 @@ module.exports = {
421
432
  | `items-center` | Exists but maps to fill, not centering — avoid for centering | Use layout + positioning |
422
433
  | `p-4` on View | No padding on containers | `m-4` on children |
423
434
  | `w-full` | Percentage-based | `w-screen` (Ti.UI.FILL) |
424
- | `rounded-full` | Needs size suffix | `rounded-full-12` |
435
+ | `rounded-full` with `w-*`/`h-*` | Fixed 8×8 circle, conflicts on size | `rounded-full-12` |
425
436
  | `composite` class | Already default | Omit it |
426
- | `w-[100px]` | Wrong syntax | `w-(100px)` |
427
- | Manual `.tss` | Overwritten by PurgeTSS | Use utility classes |
428
- | `gap` with `%` widths | Total exceeds 100% | Use explicit margins |
437
+ | `w-[100]`, `w-(100px)` | Stops the build (v7.8.0+) | `w-(100)` |
438
+ | Manual `.tss` | Duplicates classes; its rules override `app.tss` | Use utility classes (`app.tss` itself is rewritten on every run) |
439
+ | `gap` on a `%`-width column | Total exceeds 100% | `gap-*` on an inner View, or explicit margins |
429
440
  | ScrollView without `content-*` sizing | No/unexpected scroll | Add `content-w-screen` + `content-h-auto` |
430
- | `theme.View.DEFAULT` | Legacy shape in newer PurgeTSS | `theme.extend.View` |
441
+ | `theme.View` to tweak one default | Replaces all View defaults | `theme.extend.View` |
@@ -0,0 +1,137 @@
1
+ # Adopting PurgeTSS in an Existing Alloy App
2
+
3
+ How to move an Alloy app whose styles live in hand-written `.tss` files (per-controller files, `#id` rules, inline XML attributes) to PurgeTSS utility classes. For upgrading a project that already uses PurgeTSS from one version to another, see [migration-guide.md](migration-guide.md) instead.
4
+
5
+ > **Source note:** the official PurgeTSS docs have no adoption guide. This page is TiTools author guidance, assembled from behavior verified in the PurgeTSS source (v7.17.1), the Alloy style-priority rules and `utilities.tss`. Every class in the tables below exists in `utilities.tss` with the value shown.
6
+
7
+ ## Ground Rules
8
+
9
+ - **Never delete the user's `.tss` files without explicit consent.** Convert a view, show the result, and wait for confirmation before removing the old rules (see `SKILL.md` § "RESPECT USER FILES").
10
+ - **One view at a time.** Convert, compile, check on both platforms, then move on.
11
+ - **Alloy only.** The utility-class workflow does not exist in Classic projects; see [classic-projects.md](classic-projects.md).
12
+
13
+ ## What PurgeTSS Does to Your Styles
14
+
15
+ | File | What happens |
16
+ | --- | --- |
17
+ | `app/styles/app.tss` | On the first run it is backed up to `app/styles/_app.tss`. From then on PurgeTSS **rewrites `app.tss` on every run**: resets, then the contents of `_app.tss`, then only the utility classes your views use. Never edit `app.tss` directly. |
18
+ | `app/styles/_app.tss` | Your original global styles. Keep custom global classes here; they are copied into `app.tss` on each run. |
19
+ | `app/styles/<controller>.tss` | Not touched. PurgeTSS reads these files only so the classes they define are not reported as missing. |
20
+ | `alloy.jmk` | The first run adds a hook so `purgetss` runs on every Alloy compile. See [installation-setup.md](installation-setup.md). |
21
+
22
+ ### The Priority Trap
23
+
24
+ Alloy applies styles from lowest to highest priority: `styles/app.tss` (global), then `styles/<controller>.tss`, then attributes in the XML markup, with theme and platform-specific files layered in between (Alloy guide, "Style Priorities"). PurgeTSS classes land in `app.tss`, the **lowest** layer. During a partial migration this means:
25
+
26
+ - A leftover rule in `styles/index.tss` for the same element beats the utility class, silently.
27
+ - An inline attribute such as `backgroundColor="#fff"` beats both.
28
+
29
+ When a class "does nothing" mid-migration, look for a leftover rule in the controller's `.tss` or an attribute on the XML tag before suspecting PurgeTSS.
30
+
31
+ ## Workflow
32
+
33
+ ### 1. Set up
34
+
35
+ ```bash
36
+ cd your-app
37
+ purgetss init # creates ./purgetss/config.cjs
38
+ purgetss # first purge: backs up app.tss to _app.tss and installs the alloy.jmk hook
39
+ ```
40
+
41
+ Commit (or branch) before this step so the backup and the hook are easy to review.
42
+
43
+ ### 2. Convert one view
44
+
45
+ Before:
46
+
47
+ ```xml
48
+ <!-- app/views/index.xml -->
49
+ <View id="header">
50
+ <Label id="title" text="Welcome" />
51
+ </View>
52
+ ```
53
+
54
+ ```tss
55
+ // app/styles/index.tss
56
+ '#header': { backgroundColor: '#ffffff', height: 64, top: 0 }
57
+ '#title': { color: '#1f2937', font: { fontSize: 18, fontWeight: 'bold' } }
58
+ ```
59
+
60
+ After:
61
+
62
+ ```xml
63
+ <!-- app/views/index.xml -->
64
+ <View class="top-0 h-16 bg-white">
65
+ <Label class="text-lg font-bold text-gray-800" text="Welcome" />
66
+ </View>
67
+ ```
68
+
69
+ Keep the `id` attributes if controller code uses them (`$.header`); only the style rules move.
70
+
71
+ ### 3. Remove the old rules (with consent)
72
+
73
+ Once the converted view looks right on both platforms, and the user agrees:
74
+
75
+ 1. Delete the converted rules from `app/styles/index.tss`. Remove the file only if nothing is left in it.
76
+ 2. Move any global class still needed from `_app.tss` into utility classes, or leave it in `_app.tss`.
77
+ 3. Run `purgetss` (or compile) to regenerate `app.tss`.
78
+
79
+ ## Translation Tables
80
+
81
+ ### Properties
82
+
83
+ | Hand-written TSS | PurgeTSS class |
84
+ | --- | --- |
85
+ | `backgroundColor: '#ffffff'` | `bg-white` |
86
+ | `backgroundColor: '#f3f4f6'` | `bg-gray-100` |
87
+ | `color: '#1f2937'` | `text-gray-800` (sets `color` and `textColor`) |
88
+ | `font: { fontSize: 18 }` | `text-lg` |
89
+ | `font: { fontWeight: 'bold' }` | `font-bold` |
90
+ | `width: Ti.UI.FILL` | `w-screen` |
91
+ | `width: '100%'` | `w-full` |
92
+ | `height: Ti.UI.SIZE` | `h-auto` |
93
+ | `height: 64` | `h-16` |
94
+ | `height: 60` (not on the scale) | `h-(60)` |
95
+ | `top: 0` | `top-0` |
96
+ | `top: 16` | `mt-4` |
97
+ | `left: 16, right: 16` | `mx-4` |
98
+ | `borderRadius: 8` | `rounded-lg` |
99
+ | `borderWidth: 1, borderColor: '#e5e7eb'` | `border border-gray-200` |
100
+ | `opacity: 0.5` | `opacity-50` |
101
+ | `visible: false` | `hidden` |
102
+ | `layout: 'horizontal'` | `horizontal` |
103
+ | `layout: 'vertical'` | `vertical` |
104
+ | `elevation: 4` | `elevation-1` (the scale is ×4: `elevation-4` is `16`) |
105
+
106
+ Spacing classes multiply by 4 (`mt-4` = 16), and the numbers are unitless: Titanium resolves them with `ti.ui.defaultunit` (see [values-and-units.md](values-and-units.md)). For a value off the scale use an arbitrary value **without a unit**: `h-(60)`, not `h-(60px)`, which stops the build since v7.8.0 (see [arbitrary-values.md](arbitrary-values.md)). Colors in your brand palette belong in `config.cjs` (see [customization-deep-dive.md](customization-deep-dive.md)), not in arbitrary `bg-(#hex)` classes repeated across views.
107
+
108
+ ### Platform and device conditionals
109
+
110
+ | Hand-written code | PurgeTSS |
111
+ | --- | --- |
112
+ | `if (OS_IOS) { $.box.top = 40 } else { $.box.top = 20 }` | `class="ios:mt-10 mt-5"` |
113
+ | `if (OS_ANDROID) { $.card.elevation = 4 }` | `class="android:elevation-1"` |
114
+ | Tablet width set in the controller | `class="tablet:w-6/12 w-screen"` |
115
+
116
+ See [platform-modifiers.md](platform-modifiers.md) for the full modifier list.
117
+
118
+ ### Animations
119
+
120
+ | Hand-written animation | PurgeTSS Animation module |
121
+ | --- | --- |
122
+ | `Ti.UI.createAnimation({ opacity: 0, duration: 300 })` toggled by hand | `<Animation module="purgetss.ui" id="fade" class="close:opacity-0 open:opacity-100 duration-300" />` and `$.fade.play($.box)` |
123
+ | A scale-down press effect | `class="close:scale-100 open:scale-95 duration-150"` |
124
+
125
+ See [animation-system.md](animation-system.md).
126
+
127
+ ## Pitfalls
128
+
129
+ | Pitfall | Consequence | Prevention |
130
+ | --- | --- | --- |
131
+ | Editing `app.tss` directly | Overwritten on the next run | Put custom global styles in `_app.tss` |
132
+ | Leaving the old rule in `<controller>.tss` | It overrides the utility class | Remove converted rules once the user agrees |
133
+ | Keeping inline attributes (`backgroundColor="…"`) | They override every class | Move them into classes |
134
+ | Flexbox classes (`flex-row`, `justify-between`) | Classes don't exist | `horizontal` / `vertical` layouts |
135
+ | `p-*` on a `View` or `Window` | No effect: `padding` exists only on `TextField`, `TextArea` and Android `CardView` | Margins on the children |
136
+ | `w-[100]` or `w-(100px)` | Stops the build | `w-(100)` |
137
+ | Converting every view at once | Hard to find what broke | One view per step, tested on both platforms |
@@ -138,7 +138,7 @@ Values: `repeat-0` through `repeat-12`.
138
138
 
139
139
  ### rotate-* and -rotate-*
140
140
 
141
- Rotation in degrees. Range: **0** to **180**, positive and negative.
141
+ Rotation in degrees. Range: **0** to **360**, positive and negative.
142
142
 
143
143
  ```css
144
144
  '.rotate-0': { rotate: 0 }
@@ -149,7 +149,12 @@ Rotation in degrees. Range: **0** to **180**, positive and negative.
149
149
  '.rotate-12': { rotate: 12 }
150
150
  '.rotate-45': { rotate: 45 }
151
151
  '.rotate-90': { rotate: 90 }
152
+ '.rotate-135': { rotate: 135 }
152
153
  '.rotate-180': { rotate: 180 }
154
+ '.rotate-225': { rotate: 225 }
155
+ '.rotate-270': { rotate: 270 }
156
+ '.rotate-315': { rotate: 315 }
157
+ '.rotate-360': { rotate: 360 }
153
158
  '.-rotate-0': { rotate: 0 }
154
159
  '.-rotate-1': { rotate: -1 }
155
160
  '.-rotate-2': { rotate: -2 }
@@ -158,7 +163,12 @@ Rotation in degrees. Range: **0** to **180**, positive and negative.
158
163
  '.-rotate-12': { rotate: -12 }
159
164
  '.-rotate-45': { rotate: -45 }
160
165
  '.-rotate-90': { rotate: -90 }
166
+ '.-rotate-135': { rotate: -135 }
161
167
  '.-rotate-180': { rotate: -180 }
168
+ '.-rotate-225': { rotate: -225 }
169
+ '.-rotate-270': { rotate: -270 }
170
+ '.-rotate-315': { rotate: -315 }
171
+ '.-rotate-360': { rotate: -360 }
162
172
  ```
163
173
 
164
174
  ### scale-*
@@ -180,6 +190,7 @@ Scales the matrix by the specified factor. Same value for horizontal and vertica
180
190
  '.scale-110': { scale: 1.1 }
181
191
  '.scale-125': { scale: 1.25 }
182
192
  '.scale-150': { scale: 1.5 }
193
+ '.scale-200': { scale: 2 }
183
194
  ```
184
195
 
185
196
  ### Snap Classes
@@ -221,7 +232,7 @@ Prevents the drag system from promoting the active view on touch start. It does
221
232
 
222
233
  ### zoom-in-* / zoom-out-*
223
234
 
224
- Animates zoom in and zoom out. Sets the View's scale to the specified value, then animates it back to 1. Range: **0** to **150**.
235
+ Animates zoom in and zoom out. Sets the View's scale to the specified value, then animates it back to 1. Range: **0** to **200**.
225
236
 
226
237
  ```css
227
238
  '.zoom-in-0': { animationProperties: { open: { scale: 0 }, complete: { scale: 1 } } }
@@ -234,7 +245,7 @@ Animates zoom in and zoom out. Sets the View's scale to the specified value, the
234
245
  '.zoom-out-110': { animationProperties: { close: { scale: 1.1 }, complete: { scale: 1 } } }
235
246
  ```
236
247
 
237
- Full range: `zoom-in-0`, `zoom-in-1`, `zoom-in-5`, `zoom-in-10`, `zoom-in-25`, `zoom-in-50`, `zoom-in-75`, `zoom-in-90`, `zoom-in-95`, `zoom-in-100`, `zoom-in-105`, `zoom-in-110`, `zoom-in-125`, `zoom-in-150` (and same for `zoom-out-*`).
248
+ Full range: `zoom-in-0`, `zoom-in-1`, `zoom-in-5`, `zoom-in-10`, `zoom-in-25`, `zoom-in-50`, `zoom-in-75`, `zoom-in-90`, `zoom-in-95`, `zoom-in-100`, `zoom-in-105`, `zoom-in-110`, `zoom-in-125`, `zoom-in-150`, `zoom-in-200` (and same for `zoom-out-*`).
238
249
 
239
250
  ---
240
251
 
@@ -278,7 +289,7 @@ At construction time, top-level `scale`, `rotate`, and `anchorPoint` are convert
278
289
 
279
290
  `play()`, `toggle()`, `apply()`, and `sequence()` toggle internal open/close state. `open()` and `close()` set it explicitly. The active state is merged into the current base object when `animationProperties` exists.
280
291
 
281
- After a top-level `play`, `toggle`, `open`, or `close`, `animationProperties.complete` starts as a second animation. `apply()` applies `complete` immediately. The public callback belongs to the base play/apply operation; it does not wait for the second top-level `complete` animation.
292
+ After a top-level `play`, `toggle`, `open`, or `close`, and after each view of a `sequence()`, `animationProperties.complete` starts as a second animation. `apply()` applies `complete` immediately. The public callback belongs to the base play/apply operation; it does not wait for the second top-level `complete` animation.
282
293
 
283
294
  For each direct child with an active state, merge precedence is:
284
295
 
@@ -308,7 +319,7 @@ Drag precedence is precise:
308
319
  - `snap.center` invokes `snapTo()` after a valid drop; `snap.back` returns a missed drop to its captured origin.
309
320
  - No `snap.magnet` behavior exists.
310
321
 
311
- Collision detection uses the dragged view's center. On release, the last non-null hover target is a fallback when the final hit test returns `null`.
322
+ Collision detection uses the dragged view's center and runs only for views registered with `detectCollisions()`, so register the dragged views as well as the targets. Hit testing during movement runs only when a `dragCB` was supplied; in that case the last non-null hover target is a fallback when the final hit test at release returns `null`. `dragCB(source, null)` is also called whenever a registered view is released.
312
323
 
313
324
  `draggable(array)` immediately assigns each view `zIndex` from its array index. `keepZIndex` only disables later touch-start promotion. `swap()` restores z-order by the current draggable-registry order, not by arbitrary values present before registration.
314
325
 
@@ -423,3 +434,5 @@ function doAction(event) {
423
434
  ```
424
435
 
425
436
  This demonstrates: `play` for sidebar/card toggle, `open:`/`close:` modifiers for different states, `draggable` with `bounds:` modifier, and multiple Animation objects controlling different UI elements.
437
+
438
+ If this window can close, add an `onClose` handler that calls `$.draggableAnimation.undraggable($.myCard)` so the global `orientationchange` listener is removed.