--- type: plan status: active updated: 2026-09-04 --- # Initial plan ## Order 1. MQTT client, subscribing to the retained vehicle topics. Text readout only — prove the contract before drawing anything. 2. Gauges. 3. Moving map: MapLibre against the PMTiles basemap served by the Orin, with the position from `yukart/gnss/fix`. No routing involved. 4. Guidance from `yukart/nav/guidance`, once [svc-nav](gitea:yukart/svc-nav) publishes it. A moving map with position, heading and trace is most of the value in a car and needs no routing engine at all. Routing is the expensive last fraction. ## Open - **Transport.** Over USB the tablet has an IP link via RNDIS, so it can reach the broker directly. Whether it should, or should go through `svc-gw`, is decided in that repo — see its initial plan. - **CJK labels.** MapLibre cannot ship Japanese glyph sets as SDF ranges. Local font rendering must be configured, or labels will be slow or absent. - **Sunlight.** A typical tablet is unreadable through a windscreen in daylight. This is a hardware problem, but the UI should not make it worse. ## The boundary, from this side Two channels with different guarantees, not one socket: | | Down (state) | Up (commands) | |---|---|---| | Transport | push stream | request/response | | Loss | tolerated; next sample supersedes | **not** tolerated; retry until acknowledged | | On reconnect | expect current state immediately | resend anything pending | This client always initiates and owns reconnection — the Orin never dials out. Assume the link drops constantly: cable knocked, screen off, WiFi lost. ## Session marking is worth building early A button that stamps an event (`indicator on`, `cold start`, `hard braking`) into the recording, on the same clock as the CAN frames, turns the Phase 1 manual event log from a notebook-and-wristwatch exercise into structured data. It is what makes a raw capture decodable later, and it is a Phase 1 capability that happens to live in this repo. ## Mock data must look like mock data `svc-gw` can synthesise vehicle state without any real readings, which is how this app is developed with no Jetson present. The stream carries a flag when it does. Rendering synthetic readings indistinguishable from real ones, on a screen in a moving car, is a safety problem. The indication belongs on the display surface itself, not in a settings page or a startup log. ## This app is the audio sink The tablet owns the car's aux input and is the music player, so the Orin's speech has to arrive here to be heard. - TTS arrives as **discrete utterances** over the reliable channel, not as a real-time stream. Receive the whole thing, then play it — no jitter buffer. - Duck other audio with `AUDIOFOCUS_GAIN_TRANSIENT_MAY_DUCK` for the duration of the utterance, then release. That is what makes Spotify drop under the voice without either side coordinating. - The microphone stays on the Orin. This app never captures audio; ASR input never crosses the boundary.