@maccesar/titools 2.5.1 → 2.6.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/LICENSE +21 -0
- package/README.md +83 -5
- package/bin/titools.js +8 -0
- package/lib/commands/list.js +105 -0
- package/lib/config.js +1 -0
- package/package.json +1 -1
- package/skills/alloy-guides/SKILL.md +1 -1
- package/skills/alloy-howtos/SKILL.md +1 -1
- package/skills/purgetss/SKILL.md +1 -1
- package/skills/ti-api/SKILL.md +1 -1
- package/skills/ti-branding/SKILL.md +225 -0
- package/skills/ti-branding/assets/ic_launcher.xml +6 -0
- package/skills/ti-branding/references/android-adaptive-icons.md +85 -0
- package/skills/ti-branding/references/cleanup-legacy.md +112 -0
- package/skills/ti-branding/references/ios-appiconset.md +62 -0
- package/skills/ti-branding/references/master-input-guidelines.md +84 -0
- package/skills/ti-branding/references/notification-icons.md +63 -0
- package/skills/ti-branding/references/splash-screen-api.md +81 -0
- package/skills/ti-branding/references/ti-icon-paths.md +84 -0
- package/skills/ti-branding/references/tiapp-xml-snippets.md +92 -0
- package/skills/ti-branding/scripts/lib/cleanup-legacy.sh +230 -0
- package/skills/ti-branding/scripts/lib/deps.sh +58 -0
- package/skills/ti-branding/scripts/lib/gen-android-adaptive.sh +52 -0
- package/skills/ti-branding/scripts/lib/gen-android-legacy.sh +36 -0
- package/skills/ti-branding/scripts/lib/gen-ios.sh +30 -0
- package/skills/ti-branding/scripts/lib/gen-marketplace.sh +40 -0
- package/skills/ti-branding/scripts/lib/gen-notification.sh +34 -0
- package/skills/ti-branding/scripts/lib/gen-splash-icon.sh +31 -0
- package/skills/ti-branding/scripts/lib/prepare-master.sh +48 -0
- package/skills/ti-branding/scripts/lib/validate.sh +67 -0
- package/skills/ti-branding/scripts/ti-branding +462 -0
- package/skills/ti-expert/SKILL.md +1 -1
- package/skills/ti-guides/SKILL.md +1 -1
- package/skills/ti-howtos/SKILL.md +1 -1
- package/skills/ti-ui/SKILL.md +1 -1
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# Android adaptive icons (API 26+)
|
|
2
|
+
|
|
3
|
+
## Canvas and safe-zone
|
|
4
|
+
|
|
5
|
+
Adaptive icons use a fixed 108×108 dp virtual canvas composed of two layers:
|
|
6
|
+
|
|
7
|
+
- **Foreground**: the logo/glyph with transparency outside the safe-zone
|
|
8
|
+
- **Background**: solid color, gradient, or pattern filling the full canvas
|
|
9
|
+
|
|
10
|
+
The OS launcher applies a mask (circle, squircle, teardrop, rounded square — up to the OEM) and clips both layers to that shape. Only the central **66×66 dp safe-zone** is guaranteed to remain visible regardless of the mask.
|
|
11
|
+
|
|
12
|
+
Translation to padding:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
safe-zone: 66 / 108 = 61.1% of canvas
|
|
16
|
+
min padding: (108 - 66) / 2 / 108 = 19.44% per side
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Anything beyond 66dp toward the edge is at the launcher's discretion — some masks (circle) hide more, some (squircle) hide less.
|
|
20
|
+
|
|
21
|
+
## Density sizes
|
|
22
|
+
|
|
23
|
+
One pixel unit equals `density_scale × 1 dp`:
|
|
24
|
+
|
|
25
|
+
| Density | Scale | Canvas size (108 dp) |
|
|
26
|
+
|----------|-------|----------------------|
|
|
27
|
+
| mdpi | 1.0× | 108 px |
|
|
28
|
+
| hdpi | 1.5× | 162 px |
|
|
29
|
+
| xhdpi | 2.0× | 216 px |
|
|
30
|
+
| xxhdpi | 3.0× | 324 px |
|
|
31
|
+
| xxxhdpi | 4.0× | 432 px |
|
|
32
|
+
|
|
33
|
+
Ship all five. The OS picks the closest match for the user's screen density.
|
|
34
|
+
|
|
35
|
+
## Monochrome layer (API 31+)
|
|
36
|
+
|
|
37
|
+
Android 13 introduced themed icons: the user can tell the launcher to re-color all app icons with the system accent color. The OS uses the `monochrome` drawable for this treatment.
|
|
38
|
+
|
|
39
|
+
Rules for the monochrome drawable:
|
|
40
|
+
|
|
41
|
+
- All non-transparent pixels become pure white at build time — the OS tint replaces white with the theme color at render time
|
|
42
|
+
- Alpha channel must be preserved (same silhouette as foreground, transparency intact)
|
|
43
|
+
- Do NOT include color information — it will be discarded
|
|
44
|
+
|
|
45
|
+
The skill generates monochrome by taking the foreground and running ImageMagick's `-channel RGB -fill white -colorize 100 +channel` which replaces RGB with white while leaving the alpha untouched.
|
|
46
|
+
|
|
47
|
+
## XML bind
|
|
48
|
+
|
|
49
|
+
One file ties the three layers together. Ships to `mipmap-anydpi-v26/ic_launcher.xml`:
|
|
50
|
+
|
|
51
|
+
```xml
|
|
52
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
53
|
+
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
|
54
|
+
<background android:drawable="@mipmap/ic_launcher_background"/>
|
|
55
|
+
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
|
|
56
|
+
<monochrome android:drawable="@mipmap/ic_launcher_monochrome"/>
|
|
57
|
+
</adaptive-icon>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
The `v26` qualifier ensures only API 26+ devices use this file. Older devices fall through to the legacy `mipmap-*/ic_launcher.png` flat drawable.
|
|
61
|
+
|
|
62
|
+
## Legacy flat icon
|
|
63
|
+
|
|
64
|
+
For API 21–25 (~3% of active users in 2026) the launcher still uses a flat PNG:
|
|
65
|
+
|
|
66
|
+
| Density | Size |
|
|
67
|
+
|----------|------|
|
|
68
|
+
| mdpi | 48 |
|
|
69
|
+
| hdpi | 72 |
|
|
70
|
+
| xhdpi | 96 |
|
|
71
|
+
| xxhdpi | 144 |
|
|
72
|
+
| xxxhdpi | 192 |
|
|
73
|
+
|
|
74
|
+
Fill more of the canvas here — legacy launchers don't apply adaptive masking. The skill reduces the padding by 40% for this composite.
|
|
75
|
+
|
|
76
|
+
## Verifying
|
|
77
|
+
|
|
78
|
+
- Android Studio has a Resource Manager that previews adaptive icons with multiple masks. Point it at `app/platform/android/res/` to inspect.
|
|
79
|
+
- On a device/emulator running API 26+, long-press the launcher icon and the animated wiggle reveals whether the adaptive layers are wired correctly.
|
|
80
|
+
- On API 31+, toggle "Themed icons" in the launcher settings to verify the monochrome layer.
|
|
81
|
+
|
|
82
|
+
## References
|
|
83
|
+
|
|
84
|
+
- Android Developer: [Adaptive icons](https://developer.android.com/develop/ui/views/launch/icon_design_adaptive)
|
|
85
|
+
- Android Developer: [Themed app icons](https://developer.android.com/about/versions/13/features#themed-app-icons)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# `--cleanup-legacy` — removing obsolete branding artifacts
|
|
2
|
+
|
|
3
|
+
Titanium project templates ship with a lot of legacy branding assets that made sense a decade ago and are dead weight today. The `--cleanup-legacy` flag scans the project and removes them, but only after verifying through `tiapp.xml` that they are genuinely unused.
|
|
4
|
+
|
|
5
|
+
## Why cleanup matters
|
|
6
|
+
|
|
7
|
+
Legacy branding assets bloat the project in three ways:
|
|
8
|
+
|
|
9
|
+
1. **Repository size** — every `Default-XXXh@3x.png` (some 800 KB+ each) stays in git history forever unless actively deleted.
|
|
10
|
+
2. **Build output size** — some legacy assets DO get copied into the APK/IPA even when modern alternatives make them unreachable at runtime. Extra MB mean slower downloads for end users and marginally longer store review times.
|
|
11
|
+
3. **Cognitive load** — new contributors look at `res-long-port-hdpi/`, `Default-Landscape-2688h@3x.png`, `background.9.png`, and reasonably assume they matter. They don't, but nobody is willing to delete what they don't fully understand.
|
|
12
|
+
|
|
13
|
+
## The three buckets
|
|
14
|
+
|
|
15
|
+
The cleanup logic categorizes targets by how safe removal is:
|
|
16
|
+
|
|
17
|
+
### SAFE — universally obsolete
|
|
18
|
+
|
|
19
|
+
Removed without checking any project configuration. These artifacts are fossils from Android versions predating the current SDK's minimum target.
|
|
20
|
+
|
|
21
|
+
| Artifact | Why it's dead |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `app/assets/android/images/res-long-*/` | Android's `long` screen qualifier distinguished devices like the Motorola Droid (854×480) from the Nexus One (800×480) in 2009–2011. Since Android 3.0 the system uses dp-based layouts instead. No modern launcher or OS consults these folders. |
|
|
24
|
+
| `app/assets/android/images/res-notlong-*/` | Inverse of `long` — same verdict. |
|
|
25
|
+
|
|
26
|
+
These buckets are almost always empty in practice (Titanium templates create the folders but rarely populate them), so the cleanup is primarily about removing visual noise from the project tree.
|
|
27
|
+
|
|
28
|
+
### CONDITIONAL — safe given the project's current configuration
|
|
29
|
+
|
|
30
|
+
Removed only when `tiapp.xml` confirms the artifact is genuinely unused.
|
|
31
|
+
|
|
32
|
+
| Artifact | Safety rule | Why |
|
|
33
|
+
|---|---|---|
|
|
34
|
+
| `app/assets/iphone/Default-*.png`, `Default@2x.png` | `<enable-launch-screen-storyboard>true</enable-launch-screen-storyboard>` | With the storyboard active, iOS adapts dynamically to any device resolution via Auto Layout. Apple mandated this in 2020. Without storyboard, these PNGs matter and must stay. |
|
|
35
|
+
| `app/assets/android/images/res-*-land-*/`, `res-land-*/` | `tiapp.xml` declares portrait-only orientations | Landscape variants only load when the app can rotate to landscape. |
|
|
36
|
+
| `app/assets/android/default.png` | `mipmap-anydpi-v26/ic_launcher.xml` exists (adaptive icons present) | The legacy Titanium Android splash PNG is shadowed by the modern SplashScreen API, which derives the splash from the launcher icon. Only deleted when the modern path is in place. |
|
|
37
|
+
| `app/assets/android/appicon.png` | Same adaptive-icons condition | Legacy Android launcher PNG. When adaptive icons exist in `mipmap-*/`, this file is redundant. |
|
|
38
|
+
|
|
39
|
+
If a safety rule is not satisfied, the artifact is preserved and the user sees a clear reason in the cleanup plan.
|
|
40
|
+
|
|
41
|
+
### AGGRESSIVE — opt-in via `--aggressive`
|
|
42
|
+
|
|
43
|
+
Defensible but off by default because there are edge cases.
|
|
44
|
+
|
|
45
|
+
| Artifact | Reason it's usually safe |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `app/assets/android/images/res-ldpi/`, `res-*-ldpi/` | ldpi (≤120 dpi, pre-2010 low-end devices) is below 1% of active Android devices globally. |
|
|
48
|
+
| `app/platform/android/res/drawable-ldpi/`, `mipmap-ldpi/`, `values-ldpi/` | Same ldpi justification for platform-native resources. |
|
|
49
|
+
|
|
50
|
+
Users targeting specific low-density markets (some IoT devices, kiosks) should leave `--aggressive` off.
|
|
51
|
+
|
|
52
|
+
## Safety model
|
|
53
|
+
|
|
54
|
+
The flag is opinionated about not trashing anybody's work:
|
|
55
|
+
|
|
56
|
+
- `--dry-run` prints the full plan (paths, sizes, reasons) without deleting anything. Run it first.
|
|
57
|
+
- The plan always shows which `tiapp.xml` flags drove each decision (storyboard on/off, orientation, adaptive-icons presence) so the user can verify the detection is correct.
|
|
58
|
+
- The skill does not delete files outside the project's asset and platform resource directories.
|
|
59
|
+
- It does not touch `tiapp.xml`, source code, `modules/`, `i18n/`, or any application code.
|
|
60
|
+
- Conditional targets still require the safety rule to pass — even with `--cleanup-legacy`, nothing conditional deletes unless `tiapp.xml` justifies it.
|
|
61
|
+
- Aggressive-bucket targets require the explicit `--aggressive` flag on top of `--cleanup-legacy`.
|
|
62
|
+
|
|
63
|
+
## Real-world savings
|
|
64
|
+
|
|
65
|
+
Measured on SNAP Gym, a mid-sized Titanium 13.1 Alloy project, immediately after a fresh `alloy new` template:
|
|
66
|
+
|
|
67
|
+
| Bucket | Items removed | Disk freed |
|
|
68
|
+
|---|---|---|
|
|
69
|
+
| SAFE (`res-long-*` + `res-notlong-*`) | 11 folders | ~0 KB (empty templates) |
|
|
70
|
+
| CONDITIONAL (`iphone/Default-*.png` × 15) | 15 files | ~5.4 MB |
|
|
71
|
+
| CONDITIONAL (`android/default.png`, `appicon.png`) | 2 files | 52 KB |
|
|
72
|
+
| **Total (default flags)** | **28 artifacts** | **~5.5 MB** |
|
|
73
|
+
|
|
74
|
+
Running `--aggressive` on top would remove an additional ~40 KB of `ldpi` folders — small payoff per project, but compounds when applied across multiple apps.
|
|
75
|
+
|
|
76
|
+
The 5.4 MB of iOS launch images is the largest single win: those PNGs exist in source but are not shipped in modern IPAs (storyboard-driven iOS builds ignore them). Removing them from source shrinks the repo and clears confusion for new contributors.
|
|
77
|
+
|
|
78
|
+
## When NOT to run cleanup
|
|
79
|
+
|
|
80
|
+
- **Classic Titanium apps pre-SDK 10**: rely on the legacy assets. Upgrading the SDK is a prerequisite to safely cleaning up.
|
|
81
|
+
- **Apps with `<enable-launch-screen-storyboard>false</enable-launch-screen-storyboard>`**: the iOS PNGs are still consulted — the skill correctly skips them, but the user should enable the storyboard before running cleanup to get the savings.
|
|
82
|
+
- **Apps that support landscape orientation**: the `res-*-land-*` folders are preserved, which is correct.
|
|
83
|
+
|
|
84
|
+
## Usage
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
# Preview first — nothing deletes in dry-run mode
|
|
88
|
+
bash scripts/ti-branding --cleanup-legacy --dry-run
|
|
89
|
+
|
|
90
|
+
# Apply
|
|
91
|
+
bash scripts/ti-branding --cleanup-legacy
|
|
92
|
+
|
|
93
|
+
# Include ldpi
|
|
94
|
+
bash scripts/ti-branding --cleanup-legacy --aggressive
|
|
95
|
+
|
|
96
|
+
# Point at a specific project (default: current directory)
|
|
97
|
+
bash scripts/ti-branding --cleanup-legacy --project /path/to/project
|
|
98
|
+
|
|
99
|
+
# Combine with generation — brand the app and clean up in one pass
|
|
100
|
+
bash scripts/ti-branding ./logo.svg --bg-color "#0B1326" --cleanup-legacy
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Verification checklist
|
|
104
|
+
|
|
105
|
+
After applying cleanup, rebuild for each platform and visually confirm:
|
|
106
|
+
|
|
107
|
+
- [ ] iOS app on a modern device (iPhone 11 or newer): splash reaches top and bottom (no letterboxing). The storyboard is doing its job; the deleted PNGs are confirmed unused.
|
|
108
|
+
- [ ] Android app on API 31+ (Android 12 or newer): splash shows the launcher icon centered on the brand color, then transitions to the app normally.
|
|
109
|
+
- [ ] Android app on API 21–30 if the minimum target is that low: app launches without the old `default.png`. Titanium's adaptive-icon fallback kicks in.
|
|
110
|
+
- [ ] `git status` lists only the expected deletions. No source code changes.
|
|
111
|
+
|
|
112
|
+
If any of those fail, the deletion can be reverted with `git checkout -- .` (before committing) or `git restore` (after).
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# iOS appiconset (Xcode 14+)
|
|
2
|
+
|
|
3
|
+
## One master, all sizes
|
|
4
|
+
|
|
5
|
+
Since Xcode 14 (2022), Apple no longer requires the full matrix of 20+ icon sizes. A single 1024×1024 source is sufficient — Xcode generates the rest at build time.
|
|
6
|
+
|
|
7
|
+
Titanium SDK 13.x embraces this:
|
|
8
|
+
|
|
9
|
+
- Place `DefaultIcon-ios.png` (1024×1024, no alpha) at the project root
|
|
10
|
+
- On `ti build`, Titanium writes the generated appiconset to `build/iphone/Assets.xcassets/AppIcon.appiconset/`
|
|
11
|
+
- `build/` is regenerated on every build — you never commit the full set to the source tree
|
|
12
|
+
|
|
13
|
+
If you manually place `app/assets/iphone/appicon-*.png` files, Titanium respects them and only fills in the missing sizes. This skill ignores that path — it only writes the single `DefaultIcon-ios.png` master.
|
|
14
|
+
|
|
15
|
+
## Why no alpha channel
|
|
16
|
+
|
|
17
|
+
Apple's review pipeline rejects icons with transparency:
|
|
18
|
+
|
|
19
|
+
> Apps with app icons that include transparency will be rejected during app review.
|
|
20
|
+
|
|
21
|
+
The skill flattens alpha by compositing the master over the `--bg-color` before writing `DefaultIcon-ios.png`. Same for `iTunesConnect.png` (App Store submission).
|
|
22
|
+
|
|
23
|
+
## Relevant file paths
|
|
24
|
+
|
|
25
|
+
At the project root:
|
|
26
|
+
|
|
27
|
+
| File | Size | Purpose |
|
|
28
|
+
|------|------|---------|
|
|
29
|
+
| `DefaultIcon-ios.png` | 1024×1024 | Master for appiconset generation |
|
|
30
|
+
| `DefaultIcon.png` | 1024×1024 | Fallback if `DefaultIcon-ios.png` missing (Android uses this too) |
|
|
31
|
+
| `iTunesConnect.png` | 1024×1024 | Uploaded to App Store Connect |
|
|
32
|
+
|
|
33
|
+
The skill generates the first and third; the second can be a copy of the first if the user wants a shared master.
|
|
34
|
+
|
|
35
|
+
## Dark and tinted variants (iOS 18+)
|
|
36
|
+
|
|
37
|
+
iOS 18 added dark-mode and tinted versions of app icons, configured via:
|
|
38
|
+
|
|
39
|
+
- `DefaultIcon-Dark.png` — dark theme variant
|
|
40
|
+
- `DefaultIcon-Tinted.png` — tinted grayscale variant for iOS's theme engine
|
|
41
|
+
|
|
42
|
+
These are **out of scope** for this skill's v1. Users who want them can drop the files into the project root manually; Titanium SDK 13.1+ picks them up automatically.
|
|
43
|
+
|
|
44
|
+
## Launch images — deliberately not generated
|
|
45
|
+
|
|
46
|
+
The 30+ `Default-*@3x.png` launch image variants from Titanium documentation are legacy. Modern Titanium uses `LaunchScreen.storyboard`, configured in `tiapp.xml`:
|
|
47
|
+
|
|
48
|
+
```xml
|
|
49
|
+
<ios>
|
|
50
|
+
<enable-launch-screen-storyboard>true</enable-launch-screen-storyboard>
|
|
51
|
+
<default-background-color>#0B1326</default-background-color>
|
|
52
|
+
</ios>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
The storyboard adapts to any device resolution dynamically. Legacy PNG launch images were needed before iOS 14 — they are now dead weight in any app submitted to the App Store (Apple mandates storyboard-based launch as of 2020).
|
|
56
|
+
|
|
57
|
+
If a user genuinely needs legacy launch images (maintaining a pre-2020 app), that's a separate tool job — this skill explicitly does not generate them.
|
|
58
|
+
|
|
59
|
+
## References
|
|
60
|
+
|
|
61
|
+
- Apple HIG: [App icons](https://developer.apple.com/design/human-interface-guidelines/app-icons)
|
|
62
|
+
- Apple: [Configuring your project to use asset catalogs](https://developer.apple.com/documentation/xcode/configuring-your-project-to-use-asset-catalogs)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Master input guidelines
|
|
2
|
+
|
|
3
|
+
## Preferred: SVG
|
|
4
|
+
|
|
5
|
+
SVG is the best source because:
|
|
6
|
+
|
|
7
|
+
- Vector: re-renders cleanly at any density, no upscaling artifacts
|
|
8
|
+
- Preserves transparency natively
|
|
9
|
+
- Small file size (~5–50 KB for typical logos vs 100+ KB for 1024² PNG)
|
|
10
|
+
- Easy to edit by designers in Illustrator / Affinity / Figma / Inkscape
|
|
11
|
+
|
|
12
|
+
**SVG requirements**:
|
|
13
|
+
|
|
14
|
+
- Square viewBox (or content that's square within a rectangular viewBox)
|
|
15
|
+
- Paths only — avoid `<script>`, `<foreignObject>`, web fonts
|
|
16
|
+
- Solid fills or simple gradients — very complex gradients may rasterize inconsistently across densities
|
|
17
|
+
- No external references (embedded images, fonts loaded by URL)
|
|
18
|
+
|
|
19
|
+
The skill uses `rsvg-convert` to rasterize to 1024×1024 PNG before any further processing.
|
|
20
|
+
|
|
21
|
+
## Acceptable: PNG ≥ 1024×1024 with transparency
|
|
22
|
+
|
|
23
|
+
A PNG master works when SVG isn't available:
|
|
24
|
+
|
|
25
|
+
- Minimum size: 1024×1024 (smaller input produces visibly soft xxxhdpi icons)
|
|
26
|
+
- Square preferred — non-square inputs get center-cropped with a warning
|
|
27
|
+
- Transparent background for best monochrome layer results
|
|
28
|
+
|
|
29
|
+
## Accepted with warning: PNG with solid background
|
|
30
|
+
|
|
31
|
+
PNGs that already have a non-transparent background still work, but:
|
|
32
|
+
|
|
33
|
+
- The monochrome layer will be a solid square silhouette (every pixel is non-transparent, so "everything" becomes white)
|
|
34
|
+
- You cannot change the adaptive background color — it's baked in
|
|
35
|
+
- Recommend re-exporting from the source with transparency if possible
|
|
36
|
+
|
|
37
|
+
## Padding and the "pegado" problem
|
|
38
|
+
|
|
39
|
+
If the icon's content already fills the full canvas (logo touching the edges), every generated asset will show the same cramped look. The skill cannot add space that isn't there.
|
|
40
|
+
|
|
41
|
+
Two ways to fix:
|
|
42
|
+
|
|
43
|
+
1. **Prepare the master with transparent padding** — export the logo so there's ~15% empty space around it in the source
|
|
44
|
+
2. **Increase the `--padding` flag** — the skill re-centers the logo inside the target canvas. Higher padding pushes the logo inward
|
|
45
|
+
|
|
46
|
+
Recommended padding values:
|
|
47
|
+
|
|
48
|
+
| Padding | Logo fill | When to use |
|
|
49
|
+
|---------|-----------|-------------|
|
|
50
|
+
| 19 (spec floor) | 62% | Intricate logos needing maximum detail; risky with aggressive launcher masks |
|
|
51
|
+
| 22 (default) | 56% | Balanced, compliant with Android safe-zone spec + 3% buffer |
|
|
52
|
+
| 25 | 50% | Logos with fine strokes or details near the edge |
|
|
53
|
+
| 28–32 | 44–36% | Bold simple shapes, single-letter monograms |
|
|
54
|
+
|
|
55
|
+
If the user sees the logo pegado after running the skill once, re-run with a higher `--padding`.
|
|
56
|
+
|
|
57
|
+
## Alpha channel handling
|
|
58
|
+
|
|
59
|
+
PNG inputs commonly have one of three alpha configurations:
|
|
60
|
+
|
|
61
|
+
- **Straight alpha** (most common): `rgba(r, g, b, a)` — R/G/B hold true color, A holds coverage
|
|
62
|
+
- **Premultiplied alpha**: `rgba(r × a, g × a, b × a, a)` — R/G/B are scaled by A
|
|
63
|
+
- **No alpha channel**: opaque only
|
|
64
|
+
|
|
65
|
+
ImageMagick handles straight alpha transparently. Premultiplied inputs may show dark halos at the edges when composited — if this happens, re-export from the source app with straight alpha.
|
|
66
|
+
|
|
67
|
+
## Checking the master before running
|
|
68
|
+
|
|
69
|
+
Quick sanity check:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
# Dimensions and alpha info
|
|
73
|
+
magick identify -format "%wx%h alpha=%A\n" /path/to/logo.png
|
|
74
|
+
|
|
75
|
+
# Visualize the alpha channel (useful for debugging halos)
|
|
76
|
+
magick /path/to/logo.png -alpha extract /tmp/alpha.png && open /tmp/alpha.png
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
For SVG:
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
# Preview at output size
|
|
83
|
+
rsvg-convert -w 1024 -h 1024 /path/to/logo.svg -o /tmp/preview.png && open /tmp/preview.png
|
|
84
|
+
```
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Notification icons
|
|
2
|
+
|
|
3
|
+
## The white-only rule
|
|
4
|
+
|
|
5
|
+
Android notification icons, since API 21 (Lollipop), must be **white pixels on a transparent background**. The system applies a runtime tint based on the notification's `color` property — color in the source image is discarded.
|
|
6
|
+
|
|
7
|
+
If the icon is not white+alpha, it renders as a blank white square on API 21+ (a common bug symptom when developers reuse their launcher icon as the notification icon).
|
|
8
|
+
|
|
9
|
+
## Generation
|
|
10
|
+
|
|
11
|
+
The skill's `gen-notification.sh`:
|
|
12
|
+
|
|
13
|
+
1. Scales the foreground logo down to the notification size
|
|
14
|
+
2. Runs ImageMagick's `-channel RGB -fill white -colorize 100 +channel` to force all RGB channels to 255 while preserving alpha
|
|
15
|
+
3. Pads transparently to match the target canvas size
|
|
16
|
+
|
|
17
|
+
## Sizes
|
|
18
|
+
|
|
19
|
+
| Density | Size |
|
|
20
|
+
|----------|------|
|
|
21
|
+
| mdpi | 24 |
|
|
22
|
+
| hdpi | 36 |
|
|
23
|
+
| xhdpi | 48 |
|
|
24
|
+
| xxhdpi | 72 |
|
|
25
|
+
| xxxhdpi | 96 |
|
|
26
|
+
|
|
27
|
+
## File naming
|
|
28
|
+
|
|
29
|
+
Titanium has no hard convention, but the de-facto name is `ic_stat_notify.png`. The skill emits this name. To reference it:
|
|
30
|
+
|
|
31
|
+
**In JavaScript (local notification)**:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
Ti.Android.NotificationManager.notify(1, Ti.Android.createNotification({
|
|
35
|
+
contentTitle: 'Hello',
|
|
36
|
+
contentText: 'Hi there',
|
|
37
|
+
icon: Ti.App.Android.R.drawable.ic_stat_notify // white+alpha
|
|
38
|
+
}))
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**In `platform/android/AndroidManifest.xml` (Firebase default)**:
|
|
42
|
+
|
|
43
|
+
```xml
|
|
44
|
+
<meta-data
|
|
45
|
+
android:name="com.google.firebase.messaging.default_notification_icon"
|
|
46
|
+
android:resource="@drawable/ic_stat_notify"/>
|
|
47
|
+
<meta-data
|
|
48
|
+
android:name="com.google.firebase.messaging.default_notification_color"
|
|
49
|
+
android:resource="@color/notification_tint"/>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
With a matching `values/colors.xml`:
|
|
53
|
+
|
|
54
|
+
```xml
|
|
55
|
+
<color name="notification_tint">#FDD900</color>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
The `default_notification_color` is the tint the runtime applies to the white pixels.
|
|
59
|
+
|
|
60
|
+
## References
|
|
61
|
+
|
|
62
|
+
- Android: [Notifications overview](https://developer.android.com/develop/ui/views/notifications)
|
|
63
|
+
- Firebase: [Setting the default notification icon](https://firebase.google.com/docs/cloud-messaging/android/client#manifest)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
# Splash screens (modern)
|
|
2
|
+
|
|
3
|
+
## Two strategies by platform
|
|
4
|
+
|
|
5
|
+
### iOS — storyboard-driven (iOS 14+)
|
|
6
|
+
|
|
7
|
+
Modern iOS uses `LaunchScreen.storyboard`. Titanium enables this via `tiapp.xml`:
|
|
8
|
+
|
|
9
|
+
```xml
|
|
10
|
+
<ios>
|
|
11
|
+
<enable-launch-screen-storyboard>true</enable-launch-screen-storyboard>
|
|
12
|
+
<default-background-color>#0B1326</default-background-color>
|
|
13
|
+
</ios>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The storyboard is a single layout that scales dynamically to any device. No per-device PNG launch images are needed. The `<default-background-color>` sets both the storyboard background AND the gap-color between the storyboard and the first view.
|
|
17
|
+
|
|
18
|
+
This skill does NOT generate iOS launch images. It prints the `<default-background-color>` snippet for the user to paste.
|
|
19
|
+
|
|
20
|
+
### Android 12+ — SplashScreen API (API 31+)
|
|
21
|
+
|
|
22
|
+
Android 12 introduced a system-managed splash that replaces the old "put a PNG in drawable/background.png" approach. It's theme-driven:
|
|
23
|
+
|
|
24
|
+
```xml
|
|
25
|
+
<!-- platform/android/res/values-v31/splash_theme.xml -->
|
|
26
|
+
<resources>
|
|
27
|
+
<style name="Theme.SnapGym.SplashScreen" parent="Theme.SplashScreen">
|
|
28
|
+
<item name="windowSplashScreenBackground">#0B1326</item>
|
|
29
|
+
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
|
|
30
|
+
<item name="postSplashScreenTheme">@style/Theme.AppDerived</item>
|
|
31
|
+
</style>
|
|
32
|
+
</resources>
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
With a matching `AndroidManifest.xml` entry (inside `<application>`):
|
|
36
|
+
|
|
37
|
+
```xml
|
|
38
|
+
<meta-data android:name="io.tidev.titanium.splash.theme"
|
|
39
|
+
android:value="@style/Theme.SnapGym.SplashScreen"/>
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Critical: **do NOT apply this theme to `<application android:theme>` or to a specific `<activity>`** — it only affects the system SplashScreen via the manifest meta-data. Applying it to the application breaks the ActionBar / TitleBar in every subsequent screen (as SNAP Gym learned the hard way).
|
|
43
|
+
|
|
44
|
+
### Android <12 — fallback to launcher icon
|
|
45
|
+
|
|
46
|
+
On API <31, the system uses the launcher icon as the splash. No extra file needed. The `background.9.png` 9-patch pattern is obsolete in Titanium SDK 13+.
|
|
47
|
+
|
|
48
|
+
## splash_icon.png canvas (Android 12+)
|
|
49
|
+
|
|
50
|
+
The SplashScreen API spec:
|
|
51
|
+
|
|
52
|
+
- Total canvas: **288 dp**
|
|
53
|
+
- Icon safe-zone: **192 dp centered** (≈ 67% of canvas)
|
|
54
|
+
- OS applies a circular mask automatically — keep content centered
|
|
55
|
+
|
|
56
|
+
Density sizes:
|
|
57
|
+
|
|
58
|
+
| Density | Total canvas | Icon area |
|
|
59
|
+
|----------|--------------|-----------|
|
|
60
|
+
| mdpi | 288 | 192 |
|
|
61
|
+
| hdpi | 432 | 288 |
|
|
62
|
+
| xhdpi | 576 | 384 |
|
|
63
|
+
| xxhdpi | 864 | 576 |
|
|
64
|
+
| xxxhdpi | 1152 | 768 |
|
|
65
|
+
|
|
66
|
+
The skill's `gen-splash-icon.sh` places the logo at `192/288 ≈ 67%` of the canvas with transparent padding around it.
|
|
67
|
+
|
|
68
|
+
## Why we don't generate `background.9.png`
|
|
69
|
+
|
|
70
|
+
The old 9-patch splash pattern works like this:
|
|
71
|
+
|
|
72
|
+
- PNG with 1px borders marked as stretchable regions
|
|
73
|
+
- Titanium references it as `background.9.png` in `drawable-*dpi/`
|
|
74
|
+
- SDK pre-13 used it as `windowBackground` for the root activity
|
|
75
|
+
|
|
76
|
+
Titanium 13+ handles splash via the modern SplashScreen API on 12+ and via the launcher icon itself on older versions. `background.9.png` produces worse results on 12+ (competing with the SplashScreen API) and offers no benefit on older versions that the launcher fallback can't provide.
|
|
77
|
+
|
|
78
|
+
## References
|
|
79
|
+
|
|
80
|
+
- Android: [Splash screens](https://developer.android.com/develop/ui/views/launch/splash-screen)
|
|
81
|
+
- Apple: [Configuring your app's launch screen](https://developer.apple.com/documentation/xcode/configuring-your-apps-launch-screen)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Canonical paths — Titanium SDK 13.x
|
|
2
|
+
|
|
3
|
+
## Alloy layout (primary)
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
project-root/
|
|
7
|
+
├── DefaultIcon-ios.png # iOS master (1024² no alpha)
|
|
8
|
+
├── DefaultIcon.png # Generic master (1024² no alpha) — fallback
|
|
9
|
+
├── iTunesConnect.png # 1024² App Store submission
|
|
10
|
+
├── MarketplaceArtwork.png # 512² Google Play submission
|
|
11
|
+
├── tiapp.xml
|
|
12
|
+
└── app/
|
|
13
|
+
├── assets/
|
|
14
|
+
│ ├── iphone/ # (optional) manual iOS appiconset — skill doesn't write here
|
|
15
|
+
│ └── android/
|
|
16
|
+
│ ├── appicon.png # 128² legacy fallback (pre-adaptive)
|
|
17
|
+
│ └── images/ # density-scaled in-app image assets (NOT launcher)
|
|
18
|
+
└── platform/
|
|
19
|
+
└── android/
|
|
20
|
+
└── res/
|
|
21
|
+
├── mipmap-mdpi/
|
|
22
|
+
│ ├── ic_launcher.png # legacy 48²
|
|
23
|
+
│ ├── ic_launcher_foreground.png # adaptive 108²
|
|
24
|
+
│ ├── ic_launcher_background.png # adaptive 108²
|
|
25
|
+
│ └── ic_launcher_monochrome.png # themed 108²
|
|
26
|
+
├── mipmap-hdpi/ # 72 / 162 / 162 / 162
|
|
27
|
+
├── mipmap-xhdpi/ # 96 / 216 / 216 / 216
|
|
28
|
+
├── mipmap-xxhdpi/ # 144 / 324 / 324 / 324
|
|
29
|
+
├── mipmap-xxxhdpi/ # 192 / 432 / 432 / 432
|
|
30
|
+
├── mipmap-anydpi-v26/
|
|
31
|
+
│ └── ic_launcher.xml # binds the 3 adaptive layers
|
|
32
|
+
├── drawable-mdpi/
|
|
33
|
+
│ ├── ic_stat_notify.png # (optional) 24² white+alpha
|
|
34
|
+
│ └── splash_icon.png # (optional) 288² Android 12+ splash
|
|
35
|
+
├── drawable-hdpi/ # 36 / 432
|
|
36
|
+
├── drawable-xhdpi/ # 48 / 576
|
|
37
|
+
├── drawable-xxhdpi/ # 72 / 864
|
|
38
|
+
└── drawable-xxxhdpi/ # 96 / 1152
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Classic layout
|
|
42
|
+
|
|
43
|
+
Same structure, different roots. The skill detects `Resources/` and remaps:
|
|
44
|
+
|
|
45
|
+
| Alloy path | Classic path |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `app/assets/android/appicon.png` | `Resources/android/appicon.png` |
|
|
48
|
+
| `app/platform/android/res/...` | `platform/android/res/...` |
|
|
49
|
+
|
|
50
|
+
Root-level files (`DefaultIcon*.png`, `iTunesConnect.png`, `MarketplaceArtwork.png`) are identical in both layouts.
|
|
51
|
+
|
|
52
|
+
## What Titanium does at build time
|
|
53
|
+
|
|
54
|
+
- **iOS**: reads the root master → writes to `build/iphone/Assets.xcassets/AppIcon.appiconset/` (build directory, regenerated every build, never commited)
|
|
55
|
+
- **Android**: copies `app/platform/android/res/*` verbatim to `build/android/app/src/main/res/`, plus copies `app/assets/android/appicon.png` to `build/.../res/drawable-*dpi/appicon.png` if the legacy path is used
|
|
56
|
+
|
|
57
|
+
Result: anything the skill writes to `app/platform/android/res/` or `app/assets/` survives builds. Nothing the skill generates can be accidentally overwritten by `ti build`.
|
|
58
|
+
|
|
59
|
+
## What the skill writes
|
|
60
|
+
|
|
61
|
+
After confirming with the user, the skill copies from its staging directory to:
|
|
62
|
+
|
|
63
|
+
| Target | Files |
|
|
64
|
+
|---|---|
|
|
65
|
+
| Project root | `DefaultIcon-ios.png`, `iTunesConnect.png`, `MarketplaceArtwork.png` |
|
|
66
|
+
| `app/platform/android/res/mipmap-*/` | Launcher icons (adaptive triplet + legacy flat), 5 densities |
|
|
67
|
+
| `app/platform/android/res/mipmap-anydpi-v26/` | `ic_launcher.xml` |
|
|
68
|
+
| `app/platform/android/res/drawable-*/` (optional) | `ic_stat_notify.png`, `splash_icon.png` |
|
|
69
|
+
|
|
70
|
+
The skill never touches `tiapp.xml`, `config.json`, source code, or anything outside the asset/resource paths above.
|
|
71
|
+
|
|
72
|
+
## Required `tiapp.xml` entry
|
|
73
|
+
|
|
74
|
+
For the adaptive icon to be picked up, `tiapp.xml` must reference it:
|
|
75
|
+
|
|
76
|
+
```xml
|
|
77
|
+
<android>
|
|
78
|
+
<manifest>
|
|
79
|
+
<application android:icon="@mipmap/ic_launcher"/>
|
|
80
|
+
</manifest>
|
|
81
|
+
</android>
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
The skill checks for this and, if missing, prints the snippet — does not edit the file. See `tiapp-xml-snippets.md` for the full set.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# tiapp.xml snippets
|
|
2
|
+
|
|
3
|
+
The skill prints these blocks after generating assets. The user reviews and pastes them manually — `tiapp.xml` often contains sensitive info (API keys, signing identities, staging URLs) and automated editing would be fragile.
|
|
4
|
+
|
|
5
|
+
## Block 1 — iOS background color (for storyboard splash)
|
|
6
|
+
|
|
7
|
+
Under the `<ios>` element:
|
|
8
|
+
|
|
9
|
+
```xml
|
|
10
|
+
<ios>
|
|
11
|
+
<enable-launch-screen-storyboard>true</enable-launch-screen-storyboard>
|
|
12
|
+
<default-background-color>#0B1326</default-background-color>
|
|
13
|
+
</ios>
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Replace `#0B1326` with the user's `--bg-color`.
|
|
17
|
+
|
|
18
|
+
## Block 2 — Android application icon reference
|
|
19
|
+
|
|
20
|
+
Under `<android><manifest><application>`:
|
|
21
|
+
|
|
22
|
+
```xml
|
|
23
|
+
<android>
|
|
24
|
+
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
|
25
|
+
<application android:icon="@mipmap/ic_launcher"
|
|
26
|
+
android:usesCleartextTraffic="false"/>
|
|
27
|
+
</manifest>
|
|
28
|
+
</android>
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
The `android:icon="@mipmap/ic_launcher"` tells Android to use the adaptive icon XML (via `mipmap-anydpi-v26/ic_launcher.xml` on API 26+) with automatic fallback to the flat `mipmap-*dpi/ic_launcher.png` on older devices.
|
|
32
|
+
|
|
33
|
+
## Block 3 — Android 12+ splash screen (optional, requires `--with-splash-icon`)
|
|
34
|
+
|
|
35
|
+
Requires three changes:
|
|
36
|
+
|
|
37
|
+
### 3a. Splash theme resource
|
|
38
|
+
|
|
39
|
+
Create `app/platform/android/res/values-v31/splash_theme.xml`:
|
|
40
|
+
|
|
41
|
+
```xml
|
|
42
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
43
|
+
<resources>
|
|
44
|
+
<style name="Theme.App.SplashScreen" parent="Theme.SplashScreen">
|
|
45
|
+
<item name="windowSplashScreenBackground">#0B1326</item>
|
|
46
|
+
<item name="windowSplashScreenAnimatedIcon">@drawable/splash_icon</item>
|
|
47
|
+
<item name="postSplashScreenTheme">@style/Theme.AppDerived</item>
|
|
48
|
+
</style>
|
|
49
|
+
</resources>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 3b. Manifest meta-data (NOT a theme on `<application>` or `<activity>`)
|
|
53
|
+
|
|
54
|
+
Under `<android><manifest><application>`:
|
|
55
|
+
|
|
56
|
+
```xml
|
|
57
|
+
<meta-data android:name="io.tidev.titanium.splash.theme"
|
|
58
|
+
android:value="@style/Theme.App.SplashScreen"/>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 3c. DO NOT do this
|
|
62
|
+
|
|
63
|
+
Setting `android:theme="@style/Theme.App.SplashScreen"` on `<application>` or `<activity>` will strip the ActionBar / TitleBar from every screen in the app because Titanium's `Theme.AppDerived` inherits from the application theme. The SplashScreen API is designed to work through the manifest meta-data entry above, not through activity theming.
|
|
64
|
+
|
|
65
|
+
## Block 4 — Firebase Cloud Messaging notification icon (optional, requires `--with-notification`)
|
|
66
|
+
|
|
67
|
+
Create `app/platform/android/res/values/colors.xml` (if it doesn't exist) with:
|
|
68
|
+
|
|
69
|
+
```xml
|
|
70
|
+
<?xml version="1.0" encoding="utf-8"?>
|
|
71
|
+
<resources>
|
|
72
|
+
<color name="notification_tint">#FDD900</color>
|
|
73
|
+
</resources>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Then under `<android><manifest><application>`:
|
|
77
|
+
|
|
78
|
+
```xml
|
|
79
|
+
<meta-data android:name="com.google.firebase.messaging.default_notification_icon"
|
|
80
|
+
android:resource="@drawable/ic_stat_notify"/>
|
|
81
|
+
<meta-data android:name="com.google.firebase.messaging.default_notification_color"
|
|
82
|
+
android:resource="@color/notification_tint"/>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## What the skill reports
|
|
86
|
+
|
|
87
|
+
After generation, the skill prints only the blocks relevant to the flags used and the project's current state:
|
|
88
|
+
|
|
89
|
+
- Always prints Block 2 if `android:icon="@mipmap/ic_launcher"` is missing from tiapp.xml
|
|
90
|
+
- Always prints Block 1 if `<default-background-color>` is missing
|
|
91
|
+
- Prints Block 3 only if `--with-splash-icon` was used
|
|
92
|
+
- Prints Block 4 only if `--with-notification` was used
|