99c2b12192
- Calibration: still derived in angle space via the 180-degree flip, but now APPLIED in vector space as a reference-orientation rotation (Rodrigues alignment for Surface, Z-rotation for Edge), exact away from zero; tests at 30 degrees, cross-axis, and edge-polarity cases. - Angle relative zero: stores the gravity direction vector; relative reading is the angle between directions, so cross-axis movement is honest. - Edge mode: precise geometry documented (either long edge down, gravity along +/-X), placement-validity guard so e.g. Edge mode never locks on a phone lying flat; UI shows repositioning hints. - Lock/readout coherence: locked label states the tolerance (exit threshold) so the rounded readout can never contradict it; pipeline acceptance tests pin the invariant. - Sensor-vector contract: documented and pinned by SensorContractTest. The suggested negation of gravity/accelerometer fallbacks is NOT applied: per Android SensorEvent docs, a stationary flat device reads +9.81 on Z (the gravity reaction), matching the rotation-vector path as-is. The contract tests prove all paths agree. 38 tests passing. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
49 lines
2.3 KiB
Markdown
49 lines
2.3 KiB
Markdown
# 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](BRIEF.md)** — the authoritative v1 product & technical brief
|
|
- **[AUDIT.md](AUDIT.md)** — audit of the brief; the amendments it lists are incorporated
|
|
- **resources/** — concept board (visual direction)
|
|
|
|
## Building
|
|
|
|
Open in Android Studio, or:
|
|
|
|
```sh
|
|
./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 by `SensorContractTest`). 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.
|