@maccesar/titools 4.18.0 → 4.20.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 (28) hide show
  1. package/package.json +1 -1
  2. package/skills/purgetss/SKILL.md +9 -4
  3. package/skills/purgetss/references/animation-advanced.md +93 -226
  4. package/skills/purgetss/references/animation-system.md +26 -17
  5. package/skills/purgetss/references/app-branding.md +31 -8
  6. package/skills/purgetss/references/appearance-module.md +63 -9
  7. package/skills/purgetss/references/class-categories.md +2 -2
  8. package/skills/purgetss/references/class-index.md +1 -1
  9. package/skills/purgetss/references/classic-projects.md +24 -5
  10. package/skills/purgetss/references/cli-commands.md +59 -30
  11. package/skills/purgetss/references/custom-fonts.md +29 -2
  12. package/skills/purgetss/references/customization-deep-dive.md +20 -10
  13. package/skills/purgetss/references/dynamic-component-creation.md +1 -1
  14. package/skills/purgetss/references/icon-fonts.md +3 -1
  15. package/skills/purgetss/references/installation-setup.md +5 -1
  16. package/skills/purgetss/references/multi-density-images.md +35 -5
  17. package/skills/purgetss/references/purgetss-ui-classic.md +341 -0
  18. package/skills/purgetss/references/version-history.md +17 -0
  19. package/skills/ti-game/SKILL.md +5 -2
  20. package/skills/ti-game/references/api.md +38 -4
  21. package/skills/ti-game/references/debugging-performance.md +1 -1
  22. package/skills/ti-game/references/examples.md +6 -5
  23. package/skills/ti-game/references/patterns.md +1 -1
  24. package/skills/ti-game/references/project-setup.md +7 -3
  25. package/skills/ti-game/references/recipes-action.md +1 -1
  26. package/skills/ti-game/references/recipes-adventure-effects.md +1 -1
  27. package/skills/ti-game/references/roadmap.md +8 -4
  28. package/skills/ti-game/references/tilemaps.md +1 -1
@@ -30,6 +30,7 @@ For the terse flag reference, see the [`brand` command reference](./cli-commands
30
30
  - [iOS 18+ Dark and Tinted variants](#ios-18-dark-and-tinted-variants)
31
31
  - [Brand color](#brand-color)
32
32
  - [Padding guidance](#padding-guidance)
33
+ - [Rounded non-icon artwork](#rounded-non-icon-artwork)
33
34
  - [Cleanup legacy branding artifacts](#cleanup-legacy-branding-artifacts)
34
35
  - [Troubleshooting](#troubleshooting)
35
36
  - [Flag reference](#flag-reference)
@@ -143,12 +144,14 @@ On the first run, `purgetss brand` adds a `brand:` block to your existing `purge
143
144
 
144
145
  ```javascript
145
146
  brand: {
146
- background: '#FFFFFF', // inherited by every piece that doesn't set its own
147
- confirmOverwrites: true, // prompt before overwriting files (set false to skip)
148
- optimize: false, // true = quantize the generated PNGs to a palette (lossy, ~71% smaller)
147
+ background: '#FFFFFF', // inherited by every piece that doesn't set its own
148
+ artworkCornerRadius: '0%', // rounded non-icon artwork: splashes, Feature Graphic and LaunchLogo
149
+ confirmOverwrites: true, // prompt before overwriting files (set false to skip)
150
+ optimize: false, // true = quantize the generated PNGs to a palette (lossy, ~71% smaller)
149
151
 
150
152
  // One block per piece. Artwork comes from purgetss/brand/logo-<piece>.{svg,png};
151
153
  // these keys are for numbers, colors and activation. Padding is never inherited.
154
+ // Only iosSplash, androidSplash, featureGraphic and launchLogo accept cornerRadius.
152
155
  icon: { padding: '0%' }, // DefaultIcon.png + DefaultIcon-ios.png
153
156
  dark: { background: null }, // DefaultIcon-Dark.png
154
157
  tinted: {}, // DefaultIcon-Tinted.png
@@ -158,7 +161,7 @@ brand: {
158
161
  featureGraphic: { padding: '12%' }, // MarketplaceArtworkFeature.png (1024×500)
159
162
  adaptive: { padding: '18%' }, // ic_launcher_{foreground,background,monochrome}.png × 5 + ic_launcher.xml
160
163
  legacyIcon: { padding: '10%' }, // ic_launcher.png × 5
161
- appicon: {}, // appicon.png (128×128)
164
+ appicon: { padding: '10%' }, // appicon.png (128×128)
162
165
  androidSplash: { padding: '26%' }, // assets/android/default.png + images/res-*/default.png × 11
163
166
 
164
167
  // Opt-in: inert until you edit the Android theme / FCM meta-data by hand.
@@ -170,6 +173,8 @@ brand: {
170
173
 
171
174
  Change only what you want to keep as a project default. CLI flags still win for one-off runs.
172
175
 
176
+ Use flags for temporary artwork, geometry, the shared background, selection, activation, and optimization. Keep persistent choices such as `confirmOverwrites`, permanent `enabled` values, and exceptional per-piece backgrounds in `config.cjs`.
177
+
173
178
  ### Older configs update themselves
174
179
 
175
180
  PurgeTSS keeps `config.cjs` current the same way it renamed `config.js` to `config.cjs`: **on the file, once**. When the `brand:` block uses a shape from an earlier version, the next run rewrites it to the per-piece structure and carries over everything that had been customized (paddings, colors, logo paths, enabled flags), then lists each value it moved:
@@ -201,11 +206,12 @@ A key `brand:` does not define stops the run before a single file is written, at
201
206
  Unknown key(s) in the brand: section of purgetss/config.cjs:
202
207
  • brand.adaptive.paddig
203
208
 
204
- Top-level keys: background, confirmOverwrites, logo, monochromeLogo
209
+ Top-level keys: background, artworkCornerRadius, splashCornerRadius, confirmOverwrites,
210
+ optimize, logo, monochromeLogo
205
211
  Piece blocks: icon, dark, tinted, iosSplash, launchLogo, marketplace, featureGraphic,
206
212
  adaptive, legacyIcon, appicon, androidSplash, splashIcon,
207
213
  notificationIcon, ninePatch
208
- Inside a piece: logo, padding, background, enabled
214
+ Inside a piece: logo, padding, cornerRadius, background, enabled
209
215
 
210
216
  Check the spelling. Nothing was written.
211
217
  ```
@@ -214,12 +220,13 @@ A typo is deliberately **not** treated as an old structure: rewriting the block
214
220
 
215
221
  ## Brand config reference
216
222
 
217
- Every piece accepts the same four keys, where they apply:
223
+ Every piece accepts the same five keys, where they apply:
218
224
 
219
225
  | Key | What it does |
220
226
  | --- | --- |
221
227
  | `logo` | Path to this piece's artwork, when it lives outside `purgetss/brand/`. |
222
228
  | `padding` | Inset per side, as a number or a percentage string like `'19%'`. **Never inherited.** |
229
+ | `cornerRadius` | Rounded artwork corners, only for `iosSplash`, `androidSplash`, `featureGraphic`, and `launchLogo`; integer or percentage string from `0` through `50`. |
223
230
  | `background` | Hex color, or `null` for transparent. Inherited from `brand.background`. |
224
231
  | `enabled` | `false` turns a default piece off; `true` turns an opt-in piece on. |
225
232
 
@@ -228,6 +235,8 @@ And these live at the top level:
228
235
  | Key | Default | Purpose |
229
236
  | --- | --- | --- |
230
237
  | `background` | `'#FFFFFF'` | The background every piece inherits unless it declares its own: the Android adaptive background layer, the `DefaultIcon-ios.png` flatten, the splash canvases, and the marketplace flatten when a background is explicitly configured. |
238
+ | `artworkCornerRadius` | `'0%'` | Shared radius for the four supported non-icon artwork pieces. It never changes store or launcher icons. |
239
+ | `splashCornerRadius` | — | Optional splash-only override for `iosSplash` and `androidSplash`. |
231
240
  | `confirmOverwrites` | `true` | Whether `brand` asks before overwriting project files in place. |
232
241
  | `optimize` | `false` | Quantize the generated PNGs to a palette. Lossy — see [Shrinking the generated files](#shrinking-the-generated-files). |
233
242
  | `logo` | — | Path override for the main logo. |
@@ -576,6 +585,7 @@ Padding belongs to the piece, not to the project. Each piece has its own key and
576
585
  | --- | --- | --- | --- |
577
586
  | `adaptive` | `brand.adaptive.padding` | `--android-adaptive-padding` | `18%` |
578
587
  | `legacy-icon` | `brand.legacyIcon.padding` | `--android-legacy-padding` | `10%` |
588
+ | `appicon` | `brand.appicon.padding` | `--appicon-padding` | `10%` |
579
589
  | `icon` | `brand.icon.padding` | `--ios-padding` | `0%` |
580
590
  | `feature-graphic` | `brand.featureGraphic.padding` | `--feature-graphic-padding` | `12%` |
581
591
  | `launch-logo` | `brand.launchLogo.padding` | `--launch-logo-padding` | `12%` |
@@ -619,6 +629,19 @@ The `26%` default is calibrated against the Titanium template itself: the Alloy
619
629
 
620
630
  Before v7.13.0 none of this was configurable: `default.png` used a hardcoded box of 72% × 26% of its own canvas, and the `res-*` set a separate hardcoded 60%. Two rules for the same piece, neither adjustable.
621
631
 
632
+ ## Rounded non-icon artwork
633
+
634
+ `brand.artworkCornerRadius` rounds artwork only in the 16 iPhone launch images, Android `default.png` plus its 11 qualifier variants, `MarketplaceArtworkFeature.png`, and `LaunchLogo.png`. A piece may override it with `cornerRadius`; `brand.splashCornerRadius` is an optional shared override for the two legacy splash pieces.
635
+
636
+ Values are integer numbers or percentage strings from `0` through `50`, measured against the shorter side of the resized artwork. `0%` preserves the previous output byte for byte; `50%` makes square artwork circular and a wordmark capsule-shaped. Normal and `--dry-run` summaries report the effective padding and radius.
637
+
638
+ Precedence is:
639
+
640
+ - Feature Graphic / LaunchLogo: piece-specific flag → `--artwork-corner-radius` → piece config → `brand.artworkCornerRadius` → `0%`.
641
+ - Legacy splashes: platform flag → `--splash-corner-radius` → `--artwork-corner-radius` → piece config → `brand.splashCornerRadius` → `brand.artworkCornerRadius` → `0%`.
642
+
643
+ Store and launcher icons remain unmasked for platform processing. `cornerRadius` is rejected in `DefaultIcon*`, `iTunesConnect.png`, `MarketplaceArtwork.png`, adaptive, legacy, and app icons, Android 12+ `splash_icon.png`, notification icons, and any other unsupported piece; invalid, fractional, negative, non-numeric, or greater-than-50 values also abort before files are written.
644
+
622
645
  ### Adaptive icon padding
623
646
 
624
647
  Android's adaptive canvas is 108 dp. The mask leaves roughly 72 dp visible, and the **guaranteed** safe area is a 66 dp circle inscribed in it. What each padding means in those terms:
@@ -753,7 +776,7 @@ All 5 Android densities, marketplace artwork, splash canvases, and iOS variants
753
776
 
754
777
  ## Flag reference
755
778
 
756
- Every flag lives in the terse reference: [`brand` command](./cli-commands.md#brand-command) — project & output, `--only`, padding, optional asset types, the `--<piece>-logo` overrides, `--optimize`, appearance, legacy cleanup and diagnostics, with examples.
779
+ Every flag lives in the terse reference: [`brand` command](./cli-commands.md#brand-command) — project & output, `--only`, padding and corner radius, optional asset types, the `--<piece>-logo` overrides, `--optimize`, appearance, legacy cleanup and diagnostics, with examples.
757
780
 
758
781
  ## Community-Discovered Patterns
759
782
 
@@ -1,6 +1,6 @@
1
1
  # Appearance Module
2
2
 
3
- The `Appearance` export from `purgetss.ui` (added in **v7.5.3**) handles Light / Dark / System mode switching and persists the user's choice across app restarts. It is a thin, deterministic wrapper around Titanium's native `Ti.UI.overrideUserInterfaceStyle` plus `Ti.App.Properties`, exposed as a singleton so every controller in the app reads and writes the same state.
3
+ The `Appearance` export from `purgetss.ui` (added in **v7.5.3**) handles Light / Dark / System mode switching and persists the user's choice across app restarts. It is a thin, deterministic wrapper around Titanium's native `Ti.UI.overrideUserInterfaceStyle` plus `Ti.App.Properties`, exposed as a singleton so every Alloy controller or Classic module reads and writes the same state.
4
4
 
5
5
  This reference follows the same workflow-first / API-second split the official PurgeTSS documentation now uses:
6
6
 
@@ -18,7 +18,7 @@ For the color wiring that actually makes the UI *respond* to mode changes, see [
18
18
  The Appearance module sits between three moving parts: a JS singleton, the OS-level interface style, and the semantic colors generated by PurgeTSS. The diagram below shows how a single `Appearance.init()` call at startup wires them together, and what happens when the user later picks a mode in Settings.
19
19
 
20
20
  ```
21
- ┌─ app/lib/appearance.js (singleton from purgetss.ui) ─────────────────┐
21
+ ┌─ Appearance singleton from purgetss.ui ──────────────────────────────┐
22
22
  │ │
23
23
  │ Appearance.init() ────► reads 'userInterfaceStyle' │
24
24
  │ from Ti.App.Properties │
@@ -160,16 +160,67 @@ The background, text, border, and icon colors in the XML come from semantic colo
160
160
 
161
161
  > **Why named functions in Alloy controllers?** Alloy resolves `onClick="selectDark"` by looking up a top-level identifier on the controller scope. Named function declarations (`function selectDark() { ... }`) hoist and are reliably resolvable; arrow functions assigned to `const` are not hoisted and tend to bite you when an XML attribute fires before the binding has executed. The official setup guide uses named functions for this reason.
162
162
 
163
+ ## Titanium Classic
164
+
165
+ Classic loads the generated runtime from `Resources/lib/purgetss.ui.js` and keeps the native color catalog at `Resources/semantic.colors.json`:
166
+
167
+ ```json
168
+ {
169
+ "surfaceColor": { "light": "#F8FAFC", "dark": "#0F172A" },
170
+ "textColor": { "light": "#0F172A", "dark": "#F8FAFC" },
171
+ "accentColor": { "light": "#2563EB", "dark": "#60A5FA" }
172
+ }
173
+ ```
174
+
175
+ Use those semantic names directly in native Titanium color properties. Classic does not need PurgeTSS utility classes, TSS, `purgetss/config.cjs`, or any Alloy runtime file.
176
+
177
+ ```javascript
178
+ const { Appearance } = require('lib/purgetss.ui')
179
+
180
+ Appearance.init()
181
+
182
+ const window = Ti.UI.createWindow({ backgroundColor: 'surfaceColor' })
183
+ const title = Ti.UI.createLabel({
184
+ text: `Mode: ${Appearance.get()}`,
185
+ color: 'textColor'
186
+ })
187
+ const toggleButton = Ti.UI.createButton({
188
+ title: 'Toggle appearance',
189
+ color: 'surfaceColor',
190
+ backgroundColor: 'accentColor'
191
+ })
192
+
193
+ function toggleAppearance() {
194
+ Appearance.toggle()
195
+ title.text = `Mode: ${Appearance.get()}`
196
+ }
197
+
198
+ function disposeWindow() {
199
+ toggleButton.removeEventListener('click', toggleAppearance)
200
+ window.removeEventListener('close', disposeWindow)
201
+ }
202
+
203
+ toggleButton.addEventListener('click', toggleAppearance)
204
+ window.add(title)
205
+ window.add(toggleButton)
206
+ window.addEventListener('close', disposeWindow)
207
+ window.open()
208
+ ```
209
+
210
+ Run a full native build after adding or changing semantic keys. A LiveView reload alone does not refresh Titanium's native color catalog. The `purgetss semantic` command can create the JSON for a Classic project; it writes only `Resources/semantic.colors.json`, not `config.cjs`, TSS, or utility mappings.
211
+
212
+ For animation and runtime lifecycle examples in the same Classic application, see [purgetss-ui-classic.md](./purgetss-ui-classic.md).
213
+
163
214
  ## API reference
164
215
 
165
216
  ### Methods
166
217
 
167
- | Method | Description |
168
- | ------------ | --------------------------------------------------------------------------- |
169
- | `init()` | Restore the saved mode from `Ti.App.Properties` and apply it via `Ti.UI.overrideUserInterfaceStyle`. Call once at app startup before opening the first window. |
170
- | `set(mode)` | Apply and persist a mode. Accepts `'system'`, `'light'`, or `'dark'`. Any other value is silently ignored. |
171
- | `get()` | Returns the current mode as a string: `'system'`, `'light'`, or `'dark'`. |
172
- | `toggle()` | Switch between `'light'` and `'dark'`. Skips `'system'` — if current mode is `'system'` the next call produces `'dark'`. |
218
+ | Method | Description | Return |
219
+ | --- | --- | --- |
220
+ | `init()` | Restore the saved mode from `Ti.App.Properties` and apply it via `Ti.UI.overrideUserInterfaceStyle`. Call once at app startup before opening the first window. | `undefined` |
221
+ | `set(mode)` | Apply and persist a mode. Accepts `'system'`, `'light'`, or `'dark'`. Any other value is silently ignored. | `undefined` |
222
+ | `get()` | Read the current mode as `'system'`, `'light'`, or `'dark'`. | Mode string |
223
+ | `toggle()` | Switch between `'light'` and `'dark'`. Skips `'system'` — if current mode is `'system'` the next call produces `'dark'`. | `undefined` |
173
224
 
174
225
  All four methods are **synchronous**. They do not fire events; if you need to react to a mode change, call your update logic right after `Appearance.set(...)`.
175
226
 
@@ -210,10 +261,13 @@ app startup
210
261
  ## Related
211
262
 
212
263
  - [semantic-colors.md](./semantic-colors.md) — defining `app/assets/semantic.colors.json` and mapping the color names in `config.cjs` so views actually respond to mode changes.
213
- - [cli-commands.md#semantic-command](./cli-commands.md#semantic-command) — the `purgetss semantic` command, which writes both the JSON and the `config.cjs` mapping for you.
264
+ - [cli-commands.md#semantic-command](./cli-commands.md#semantic-command) — the `purgetss semantic` command; Alloy also receives `config.cjs` mappings, while Classic receives only the native JSON.
214
265
  - [customization-deep-dive.md](./customization-deep-dive.md) — full `config.cjs` structure, including the `theme.extend.colors` section where semantic names are registered.
266
+ - [purgetss-ui-classic.md](./purgetss-ui-classic.md) — generated module path, Classic animation factory, method contracts, and cleanup.
215
267
 
216
268
  ## Community-Discovered Patterns
217
269
 
270
+ These field-tested patterns are now also confirmed by the official Appearance documentation:
271
+
218
272
  - **Always call `Appearance.init()` before opening the first window.** Opening the window first causes a visible flicker on cold launch as the UI repaints from the system default to the saved mode. The official best-practices guide puts `Appearance.init()` on line 3 of `app/controllers/index.js`, immediately before `$.navWin.open()`, for exactly this reason.
219
273
  - **`toggle()` is not a three-state cycle.** It only alternates between `'light'` and `'dark'`. If the saved mode is `'system'`, the first `toggle()` call lands on `'dark'`. Build a cycle yourself with `get()` + `set(...)` when you need one.
@@ -193,8 +193,8 @@ Complete inventory of all class prefixes organized by functional category. For n
193
193
  | `duration-*` | 22 | `duration-0`, `duration-50` to `duration-5000` |
194
194
  | `delay-*` | 22 | `delay-0`, `delay-50` to `delay-5000` |
195
195
  | `repeat-*` | ~31 | `repeat-*` variants |
196
- | `snap-*` (v7.4.0+) | 6 | `snap-back`, `snap-back-false`, `snap-center`, `snap-center-false`, `snap-magnet`, `snap-magnet-false` — drop behaviors for draggable views |
197
- | `keep-z-index` (v7.4.0+) | 2 | `keep-z-index`, `keep-z-index-false` — preserves z-order during drag when using `transition` layouts |
196
+ | `snap-*` runtime behavior (v7.4.0+) | 4 | `snap-back`, `snap-back-false`, `snap-center`, `snap-center-false` — implemented drop behaviors. Generated inventories may still contain `snap-magnet*`, but the runtime does not consume them |
197
+ | `keep-z-index` (v7.4.0+) | 2 | `keep-z-index`, `keep-z-index-false` — prevents touch-start promotion; it does not stop `draggable(array)` from assigning index-based z-order |
198
198
 
199
199
  ### Shadows & Elevation
200
200
 
@@ -196,7 +196,7 @@ The rest of this document collects conventions, prohibitions, and insights surfa
196
196
 
197
197
  ## All 364 Unique Prefixes (Alphabetical)
198
198
 
199
- > **NOTE**: Recent additions — v7.4.0 introduced `snap-back`, `snap-back-false`, `snap-center`, `snap-center-false`, `snap-magnet`, `snap-magnet-false`, `keep-z-index`, and `keep-z-index-false` for the Animation module drop/drag system. v7.5.3 introduced font-family classes `font-sans`, `font-serif`, `font-mono` alongside the existing weight classes.
199
+ > **NOTE**: v7.4.0 introduced `snap-back`, `snap-back-false`, `snap-center`, `snap-center-false`, `snap-magnet`, `snap-magnet-false`, `keep-z-index`, and `keep-z-index-false`. The current runtime implements back, center, and touch-start z-index preservation but does not read `snap.magnet`; do not suggest the generated magnet classes as working behavior. v7.5.3 added `font-sans`, `font-serif`, and `font-mono`.
200
200
 
201
201
 
202
202
  ```
@@ -1,6 +1,6 @@
1
1
  # Classic Project Support
2
2
 
3
- PurgeTSS 7.15 keeps its utility-class lifecycle Alloy-only while allowing independent asset and CommonJS commands to run in Titanium Classic projects. Detect the project layout before choosing a command or output path.
3
+ Since PurgeTSS 7.15, the utility-class lifecycle remains Alloy-only while independent asset and CommonJS commands can run in Titanium Classic projects. Detect the project layout before choosing a command or output path.
4
4
 
5
5
  Official source: <https://purgetss.com/docs/commands#alloy-and-classic-compatibility>
6
6
 
@@ -11,8 +11,8 @@ Official source: <https://purgetss.com/docs/commands#alloy-and-classic-compatibi
11
11
  | `brand` | yes | yes | Writes branding assets to Classic paths and follows enabled `tiapp.xml` deployment targets; explicit `--only` overrides that filter. |
12
12
  | `images` | yes | yes | Writes density variants under `Resources/android/images/res-*/` and `Resources/iphone/images/`; follows deployment targets unless `--android` or `--ios` is explicit. |
13
13
  | `semantic` | yes | yes | Writes only `Resources/semantic.colors.json`; it does not create `purgetss/`, `config.cjs`, TSS, `app/`, or a hook. |
14
- | `shades` | yes | yes | Output-only modes work anywhere. Saving creates or updates `purgetss/config.cjs` as a development-time color source. |
15
- | `color-module` | yes | yes | Writes `app/lib/purgetss.colors.js` or `Resources/lib/purgetss.colors.js`. |
14
+ | `shades` | yes | yes | Output-only modes work anywhere. On a fresh Classic project, saving creates only `purgetss/config.cjs`; if the color module already exists, it is regenerated. |
15
+ | `color-module` | yes | yes | Writes `app/lib/purgetss.colors.js` or `Resources/lib/purgetss.colors.js`; Classic creates no unrelated empty source folders. |
16
16
  | `module` | yes | yes | Writes `app/lib/purgetss.ui.js` or `Resources/lib/purgetss.ui.js`. |
17
17
  | `icon-library` | yes | yes | Copies fonts to `Resources/fonts/` and optional modules to `Resources/lib/`; `--styles` is skipped in Classic. |
18
18
  | `build-fonts` | yes | yes | Copies fonts to `Resources/fonts/` and optionally writes `Resources/lib/purgetss.fonts.js`; it does not generate TSS in Classic. |
@@ -30,12 +30,14 @@ A Classic project does not receive or need:
30
30
  - `alloy.jmk`
31
31
  - utility classes in views or controllers
32
32
  - `$.UI.create()`
33
- - PurgeTSS during application compilation or at runtime
33
+ - the PurgeTSS CLI/package during application compilation or as an app dependency (generated CommonJS modules execute normally)
34
34
 
35
35
  Files generated under `Resources/` are native Titanium resources. Compile the Classic app normally with `ti build`.
36
36
 
37
37
  Do not interpret the presence of `purgetss/config.cjs` in a Classic project as permission to use utilities. Commands such as `brand`, `images`, `shades`, and `color-module` may use that file as development-time input without installing the Alloy lifecycle.
38
38
 
39
+ Classic `shades` and `color-module` do not scaffold the empty `purgetss/brand/`, `purgetss/fonts/`, or `purgetss/images/` conventions created by Alloy initialization. On a fresh project, `shades` creates only its config; `color-module` creates that config when missing plus its module. If the module already exists, saving a palette refreshes it automatically.
40
+
39
41
  ## Layout and Output Routing
40
42
 
41
43
  | Artifact | Alloy | Classic |
@@ -45,9 +47,25 @@ Do not interpret the presence of `purgetss/config.cjs` in a Classic project as p
45
47
  | iPhone UI scales | `app/assets/iphone/images/` | `Resources/iphone/images/` |
46
48
  | Font files | `app/assets/fonts/` | `Resources/fonts/` |
47
49
  | Color module | `app/lib/purgetss.colors.js` | `Resources/lib/purgetss.colors.js` |
48
- | UI module | `app/lib/purgetss.ui.js` | `Resources/lib/purgetss.ui.js` |
50
+ | UI module | `app/lib/purgetss.ui.js` | `Resources/lib/purgetss.ui.js` (see [`purgetss.ui` in Classic](./purgetss-ui-classic.md)) |
49
51
  | Custom-font module | `app/lib/purgetss.fonts.js` | `Resources/lib/purgetss.fonts.js` |
50
52
 
53
+ ## Loading Generated Modules in Classic
54
+
55
+ Titanium resolves local CommonJS paths from `Resources/`. Omit both the `Resources/` prefix and the `.js` extension from `require()`.
56
+
57
+ | Generated file | Classic `require()` path |
58
+ | --- | --- |
59
+ | `Resources/lib/purgetss.colors.js` | `require('lib/purgetss.colors')` |
60
+ | `Resources/lib/purgetss.ui.js` | `require('lib/purgetss.ui')` |
61
+ | `Resources/lib/purgetss.fonts.js` | `require('lib/purgetss.fonts')` |
62
+ | `Resources/lib/fontawesome.js` | `require('lib/fontawesome')` |
63
+ | `Resources/lib/materialicons.js` | `require('lib/materialicons')` |
64
+ | `Resources/lib/materialsymbols.js` | `require('lib/materialsymbols')` |
65
+ | `Resources/lib/framework7icons.js` | `require('lib/framework7icons')` |
66
+
67
+ This follows Titanium's [CommonJS module path resolution](https://titaniumsdk.com/guide/Titanium_SDK/Titanium_SDK_Guide/Best_Practices_and_Recommendations/CommonJS_Modules_in_Titanium.html#javascript-module-path-resolution).
68
+
51
69
  ## Deployment Targets
52
70
 
53
71
  `brand` and `images` read `<deployment-targets>` from `tiapp.xml` independently of whether the layout is Alloy or Classic.
@@ -94,3 +112,4 @@ When auditing a Classic project that uses PurgeTSS:
94
112
  - [Semantic Colors](./semantic-colors.md)
95
113
  - [Icon Font Libraries](./icon-fonts.md)
96
114
  - [Custom Fonts](./custom-fonts.md)
115
+ - [`purgetss.ui` in Titanium Classic](./purgetss-ui-classic.md)
@@ -70,25 +70,32 @@ module.exports = {
70
70
  }
71
71
  },
72
72
  brand: {
73
- background: '#FFFFFF', // inherited by every piece that doesn't set its own
74
- confirmOverwrites: true, // prompt before overwriting files (set false to skip)
75
- optimize: false, // true = quantize the generated PNGs to a palette (lossy)
73
+ background: '#FFFFFF', // inherited by every piece that doesn't set its own
74
+ artworkCornerRadius: '0%', // splashes, Feature Graphic and LaunchLogo
75
+ confirmOverwrites: true, // prompt before overwriting files (set false to skip)
76
+ optimize: false, // true = quantize the generated PNGs to a palette (lossy)
76
77
 
77
78
  // One block per piece — see the `brand` Command section for the full list.
78
79
  icon: { padding: '0%' }, dark: { background: null }, tinted: {},
79
80
  iosSplash: { padding: '26%' }, launchLogo: { padding: '12%' },
80
81
  marketplace: {}, featureGraphic: { padding: '12%' },
81
82
  adaptive: { padding: '18%' }, legacyIcon: { padding: '10%' },
82
- appicon: {}, androidSplash: { padding: '26%' },
83
+ appicon: { padding: '10%' }, androidSplash: { padding: '26%' },
83
84
 
84
85
  // Opt-in: inert until you edit the Android theme / FCM meta-data by hand.
85
86
  splashIcon: { enabled: false }, notificationIcon: { enabled: false },
86
87
  ninePatch: { enabled: false }
87
88
  },
89
+ // Sources in purgetss/images/ are 4x masters: a 1024px file yields
90
+ // 256 (mdpi/@1x), 384 (hdpi), 512 (xhdpi/@2x), 768 (xxhdpi/@3x), 1024 (xxxhdpi).
91
+ // There is no width to configure here — the source's own pixels decide.
92
+ // SVGs have no natural pixels; pin theirs in files: [] below.
88
93
  images: {
89
- quality: 85, // JPEG/WebP/AVIF quality (0-100)
94
+ quality: 85, // webp/jpeg/avif/tiff quality (0-100); PNG and GIF ignore it
90
95
  format: null, // null = keep original; 'webp' | 'jpeg' | 'png' to convert every image
91
- confirmOverwrites: true // prompt before overwriting files (set false to skip)
96
+ autoSync: true, // false = SVG pipeline computes dims but doesn't write to images.files
97
+ confirmOverwrites: true, // prompt before overwriting files (set false to skip)
98
+ files: [] // per-file overrides: [{ filename: 'images/<sub>/<name>.<ext>', width, height? }]
92
99
  },
93
100
  theme: {
94
101
  extend: {}
@@ -170,7 +177,7 @@ Recommended VSCode extensions:
170
177
 
171
178
  ### Commands Executed Internally
172
179
 
173
- `purgetss create "Name of the Project" [--dependencies --vendor=fa,mi,ms,f7]` runs: `ti config` (reads idprefix/workspace), `ti create -t app -p all -n "Name"`, `alloy new`, `purgetss w`, `purgetss b`, optional `--vendor` (copies fonts + CommonJS module), optional `--dependencies` (installs Tailwind CSS, ESLint with Titanium plugins, and config files), then opens the project in VS Code, Sublime Text, or Finder.
180
+ `purgetss create "Name of the Project" [--dependencies --vendor=fa,mi,ms,f7]` runs: `ti config` (reads idprefix/workspace), `ti create -t app -p all -n "Name"`, `alloy new`, `purgetss w`, `purgetss b`, optional `--vendor` (copies fonts + CommonJS module), optional `--dependencies` (installs Tailwind CSS and ESLint, and copies the config files — see [`install-dependencies`](#install-dependencies-command)), then opens the project in VS Code, Sublime Text, or Finder.
174
181
 
175
182
  ## `brand` Command
176
183
 
@@ -211,15 +218,20 @@ The 14 pieces, their config keys and what each one writes are tabulated in [app-
211
218
  | `--padding <n>` | Shortcut: sets both Android launcher paddings to the same value for one run. |
212
219
  | `--android-adaptive-padding <n>` | Adaptive icon safe-zone % (default `18`). |
213
220
  | `--android-legacy-padding <n>` | Legacy `ic_launcher.png` padding % (default `10`). |
221
+ | `--appicon-padding <n>` | `appicon.png` padding % (default `10`). |
214
222
  | `--ios-padding <n>` | Padding % for the four square iOS/marketplace pieces — `icon`, `dark`, `tinted`, `marketplace` (default `0`, full-bleed). |
215
223
  | `--feature-graphic-padding <n>` | Vertical padding % for `MarketplaceArtworkFeature.png` (range `0-40`, default `12`). |
216
224
  | `--launch-logo-padding <n>` | Padding % for `LaunchLogo.png` (default `12`). |
217
225
  | `--splash-padding <n>` | Shortcut: sets both splash paddings to the same value for one run. |
218
226
  | `--android-splash-padding <n>` | Padding % for `default.png` and the 11 `res-*` splashes (default `26`). |
219
227
  | `--ios-splash-padding <n>` | Padding % for the 16 iPhone launch images (default `26`). |
228
+ | `--artwork-corner-radius <n>` / `--splash-corner-radius <n>` | Shared non-icon radius, or a splash-only one-run override (range `0-50`, default `0`). |
229
+ | `--ios-splash-corner-radius <n>` / `--android-splash-corner-radius <n>` | Per-platform legacy splash artwork radius (range `0-50`). |
230
+ | `--feature-graphic-corner-radius <n>` / `--launch-logo-corner-radius <n>` | Per-piece Feature Graphic or LaunchLogo artwork radius (range `0-50`). |
220
231
 
221
232
  Splash padding is a share of the canvas's **shorter** side, so one number keeps the logo at the same visual weight in portrait and in landscape: the `26%` default leaves it at 48% of the shorter side.
222
233
 
234
+ Radius precedence and the outputs intentionally left unmasked are documented in [Rounded non-icon artwork](./app-branding.md#rounded-non-icon-artwork). Normal and `--dry-run` summaries report effective padding and radius.
223
235
  **Optional asset types**
224
236
 
225
237
  | Flag | Purpose |
@@ -227,7 +239,6 @@ Splash padding is a share of the canvas's **shorter** side, so one number keeps
227
239
  | `--notification-icon` | Also emit `ic_stat_notify.png × 5`. |
228
240
  | `--splash-icon` | Also emit `splash_icon.png × 5`. |
229
241
  | `--nine-patch` | Declared but not implemented yet; prints a warning and writes nothing. |
230
-
231
242
  **Logo variants & overrides**
232
243
 
233
244
  Every piece has a `--<piece>-logo <path>` flag — with no exceptions since v7.13.0 — each overriding the matching `purgetss/brand/logo-<piece>.{svg,png}`:
@@ -235,7 +246,6 @@ Every piece has a `--<piece>-logo <path>` flag — with no exceptions since v7.1
235
246
  `--icon-logo`, `--dark-logo`, `--tinted-logo`, `--ios-splash-logo`, `--launch-logo`, `--marketplace-logo`, `--feature-graphic-logo`, `--adaptive-logo`, `--legacy-icon-logo`, `--appicon-logo`, `--android-splash-logo`, `--splash-icon-logo`, `--notification-icon-logo`.
236
247
 
237
248
  `--launch-logo` is the one that also **activates** its piece. Two more sources are not pieces: `--monochrome-logo <path>` (the silhouette shared by the adaptive monochrome layer and the notification icons, `logo-mono.{svg,png}`) and the positional `<logo>` argument (the main logo).
238
-
239
249
  **Output size**
240
250
 
241
251
  | Flag | Purpose |
@@ -274,11 +284,11 @@ Every piece has a `--<piece>-logo <path>` flag — with no exceptions since v7.1
274
284
 
275
285
  ### Config block (v7.13.0 per-piece structure)
276
286
 
277
- Defaults live under `brand:` in `purgetss/config.cjs`. Since v7.14.0, a standalone Classic run creates the canonical config when it is missing. The block has **one entry per piece**; each accepts the same four keys where they apply: `logo`, `padding` (never inherited), `background` (inherited from `brand.background`), `enabled`. Top-level: `background`, `confirmOverwrites`, `optimize`, `logo`, `monochromeLogo`.
287
+ Defaults live under `brand:` in `purgetss/config.cjs`. Since v7.14.0, a standalone Classic run creates it when missing. Each piece accepts `logo`, `padding`, `cornerRadius`, `background`, and `enabled` where applicable; radius is valid only for the two legacy splashes, Feature Graphic, and LaunchLogo. Top-level settings include shared `artworkCornerRadius`, optional `splashCornerRadius`, background, persistence, optimization, and logo values.
278
288
 
279
289
  An unknown key aborts the run before a single file is written. A `brand:` block written for an older PurgeTSS is **rewritten on disk** on the next run, carrying over every customized value.
280
290
 
281
- Full annotated block and per-key reference: [app-branding.md → The `brand:` config section](./app-branding.md#the-brand-config-section) and [Older configs update themselves](./app-branding.md#older-configs-update-themselves). The recommended workflow is convention-first: drop files in `purgetss/brand/`, let auto-discovery pick them up, and use `config.cjs` only for a persistent override.
291
+ Full annotated block and per-key reference: [app-branding.md → The `brand:` config section](./app-branding.md#the-brand-config-section). Use flags for one-run sources, geometry, selection, activation, background, or optimization; keep persistent preferences in `config.cjs`.
282
292
 
283
293
  ### Confirmation prompt
284
294
 
@@ -295,12 +305,12 @@ purgetss brand --adaptive-logo ./docs/app-icon.svg # dedicated square And
295
305
  purgetss brand --splash-icon --splash-icon-logo ./docs/splash.svg # custom Android 12+ splash artwork
296
306
  purgetss brand --launch-logo ./docs/wordmark.svg # iOS launch screen logotype
297
307
  purgetss brand --feature-graphic-logo ./docs/feature.svg # custom Google Play Feature Graphic
298
- purgetss brand --feature-graphic-padding 8 # tighter Feature Graphic padding
308
+ purgetss brand --artwork-corner-radius 22 # round supported non-icon artwork
309
+ purgetss brand --splash-corner-radius 18 # override both legacy splash sets
310
+ purgetss brand --appicon-padding 14 # temporary appicon.png inset
299
311
  purgetss brand --notification-icon --splash-icon # add notification + splash icons
300
- purgetss brand --no-tinted # skip iOS 18+ tinted variant
301
312
  purgetss brand --optimize # quantize the generated PNGs
302
313
  purgetss brand --dry-run # preview without writing
303
- purgetss brand --cleanup-legacy --dry-run # preview legacy cleanup
304
314
  ```
305
315
 
306
316
  ### Android output groups
@@ -327,7 +337,7 @@ purgetss images background/ # re-process one subfolder
327
337
  | `--android` | Only emit Android density variants. Mutually exclusive with `--ios`. |
328
338
  | `--ios` | Only emit iPhone scale variants. Mutually exclusive with `--android`. |
329
339
  | `--format <ext>` | Convert all outputs to `webp`, `jpeg`, `png`, `avif`, `gif`, or `tiff`. Default: keep source format. |
330
- | `--quality <n>` | Quality `0-100` for lossy formats. Default `85`. |
340
+ | `--quality <n>` | Quality `0-100` for `webp`, `jpeg`, `avif` and `tiff`. PNG and GIF ignore it. Default `85`. |
331
341
  | `--width <n>` | (v7.8.0) Pin Android `mdpi` (= iPhone `@1x`) to `<n>` pixels wide. Larger scales derive as ×1.5, ×2, ×3, ×4 from that base; height stays proportional to the source's aspect ratio. Integer in `[1, 8192]`. |
332
342
  | `--opacity <n>` | (v7.10.0) Multiply alpha of every density by `n/100`. Integer in `[0, 100]`. With `--format jpeg`, alpha flattens on white. |
333
343
  | `--padding <n>` | (v7.10.0) Shrink the rendered image inside each density canvas by `n%` symmetric borders. Integer in `[0, 40]`. |
@@ -365,12 +375,16 @@ Defaults live under `images:` in `purgetss/config.cjs`:
365
375
 
366
376
  ```javascript
367
377
  images: {
368
- quality: 85, // JPEG/WebP/AVIF quality (0-100)
378
+ quality: 85, // webp/jpeg/avif/tiff quality (0-100); PNG and GIF ignore it
369
379
  format: null, // null = keep original; 'webp' | 'jpeg' | 'png' | 'avif' | 'gif' | 'tiff'
370
- confirmOverwrites: true // prompt before overwriting files
380
+ autoSync: true, // false = SVG pipeline computes dims but doesn't write to images.files
381
+ confirmOverwrites: true, // prompt before overwriting files
382
+ files: [] // per-file overrides: [{ filename, width, height? }]
371
383
  }
372
384
  ```
373
385
 
386
+ Those five keys are the whole section. Since v7.17.0 any other key — including `width`, `opacity`, `padding` and `output`, which are CLI flags — aborts the run before writing anything, and so does a `files[]` entry with an unknown key or no `filename`. See [Unknown keys are an error](./multi-density-images.md#unknown-keys-are-an-error-v7170).
387
+
374
388
  Like `brand`, `images` writes in place and asks `Continue? [y/N/a]` before overwriting. Selecting `a` flips `confirmOverwrites: false` in `config.cjs`. Skipped automatically when `stdin` is not a TTY, when `-y`/`--yes` is passed, or when `PURGETSS_YES=1` is set.
375
389
 
376
390
  ### Examples
@@ -477,6 +491,15 @@ purgetss install-dependencies
477
491
  purgetss id
478
492
  ```
479
493
 
494
+ ### What it installs (v7.17.0)
495
+
496
+ `npm i -D eslint @eslint/js` plus a flat `eslint.config.mjs` in the project root, `.editorconfig`, `.vscode/{extensions,settings}.json` when the `code` command exists, and `tailwindcss@3` for IntelliSense. `create --dependencies` runs the same ESLint and Tailwind steps. `eslint-config-axway` and `eslint-plugin-alloy` are no longer installed.
497
+
498
+ The shipped config declares the Titanium and Alloy globals itself (`Ti`, `Titanium`, `Alloy`, `Backbone`, `$`, `$model`, `_`, `L`, `Widget`, `OS_*`, `ENV_*`, `DIST_*`, `console`, `alert`, the timer functions, and `task` for `alloy.jmk`). It lints `app/**/*.js` and ignores `Resources/`, `build/`, `node_modules/`, `purgetss/`, plus the six libraries PurgeTSS copies into `app/lib/`, listed by name so the developer's own files there keep being linted. `no-unused-vars` is a **warning**: Alloy wires handlers from the XML view, so a controller function with no caller in the JS may still be in use.
499
+
500
+ > **Warning**
501
+ > Before v7.17.0 this command shipped an `.eslintrc.js` extending `eslint-config-axway/env-alloy` and installed `eslint-plugin-alloy`. That setup cannot run under ESLint 9 — it stopped reading `.eslintrc.*`, axway removed `env-alloy` in `eslint-config-axway@10.0.0`, and the unmaintained plugin throws `This method cannot be used with flat config`. Projects scaffolded between December 2025 and v7.17.0 have a lint that never ran; re-run `purgetss install-dependencies` to replace it.
502
+
480
503
  > **Caution**
481
504
  > This command overwrites any existing `extensions.json` and `settings.json` files. Back them up if you want to keep your current versions.
482
505
 
@@ -521,13 +544,14 @@ purgetss bf [-m] [-f]
521
544
 
522
545
  | Flag | Purpose |
523
546
  | --- | --- |
524
- | `-m, --module` | Also generates `app/lib/purgetss.fonts.js` (Alloy) or `Resources/lib/purgetss.fonts.js` (Classic), exposing `exports.icons` and `exports.families`. |
547
+ | `-m, --module` | Also generates `app/lib/purgetss.fonts.js` (Alloy) or `Resources/lib/purgetss.fonts.js` (Classic). `exports.families` contains every processed TTF/OTF PostScript name; icon CSS additionally populates `exports.icons`. |
525
548
  | `-f, --font-class-from-filename` | Uses the font filename as the class name and icon prefix instead of the font family. Replaces the old `-p` flag. |
526
549
 
527
550
  ### What it does
528
551
 
529
552
  1. Copies font files to `app/assets/fonts/` (Alloy) or `Resources/fonts/` (Classic), renamed to their PostScript names.
530
553
  2. In Alloy only, creates `purgetss/styles/fonts.tss` with the TSS class definitions.
554
+ 3. With `--module`, creates the CommonJS module even for text-only font collections. Classic loads it with `require('lib/purgetss.fonts')`; see the [Classic module path table](./classic-projects.md#loading-generated-modules-in-classic).
531
555
 
532
556
  > **Tip**
533
557
  > This is a quick reference. See [Custom Fonts](./custom-fonts.md) for the complete guide — folder organization, class renaming, adding icon libraries, the `--module` output structure, and `--font-class-from-filename` workflow.
@@ -539,7 +563,7 @@ purgetss bf [-m] [-f]
539
563
 
540
564
  The `shades` command generates shades and tints for a given color and writes the palette to `config.cjs`.
541
565
 
542
- Saving works in Alloy and Classic. In Classic, `config.cjs` is only a development-time color source for commands such as `color-module`; it does not install the PurgeTSS utility lifecycle. `--log`, `--json`, and `--tailwind` write nothing and work outside a project.
566
+ Saving works in Alloy and Classic. In Classic, `config.cjs` is only a development-time color source for commands such as `color-module`; it does not install the PurgeTSS utility lifecycle or create empty brand, font, or image source folders. If `Resources/lib/purgetss.colors.js` already exists, saving refreshes it. `--log`, `--json`, and `--tailwind` write nothing and work outside a project.
543
567
 
544
568
  ```bash
545
569
  purgetss shades [hexcode] [name]
@@ -641,7 +665,9 @@ purgetss s '#65e92c' -j
641
665
 
642
666
  ## `color-module` Command
643
667
 
644
- This command creates `purgetss.colors.js` with all colors defined in `config.cjs`: `app/lib/` in Alloy or `Resources/lib/` in Classic. A missing config is created as the color source, but Classic receives no Alloy hook or TSS.
668
+ This command creates `purgetss.colors.js` with all colors defined in `config.cjs`: `app/lib/` in Alloy or `Resources/lib/` in Classic. A missing config is created as the color source, but Classic receives no empty `purgetss/brand/`, `purgetss/fonts/`, or `purgetss/images/` folders, Alloy hook, or TSS.
669
+
670
+ Classic loads the result with `require('lib/purgetss.colors')`; see [Classic module paths](./classic-projects.md#loading-generated-modules-in-classic).
645
671
 
646
672
  ```bash
647
673
  purgetss color-module
@@ -706,12 +732,17 @@ The command installs a task in `alloy.jmk`:
706
732
 
707
733
  ```javascript
708
734
  task('pre:compile', (event, logger) => {
709
- require('child_process').execSync('purgetss', logger.warn('::PurgeTSS:: Auto-Purging ' + event.dir.project));
710
- });
735
+ logger.warn(`::PurgeTSS:: Auto-Purging ${event.dir.project}`)
736
+ try {
737
+ require('child_process').execSync('purgetss', { stdio: 'inherit' })
738
+ } catch (error) {
739
+ logger.error('::PurgeTSS:: Auto-Purge failed. Run `purgetss` from the project root to see the cause.')
740
+ throw error
741
+ }
742
+ })
711
743
  ```
712
744
 
713
- > **Info**
714
- > This feature works with standard Alloy projects compiled using `ti build`. It has not been tested with project types built using Webpack or Vue.
745
+ The default synchronous hook inherits CLI output so validation details appear before Alloy's generic failure. Async mode forwards `stdout` and `stderr` and prints the same final hint. `init` refreshes old active or disabled hooks without changing their state; invoking `watch` normally enables a disabled hook.
715
746
 
716
747
  To deactivate it, use `--off`.
717
748
 
@@ -733,7 +764,9 @@ purgetss w -d
733
764
 
734
765
  ## `module` Command
735
766
 
736
- The `module` command installs the self-contained `purgetss.ui.js` in `app/lib/` (Alloy) or `Resources/lib/` (Classic). A Classic app does not need PurgeTSS during compilation or at runtime.
767
+ The `module` command installs the self-contained `purgetss.ui.js` in `app/lib/` (Alloy) or `Resources/lib/` (Classic). Classic executes that generated file but needs no PurgeTSS CLI/package at build time or as an app dependency.
768
+
769
+ Classic loads it with `require('lib/purgetss.ui')`; see [Classic module paths](./classic-projects.md#loading-generated-modules-in-classic).
737
770
 
738
771
  ```bash
739
772
  purgetss module
@@ -742,11 +775,7 @@ purgetss module
742
775
  purgetss m
743
776
  ```
744
777
 
745
- The PurgeTSS module includes:
746
-
747
- - Animation: methods for playing or applying basic animations and transformations to Titanium views.
748
-
749
- See [Animation System](./animation-system.md) for details.
778
+ The module exports `AnimationProperties`, `createAnimation(args)`, `Appearance`, `deviceInfo()`, and `saveComponent()`. Its animation object exposes 15 state, drag, collision, position, feedback, and layout methods. See [Animation System](./animation-system.md) for Alloy or [`purgetss.ui` in Classic](./purgetss-ui-classic.md) for native JavaScript.
750
779
 
751
780
  ## `update` Command
752
781