| Age | Commit message (Collapse) | Author | Files | Lines |
|
Apply evals each monitor's hl.monitor line, one call each because eval
wraps its argument in a return. Keep writes sections/monitors.lua whole;
Revert or 15s without an answer is hyprctl reload, which reapplies the
untouched file. A refusal also reloads, since an earlier monitor's eval
may have gone through.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The page binds the canvas to size(), and an empty or partial scale gave
Infinity or NaN and broke the fit. Apply is still held back until the
scale is a positive number. Also marks the per-axis snap as a ceiling
and checks a rotated scaled monitor and a two-monitor file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The Lua for a monitor and for monitors.lua, logical size, edge snapping
and the mode list, with the duplicates the ASUS reports collapsed and the
current mode matched by nearest refresh (99.943 against 99.94).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Four tasks: Mon.js with its node check, the module with try, keep and
revert, the canvas and cards, then the README and AGENTS.md. The JS in
task 1 was run from the plan and passes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The page owns sections/monitors.lua and regenerates it whole. A change
is tried live through hyprctl eval and written only on Keep; Revert or a
15s timeout is hyprctl reload, so a setting that blanks a screen never
reaches the file.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
One section per monitor from hyprctl monitors -j, read in the same
pass as the system facts: make, model, resolution, refresh, scale,
rotation, diagonal and position. The description is left out because
it carries the panel's serial number.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
local-chat (llamachat) is archived and uninstalled, superseded by
desktop-assistant, so its row could only ever read stopped and its
buttons called a command that no longer exists. Also folds the control
comment that described llamachat's restart dance down to one line.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
breaktimer is parked and imggen and fanfictioner are archived and
uninstalled, so the shell was reading files nothing writes and offering
buttons that call commands that no longer exist.
Status: remove the bt* properties, the file watchers behind them, the
verb runner and the presentation-mode pause/resume. The status page loses
BreakRow and the tile falls back to "All clear".
AI: remove the imggen and fanfictioner rows from ai-state.sh, their
labels and controls, and the pid-based fanfictioner stop. The sd-cli
engine row stays, since the wallpaper upscaler uses sd-cli too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The full-screen dim over the live windows is replaced by DP-1's own
wallpaper, read from ~/.config/wallp/wall_h on each open and drawn
opaque, so the previews sit on what looks like an empty desktop the way
Mission Control does it. A light 40% Theme.base layer stays on top of
it, because a bright wallpaper at full strength glared behind the
previews.
The overlay fades in over 220ms instead of appearing at once. The fade
waits for the image to decode (or to fail, or for there to be no
wallp file), otherwise Theme.base would flash first. Opacity is
derived from the image status rather than starting at 1, so the
initial Null status cannot play a 1-to-0 animation. Closing is still
instant: fading out would keep the layer surface alive past the 60ms
focus timer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A staged wallpaper smaller than its screen (yellow or red border) gets an
"Upscale 4x" button. It rewrites the file with Real-ESRGAN through
stable-diffusion.cpp's `sd-cli -M upscale`, keeping the name, so wallp's
state and the engine's lists, which name it by path, still find it.
sd-cli writes to a dot-named sibling the scan skips, and only a
successful run is moved over the original.
Success needs no [E] line as well as exit 0: with a model that fails to
load, sd-cli logs "[E] new_upscaler_ctx failed", saves the input
unscaled and exits 0 (measured).
The button takes two clicks so the model choice shows before anything is
rewritten. The first runs Imajev-4B, a small Jev-style vision decision
model, through llama-mtmd-cli on a 512 px thumbnail, with a grammar that
allows only A (anime) or B (photo or render); greedy decoding then
returns the higher-logit option, about 1.7 s. The label becomes
"Upscale 4x (anime)" or "(photo)", and the second click upscales with
the anime or the general model. Anything but A, including a failed
decider, picks the general model, safe on any image.
Imajev-4B was chosen by measurement on 22 wallpapers: all 12 anime and 4
photos right, 4 of 6 painted 3D renders called anime (those come out
smoother than painted). The 2B got 17 of 22, leaning to photo; a
three-way prompt adding "painted or render" dropped both to 15 or
fewer, with most anime called painted.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The appearance README gains the burn (the cover, the covered()
handshake and why, the shader cache trap) and the engine (sources,
shuffle, light run, homes, the draft page, where its state lives and
what starts it). The spec records what changed while building it: Prefs
instead of list files, a page of its own, folder sources, the header
buttons, the cover handshake.
AGENTS.md gains the Field.edited trap, which applies to every page with
a field and a button: a click does not end editing, so the value a
button acts on must be read on every change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A brief flicker was left at the start of the burn on both screens. The
cover drew each picture as soon as it decoded, and the new one, under
the old, usually decodes first, so it showed for a frame or two before
the old one covered it. Both now stay hidden until both are ready; the
surface is clear until then, and swaybg underneath is still showing
the old picture, since wallp waits for covered().
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The new wallpaper flashed in for a moment, the old one came back over
it, and only then did it burn. run() started wallp in the same turn as
swapping, while the cover was still mapping and decoding its two
pictures asynchronously, so swaybg swapped under an empty cover.
run() now holds wallp until each cover reports it is drawing (its
pictures decoded, then 50ms for a few frames), with a 1.5s fallback for
a cover that never comes: a missing screen or a picture that fails to
load. A run with nothing to cover starts at once, as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The page was the only settings page without the header's buttons, and
it switched the engine from a checkbox beside the interval. Both looked
like the engine had been started when it had not:
- The minutes field saved on editingFinished, which needs Enter or a
focus change. Clicking the checkbox takes neither, so a typed 1 was
left at 30 and the first change was half an hour away.
- Even at the right interval, the first change waited one full
interval, so starting the engine did nothing visible.
The interval and the two sources are now a draft in WallEngine, updated
on every keystroke, and the header carries the state ("running, next
change at hh:mm", "stopped", "unsaved changes") with Reset, Stop and
Start, which reads Apply while running. Start commits the draft, sets
the homes and changes the wallpapers straight away; Apply commits and
restarts the timer. Hearts stay undrafted, written as clicked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Every wallpaper in the gallery is wide, so hearting a whole folder one
thumbnail at a time is the long way to say "this folder". Each screen
now has a source on the engine page: its hearted list, or one gallery
folder picked by chip, stored as the Wallpapers.groups key in Prefs
(folderH, folderV, "" for the hearts).
A folder that has left the gallery gives an empty pool, so that screen
is left alone rather than quietly falling back to its hearts. The
hearted list stays saved behind a folder source and comes back with the
Hearted chip. Switching source needs nothing from the shuffle: draw()
already drops bag entries that are no longer in the pool.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A page for the wallpaper engine: the on switch, the interval in
minutes, a Next button, and each screen's hearted list with a remove
control and a dim for files the gallery's scan did not find. The module
reads WallEngine.on itself, because a singleton is built on first use
and the timer has to run from session start, page opened or not.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A heart on each gallery thumbnail adds or removes the image from the
engine's list for the screen the picker targets. It is the last child of
the thumbnail, so it sits above the pick MouseArea and takes its own
click, and it is outlined so it reads on a light image.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Ticks go through Wallpapers.run as the light run so the burn plays without
touching GRUB, the homepage or SDDM. Switching off returns each screen to
its home with a full run, deferred until any run in flight finishes. Not
yet registered in the shell; that comes with the settings page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The engine's timer must set wallpapers the same way Apply does so the
burn plays. run() is that one path; applied stays Apply's alone (save bar,
window close) while finished marks every run's end, which is what the
spread overlay now hides on.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The engine needs on/off, an interval, per-screen lists and a home per
screen to survive restarts. They live in prefs rather than list files
because the lists can be empty, and an empty FileView write writes nothing.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Each round shows every hearted wallpaper once, in random order, so no
picture is skipped or doubled within a round. A reshuffle never opens
with the picture on screen, so the same wallpaper cannot appear twice
in a row across the round boundary.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Per-screen lists picked with the heart, one shuffled tick for both
screens, a light accent run for timer changes that leaves GRUB, the
homepage and SDDM alone, and a home wallpaper each screen returns to
when the engine is switched off, so the desktop matches those three
again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
swaybg has no transitions: wallp kills the running one and starts a new
one, which can show a frame of nothing in between. WallpaperSpread puts a
click-through surface on the bottom layer of each screen, above swaybg and
below every window, holding the old picture while wallp runs. A shader
burns it away over the new one: each pixel's threshold mixes its distance
from a random starting point with fractal noise, and a flame and char band
runs just ahead of the front. The surface goes once wallp has exited, or
at once if it failed, since a failed set may have left either picture.
Wallpapers.apply() announces each swap with the old path before wallp
runs, while current still names it. Sets from a terminal get no effect:
by the time wall_h changes, swaybg has already swapped.
The animation is linear, 3.5s: an ease spent its slow ends where nothing
was left to burn, and read as well under the 2.6s it was given. The
compiled .qsb is committed beside its source, since nothing builds it.
AGENTS.md gains the shader cache trap hit on the way: a running shell
keeps a shader by URL, so a recompiled .qsb under the same name is
ignored.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The desktop shell's recurring 100% CPU spin is a Qt bug set off by the
volume OSD. Its grain Canvas called createImageData on every paint, and
Qt 6.11 subtracts that pixel buffer from the V4 unmanaged-heap counter
without having added it. The first GC after an OSD show wrapped the
size_t counter, and from then on every JS allocation ran a full GC until
a restart. The OSD shows on volume keys, track changes and resume, which
is why the spin followed all three.
Found by running each always-on unit of the desktop in its own qs with
GC stats: only the sound module wrapped, 3 s after a resume, and a
volume nudge reproduced it on demand. Qt's qml tool with a bare Canvas
confirms it is createImageData alone: 17,856 of 17,856 GCs wrapped, the
same canvas drawing with fillRect 0 of 5. With the grain removed, 8 OSD
shows under forced GCs left the counter intact.
The grain was alpha 14/255, so the OSD looks nearly the same. vram.sh's
comment blamed the fdinfo parse for the underflow; corrected, and the
lesson is in AGENTS.md.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The chibi 2B companion is retired for now. Its last state is kept in the
signed tag archive/companion (the commit before this one), so it can be
revisited with `git checkout archive/companion`; hypr-theme carries a tag
of the same name for its compositor hooks (typing/delete events and the
SUPER+\ bind).
Removed with it, since nothing else used them: the Companion, phrases
and artists settings pages, the five companion prefs in Prefs.qml and
Prefs.ready, the wallpaper heart (Admired.qml's list), the assistant's
replied() signal and cardTop, and the keybinds reminder's name for the
code:49 bind. The design specs and plans under docs/ stay as history.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A settings page under Appearance > Fonts holds one pixel size for the
whole desktop and an override wherever a system needs its own, saved as
~/.config/keystone/fonts.json, all in px. At scale 1 the logical DPI is
96, so a point is 4/3 px, and each system is written in its own unit:
Theme.fontSize reads the json itself, so every shell follows live;
qt5ct/qt6ct and the GTK settings files are edited in place, size only,
plus gsettings; kitty, rofi and hyprlock read generated files under
~/.config/keystone that their configs include over designed fallbacks;
the groupbar is a keystone.lua line.
rofi and hyprlock are sections of designed sizes that scale together
from their body text, the smallest entry, each keeping its ratio unless
given its own size. The design is read from the fallbacks themselves,
var(kf-..., "Family N") in the rofi files and $kf_... = N in
hyprlock.conf, so a new entry appears on the page with no list to keep.
With no fonts.json the page starts from what the files say, base 16 and
an override per system at its current size, so the first save changes
nothing; seeded to 0.01px, since 0.1 scaled rofi's 72pt glyph to 72.2.
Each stepper shows px then pt in fixed columns, the system's own unit
highlighted.
Check: node desktop/modules/fonts/test_fonts.js
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
All three edit Hyprland's own config or its companion daemons, so they
sit with the shortcuts and options pages rather than under Desktop.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Keyboard shortcuts lists every bind hyprctl reports, joined to the
hl.bind call in ~/.config/hypr that made it: hyprctl gives every Lua
action as an opaque __lua number, so the action and file:line only
exist in the source. The join is by description, then combo, then the
longest literal head of a description built in a loop. List, Source
and Clashes tabs. A combo the source writes as a plain string (or from
file-level string locals) can be changed: hyprctl eval of a do-nothing
bind checks it first, refusing an unknown modifier or keysym, then the
call's first argument is rewritten and Hyprland autoreloads.
Options lists all 353 options from hyprctl descriptions, with values
from one batched getoption, since descriptions' own "current" field is
stale. Filters for everything, set in the config, and changed from the
default. A change is one line in hypr-theme's sections/keystone.lua,
required last, and is run through hyprctl eval first, which refuses an
unknown key or a wrongly shaped value without changing anything.
Both modules keep their own copy of the file text: FileView.text()
returns the old text right after setText(), and a second quick edit
built from it dropped the first. The AGENTS.md notes record that and
the hyprctl quirks found on the way.
Check: node desktop/modules/hyprland/test_hypr.js
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Settings > Desktop > Shells lists every directory holding a shell.qml,
running or stopped by `qs list --all`, with Restart (Start when it is not
running) per row and a Restart all. Every button runs reload.sh through
Quickshell.execDetached, which leaves the script outside the desktop
shell's process, so restarting desktop from its own settings window
works: the window closes and the new process carries on.
restart.sh wraps reload.sh and sends one notification naming the shells
that came back, or a critical one naming those that did not. Back means
qs lists an instance on the shell's config path under a pid it did not
have before, within 5s; the old instance can linger in the list for a
moment after qs kill. It checks the process, not the config, so a shell
that starts with a broken component still counts as back.
The rows reuse the ai module's AiRow rather than a copy of it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A process holding thousands of DRM fds makes the fdinfo scan a few
hundred KB. Parsing that in QML every 2s drove Qt's unmanaged-heap
counter to underflow, after which the V4 engine ran a GC on every
allocation and the shell sat at 100% CPU.
vram.sh does the scan and the per-client-id sum in awk and prints one
number, or nothing when no xe client is found, which the panel draws as
a dash. Perf.js loses vram() and its test; test_vram.sh carries the same
cases against the script, which takes a file argument instead of
scanning so the test can feed it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The Load button reads Unload on the loaded model and posts to the
router's /models/unload. An error from the router lands in modelError,
the same place a failed load reports, and the list is re-read either way.
The model comes back on the next request for it or when the canvas opens.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The llama.cpp row offers Unload while a model is loaded. It posts to the
router's /models/unload, which frees the VRAM and leaves llama-server up,
so its web UI stays available; the engines themselves are still never
stopped from here. The answer is not read: the next poll shows the row
without a model, or with it if the unload failed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The flat grid mixed Proxmox services with the phone, printers and IoT.
hosts.py now gives every entry a group: the node named in its note's
`node`, its own name when other notes name it as their node (so the node
card heads its section), "Devices" for anything else on a private address,
"Remote" for the rest. The list is sorted node by node, node card first,
and the grid starts a titled section at each group change. Up/Down move by
visual row and keep the column, since rows are no longer a fixed five.
`hosts.py --probe` checks every host at once, about a second for the whole
list, and runs beside the list rather than ahead of it. A host with a port
or url is up only when that port accepts a TCP connect, so a service whose
CT is up and whose daemon is down reads red; anything else gets one ping.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The list fills about 2s after the page opens and can show fewer than five
rows, which resized the CPU card and shifted every card below it. A
FontMetrics-sized Column keeps the height fixed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
The rx/tx graph, the LAN address and the public IP with its pin move from
the perf page's NET card to the network page, where they belong; the NET
card is gone. Perf still samples and owns all of them: the graph opens on
the last minute of history, and a public IP that differs from the pin
still lights the perf tile's dot.
Below the graph, the five busiest processes. nethogs is installed but
cannot open any interface unprivileged, so the rates come from
`ss -tinpH`: per-socket byte counters diffed every 2s while the page is
open, summed by process name. That counts TCP only, and only the user's
own processes, so QUIC and system services are missing. The list is held
at five rows tall so the IP lines under it never move.
Perf.js gains sockets() and netProcs(), with tests in test_perf.js.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Down switches the strip and preview from the library to store results,
searched as you type with a 350ms debounce through the store's keyless
api/storesearch endpoint, using QML's own XMLHttpRequest rather than a
process. Results already in the library read Owned or Installed in
green, the rest their price; Enter opens steam://store/<appid> in the
client, Up or Escape returns to the library with the query kept, so a
name that matches nothing locally is one keypress from the store.
The endpoint answers {"total":0} for every term when no cc is given,
despite looking like it geolocates, and the locale here is en_US, so
the country is fixed to Italy. Store art comes from Steam's CDN; newer
apps keep theirs under hashed paths that 404, so the preview layers the
search's capsule under the hero and the tile shows the initial until
its cover is actually ready.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Hyprland's class rules only catch Proton games (steam_app_N) and
whatever else is listed by name, so a non-Steam shortcut, here a GOG
Ren'Py build with its own class, opened on the current workspace.
Steam sets SteamGameId in the environment of everything it launches,
native, Proton and shortcuts alike, so on openwindow the shell looks up
the window's pid and moves it when /proc/<pid>/environ carries that
variable. Checked with the shortcut that motivated it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
An overlay on DP-1: a looping PathView of slanted tiles along the bottom,
the centred one shown large above it in Steam's hero art with its title.
Installed games and non-Steam shortcuts come first, by last played; owned
games that are not installed follow, framed in peach, and Enter installs
them. Launches go through steam -silent so the Steam window stays down.
games.py reads appmanifests, the binary shortcuts.vdf and Steam's library
cache on every opening; owned games come from the Web API through a cache
refreshed in the background.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A new standalone shell, shaped like hosts, on SUPER+b. bookmarks.py reads
the bookmark tree and favicons of the profile a running Firefox holds
(found through the pid in its lock symlink; the last-modified places.sqlite
was tried first and picked the guest profile after a stray launch touched
it). Firefox keeps both databases in exclusive lock mode, so they are
copied with their -wal and the copy is read: an immutable=1 open of the
original skipped the log and kept showing bookmarks deleted minutes before.
The grid spans DP-1, a ListView of card rows so only visible rows exist,
grouped by folder with each folder's own bookmarks before its subfolders.
Six icon buttons (Ctrl+S cycles) sort by folder, newest, title, site, most
visited or link state. The wheel scrolls three rows a notch through a
MouseArea, since Flickable's own step crawled; only the selected card
carries a Glow, through a Loader.
Favicons are extracted by content hash; a page without one takes any icon
Firefox holds for its host, which found 52 more of 504.
bookmarks.py --links (Ctrl+R) checks every http(s) bookmark, HEAD then GET,
32 at a time, in about 22s, and caches the result. Dead means 404/410, an
NXDOMAIN or a refused connection; 403, 429, timeouts, TLS and resolver
failures are only "unsure", because a 32-thread burst produced EAI_AGAIN
that a serial retry resolved.
Bookmarks open with xdg-open: a plain `firefox <url>` does not reach an
instance started with -P and opened the default profile beside it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
A new standalone shell, shaped like keybinds, that replaces the rofi
SSH menu (blackpearl-sshmenu.sh) on ALT+SHIFT+Return. hosts.py reads
the frontmatter of every host note in the vault's Local Network/services
folder and the plain lines of ~/.ssh/config, and joins each alias to the
note whose ip or hostname is its HostName (or whose short hostname is the
alias). Aliases that match no note get cards of their own, so everything
the rofi menu listed is still reachable. It runs on every opening, so a
vault edit shows next time with no cache to go stale.
Each card shows ip:port, hostname, the Proxmox node and CT id, and only
the actions its data allows: ssh per alias (a kitty tab, via ssh-tab,
lifted from the rofi script), open for a url, copy for the address.
Enter runs the first.
The cards are laid out in rows of five inside a Flickable rather than a
GridView, because a GridView gives every cell one height: a fixed height
tall enough for the most aliased host left every other card half empty,
and a short one clipped its chips. Each row now takes its busiest card's
height. The grid keeps a 24px margin inside its clip, without which the
first row's glow was cut off at the top.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Seed 42 drew a third hand, the new one plus both still on the bench, on
every dress frame among sit-think, sit-listen and sit-wave, and on
leotard/sit-think. The comments name the seeds that replaced it so a
remake does not have to find them again.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Naming a ledge in SIT drew a grey bar across the whole image, so SIT now
names nothing under her. Its "keep her sitting pose exactly" also froze
her arms, so the posed seated frames do without it: sit-point came out as
the plain sit with a smirk, and at seed 42 kept her old hand on her hip
too (seed 7 kept). dress/sit-read is hand made, a masked inpaint recorded
in the art's recipe.txt, since no edit would bend her forward, and
leotard/sit-read names the lowered gaze that ${LEOTARD} turned to the
viewer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Both images faded at once, so mid-swap each sat near half opacity and she
blinked see-through on every turn of the dj loop. The incoming frame now
fades in on top while the outgoing one stays opaque under it. With the
blink gone the loop could run faster: 300 ms a frame, from 450.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Records that Hyprland's typing binds fire under the canvas's exclusive
keyboard, which is why the canvas reports no typing of its own, and that
the seat fixes her right edge rather than her centre.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
Edited from base-sitting, the original sitting rest pose dress/base came
from, so the legs already dangle and klein only changes the arms and
expression. The leotard set follows its dress frames as before.
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
|
|
hopping counts as away, so a goal change during the exit (the chat card
closing mid-drop) moved the window before the drop had played. settled
already takes the latest goal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
|
While the canvas shows its tall card she hops onto its top edge, through
the monitor hop: the exit plays, the window's margins move, the entrance
plays. The tall card's top is fixed, so nothing follows a moving edge.
Seated she ignores focus changes and balloons, and shows Mood.seatFrame
of whatever she would show standing.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
|
|
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|