Browsers (Chrome, Safari, mobile Firefox) create every AudioContext
suspended and refuse to start it without a user gesture. Bevy -> rodio ->
cpal build their context at startup, so it stayed suspended and no sound
played except on lenient desktop Firefox.
Wrap the AudioContext constructor in the web shell to track created
contexts and resume them on the first pointer/key/touch gesture.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The mouse wheel's per-frame delta is a Vec2, so it maps directly onto
axis actions alongside gamepad sticks. hardware_to_actions now reads
AccumulatedMouseScroll in the Axis branch (max-magnitude combine); the
digital branch ignores it, and Scalar is unchanged.
Since an axis is refreshed every frame and the scroll delta is zero when
idle, on_action fires exactly while the wheel turns and the piped value
is the delta — no persistence or edge-guarding needed. Enables e.g.
`.bind(Action::Zoom, [Binding::Scroll])`.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- The #[action_kind(..)] attribute is now optional and defaults to instant
(the most common kind), so bare enum variants are instant actions.
- Document the multiple-plugin pattern: add one ActionsPlugin::<T> per action
enum (gameplay/menu/audio/debug) for separation of concerns, each with its
own independent ActionState/InputMap/systems, plus the run_if(in_state(..))
approach for mutually-exclusive sets.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Derive Default on ActionSource so it satisfies bevy's template system
(Template/FromTemplate are blanket-impl'd only for Clone + Default + Unpin),
letting it be spawned as a component in a bsn! scene. The bound sits on the
derived Default impl only, so the Component impl stays generic over every
GameAction — the fan-in systems keep working for non-Default actions.
- Improve #[derive(GameAction)] diagnostics: each now names the offending
variant and shows the exact expected syntax (not-an-enum, non-unit variant,
missing/duplicate/unknown action_kind, malformed action_handler).
- Add a #[cfg(test)] module exercising all four kinds + an #[action_handler]
each + ActionsPlugin + App::on_action, proving the macro codegen compiles.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Both remove the add_systems(.., run_if(on_action(..))) boilerplate:
- `#[action_handler(path)]` derive attribute colocates a handler with its
action variant and wires it for its kind — a gated plain system for
instant/toggle, a typed pipe (axis_value/scalar_value) plus gate for
axis/scalar. The derive generates an `impl GameActionHandlers` (empty when
no variant declares one), which ActionsPlugin calls on build.
- `App::on_action(schedule, action, system)` (AppActionExt) — the explicit,
no-macro form that keeps registration visible in main.
ActionsPlugin's Plugin impl now requires T: GameActionHandlers (satisfied
automatically by the derive).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds a fourth ActionKind, Scalar, carrying an f32 from a slider's
ValueChange<f32>. It is edge-triggered like Instant but value-carrying
like Axis, completing the edge/level split (Instant/Scalar vs Toggle/Axis).
- ActionValue::Scalar(f32) + as_scalar(); ActionState scalar()/set_scalar().
- active() is now kind-dispatched: edge kinds report "this frame", level
kinds report current state.
- slider_to_action observer stores live value on every change but only
triggers on is_final, so gated consumers run once per settled change.
- scalar_value(a) typed provider pipes a bare f32 into In<f32>.
- #[action_kind(scalar)] added to the derive macro.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Introduce engine::actions: an input-source-agnostic action layer that
fans keyboard, gamepad, and Feathers UI (Button/Checkbox) input into a
single ActionState<T> resource, so games gate systems on abstract actions
rather than raw inputs.
- GameAction trait + #[derive(GameAction)] proc macro (new engine_macros
crate) to declare each enum variant's ActionKind via #[action_kind(...)].
- Three kinds: Instant (momentary), Toggle (persistent on/off), Axis (Vec2).
- Remappable InputMap<T> with additive bind(action, [Binding, ...]).
- Symmetrical entry points over a unified ActionValue: run_if(on_action(a))
to gate any kind, action_value(a).pipe(sys) to deliver its payload;
typed axis_value/toggle_value helpers for bare Vec2/bool.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
There is a new bug related to sound not playing but I think that's
because we're re-assigning sounds soon after spawning cells which is
understandable...