Web press feedback
motion.press() adds finite pointer and keyboard feedback to a declared HTML surface. It uses the Web runtime, without Vue, React or a permanent frame loop. This experimental API ships in 0.1.0-rc.5; see installation. Mavis integration follows separately.
Imperative usage
import { createWebRuntime } from '@rafaelaugusto/jolt/web'
const motion = createWebRuntime(document) // after mounting
motion.set(button, { scale: 1.1 })
const feedback = motion.press(button) // scale: 0.96, snappy spring
// Application motion can change while the pointer or Space/Enter is held.
motion.animate(button, { scale: 1.2 }, 'snappy')
feedback.update({ loading: true }) // cancels feedback; does not disable HTML activation
feedback.update({ loading: false }) // next input may press again
// On component disposal, or before replacing its declared surface:
feedback.dispose() // immediately removes only its contribution and input listeners
motion.release(button) // release the entire surface when its lifecycle ends
motion.dispose() // dispose the context when no longer neededOptional values use the runtime's numeric channels: motion.press(button, { scale: 0.96, opacity: 0.8 }, { transition: 'snappy', disabled: false, loading: false }). Scale/opacity multiply; translation/rotation add. Feedback always returns to its neutral contribution, not a captured application value.
| State | Visual scale |
|---|---|
| Application at 1.1 | 1.1 |
| Held with factor 0.96 | 1.056 |
| Application retargeted to 1.2 while held | 1.152 |
| Released or feedback disposed | 1.2 |
One binding per surface is supported. The private jolt:press: layer namespace is reserved. pressed reports input state; animation exposes the latest finite handle. Interrupted feedback resolves finished to false; completed feedback resolves to true, once. Retargeting uses the current position and velocity. A stale handle cannot reclaim newer motion. Live reduced-motion settings follow the runtime policy.
Input and lifecycle
Primary pointer input works on transformable HTML boxes. Native <button> elements additionally get Space/Enter feedback. Jolt does not synthesize clicks, change focus, call preventDefault(), set touch-action or request pointer capture. Native button activation, form submission and keyboard repeat behavior remain the browser's. Other elements receive pointer feedback only; the application owns their keyboard and accessibility semantics. Nested interactive controls are ignored.
Release outside, pointer cancellation/lost capture, mouse exit, ancestor scrolling, focus/window loss and page hiding cancel feedback. Scroll takeover remains available. Native :disabled (including fieldsets), aria-disabled, aria-busy on the target, ancestor inert, and update({ disabled, loading }) block feedback and cancel a held press. These flags govern feedback only: the component must implement its activation, focus and loading semantics, usually with the native disabled property.
Targets must be mounted. Detached targets are released automatically, including in shadow roots; explicit disposal is idempotent and works immediately after removal. Bind the replacement surface anew. Use the runtime's CSS surface policy: static 2D baseline, no competing CSS animations/transitions or changing motion styles/classes while claimed. A dedicated inner surface can separate component styling from motion.
Native reference and verification
Native press behavior is unchanged. These preserved English recordings show its existing layered composition; they do not demonstrate Web code or a shared Mavis screen.
Run npm run web:press:typecheck and npm run web:press:test. Chromium, Firefox and WebKit cover input, composition and cleanup; the actual touch-scroll gesture uses Chromium CDP only. See the verification and recording report.