It was butted straight up against the Clear/Send row, so a band of night
sky touched a button and read as part of the form. Now there is a fixed
14px gap under the buttons and a stretch either side of the scene, which
centres it in whatever space the form leaves.
And the coins come in handfuls. One at a time reads as a metronome, so
Send now has three of them: usually one goes past, sometimes two, and
about one time in seven all three, staggered by a beat so they arrive
together rather than in a rank. Each rolls its own height, size, duration
and spin direction.
Claude-Session: https://claude.ai/code/session_01VLQ5DsgKv23osGANoFT3zF
The crash launched him. Rotating 66 degrees about a pivot inside the
sprite, shearing him through the middle and scaling him about the same
point left him diagonal in mid-air, elongated, nowhere near the ground —
a stunt, not a trip.
It is now a face-plant and a skid: 26 degrees, a 21px drop so the snout
reaches the grass, and 26px of forward slide along the ground with the
dust coming up. The shear is gone entirely. The pivot is the snout at the
grass line rather than a point inside the body.
The other half of looking airborne was the frozen frame: stopping a run
cycle leaves whatever mid-stride pose the gif was on, legs extended. He
now lands on frame 4, the one with the legs tucked under him.
Clearing the field and getting across now says WIN, with the tally, the
way eating it says GAME OVER. Before, a won lap just ended and the next
one opened with a doge sitting down, which reads as nothing having
happened.
And the scene comes in three amounts, because a form should not have to
compete with a dog: History runs the whole thing, Receive is a doge
sitting in the field, Send is money blowing past and nothing else. One
QML file, gated by mode; the beat machine only runs where there is a run.
Claude-Session: https://claude.ai/code/session_01VLQ5DsgKv23osGANoFT3zF
Every tab was running the identical eight seconds forever. Three changes:
- Each lap rolls its own timing: 3-5s of empty field, and the money now enters
on its own delay at its own pace instead of shadowing the doge every time.
- Roughly one lap in six the doge eats it partway down the field: he tips
nose-first onto the grass, GAME OVER comes up, and the coins he never reached
are still sitting there. Costs no new art — it is the running sprite pivoted
on its own feet.
- A `variant` on SceneWidget picks the sky: dusk (History, lock screen), dawn
(Receive), night (Send, with stars and a moon instead of the sun).
The cycle is now a timer-driven state machine rather than one SequentialAnimation.
That is not stylistic: a lap that rolls its own durations has to assign them
somewhere, and assigning a duration to a child of a *running* SequentialAnimation
makes the group recompute and re-enter its own ScriptAction until the JS stack
blows. Qt flags the binding form of the same mistake as a binding loop.
Verified by headless qml6 render: a forced trip lap, and a clean run with no QML
warnings.
Send had a large empty region under the form doing nothing, and Receive had
nothing at all. Both get the scene back — but as real layout items, not as the
overlay that painted over the forms last time.
Send: the form only ever needed the top of the tab, so the QFormLayout is now
wrapped in a vbox and the scene takes the rest. The widget's vertical size
policy was Maximum, which made it hug the form; it owns the whole tab now. The
form itself is untouched, and nothing is drawn on top of the address or amount
fields.
Receive: a short banner under the address table.
Built and smoke-tested from the AppImage lane.
IdleDoge scaled its movie from `currentImage()` after `jumpToFrame(0)`, but the
first frame is not decoded at that point, so the size came back null, the
scaling was skipped, and the QLabel ended up at the GIF's full 500x397. Parked
at the bottom-right of the form it painted an opaque 500x397 slab of window
background over the lower half of Send and over the Receive address table.
Send is the screen where money leaves the wallet; it does not get an overlay
sitting on top of the address and amount fields at all. Receive loses it for
the same reason. SendWidget.cpp and ReceiveWidget.cpp are back to exactly their
pre-ambient state, and the widget is removed rather than left unused.
The ambient scene keeps the places where it has its own real estate: the lock
screen, the History banner, and the mining tab.
- Lock screen: full ambient scene above the unlock form (the idle 'screensaver'
— wallet auto-locks here) instead of a thin banner.
- History ('home'): full scene as a top banner.
- Send/Receive: IdleDoge — a small click-through sitting doge in the corner,
the 'most quiet' idle for task screens.
- Mining keeps its own scene.
All gated by Config::reducedMotion (scenes freeze, doge shows a still frame).