3ebb36f265a4561dcd69715efaf0c125098126e3
36c0cfa): dynamic + init-race fixes
P1 - Tick cadence now reacts immediately to changing tilt. The due time is recomputed every update from the last-tick anchor plus the CURRENT interval, so dropping from 5deg to 0.4deg accelerates to the fast cadence at once instead of waiting out the stale slow interval. Anchor advances by whole intervals (no drift) and resyncs to now if a full interval behind (no burst). Added far->near and near->far transition tests. P1 - One-shot cues no longer lost to async loading. SonarSoundPool queues a Level asked for before its sample loads and plays it on load-complete (and cancels the queued Level on unlock/gate). VoiceSpeaker queues the latest phrase requested before TTS finishes init and speaks it on ready. The policy fires these once, so they can't rely on retries. P2 - Unlock stops the level.wav tail BEFORE playing the resumed tick (order was reversed, allowing a brief overlap). P2 - Audio-mode preference write moved from the screen's rememberCoroutineScope to container.applicationScope, so a quick navigation can't cancel it (matches the earlier persistence hardening). Cleanup: AudioAssistMode and LevelPipeline comments now describe ticking, not the retired radar pings/homing bands; AUDIO_DESIGN_LOG cadence principle reconciled with the 125 ms continuous-tick near rate. 78 tests passing; assembleDebug clean. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On the Level
Offline-first Android pocket toolset: a trustworthy level, angle meter, and calibrated screen ruler (Pro). Kotlin + Jetpack Compose, single module, no backend.
- BRIEF.md — the authoritative v1 product & technical brief
- AUDIT.md — audit of the brief; the amendments it lists are incorporated
- resources/ — concept board (visual direction)
Building
Open in Android Studio, or:
./gradlew assembleDebug # build
./gradlew testDebugUnitTest # measurement-math unit tests
Scaffold status
The project skeleton follows BRIEF.md §Sensor and measurement architecture. Implemented and tested:
core/sensors— sensor selection (game rotation vector → gravity → low-passed accelerometer), device-frame gravity stream, and the pure measurement math: orientation mapping, two-sample per-mode calibration (derived in angle space, applied in vector space so it stays correct away from zero), EMA smoothing, lock hysteresis/dwell/debounce, display deadband, placement validity, and the sensor-vector contract (all sources emit device-frame world-up; flat = +9.81 on Z, pinned bySensorContractTest). All unit-tested.core/settings— DataStore preferences and per-mode calibration persistence.core/billing— entitlement interface with a stub (free-tier) implementation.feature/level,feature/angle— live numeric scaffolds wired to the real sensor pipeline, with manual Surface|Edge selection, placement-validity hints, lock state (locked label states the tolerance so it can never contradict the rounded readout), and directional hold-to-zero (vector reference, not magnitude subtraction).feature/ruler,feature/tools— static placeholders.
Not yet implemented (deliberately — see TODO markers):
- The tactile vial visuals and the spring-animated display value (value 3 of 3 in the brief); scaffold screens render the deadbanded stable value directly.
- Guided calibration flow UI (math and persistence are done).
- Edge-mode readout counter-rotation on the portrait-locked activity.
- Play Billing implementation of
ProEntitlementRepository. - Screen ruler measurement UI and per-display scale persistence.
- Audio cue, reduced-motion behaviors, preferences UI.
Description
Languages
Kotlin
83.9%
HTML
16.1%