Repository navigation
A wayfinding HUD that does not flicker
An AR wayfinding overlay is a small set of obvious ideas: an arrow at the edge of the screen for targets behind you, a ring around targets in front of you, a distance label so people know whether "ahead" means ten metres or two hundred.
Each is simple. Together they produce, on the first implementation, an interface that strobes.
Every element above is driven by a boolean derived from a continuous quantity.
- "Is the target off-screen?" — derived from an angle.
- "Is the user close enough to hide the indicator?" — derived from a distance.
Continuous quantities are noisy. Distance to a waypoint is computed from a position that moves with the user's gait, GPS updates and alignment refinements. When that distance sits near your threshold, it crosses it repeatedly — several times a second — and the indicator appears, disappears, appears.
The user reads this as the app malfunctioning. It is doing exactly what it was told.
The fix is hysteresis: separate the condition for appearing from the condition for disappearing, and leave a gap between them.
- Show the indicator when the target is further than X.
- Hide it when the user gets closer than Y, where Y is meaningfully smaller than X.
Between Y and X, the state simply persists. Small oscillations cannot cross both boundaries, so the indicator is stable. To change state, the user must genuinely move.
Framed as behaviour rather than mathematics: "show beyond X, hide when you arrive at Y". Deadband widths become a design decision — how far must someone move for the interface to change its mind — rather than an accident of sensor noise.
Once seen, this pattern is impossible to unsee, and it applies well outside AR:
- Connection-status indicators flapping between online and offline.
- "Nearby" lists reordering constantly as two items trade places.
- Auto-scaling systems adding and removing capacity in a loop.
- Battery-saver modes toggling at the threshold percentage.
Any boolean derived from a noisy continuous signal needs either hysteresis or a minimum dwell time. There is no third option that works.
A wayfinding HUD makes several decisions that are easy to get subtly wrong:
Edge arrows must encode direction honestly. An arrow pinned to the edge of the screen has to indicate which way to turn, and the mapping from a 3D direction to a 2D screen edge position is where implementations differ. Getting it wrong produces an arrow that is technically pointing at the target and useless to a human.
Distance formatting is UX, not formatting. "127.3 m" implies precision the system does not have and updates distractingly. "≈130 m" is more honest and calmer.
Multiple targets need a policy. Six waypoints and six arrows is a mess. Nearest-only, or a cap, or grouping — but a decision, not an accident of how many targets exist.
The demo runs in two modes, and the second is what makes the first maintainable: a desktop walk simulator, WASD to move and drag to look, driving the real HUD in explicit-tick mode rather than a mock of it — so you can try it right now without a phone.
That is what the end-to-end tests exercise. Hysteresis is precisely the kind of behaviour that unit tests can assert cleanly — walk toward a target, cross Y, assert hidden; walk back, cross Y again, assert still hidden until X — and precisely the kind that is miserable to verify by walking around outdoors hoping to catch a flicker.
The interface bug that only shows up while moving is testable, as long as something can move without a human doing the walking.
Start here
Building with it
How the alignment works
Testing & debugging
Perception
Shipping it
12 more pages — see the page list above.