Add authoritative v1 product & technical brief (Codex)
This commit is contained in:
@@ -0,0 +1,185 @@
|
||||
# On the Level — v1 Product & Technical Brief
|
||||
|
||||
**Status:** Ready for final Claude review before implementation
|
||||
**Date:** 2026-07-11
|
||||
**Companion audit:** [`AUDIT.md`](AUDIT.md)
|
||||
|
||||
## Product decision
|
||||
|
||||
On the Level is an offline-first Android pocket-tool app for quick, trustworthy
|
||||
level and angle work. It should feel like a responsive physical instrument—not
|
||||
a novelty simulation—while keeping displayed measurements stable and honest.
|
||||
|
||||
v1 is deliberately small: a level, an angle meter, a calibrated screen ruler,
|
||||
and the settings necessary to make them dependable. There is no account,
|
||||
backend, advertising, camera/AR measurement, cloud sync, analytics dependency,
|
||||
or subscription in v1.
|
||||
|
||||
## Audience and promise
|
||||
|
||||
For everyday DIY, hanging pictures, shelving, small home jobs, and quick rough
|
||||
measurements. The app is not a substitute for a certified or safety-critical
|
||||
instrument. Screen-ruler copy must state that it is for short, rough
|
||||
measurements only.
|
||||
|
||||
## Navigation and layout
|
||||
|
||||
Use a simple three-destination bottom navigation: **Level**, **Angle**, and
|
||||
**Tools**. The app is portrait-locked in v1. The UI is edge-to-edge and must
|
||||
correctly handle system insets and back gestures.
|
||||
|
||||
### 1. Level — default destination
|
||||
|
||||
- Header: `LEVEL`, live/calibrated status, calibration/settings action.
|
||||
- Explicit mode selector: **Surface** | **Edge**. Do not auto-switch modes in
|
||||
v1; unexpected switching undermines confidence while positioning the phone.
|
||||
- **Surface:** phone lying screen-up on a surface; use a two-axis cross-vial
|
||||
visualization with meaningful pitch and roll readings.
|
||||
- **Edge:** phone held upright on its long edge against a wall, shelf, or
|
||||
picture frame; use a single, prominent vial/readout for that plane.
|
||||
- The central visual is tactile: its bubble has restrained spring/damping,
|
||||
settles naturally, and responds immediately to device movement.
|
||||
- A locked state is a brief, accessible success reaction with a debounced
|
||||
system-respecting haptic/audio cue. It is not the persistent normal UI.
|
||||
- Keep the screen on while this destination is visible.
|
||||
|
||||
### 2. Angle
|
||||
|
||||
- Large primary angle readout.
|
||||
- Secondary pitch, roll, and percent-grade readings.
|
||||
- **Hold to zero** sets a relative reference and is always free.
|
||||
- Percent grade is `tan(pitch) × 100`; define a sensible cap or infinity
|
||||
presentation near a vertical surface.
|
||||
- Target-angle alerts and saved named references are Pro features.
|
||||
|
||||
### 3. Tools
|
||||
|
||||
- **Screen Ruler**: a Pro tool with a clear preview and calm, intentional
|
||||
paywall—not an interruption in the free level/angle flow.
|
||||
- Calibration entry point.
|
||||
- Units, haptic/audio, and motion/accessibility preferences.
|
||||
|
||||
## Visual and interaction direction
|
||||
|
||||
Use the concept board's deep graphite base, warm amber bubble, and lime level
|
||||
lock as direction rather than a literal spec. Numeric measurements remain
|
||||
near-white and must be readable in bright conditions. Never convey accuracy,
|
||||
state, or purchase status by color alone.
|
||||
|
||||
The visual vial may be expressive, but it must never contradict the numeric
|
||||
reading. Provide an in-app reduced-motion option and respect disabled system
|
||||
animations. Respect device haptic settings; do not force vibration.
|
||||
|
||||
## Measurement modes and calibration
|
||||
|
||||
Only promise calibration for the two physical orientations explicitly supported
|
||||
in v1:
|
||||
|
||||
1. **Surface** — screen-up, flat contact plane.
|
||||
2. **Long Edge** — upright, long-edge contact plane.
|
||||
|
||||
Store a reference orientation for each supported mode—not a scalar angle offset.
|
||||
The calibration flow uses two samples: place the device, record; rotate it 180°
|
||||
on the same plane, record; derive the reference/bias from both samples. This
|
||||
reduces fixed device bias without requiring the user to start on a known-level
|
||||
surface. Calibration UI must give exact, mode-specific placement instructions.
|
||||
|
||||
Screen-ruler calibration is separate from sensor calibration. Offer calibration
|
||||
against a standard credit-card width (85.60 mm) and a conventional ruler option.
|
||||
Store scale with the active display/configuration characteristics and request
|
||||
recalibration whenever a material display change makes the prior scale suspect.
|
||||
|
||||
## Sensor and measurement architecture
|
||||
|
||||
Use a small native Android/Kotlin Compose application. Keep one app module for
|
||||
v1, with a manual application container rather than premature modularization or
|
||||
Hilt.
|
||||
|
||||
```text
|
||||
app/
|
||||
core/design/ theme, typography, tactile animation primitives
|
||||
core/sensors/ sensor source, device-axis mapping, measurement math
|
||||
core/settings/ DataStore preferences and calibration persistence
|
||||
core/billing/ entitlement abstraction and Play Billing implementation
|
||||
feature/level/ state and UI for Surface / Edge level modes
|
||||
feature/angle/ relative-zero logic and UI
|
||||
feature/ruler/ ruler calibration and UI
|
||||
feature/tools/ tools and settings UI
|
||||
```
|
||||
|
||||
Require an accelerometer in the manifest. Select sensors in this order:
|
||||
|
||||
1. `TYPE_GAME_ROTATION_VECTOR`
|
||||
2. `TYPE_GRAVITY`
|
||||
3. A low-pass-filtered `TYPE_ACCELEROMETER`
|
||||
|
||||
The app does not need north/heading. Map device-frame sensor values explicitly
|
||||
for the portrait-locked UI and for each measurement mode. Handle unavailable
|
||||
sensors with a clear unsupported-device state.
|
||||
|
||||
Maintain three distinct values:
|
||||
|
||||
1. **Raw sensor value** — received from the selected sensor source.
|
||||
2. **Stable calibrated measurement** — reference-orientation calibration plus
|
||||
a defined EMA/low-pass filter. This is the sole input to numeric readouts
|
||||
and level-lock detection.
|
||||
3. **Animated display value** — a critically damped spring derived from the
|
||||
stable value and used only to move the vial/bubble.
|
||||
|
||||
Readouts use 0.1° resolution and a display deadband to prevent flickering. Lock
|
||||
behavior starts at no more than 0.2°, exits at at least 0.35°, has a short dwell
|
||||
time, and has a multi-second haptic debounce. Exact constants remain tunable,
|
||||
but lock and readout must always use the same stable calibrated measurement.
|
||||
|
||||
Register sensors only while a relevant screen is foregrounded; unregister them
|
||||
when backgrounded.
|
||||
|
||||
## Monetization
|
||||
|
||||
Use one permanent, non-consumable **On the Level Pro** Google Play product. Do
|
||||
not use a subscription. The free product is complete:
|
||||
|
||||
- Surface and Edge level modes
|
||||
- Angle measurement, pitch/roll, degree/grade display
|
||||
- Hold-to-zero
|
||||
- Calibration and basic feedback/unit preferences
|
||||
|
||||
Pro adds deliberate, additive measurement tools:
|
||||
|
||||
- Calibrated Screen Ruler
|
||||
- Target-angle haptic/audio alerts
|
||||
- Saved and named angle references
|
||||
|
||||
Expose entitlement as `StateFlow<Entitlement>` from `core/billing`. Billing
|
||||
initialization must be asynchronous/lazy: free tools render immediately and
|
||||
never block on Play services. Cache a previously Play-confirmed entitlement for
|
||||
offline job-site use, refresh owned purchases when possible (including resume),
|
||||
and never grant from an arbitrary preference value or a pending purchase.
|
||||
|
||||
## Testability and release gates
|
||||
|
||||
Keep all math—device-axis mapping, calibration, smoothing, hysteresis, grade,
|
||||
and lock transitions—in pure Kotlin. Place sensor I/O behind an injected
|
||||
`SensorSource` so tests can use synthetic and recorded real-device traces.
|
||||
|
||||
Before release, verify:
|
||||
|
||||
- Surface and Edge readings across supported orientations and screen rotation
|
||||
conditions.
|
||||
- Two-sample calibration improves repeatability and remains isolated per mode.
|
||||
- Numeric readings, vial animation, and lock feedback stay consistent.
|
||||
- Haptic debounce, system haptic settings, reduced motion, and bright-light
|
||||
readability.
|
||||
- Sensor absence, app backgrounding, and screen wake behavior.
|
||||
- Pro purchase, restore, pending purchase, offline cached entitlement, and
|
||||
billing-unavailable behavior without degrading free tools.
|
||||
- Ruler calibration, display/configuration changes, and honest rough-measure
|
||||
wording.
|
||||
|
||||
## Explicitly out of scope for v1
|
||||
|
||||
- Camera-assisted or AR distance measurement
|
||||
- Accounts, server verification, cloud storage, sharing, or collaboration
|
||||
- Ads, subscription plans, consumable credits, or trial metering
|
||||
- Automatic flat/edge mode switching
|
||||
- Support claims for every device edge, case, or external/foldable display
|
||||
Reference in New Issue
Block a user