aboutsummaryrefslogtreecommitdiffstats
path: root/docs/superpowers/specs/2026-10-23-companion-blush-design.md
diff options
context:
space:
mode:
Diffstat (limited to 'docs/superpowers/specs/2026-10-23-companion-blush-design.md')
-rw-r--r--docs/superpowers/specs/2026-10-23-companion-blush-design.md74
1 files changed, 74 insertions, 0 deletions
diff --git a/docs/superpowers/specs/2026-10-23-companion-blush-design.md b/docs/superpowers/specs/2026-10-23-companion-blush-design.md
new file mode 100644
index 0000000..3ef8c9d
--- /dev/null
+++ b/docs/superpowers/specs/2026-10-23-companion-blush-design.md
@@ -0,0 +1,74 @@
+# Companion: blushing at a wallpaper
+
+She turns to look at the wallpaper behind her and blushes, for the
+wallpapers on a list, when the workspace in front of her is empty enough
+for her to see it.
+
+## Trigger
+
+Checked at two moments, in `Companion.qml`:
+
+- the focused workspace changes or loses a window (`workspacev2`,
+ `closewindow`), so switching to an empty workspace or closing its last
+ window counts;
+- she stops being away: shown (SUPER+\ or the settings switch), back
+ from a remap after another layer opened, moved to another monitor with
+ the focus, back from a dodge, or out of fullscreen.
+
+It fires when all three hold:
+
+- the focused workspace has no windows (`toplevels.values.length === 0`,
+ after `Hyprland.refreshToplevels()`);
+- the wallpaper on her monitor is on the list;
+- at least 3 minutes since the last blush (`T.admireCooldown`).
+
+Her monitor's wallpaper: wallp's `wallp.conf` maps `OUTPUT_H` and
+`OUTPUT_V` to connectors, and `Wallpapers.currentH`/`currentV` say what is
+on each. The connector names are read from `wallp.conf`, not hardcoded. A
+monitor matching neither has no wallpaper and never fires.
+
+## Reaction
+
+A new state in `Mood.js`, `admire`, stamped by `admireAt`:
+
+| since `admireAt` | frame |
+| --- | --- |
+| 0 to 1.5 s (`T.admireLook`) | `watch`, the back view: she turns to the wallpaper |
+| 1.5 to 4.5 s (`T.admireBlush`) | `blush3` |
+
+`watch` and `blush3` exist in both outfits, so no new art is generated.
+
+Priority: below destruct, scorched, dodge, shoved, listen, think, wave and
+clicks; above mock, watch (typing), stretch, muse and idle. A click during
+it wins, as it does over everything below it now.
+
+A line from a `wallpaper` set in `Lines.js` as the blush starts, under the
+usual 30 s line cooldown.
+
+## The list
+
+A plain text file: one absolute path per line, blank lines and lines
+starting with `#` skipped. Paths compare exactly with what wallp writes to
+`wall_h`/`wall_v`.
+
+- Default path `~/.config/keystone/companion-blush.txt`; a missing file is
+ an empty list.
+- The path is `Prefs.companionBlushFile`, with a text field on Settings >
+ Desktop > Companion (`desktop/modules/companion/`).
+- Watched with a `FileView`, so a hand edit applies live.
+- The wallpaper picker (`WallpaperTab.qml`) draws a heart toggle on each
+ thumbnail, filled when the path is listed. Toggling rewrites the file
+ through a `Process` running `cat > <file>`, because
+ `FileView.setText("")` on an emptied list writes no file (AGENTS.md).
+ Comments in the file are kept on rewrite; only the toggled path's line is
+ added or removed.
+
+The parsed list lives in one place both the companion and the picker read,
+a small singleton in `desktop/companion/`.
+
+## Check
+
+`test_mood.js` gains: the `watch` then `blush3` sequence and its end, the
+3 minute cooldown, a click winning over it, and it winning over typing.
+The trigger is checked by hand: an empty workspace with a listed
+wallpaper, a non-empty one, an unlisted wallpaper, each monitor.