Skip to content

perf: skip the web-haptics engine on desktop browsers without vibration - #45

Merged
joeblau merged 1 commit into
mainfrom
perf/37-skip-engine-without-vibration
Oct 21, 2026
Merged

joeblau merged 1 commit into
mainfrom
perf/37-skip-engine-without-vibration

Conversation

@joeblau

@joeblau joeblau commented Oct 21, 2026 •

Copy link
Copy Markdown
Contributor

Closes #37

What

When a target is tapped, requestFeedback now returns before it creates or triggers a WebHaptics engine if all of these hold:

  • typeof navigator.vibrate !== 'function', checked at tap time rather than through the module-load WebHaptics.isSupported.
  • webHapticsOptions.debug isn't set.
  • webHapticsOptions.showSwitch isn't set.

On desktop browsers without vibration, the engine's hidden <label> + <input switch> and its rAF pattern loop produced no feedback. The vibration path and the iOS native path are unchanged. Debug audio and the visible switch work exactly as before.

Tests:

  • The shared beforeEach now stubs navigator.vibrate. The existing engine tests ran without a stub, so they now exercise the vibration path they assert on.
  • New tests in an unsupported desktop suite:
    • With no options, or with debug: false / showSwitch: false, no engine is created, no trigger fires and no body nodes are added, and the host action still fires once.
    • With debug: true and with showSwitch: true, the engine is still constructed and triggered.
    • Vibration support is re-checked on every tap.

Implemented with the Codex CLI on the shared box and verified by hand.

Benchmark (npm run bench, same box)

The desktop-without-vibration path wasn't touched by #42, #43 or #44, so the quieter 78ec2f2 runs from earlier today are a valid baseline. "Interleaved" means back-to-back runs on main at 1ea44a1 while another agent's build was saturating the box.

Desktop without vibration Quiet baseline (3 runs) Interleaved main (2 runs) This PR (2 runs)
Engines after 100 distinct taps 100 100 0
Body nodes / engine labels / rAF per tap after 100 taps 300 / 100 / 2 300 / 100 / 2 0 / 0 / 0
First-tap cost (instrumented ms) 1.56 / 1.75 / 1.85 5.81 / 10.19 0.48 / 0.38 (≥ −69%)
Remaining 99 distinct taps (ms/tap) 0.38 / 0.38 / 0.38 0.49 / 0.79 0.050 / 0.041
Warmed desktop click (median ms/tap) 0.075 / 0.075 / 0.069 0.124 / 0.159 0.074 / 0.033

The vibration and iOS rows show no change beyond noise; vibration engines stay at 100 and iOS engines at 0. Full ESM goes from 4,583 to 4,607 gzip bytes (+24 B).

Verification

Device-testing notes

These are simulated-browser numbers from Node 24 with production React and jsdom, using a stubbed Linux navigator with no vibrate. None were measured on physical devices, and no physical device was used. Physical iPhone/Android/iPadOS/VoiceOver certification is still tracked in #9.

@joeblau
joeblau force-pushed the perf/37-skip-engine-without-vibration branch from 2d104a0 to 2856cb1 Compare October 21, 2026 01:03
@joeblau
joeblau merged commit 26603e7 into main Oct 21, 2026
7 checks passed
@joeblau
joeblau deleted the perf/37-skip-engine-without-vibration branch October 21, 2026 01:04
@joeblau joeblau mentioned this pull request Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Skip WebHaptics engine, hidden DOM and rAF loop on desktop browsers without vibration

1 participant