@olegkoval/agent-skills 1.28.0 → 1.30.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 (98) hide show
  1. package/.claude-plugin/plugin.json +7 -2
  2. package/.cursor-plugin/index.json +26 -1
  3. package/.grok-plugin/index.json +26 -1
  4. package/.kiro/steering/garmin-watchface.md +83 -31
  5. package/.windsurf/rules/garmin-watchface.md +83 -31
  6. package/README.md +8 -3
  7. package/catalog/skills.json +117 -1
  8. package/collections/software-development.json +2 -1
  9. package/package.json +1 -1
  10. package/packages/software-development/branch-cleanup/SKILL.md +204 -0
  11. package/packages/software-development/branch-cleanup/adapters/claude/plugin.json +5 -0
  12. package/packages/software-development/branch-cleanup/adapters/claude/skills/branch-cleanup/SKILL.md +205 -0
  13. package/packages/software-development/branch-cleanup/adapters/codex/README.md +19 -0
  14. package/packages/software-development/branch-cleanup/adapters/cursor/plugin.json +6 -0
  15. package/packages/software-development/branch-cleanup/adapters/cursor/skills/branch-cleanup/SKILL.md +205 -0
  16. package/packages/software-development/branch-cleanup/adapters/grok/plugin.json +6 -0
  17. package/packages/software-development/branch-cleanup/adapters/grok/skills/branch-cleanup/SKILL.md +205 -0
  18. package/packages/software-development/morning-routine/SKILL.md +149 -0
  19. package/packages/software-development/morning-routine/adapters/claude/plugin.json +5 -0
  20. package/packages/software-development/morning-routine/adapters/claude/skills/morning-routine/SKILL.md +150 -0
  21. package/packages/software-development/morning-routine/adapters/codex/README.md +19 -0
  22. package/packages/software-development/morning-routine/adapters/cursor/plugin.json +6 -0
  23. package/packages/software-development/morning-routine/adapters/cursor/skills/morning-routine/SKILL.md +150 -0
  24. package/packages/software-development/morning-routine/adapters/grok/plugin.json +6 -0
  25. package/packages/software-development/morning-routine/adapters/grok/skills/morning-routine/SKILL.md +150 -0
  26. package/packages/software-development/pr-finalize-complete/adapters/claude/plugin.json +1 -1
  27. package/packages/software-development/pr-finalize-complete/adapters/codex/README.md +7 -11
  28. package/packages/software-development/pr-finalize-complete/adapters/cursor/plugin.json +1 -1
  29. package/packages/software-development/pr-finalize-complete/adapters/grok/plugin.json +1 -1
  30. package/packages/software-development/release-day/SKILL.md +286 -0
  31. package/packages/software-development/release-day/adapters/claude/plugin.json +5 -0
  32. package/packages/software-development/release-day/adapters/claude/skills/release-day/SKILL.md +287 -0
  33. package/packages/software-development/release-day/adapters/codex/README.md +19 -0
  34. package/packages/software-development/release-day/adapters/cursor/plugin.json +6 -0
  35. package/packages/software-development/release-day/adapters/cursor/skills/release-day/SKILL.md +287 -0
  36. package/packages/software-development/release-day/adapters/grok/plugin.json +6 -0
  37. package/packages/software-development/release-day/adapters/grok/skills/release-day/SKILL.md +287 -0
  38. package/packages/software-development/vinted-listing/SKILL.md +58 -0
  39. package/packages/software-development/vinted-listing/adapters/claude/plugin.json +5 -0
  40. package/packages/software-development/vinted-listing/adapters/claude/skills/vinted-listing/SKILL.md +59 -0
  41. package/packages/software-development/vinted-listing/adapters/claude/skills/vinted-listing/references/photo-and-duplicate-policy.md +20 -0
  42. package/packages/software-development/vinted-listing/adapters/codex/README.md +3 -0
  43. package/packages/software-development/vinted-listing/adapters/cursor/plugin.json +6 -0
  44. package/packages/software-development/vinted-listing/adapters/cursor/skills/vinted-listing/SKILL.md +59 -0
  45. package/packages/software-development/vinted-listing/adapters/cursor/skills/vinted-listing/references/photo-and-duplicate-policy.md +20 -0
  46. package/packages/software-development/vinted-listing/adapters/grok/plugin.json +6 -0
  47. package/packages/software-development/vinted-listing/adapters/grok/skills/vinted-listing/SKILL.md +59 -0
  48. package/packages/software-development/vinted-listing/adapters/grok/skills/vinted-listing/references/photo-and-duplicate-policy.md +20 -0
  49. package/packages/software-development/vinted-listing/references/photo-and-duplicate-policy.md +20 -0
  50. package/packages/wearables/garmin-watchface/SKILL.md +82 -35
  51. package/packages/wearables/garmin-watchface/adapters/claude/plugin.json +1 -1
  52. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/SKILL.md +82 -35
  53. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/design-proposals.md +99 -0
  54. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/devices.md +112 -0
  55. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/display.md +78 -3
  56. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/inspiration-wizard.md +140 -0
  57. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/layout.md +28 -0
  58. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/publishing.md +134 -5
  59. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/references/simulator.md +86 -2
  60. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-inspire +329 -0
  61. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-mock +502 -0
  62. package/packages/wearables/garmin-watchface/adapters/claude/skills/garmin-watchface/scripts/ciq-release +12 -6
  63. package/packages/wearables/garmin-watchface/adapters/cursor/plugin.json +1 -1
  64. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/SKILL.md +82 -35
  65. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/design-proposals.md +99 -0
  66. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/devices.md +112 -0
  67. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/display.md +78 -3
  68. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/inspiration-wizard.md +140 -0
  69. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/layout.md +28 -0
  70. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/publishing.md +134 -5
  71. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/references/simulator.md +86 -2
  72. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-inspire +329 -0
  73. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-mock +502 -0
  74. package/packages/wearables/garmin-watchface/adapters/cursor/skills/garmin-watchface/scripts/ciq-release +12 -6
  75. package/packages/wearables/garmin-watchface/adapters/grok/plugin.json +1 -1
  76. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/SKILL.md +82 -35
  77. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/design-proposals.md +99 -0
  78. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/devices.md +112 -0
  79. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/display.md +78 -3
  80. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/inspiration-wizard.md +140 -0
  81. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/layout.md +28 -0
  82. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/publishing.md +134 -5
  83. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/references/simulator.md +86 -2
  84. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-inspire +329 -0
  85. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-mock +502 -0
  86. package/packages/wearables/garmin-watchface/adapters/grok/skills/garmin-watchface/scripts/ciq-release +12 -6
  87. package/packages/wearables/garmin-watchface/adapters/kiro/steering/garmin-watchface.md +83 -31
  88. package/packages/wearables/garmin-watchface/adapters/windsurf/rules/garmin-watchface.md +83 -31
  89. package/packages/wearables/garmin-watchface/references/design-proposals.md +99 -0
  90. package/packages/wearables/garmin-watchface/references/devices.md +112 -0
  91. package/packages/wearables/garmin-watchface/references/display.md +78 -3
  92. package/packages/wearables/garmin-watchface/references/inspiration-wizard.md +140 -0
  93. package/packages/wearables/garmin-watchface/references/layout.md +28 -0
  94. package/packages/wearables/garmin-watchface/references/publishing.md +134 -5
  95. package/packages/wearables/garmin-watchface/references/simulator.md +86 -2
  96. package/packages/wearables/garmin-watchface/scripts/ciq-inspire +329 -0
  97. package/packages/wearables/garmin-watchface/scripts/ciq-mock +502 -0
  98. package/packages/wearables/garmin-watchface/scripts/ciq-release +12 -6
@@ -1,11 +1,6 @@
1
1
  ---
2
2
  name: garmin-watchface
3
3
  description: Build, test, screenshot and publish Garmin Connect IQ watch faces in Monkey C. Use when working on a Connect IQ watch face or app - creating one, fixing layout that clips or overlaps, capturing simulator screenshots, adding app settings, widening device support, or preparing a Connect IQ Store submission. Encodes the traps that silently produce a passing build and a broken face.
4
- license: MIT
5
- allowed-tools: Bash, Read, Write, Edit, Grep, Glob
6
- compatibility: Codex, Claude Code, Cursor, GitHub Copilot, Windsurf, Kiro, and other Agent Skills compatible tools. Requires macOS, the Connect IQ SDK, a JDK, and Python 3 (Pillow for screenshot cropping).
7
- metadata:
8
- targets: [_source-only]
9
4
  ---
10
5
  <!-- Generated by scripts/build-adapters.sh. Do not edit directly. -->
11
6
 
@@ -16,43 +11,43 @@ that draws off the bottom of the screen, a test suite that contains no tests, an
16
11
  a colour that is not the colour you get. Everything below is a failure mode that
17
12
  looked like success first.
18
13
 
19
- **Read `references/` files as needed — do not read them all up front.**
14
+ **Read `reference/` files as needed — do not read them all up front.**
20
15
 
21
16
  | File | When |
22
17
  | --- | --- |
23
- | `references/display.md` | Choosing colours, anything about brightness or legibility |
24
- | `references/layout.md` | Positioning anything; content clipped, overlapping, or off-screen |
25
- | `references/testing.md` | Writing tests; a suspiciously clean test run |
26
- | `references/simulator.md` | Screenshots, settings not applying, monkeydo hanging |
27
- | `references/devices.md` | Adding device support, launcher icons, API levels |
28
- | `references/store.md` | Publishing, listing copy, IP questions |
29
- | `references/publishing.md` | Driving the store portal in a browser; upload/update flow, validator rejections |
18
+ | `reference/display.md` | Choosing colours, brightness, legibility; **AMOLED always-on and burn-in** |
19
+ | `reference/layout.md` | Positioning anything; content clipped, overlapping, or off-screen |
20
+ | `reference/testing.md` | Writing tests; a suspiciously clean test run |
21
+ | `reference/simulator.md` | Screenshots, settings not applying, monkeydo hanging |
22
+ | `reference/devices.md` | Adding device support, launcher icons, API levels |
23
+ | `reference/store.md` | Publishing, listing copy, IP questions |
24
+ | `reference/publishing.md` | Driving the store portal in a browser; upload/update flow, validator rejections |
30
25
 
31
26
  ## Tools
32
27
 
33
28
  Run these rather than reinventing them. All are standalone.
34
29
 
35
30
  ```bash
36
- <skill-dir>/scripts/ciq-doctor # toolchain check: SDK, JDK, key, devices
37
- <skill-dir>/scripts/ciq-devices # survey installed devices by resolution
38
- <skill-dir>/scripts/ciq-devices --same-as fenix6pro # products you can add with no code change
39
- <skill-dir>/scripts/ciq-capture out.png # calibrated simulator screenshot
40
- <skill-dir>/scripts/ciq-capture out.png --face --size 260 # cropped + masked to the round display
41
- <skill-dir>/scripts/ciq-calibrate # re-derive the display rect if capture looks wrong
42
- <skill-dir>/scripts/ciq-release # pre-submission check: package, screenshots, icon, keys, copy
31
+ bin/ciq-doctor # toolchain check: SDK, JDK, key, devices
32
+ bin/ciq-devices # survey installed devices by resolution
33
+ bin/ciq-devices --same-as fenix6pro # products you can add with no code change
34
+ bin/ciq-capture out.png # calibrated simulator screenshot
35
+ bin/ciq-capture out.png --face --size 260 # cropped + masked to the round display
36
+ bin/ciq-calibrate # re-derive the display rect if capture looks wrong
37
+ bin/ciq-release # pre-submission check: package, screenshots, icon, keys, copy
43
38
  ```
44
39
 
45
- `<skill-dir>/scripts/ciq-release` is what you run before opening the store
46
- portal. Every check in it is something otherwise discovered halfway through the
47
- submission form -- a stale screenshot set, an icon still copied from the last
48
- project, or copy containing a character the description validator rejects.
40
+ `bin/ciq-release` is what you run before opening the store portal. Every check
41
+ in it is something otherwise discovered halfway through the submission form --
42
+ a stale screenshot set, an icon still copied from the last project, or copy
43
+ containing a character the description validator rejects.
49
44
 
50
- `<skill-dir>/scripts/ciq-capture` exists because `screencapture -R` grabs a screen *region*, not
45
+ `bin/ciq-capture` exists because `screencapture -R` grabs a screen *region*, not
51
46
  a window: without a frontmost check it silently photographs whatever is on top,
52
47
  and the window moves between simulator restarts. Both failure modes produce a
53
48
  plausible PNG of the wrong thing.
54
49
 
55
- ## The five things that will bite you
50
+ ## The seven things that will bite you
56
51
 
57
52
  ### 1. `make test` can compile zero tests and report success
58
53
 
@@ -62,7 +57,7 @@ get `BUILD SUCCESSFUL` and a green run with nothing compiled — even when the t
62
57
  files reference symbols that no longer exist.
63
58
 
64
59
  Fix: a second jungle passed as an additional `-f`. See
65
- `<skill-dir>/templates/monkey.test.jungle` and the `test` target in `<skill-dir>/templates/Makefile`.
60
+ `templates/monkey.test.jungle` and the `test` target in `templates/Makefile`.
66
61
 
67
62
  **Prove it before you trust it.** Put a deliberately unresolvable symbol in one
68
63
  test and confirm the build fails:
@@ -83,6 +78,13 @@ they look. Measured on fenix 6 Pro:
83
78
  | `FONT_SMALL` | 32 |
84
79
  | `FONT_NUMBER_MEDIUM` | 74 |
85
80
 
81
+ **Font tiers already scale with the device.** `FONT_XTINY` is a tier, not a
82
+ pixel height: a 454px watch supplies a proportionately taller glyph than a
83
+ 260px one, unasked. So when text looks wrong at a new resolution, the bug is a
84
+ LENGTH that failed to scale, never the font. Do not add screen-size branching
85
+ to pick a bigger tier -- doing so double-scales, and labels end up wider than
86
+ the containers naming them.
87
+
86
88
  Content drawn past the screen height is simply invisible — no error, no warning,
87
89
  no clipping indicator. A two-line `FONT_NUMBER_MEDIUM` block is 148px of a 260px
88
90
  face.
@@ -97,7 +99,7 @@ function clampRuleY(derived as Number, footerH as Number) as Number {
97
99
  }
98
100
  ```
99
101
 
100
- See `references/layout.md`.
102
+ See `reference/layout.md`.
101
103
 
102
104
  ### 3. The screen is round; your layout is not
103
105
 
@@ -126,7 +128,7 @@ simulator's backlit LCD.
126
128
  Corollary: a saturated colour on a glyph reflects only its own channel, making
127
129
  the thing you want to read the *dimmest* thing on screen.
128
130
 
129
- See `references/display.md`.
131
+ See `reference/display.md`.
130
132
 
131
133
  ### 5. The simulator lies about settings
132
134
 
@@ -137,14 +139,59 @@ settings code.
137
139
 
138
140
  Reset also drops the loaded device, so relaunch and re-push afterwards.
139
141
 
140
- See `references/simulator.md`.
142
+ See `reference/simulator.md`.
143
+
144
+ ### 6. On AMOLED, the face you designed is the one that fails review
145
+
146
+ `requiresBurnInProtection` devices must show a restricted always-on frame
147
+ between wrist raises. The trap is that the *stronger* your face's identity —
148
+ a bright panel, a filled dial — the worse a dimmed version of it performs,
149
+ because it still lights most of the screen. The always-on frame has to be a
150
+ different drawing: outlines where there were fills, and shifted a few pixels on
151
+ a cycle so no pixel is driven continuously.
152
+
153
+ Also note the flag can be **null** on older products, and a null propagating
154
+ into a `Boolean` field throws at the first wrist drop.
155
+
156
+ See the AMOLED section of `reference/display.md`.
157
+
158
+ ### 7. A watch face CAN have settings on the watch
159
+
160
+ `AppBase.getSettingsView()` has existed since **API 3.2.0** and the SDK
161
+ documents it as "only applicable to watch faces and data fields". Plenty of
162
+ store copy — including, at one point, this author's own — claims settings are
163
+ reachable only from the phone. They are not.
164
+
165
+ The override signature must include `or Null` or the compiler rejects it as
166
+ narrowing:
167
+
168
+ ```monkeyc
169
+ function getSettingsView() as
170
+ [WatchUi.Views] or [WatchUi.Views, WatchUi.InputDelegates] or Null {
171
+ return [new SettingsMenu(), new SettingsMenuDelegate()];
172
+ }
173
+ ```
174
+
175
+ Two things to get right in the menu itself:
176
+
177
+ - `ToggleMenuItem` has **already flipped its own state** by the time `onSelect`
178
+ runs. Read `isEnabled()`; negating the stored value inverts the setting.
179
+ - A picker should `setFocus()` the current choice, not open at the top of a long
180
+ list. If the list filters out unavailable options, item position is *not* the
181
+ option id — count the focus row as you build the list.
182
+
183
+ Keep one module that owns every property read, each wrapped with a default, and
184
+ have both the phone path and the on-watch menu go through it. Two readers with
185
+ two sets of defaults is exactly how the watch and the phone come to disagree
186
+ about what "off" means — and check the fallbacks actually match
187
+ `properties.xml`, because nothing enforces that.
141
188
 
142
189
  ## Workflow
143
190
 
144
191
  ### Starting a face
145
192
 
146
- 1. `<skill-dir>/scripts/ciq-doctor` — confirm SDK, JDK, developer key, target device installed.
147
- 2. Copy `<skill-dir>/templates/Makefile`, `<skill-dir>/templates/monkey.jungle`, `<skill-dir>/templates/monkey.test.jungle`.
193
+ 1. `bin/ciq-doctor` — confirm SDK, JDK, developer key, target device installed.
194
+ 2. Copy `templates/Makefile`, `templates/monkey.jungle`, `templates/monkey.test.jungle`.
148
195
  3. Generate a fresh app id: `python3 -c "import uuid;print(uuid.uuid4().hex)"`.
149
196
  4. Split source by responsibility. This structure has held up well:
150
197
 
@@ -173,7 +220,7 @@ Capture and *look at it*. Layout bugs are invisible in a passing test run:
173
220
 
174
221
  ```bash
175
222
  make build && make sim
176
- <skill-dir>/scripts/ciq-capture /tmp/face.png --face --size 260
223
+ bin/ciq-capture /tmp/face.png --face --size 260
177
224
  ```
178
225
 
179
226
  Then Read the PNG. Every layout bug in this skill's history was found by looking,
@@ -206,7 +253,7 @@ are what makes it recognisable:
206
253
  - **Where the legends sit** — maker's name on the bezel, not the glass.
207
254
 
208
255
  No system font is a segment display. If you need one, draw it: see
209
- `references/layout.md` for a working seven-segment renderer, including the ghost
256
+ `reference/layout.md` for a working seven-segment renderer, including the ghost
210
257
  (unlit) segments that are most of what sells the effect.
211
258
 
212
- **Do not print a real brand on the face.** See `references/store.md`.
259
+ **Do not print a real brand on the face.** See `reference/store.md`.
@@ -0,0 +1,99 @@
1
+ # Proposing a face in SVG before writing Monkey C
2
+
3
+ A Monkey C iteration is a build, a simulator launch, a screenshot and a look:
4
+ minutes. An SVG iteration is a file write: seconds. Every visual decision that
5
+ can be made in SVG should be made there, because the ones that reach Monkey C
6
+ get made once and then defended.
7
+
8
+ The failures this prevents are the expensive ones -- a subdial layout that turns
9
+ out to be unreadable, a status row that collides with the index band, a digit
10
+ cell too small for the stroke inside it. All of those survive a green test suite
11
+ and only show up in a capture.
12
+
13
+ ## The rule that makes a mock worth anything
14
+
15
+ **An SVG mock must be constrained to what the panel can draw, or it is a lie.**
16
+
17
+ A browser gives you 16.7 million colours, alpha, gradients, blur and free
18
+ anti-aliasing. A fenix MIP panel gives you 64 colours on a 4x4x4 lattice, no
19
+ alpha blending at all, and no anti-aliasing. A mock that uses the browser's
20
+ extras gets approved and then cannot be implemented, and the gap is discovered
21
+ after the geometry is already committed.
22
+
23
+ `scripts/ciq-mock` exists to close that gap: it renders each proposal with every
24
+ colour quantised to the lattice, inside the round bezel, and lists what will not
25
+ survive.
26
+
27
+ ```bash
28
+ <skill-dir>/scripts/ciq-mock /tmp/proposals.html a.svg b.svg c.svg --device fenix6pro
29
+ ```
30
+
31
+ Then **open it and look at it**, the same way you would a simulator capture.
32
+
33
+ ## What to write, and what not to
34
+
35
+ | Use | Not |
36
+ | --- | --- |
37
+ | `<rect>` `<circle>` `<line>` `<polygon>` `<path>` | `<image>`, `<pattern>` |
38
+ | flat `fill` on the lattice | `<linearGradient>`, `<radialGradient>` |
39
+ | `stroke-width` 2 or more | hairlines; a 1px diagonal is a dotted line |
40
+ | solid colour to separate shapes | `opacity` / `fill-opacity` of any kind |
41
+ | `<g transform="rotate(...)">` for hands | anything you cannot express as sin/cos |
42
+ | `<text>` as a *placeholder* | `<text>` as a measurement |
43
+
44
+ `<path>` is fine to draw with, but nothing in Monkey C consumes one: it has to
45
+ become `fillPolygon`, `drawArc` or `drawLine`. If a shape cannot be decomposed
46
+ into those, it is not a shape you can ship.
47
+
48
+ `<text>` deserves its own warning. Browser font metrics are not device font
49
+ metrics and never will be. Use text to reserve *approximate* space, then derive
50
+ the real box from `dc.getFontHeight()` and `dc.getTextWidthInPixels()` at draw
51
+ time. See `layout.md`.
52
+
53
+ ## The lattice
54
+
55
+ `0x00 / 0x55 / 0xAA / 0xFF` per channel. Write colours on it directly and the
56
+ mock and the watch agree. Write anything else and `ciq-mock` will tell you what
57
+ it becomes -- usually a bigger jump than expected, and two carefully separated
58
+ greys frequently collapse onto one.
59
+
60
+ Rank by luminance, not by hue: on a transflective panel brightness *is*
61
+ reflectance. See `display.md`.
62
+
63
+ ## The bezel
64
+
65
+ `ciq-mock` checks the farthest point of every `rect`, `circle`, `ellipse`,
66
+ `line`, `polygon` and `polyline` against the glass radius. It does **not** check
67
+ `<path>` shapes -- that needs a real path renderer and remains unchecked -- and
68
+ it does not validate text extents (font metrics come from the device, not the
69
+ browser).
70
+
71
+ The check that matters most is the rectangle one: a rectangle inscribed in a
72
+ circle fails at its **corners** long before its sides, and the amount by which
73
+ it fails is `sqrt(w^2 + h^2)/2`, not `w/2`. Radial markers have the same
74
+ problem: a marker of width `w` ending at radius `r` actually reaches
75
+ `sqrt(r^2 + (w/2)^2)`.
76
+
77
+ ## Proposing to a human
78
+
79
+ Exactly three variants, not one and not seven. One is an ultimatum; seven is a survey.
80
+
81
+ Make the three differ on **one axis you actually want an answer about** --
82
+ information density, or dial polarity, or analog versus digital -- and hold
83
+ everything else constant. Variants that differ in five ways at once produce
84
+ "I like bits of each", which is not a decision.
85
+
86
+ State what is fixed by the device (resolution, colour count, no alpha) so the
87
+ feedback lands on choices rather than constraints, and say plainly that colours
88
+ shown are post-quantisation.
89
+
90
+ ## After approval
91
+
92
+ Freeze the chosen variant into constants before writing drawing code: every
93
+ radius, every centre, every width, as named values in `Layout.mc`. The SVG is a
94
+ picture; `Layout.mc` is the specification, and keeping it free of `Dc` calls is
95
+ what makes the geometry unit-testable.
96
+
97
+ Then re-derive the mock from those constants if you change them. A stale mock
98
+ that no longer matches the code is worse than none, because it is what the human
99
+ remembers approving.
@@ -90,9 +90,121 @@ does not "helpfully" add products:
90
90
  bezel. Another size or shape will compile and look wrong, not fail. -->
91
91
  ```
92
92
 
93
+ ## Launcher icons differ within a resolution family
94
+
95
+ `ciq-devices --same-as <device>` prints this, and it is easy to skip past. Sizes
96
+ seen in practice: 35×35 (vivoactive 4, the legacy hero editions), 40×40 (fenix
97
+ 6/7 at 260×260), 60×60 (descent mk3 51mm, epix 2 pro 51mm), 65×65 (the 454×454
98
+ AMOLED group).
99
+
100
+ Give each size its own `resourcePath` in the jungle, listed *after* the base so
101
+ its drawables win:
102
+
103
+ ```
104
+ fr970.resourcePath = $(base.resourcePath);resources-65
105
+ ```
106
+
107
+ **Do not upsample.** A 40×40 icon scaled to 65×65 turns 2px segment bars into
108
+ grey smears. Draw it at size — render at 8× and downsample once with a good
109
+ filter, which is what gives rounded corners and stroke ends clean edges at these
110
+ sizes. Keep the generator in `tools/` so the next size is one command.
111
+
112
+ ## Making `Layout` resolution-aware
113
+
114
+ Worth doing once a face has traction, and much less risky than it sounds if you
115
+ treat the original numbers as a **design grid** rather than replacing them:
116
+
117
+ ```monkeyc
118
+ const DESIGN = 260; // a unit, not a screen size
119
+ var FRAME_W as Number = 204; // var, not const -- init() rewrites these
120
+
121
+ // Round, don't truncate: truncation biases every constant down by up to a
122
+ // pixel, and across a gasket and two insets that is a visible seam.
123
+ function grid(value as Number) as Number {
124
+ return ((value * SCREEN) + (DESIGN / 2)) / DESIGN;
125
+ }
126
+
127
+ function init(width as Number) as Void {
128
+ SCREEN = width;
129
+ CENTER = width / 2;
130
+ FRAME_W = grid(204);
131
+ // ...
132
+ if (STROKE < 1) { STROKE = 1; } // a stroke rounded to 0 draws nothing
133
+ }
134
+ ```
135
+
136
+ Call it from `onLayout(dc)` with `dc.getWidth()` — never from a device name, so
137
+ a new product needs no code at all.
138
+
139
+ **Constants outside `Layout.mc` are the trap.** Widget modules accumulate their
140
+ own pixel values -- an arc radius, a digit cell, a gap -- and a design-grid
141
+ conversion that only edits `Layout.mc` leaves every one of them at the old size.
142
+ The result compiles, passes every test, and renders as a small face marooned in
143
+ the middle of a larger screen. Grep the whole `source/` tree for numeric
144
+ constants, not just the geometry module, and give each widget its own `build()`
145
+ called from `onLayout` after `Layout.init`. Exclude angles and bit masks: a
146
+ sweep is 270 degrees at every size.
147
+
148
+ Three things this gets wrong if you are not careful:
149
+
150
+ 1. **Relational tests keep passing at the new size but prove nothing new.** Most
151
+ layout assertions are written as comparisons, so they hold at any scale
152
+ *given whatever Layout currently holds*. Add a test that sweeps every shipped
153
+ resolution, calling `init()` for each and restoring the design grid on exit.
154
+ 2. **A scale function that ignored its argument would pass all of those.** Pin
155
+ growth explicitly: 204 on the grid must land near 356 at 454.
156
+ 3. **Rounding direction is untested by default.** Assert `grid(1) == 2` at 454,
157
+ not just `grid(1) >= 1`.
158
+
159
+ ### Derived constants are baked at compile time
160
+
161
+ This is the one that will cost you an afternoon. A constant defined in terms of
162
+ another constant is evaluated ONCE, at build time, from the design-grid values:
163
+
164
+ ```monkeyc
165
+ const SUB_N_X = CENTER; // baked as 130, forever
166
+ const SUB_N_Y = CENTER - SUB_OFFSET; // baked as 78
167
+ ```
168
+
169
+ `init()` rewriting `CENTER` does not move them. On a 454 screen every one of
170
+ those subdials stayed clustered in the top-left corner, on top of each other and
171
+ the crest, while the chapter ring and hands scaled perfectly. It compiled, and
172
+ every test passed.
173
+
174
+ Convert them to `var` and recompute them at the END of `init()`, after
175
+ everything they depend on is set.
176
+
177
+ **Give them real design-grid defaults, not 0.** Unit tests never call `init()`,
178
+ so a derived var initialised to 0 reads as `band 0` in assertions that were
179
+ previously passing for the right reason. Four layout tests failed that way, and
180
+ the failure looks like a geometry regression rather than an initialisation
181
+ order problem.
182
+
183
+ ### A checklist for the whole conversion
184
+
185
+ Grep the entire `source/` tree, not just `Layout.mc`:
186
+
187
+ ```bash
188
+ grep -rn "const [A-Z_][A-Z_0-9]* =" source/
189
+ ```
190
+
191
+ Then sort what you find into three buckets:
192
+
193
+ | Bucket | Examples | Scale? |
194
+ | --- | --- | --- |
195
+ | Lengths | radii, widths, offsets, gaps, Y positions | **yes** |
196
+ | Counts | station count, rows, bars, ticks | never |
197
+ | Angles and masks | sweep degrees, start angle, `SEG_A = 0x01` | never |
198
+
199
+ Scaling a count deforms the dial rather than resizing it, and scaling a bitmask
200
+ produces garbage. Both compile.
201
+
93
202
  ## Recommended order
94
203
 
95
204
  1. Ship one resolution, verified on your own wrist.
96
205
  2. Add the same-resolution family — biggest reach per unit of risk.
97
206
  3. Make `Layout` resolution-aware only if it gets traction. It is real work and
98
207
  it risks the pixel-exact look you tuned.
208
+ 4. Crossing to AMOLED is a *separate* step from crossing resolution, even though
209
+ the 454×454 group makes them arrive together. See the always-on section in
210
+ `reference/display.md` — that is the part that fails review, not the layout.
@@ -115,6 +115,81 @@ function panelIsLighterThanItsSegments(logger as Logger) as Boolean {
115
115
 
116
116
  ## AMOLED devices
117
117
 
118
- Venu and newer devices are emissive and do not share these constraints, but they
119
- do have burn-in protection requirements and an always-on mode with a pixel budget.
120
- Do not carry MIP palette reasoning onto them unexamined.
118
+ Venu, Forerunner 265/965/970, fenix 8 (non-solar) and epix are **emissive**.
119
+ Almost every rule above inverts, and the one that matters most is not about
120
+ colour at all.
121
+
122
+ Read the device rather than guessing — `compiler.json` carries `displayType`,
123
+ `bitsPerPixel` and `alphaBlendingSupport`:
124
+
125
+ | | fenix 6 Pro | Forerunner 970 |
126
+ | --- | --- | --- |
127
+ | `displayType` | `mip` | `amoled` |
128
+ | Resolution | 260×260 | 454×454 |
129
+ | `bitsPerPixel` | 8 | 16 |
130
+ | `alphaBlendingSupport` | false | **true** |
131
+ | Launcher icon | 40×40 | **65×65** |
132
+
133
+ So on AMOLED you get anti-aliasing and real colour, and the 4×4×4 lattice stops
134
+ being a constraint. Lattice colours still render correctly, so a palette tuned
135
+ for MIP is safe to ship to both — it is merely conservative.
136
+
137
+ ### The always-on frame is the whole problem
138
+
139
+ `System.getDeviceSettings().requiresBurnInProtection` is true on these devices.
140
+ Between wrist raises the face must show a restricted frame: a small fraction of
141
+ pixels lit, and not always the *same* pixels. Garmin rejects faces that ignore
142
+ this.
143
+
144
+ The property arrived after some supported products shipped and **can be null**,
145
+ so check both the symbol and the value — a null flowing into a `Boolean` field
146
+ throws at the first wrist drop:
147
+
148
+ ```monkeyc
149
+ private function needsAlwaysOn() as Boolean {
150
+ var s = System.getDeviceSettings();
151
+ if (!(s has :requiresBurnInProtection)) { return false; }
152
+ var flag = s.requiresBurnInProtection;
153
+ return flag != null && flag;
154
+ }
155
+ ```
156
+
157
+ **The always-on frame is a different drawing, not a dimmed one.** This is the
158
+ part that bites: if the face's identity is a large bright area — a lit LCD
159
+ panel, a white dial, a filled gauge — then dimming it still lights most of the
160
+ screen. Reach instead for what the real object looks like with the power off.
161
+ An outline where there was a fill; strokes where there was a panel.
162
+
163
+ Budget check: on 454×454 (206k pixels), seven-segment strokes for four digits
164
+ plus a 1px frame outline is roughly 2% lit. A filled rounded rectangle the size
165
+ of that frame alone is 40k pixels — 19%.
166
+
167
+ ### Move the lit pixels
168
+
169
+ Static content burns the pixel even at low duty. Shift the whole block by a few
170
+ pixels on a cycle, and make the horizontal and vertical periods **coprime** so
171
+ the pair does not return to the same offset every few minutes:
172
+
173
+ ```monkeyc
174
+ const SHIFT_PERIOD = 7; // x
175
+ const SHIFT_PERIOD_Y = 5; // y -> 35 distinct positions, not 7
176
+
177
+ function shiftX(minute as Number) as Number {
178
+ return (minute % SHIFT_PERIOD) - (SHIFT_PERIOD / 2);
179
+ }
180
+ ```
181
+
182
+ Both periods dividing into 60 is the trap: with 6 and 3 you get 6 positions and
183
+ park a segment edge on the same pixels ten times an hour.
184
+
185
+ Test the arithmetic even though you cannot test the drawing — that the offsets
186
+ stay small enough to keep content on screen, that **every** offset in range is
187
+ actually visited (a `shiftX` stuck at 0 passes "stays small" and protects
188
+ nothing), and that the (x, y) pair yields the full period.
189
+
190
+ ### Helpers that pick their own colour
191
+
192
+ Segment and hand renderers commonly call `dc.setColor(Palette.SEGMENT, ...)`
193
+ internally. Reusing them for the always-on frame silently repaints it in the
194
+ lit-face colour. Either pass the colour in, or draw the always-on frame against
195
+ the mask primitives directly.
@@ -0,0 +1,140 @@
1
+ # Wizard mode: from "make me a watch face" to a frozen spec
2
+
3
+ Use this when the brief is a mood rather than a design -- "something modern",
4
+ "like a chronograph", "match my brand". Do not use it when the user already
5
+ knows what they want; skip to `design-proposals.md`.
6
+
7
+ The wizard is five stages and **two** questions to the human. Stopping at every
8
+ stage for approval is how a design session becomes a survey; stopping at none is
9
+ how you build the wrong face beautifully.
10
+
11
+ The order below is the point. Constraints come before ideas, because the device
12
+ facts invalidate whole categories of idea and it is cheaper to lose them now.
13
+
14
+ ---
15
+
16
+ ## Stage 0 -- Constraints, before a single idea
17
+
18
+ ```bash
19
+ <skill-dir>/scripts/ciq-doctor
20
+ <skill-dir>/scripts/ciq-devices --same-as <target>
21
+ ```
22
+
23
+ Then read the target's `compiler.json` yourself and write down four numbers:
24
+
25
+ | Fact | Why it kills ideas |
26
+ | --- | --- |
27
+ | resolution + shape | the round bezel eliminates most rectangular layouts |
28
+ | `bitsPerPixel` | 8bpp is 64 colours; photographic anything is out |
29
+ | `alphaBlendingSupport` | almost always false: no translucency, no soft edges |
30
+ | `watchFace` memoryLimit | typically ~112 KB: vector only, no bitmap dial |
31
+
32
+ A face conceived without these gets redesigned after it is built.
33
+
34
+ ---
35
+
36
+ ## Stage 1 -- Gather
37
+
38
+ ```bash
39
+ <skill-dir>/scripts/ciq-inspire --brand acme.com --json /tmp/tokens.json
40
+ <skill-dir>/scripts/ciq-inspire --image ~/crest.png
41
+ <skill-dir>/scripts/ciq-inspire --prior-art "chronograph"
42
+ ```
43
+
44
+ Three axes worth gathering along:
45
+
46
+ - **Object** -- if there is a real watch or instrument behind the brief, its
47
+ proportions and polarity are what make it recognisable. Get those first; see
48
+ the homage section in `SKILL.md`.
49
+ - **Palette** -- from a brand domain, or from an image the user already owns.
50
+ Everything comes back quantised, so what you show is what ships.
51
+ - **Prior art** -- read other people's Monkey C for *technique*, not for code.
52
+ Most Connect IQ repositories carry no licence, which means all rights
53
+ reserved.
54
+
55
+ **IP boundary.** Use brand research and design references as inspiration only:
56
+ implementation must be original, and distinctive creative elements or
57
+ compositions must not be copied verbatim. Names, wordmarks and logos are not
58
+ permissible -- not in the face, the launcher icon, the screenshots or the copy.
59
+ `ciq-inspire --brand` will return another company's logo without complaint; that
60
+ is a research artefact, not an asset. See `store.md`.
61
+
62
+ ---
63
+
64
+ ## Stage 2 -- Question one: the axis
65
+
66
+ Ask the human **one** question, with three or four concrete options, about the
67
+ axis you cannot infer. In practice it is nearly always one of:
68
+
69
+ | Axis | Options that actually differ |
70
+ | --- | --- |
71
+ | Form | analog hands / digital numerals / hybrid |
72
+ | Density | core metrics only / moderate / dense |
73
+ | Polarity | dark dial, bright ink / light dial, dark ink |
74
+ | Character | instrument, tactical, minimal, retro homage |
75
+
76
+ Alongside it, settle the boring-but-load-bearing ones in the same breath,
77
+ because each changes the code shape rather than the look:
78
+
79
+ - **Which devices.** One device is a manifest line; a second resolution is a
80
+ second layout. Widening later is cheap only if you stayed vector-only.
81
+ - **Sweeping seconds.** This is a battery decision, not an aesthetic one. It
82
+ forces `onPartialUpdate`, a 20 ms budget, clip-box arithmetic and an
83
+ `onPowerBudgetExceeded` fallback ladder. Costs roughly a third of the build.
84
+ - **Settings.** Themes and toggles mean `properties.xml`, `settings.xml`, and
85
+ the simulator's habit of ignoring changed defaults. Also: watch face settings
86
+ are unreachable from the watch, only from the phone app -- if you add them,
87
+ the listing has to say so or every user reports them missing.
88
+
89
+ ---
90
+
91
+ ## Stage 3 -- Diverge: exactly three variants as SVG
92
+
93
+ Write exactly three SVG files that differ on **the one axis you asked about**,
94
+ holding everything else constant. Then:
95
+
96
+ ```bash
97
+ <skill-dir>/scripts/ciq-mock /tmp/proposals.html a.svg b.svg c.svg --device <target>
98
+ ```
99
+
100
+ Read `design-proposals.md` before writing the SVG -- the constraints there are
101
+ what stop a mock promising something the panel cannot render. Open the HTML and
102
+ look at it yourself before showing anyone. Fix anything the audit flags; an
103
+ approved design with a bezel violation in it is a design that will be quietly
104
+ changed later.
105
+
106
+ Density is where these get decided in practice. The most-cited reason people
107
+ uninstall a fenix face is data crammed in too small to read -- so if the
108
+ variants differ in density, the dense one must be honestly dense, at real font
109
+ sizes, or the comparison is rigged.
110
+
111
+ ---
112
+
113
+ ## Stage 4 -- Question two: converge
114
+
115
+ Show the sheet. Ask which variant, and what to change about it. Expect the
116
+ answer to be "B, but with A's date placement" -- that is a good answer and it is
117
+ why the variants held everything else constant.
118
+
119
+ Do **one** revision round, re-run `ciq-mock`, and stop. A third round means the
120
+ axis in Stage 2 was the wrong one; go back and ask a better question rather than
121
+ iterating on pixels.
122
+
123
+ ---
124
+
125
+ ## Stage 5 -- Freeze
126
+
127
+ Turn the approved picture into a specification before writing drawing code:
128
+
129
+ - every radius, centre, width and offset as a named constant in `Layout.mc`
130
+ - the palette as **roles** (`DIAL`, `RULE`, `INDEX`, `HAND`, `ACCENT`), not as
131
+ colour names, so a second theme is a table row rather than a rewrite
132
+ - the draw order, written down -- a later fill erases an earlier ring
133
+ - the two or three places where the layout is nearly out of room, with the
134
+ remedy already chosen, so the fix later is not an ad-hoc nudge
135
+
136
+ Keep `Layout.mc` free of `Dc` calls. That is what lets the geometry be
137
+ unit-tested against the bezel across the full sweep, which is the only automated
138
+ check that catches a clipped layout.
139
+
140
+ Then, and only then, start Phase 0 of the build.