aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-10-23-companion-design.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/specs/2026-10-23-companion-design.md')
-rw-r--r--docs/superpowers/specs/2026-10-23-companion-design.md37
1 files changed, 23 insertions, 14 deletions
diff --git a/docs/superpowers/specs/2026-10-23-companion-design.md b/docs/superpowers/specs/2026-10-23-companion-design.md
index b8910d8..28203cf 100644
--- a/docs/superpowers/specs/2026-10-23-companion-design.md
+++ b/docs/superpowers/specs/2026-10-23-companion-design.md
@@ -91,15 +91,26 @@ Never in the repo: 2B is Square Enix's character and the repo is public
under GPLv2. Generated images and their recipe live in
`~/.local/share/keystone/companion/2b/`; `prep-frames` writes the
prepared PNGs, 256 px tall with a transparent background, to `frames/`
-inside it. The component loads `frames/<name>.png` and falls back to
-`frames/base.png` when a frame is missing, so it works from the first
-commit with the three frames that exist.
+inside it.
-| Method | Frames |
+Two outfits, the same frames in each: `frames/dress/<name>.png` and
+`frames/leotard/<name>.png`. The component loads the current outfit's
+`<name>` and falls back to that outfit's `base`, never to the other
+outfit, so a missing frame cannot put the skirt back mid-scene. It works
+from the first commit with the three dress frames that exist; until
+`leotard/base` exists, the self-destruct ends in the dress.
+
+| Method | Frames, per outfit |
| --- | --- |
-| Made | `base`, `smile`, `wave` |
+| Made (dress) | `base`, `smile`, `wave` |
| img2img from `base`, strength 0.75 | `mad`, `smirk`, `blush1`, `blush2`, `blush3`, `sleepy` |
-| klein edit of `base` | `watch`, `point`, `yawn`, `lying`, `listen`, `think`, `muse`, `stretch`, `leotard`, `leotard-scorched` |
+| klein edit of `base` | `watch`, `point`, `yawn`, `lying`, `listen`, `think`, `muse`, `stretch` |
+| klein edit of the dress frame | every `leotard/<name>`: "her skirt is gone, revealing a plain white leotard; change nothing else" |
+| klein edit of `leotard/base` | `scorched`, leotard only: the moment after the explosion |
+
+Each leotard frame is made from its own dress frame rather than from
+`leotard/base`, so the pose comes along unchanged. 17 frames a set, 35 in
+all with `scorched`.
Dodging, shoving, the drop-in and the explosion are QML motion, not
frames. She is drawn 128 px tall; both monitors are at scale 1. No size
@@ -114,7 +125,7 @@ timers.
| Priority | State | Trigger | Frame | Ends |
| --- | --- | --- | --- | --- |
-| 1 | Self-destruct | 7th click of a burst | glow, flash, explosion, then `leotard-scorched` | see below |
+| 1 | Self-destruct | 7th click of a burst | glow, flash, explosion, then `leotard/scorched` | see below |
| 2 | Dodge | pointer rests on her 0.6 s with no click | slides out of the corner | returns after 5 s |
| 3 | Shoved | a balloon is on screen on her monitor | `mad`, slid left by the stack's width | balloons gone |
| 4 | Assistant | recording / working / reply arrived | `listen` / `think` / `wave` | state ends; wave lasts 3 s |
@@ -127,13 +138,11 @@ timers.
- **Self-destruct, as in the game.** She glows, says "Self-destruct
sequence initiated.", a white flash covers the sprite for about a
second with particles and a shockwave ring, and she is back in place
- without her skirt (`leotard-scorched`, then `leotard`), saying
- "...That was unpleasant." The skirt returns after 60 s, or at the next
- hide and show, whichever is first. Every other frame has the skirt, so
- for those 60 s she stays on `leotard` whatever the state: reactions
- still happen, as lines and motion, but the frame does not change.
- ponytail: one skirtless frame; skirtless variants of the others only if
- the 60 s feel frozen.
+ without her skirt (`leotard/scorched` for 3 s), saying "...That was
+ unpleasant." The outfit is then `leotard` for 60 s, or until the next
+ hide and show, whichever is first, and every state plays as usual from
+ the leotard set. The outfit is the only thing the self-destruct
+ changes: `Mood.js` picks the state, the outfit picks the folder.
- **Dodge.** She cannot feel the pointer until it is over her: Quickshell
has no global pointer and Hyprland sends no motion events. A click
before the 0.6 s still reaches her, so clicking her keeps working. If