Skip to content

Releases: Denjino/Horizon-View

v1.0.0

23 May 14:58
edaa96d

Choose a tag to compare

Make the live-tune (F1) hotkey rebindable from the dashboard

The settings-overlay hotkey was config-only; now it has the same
press-a-key rebind dialog as the tracking toggle. RebindHotkey takes
a `target` prop ("activate" | "settings") and routes to the matching
Rust command (rebind_hotkey / rebind_settings_hotkey, both already
present). Dashboard adds a "Change" button next to the live-tune
hotkey row in Advanced.

Kept at 1.0.0 — no version bump.

v0.1.9

21 May 00:50
dec35b1

Choose a tag to compare

Mirror dashboard/overlay tune sliders, add center deadzone, asymmetri…

v0.1.8

20 May 23:56
45fab69

Choose a tag to compare

Fix smoothing direction, recenter action, landmark overlay, one-shot …

v0.1.7

20 May 22:53
e86c5d0

Choose a tag to compare

Rescale sensitivity, add curve and smoothing sliders, in-game tune ov…

v0.1.6

20 May 21:43
6823c37

Choose a tag to compare

Tame the in-game feel: stop on toggle-off, smoother defaults, cursor …

v0.1.5

20 May 18:11
a0f94a7

Choose a tag to compare

Make calibration robust to MediaPipe's yaw sign convention

Calibration was rejecting valid captures with "head moved the wrong
way for at least one dot" even when the user followed the prompts.
Two contributing bugs:

1. The spline assumed positive yaw == looking right. MediaPipe's
   facialTransformationMatrix output sign depends on driver and
   mirroring conditions, and on at least some setups it's inverted
   relative to that assumption. The spline then sorted samples by
   yaw and checked that screenX was strictly INCREASING along that
   order — which fails the moment the convention is flipped, because
   sorted yaw walks screenX from +1 down to -1.

   Fix: infer the sign from the first/last screenX pair and apply it
   transparently in both fit and evaluate. The fitter only needs the
   yaws to be monotonic; either direction works.

2. The calibration listener was being fed the *raw* per-frame yaw, not
   the One-Euro-filtered yaw. A single noisy frame at the moment of
   Space press could push one capture far enough off-axis to flip an
   adjacent pair. Now the listener receives both filtered and raw,
   and calibration captures the filtered value (the filter is already
   running every frame regardless).

Error messages on the remaining genuine failure modes are sharper:
duplicate yaws now say "turn your head more deliberately between
dots", non-monotonic says "redo with slower, more deliberate head
turns".

v0.1.4

20 May 17:48
d856807

Choose a tag to compare

Allow WebAssembly + workers in the packaged CSP

v0.1.3 bundled MediaPipe locally but still failed to start because
the packaged CSP blocked WASM compilation:

  CompileError: WebAssembly.instantiate() ... 'wasm-eval' is not an
  allowed source of script in 'script-src 'self' 'sha256-...'

Root cause: I had put 'unsafe-eval' on default-src, but Tauri injects
its own script-src (with hashes for its bootstrap scripts) and that
directive does NOT inherit from default-src — so the keyword never
applied to script execution. Same story for MediaPipe's worker, which
it spawns from a blob: URL.

- Set explicit script-src 'self' 'wasm-unsafe-eval' blob: — Tauri
  appends its sha256 hashes to our directive instead of synthesizing
  its own, and 'wasm-unsafe-eval' permits WebAssembly compilation
  without re-enabling general eval().
- Set explicit worker-src 'self' blob: for MediaPipe's worker.
- Tighten everything else: drop the broad `https:` allowance from
  default-src (assets are local now), drop the jsdelivr/googleapis
  connect-src entries that were only needed before bundling.

v0.1.3

20 May 17:35
5f9a321

Choose a tag to compare

Bundle MediaPipe locally and surface real init errors

Packaged WebView2 was failing to initialize the Face Landmarker when
fetching the WASM/model from jsdelivr + googleapis — the error came
through to our handler as a non-Error object, so the UI degraded to
the unhelpful "failed to start face tracker" fallback.

- scripts/setup-mediapipe.mjs runs as part of pnpm build (and pnpm dev),
  copies the tasks-vision WASM out of node_modules into public/
  mediapipe/wasm, and downloads face_landmarker.task into the same
  folder. Vite then publishes the lot into dist/, so the packaged
  app loads everything from app:// rather than the network.
- HeadLandmarker points at the local paths, tries the GPU delegate
  first and falls back to CPU automatically if GPU compilation throws.
  Either path failing now surfaces a real message instead of a
  swallowed exception.
- Calibration's catch handler properly stringifies whatever MediaPipe
  threw (Error / string / object with .message / JSON) and logs the
  raw value to the console so we can still see it if the stringified
  form is opaque.

Installer grows ~37 MB (WASM + model) — worth it for offline first-
run and to remove a fragile remote dependency. Bump to 0.1.3.

v0.1.2

20 May 17:22
83b60e8

Choose a tag to compare

Fix CameraPreview.ready never resolving after a parent re-render

The original built the readiness Promise with `useRef(new Promise(...))`
and stashed the resolver in a *separate* ref captured inside the
constructor. The constructor expression ran on every render and
overwrote the resolver, while useRef stuck with the very first promise.
So once anything in the parent (e.g. setInitStatus during calibration
boot) triggered a re-render between mount and the webcam coming up,
the resolver that fired was attached to a brand-new throwaway promise,
and the one the caller was awaiting stayed pending forever — which
manifested as calibration stuck on "Starting webcam…" even though the
stream itself was visibly playing in the corner.

Pair the promise and its resolver in a single lazily-initialized ref
so they can't drift, and mark `resolved` so a future re-fire (e.g.
deviceId change re-running the effect) is a no-op rather than calling
a stale resolver.

v0.1.1

20 May 16:54
e4c76b4

Choose a tag to compare

Make calibration capture diagnose its own failures

Pressing Space silently no-op'd whenever latestYawRef was still null,
which gave the user no signal that anything was wrong. There are at
least three real causes (MediaPipe model still downloading, init
exception, no face yet detected) and none of them surfaced.

- Show init phase ("Loading face tracker…" / "Waiting for your face…"
  / "Tracker ready") with a live yaw readout, so the user can see when
  the pipeline is alive before pressing Space.
- Visible mini camera preview during calibration. Doubles as a sanity
  check that the webcam stream is up, and avoids `display: none` on
  the source <video>, which can suppress frame decoding in some
  WebView2 builds.
- "Capture this point" button as a backup for Space (and disabled
  until init is ready). Space presses on a not-yet-ready tracker now
  flash a transient hint instead of being eaten.
- Catch and surface init errors inline rather than swallowing them.

Bump to 0.1.1 so the next tag picks this commit up.