v1.4.0
Flux Hourglass 1.4.0
A small but very physical release. Rotate the phone and the sand and
LEDs now actually obey gravity, and the bottom controls finally stay
readable when they sit on top of a white pile.
Highlights
- Gravity-aware orientation. The accelerometer is sampled every
frame and snapped to one of four 90° orientations (portrait,
upside-down, landscape-left, landscape-right). The running screen
rotates its content so the sand always falls from the physical
12 o'clock toward the physical 6 o'clock, and the pile always lives
on the gravity-down edge of the device. Hold the phone sideways and
the sand falls sideways — the way you would expect. - LED grid follows gravity too. The 16 × 32 LED grid fills from
the physical bottom regardless of how you hold the device, matching
the sand mode's behaviour. - Readable PAUSE / RESET pills. The bottom controls now sit on a
semi-transparent black rounded pill so they stay legible when the
white sand pile (or a fully lit LED grid) reaches them. The label
alpha also went up from 0.65 to 0.95 — they read clearly without
having to stand out against the background alone.
Implementation notes
- A
GravityOrientenum classifies device-frame gravity into the
four 90° orientations with hysteresis: the dominant axis has to
beat the other by 1.5× and exceed 5 m/s² before we snap, so a
phone held near the diagonal does not flip-flop every frame. - The running screen wraps its Canvas + overlay in a
BoxWithConstraintsthat picks logical dimensions (swapped for
landscape) and appliesgraphicsLayer(rotationZ = …)to the
inner box. The physics never sees device coordinates — it always
runs in a logical frame where+yis gravity-down. Tilt input
is projected throughGravityOrient.logicalGravitybefore being
passed toParticleSystem.update. ParticleSystem.initDimensionsnow rescalesheights[]
proportionally when the logical height changes, so an in-flight
pile keeps the same fill ratio across a rotation instead of
appearing empty or overflowing.- Tap detection lives on the unrotated outer container, so taps
resolve in device coordinates regardless of rotation while the
visual content rotates underneath.