Skip to content

Bootstrap bevy_config v0.1.0 (Bevy 0.18.1) - #1

Merged
stuartparmenter merged 11 commits into
mainfrom
bootstrap-v0.1.0
May 1, 2026
Merged

Bootstrap bevy_config v0.1.0 (Bevy 0.18.1)#1
stuartparmenter merged 11 commits into
mainfrom
bootstrap-v0.1.0

Conversation

@stuartparmenter

Copy link
Copy Markdown
Contributor

Summary

Initial implementation of bevy_config — a capability-aware configuration system for Bevy. Detects adapter caps, picks platform-appropriate defaults, layers user overrides, clamps to caps, and binds the result to engine resources (Window, anti-alias components, MSAA, optional DLSS).

Targets Bevy 0.18.1. A 0.19-dev branch will be cut from main after this lands to track Bevy main for the next-release line.

What's in the box

  • Kernel (caps.rs, config.rs, backend.rs, plugin.rs):
    • AdapterCaps resource (plain bools/ints/enums; no wgpu types in public API)
    • PlatformTarget enum + detect() (cfg-based)
    • Config trait (platform_default / merge / clamp_to / current_overrides)
    • ConfigBackend trait + native FileBackend (RON, atomic write) + wasm LocalStorageBackend (JSON via web-sys)
    • ConfigPlugin<C> build/finish lifecycle, ConfigApplied<C> event, BevyConfigSet SystemSet, SaveConfig<C> command
  • Universal schema (common/):
    • CommonConfig { Display, Render, Accessibility } + sparse CommonConfigOverrides
    • Audio is intentionally absent — it's backend-specific (firewheel/seedling/etc.) and will ship in a future feature-gated companion type
  • Graphics bindings (bindings/):
    • BevyConfigCamera marker
    • DisplayPrimaryWindow (mode/vsync/resolution)
    • Render.anti_alias / msaaTemporalAntiAliasing / Fxaa / Smaa / Msaa per camera
    • DLSS via bevy_anti_alias::Dlss<DlssSuperResolutionFeature> behind the dlss cargo feature
    • On<Add, BevyConfigCamera> observer covers deferred-spawn cameras (e.g., OnEnter(AppState::InGame))
  • Examples: basic.rs (Startup spawn) and deferred_camera.rs (state-transition spawn with verification)
  • Tests: 11 merge / clamp / platform-default tests in tests/merge.rs
  • Docs: README usage section, lib.rs quickstart doctest, [package.metadata.docs.rs] configured for ["ron"] feature only (skips DLSS — NVIDIA SDK not on docs.rs)

CI / release infrastructure

Lifted from pavlov-net/tripo3d-rs and adapted for a library:

  • ci.yml — Linux/Mac/Windows test matrix (drops --all-features to skip dlss)
  • lint.yml — prek (cargo-fmt + clippy)
  • docs.ymlcargo doc --no-deps --workspace
  • release-drafter.yml (config) + workflows/release-drafter.yml (workflow that drafts releases from PR labels and bumps version via cargo set-version; paths adapted for single-crate vs workspace)
  • release.yml — heavily simplified for a library: drops the binary build matrix, Windows code signing, Azure OIDC, release-asset upload. Just cargo publish --locked on tag, gated by a crates-io GitHub environment for Trusted Publisher

Test plan

  • cargo build (lib + examples)
  • cargo test — 11/11 merge tests pass + 1 doctest
  • cargo clippy --workspace --all-targets -- -D warnings
  • cargo build --target wasm32-unknown-unknown --lib
  • cargo fmt --all -- --check
  • cargo doc --no-deps — warning-free
  • cargo package --no-verify — packages 24 files cleanly, ready to publish
  • CI workflows pass (will run on PR push)
  • Configure crates-io GitHub environment + Trusted Publisher entry on crates.io before the first release

Follow-ups (not in this PR)

  • Cut 0.19-dev branch from main after merge, retarget deps to git = "https://github.com/bevyengine/bevy" for ongoing development
  • Bevy 0.19 ships → cut v0.2.0 from 0.19-dev with versioned deps
  • Audio companion type behind a seedling/firewheel cargo feature
  • Input rebinding companion behind a leafwing cargo feature

Capability-aware configuration system for Bevy: detect adapter caps,
pick a platform default, layer user overrides, bind to engine resources.

Kernel:
- AdapterCaps resource (plain bools/ints, no wgpu types in public API)
- PlatformTarget enum with cfg-based detect()
- Config trait (platform_default / merge / clamp_to / current_overrides)
- ConfigBackend trait + native FileBackend (RON, atomic write) and wasm
  LocalStorageBackend (JSON via web-sys), cfg-split per target
- ConfigPlugin<C>: build() loads + merges, finish() detects caps + clamps,
  Startup triggers ConfigApplied<C>
- BevyConfigSet system set; SaveConfig<C> command for persisting changes

Common schema (CommonConfig + sparse CommonConfigOverrides):
- Display (window mode, vsync, monitor, resolution, fps cap, HDR slot)
- Render (anti-alias, MSAA, upscaler, render scale, sharpness, RT toggle)
- Audio (per-bus volumes, output device, channel mode) — schema only
- Accessibility (subtitles, motion, color-blind mode)

Common bindings (graphics only):
- BevyConfigCamera marker
- Display → PrimaryWindow (mode, present_mode, resolution)
- Render.anti_alias → TemporalAntiAliasing / Fxaa / Smaa per camera
- Render.msaa → Msaa component
- DLSS via bevy_anti_alias::Dlss<DlssSuperResolutionFeature> behind the
  `dlss` cargo feature, gated on caps.supports_dlss

Tracks Bevy git default branch; will pin to versioned dep when 0.19 ships.
Cameras spawned after the initial config-applied tick (e.g. in
OnEnter(AppState::InGame), post-asset-load, or split-screen mid-game)
were coming up without configured anti-alias / MSAA / upscaler — the
PostUpdate `apply_render` system's `resource_changed::<CommonConfig>`
pulse fires once, on the first tick, before deferred-spawn cameras
exist.

Extracts the per-entity body into `apply_render_to_entity` and
registers an `On<Add, BevyConfigCamera>` observer that calls it with
the current Render config and AdapterCaps. The observer takes
`Option<Res<AdapterCaps>>` to tolerate the Plugin::build window
before finish() populates caps; `apply_upscaler` already handles
that path (logs + falls back to Native).

apply_display doesn't need a sibling observer — display config is
window-scoped, and the primary window already exists by the time
Res<CommonConfig> first changes.

Both new items are pub(super); no public API changes.
`#[derive(Default)]` over a generic `<C>` adds a `C: Default` bound
even when the only generic-parameterised field is `PhantomData<C>`,
which doesn't actually require it. Any consumer whose Config type
doesn't derive Default — and no Config type should have to —
hits `the trait bound `MyConfig: Default` is not satisfied` at the
`SaveConfig::<MyConfig>::default()` call site.

Manual impl drops the bogus bound for both lifecycle types.
Will switch to release-drafter generating GitHub Releases from PR
titles/labels once the workflow is set up. Hand-maintained changelogs
decay; release-drafter pulls metadata that's already required for
the PR review flow.
The 6-bus convention (master/music/sfx/voice/ui/ambient) baked a
seedling-shaped opinion into the universal schema. The bus model is
genuinely backend-specific — firewheel (the long-term Bevy audio
direction, and seedling's underlying engine), kira, oddio, and direct
firewheel users all model buses differently.

Audio config will return as its own `Config` type behind a cargo
feature (e.g. `firewheel` or `seedling`) once the binding shape is
designed. Consumers register `ConfigPlugin<FirewheelAudioConfig>`
alongside `ConfigPlugin<CommonConfig>` — the trait already supports
side-by-side configs.

Removes ~150 lines (audio.rs schema + axis-of-CommonConfig wiring +
test assertions). README updated to document the rationale.
- Mark plausibly-growing public enums #[non_exhaustive]: Backend,
  GpuVendor, PlatformTarget, AntiAlias, Upscaler, UpscalerPreset,
  ColorBlindMode, MonitorSelection. Truly-exhaustive enums
  (WindowMode, VsyncMode, Resolution, FpsCap, HdrPreference,
  MsaaLevel) stay un-annotated — they cover their design space.
- #[must_use] on ConfigBackend::store so save errors can't be
  silently dropped.
- let-else in SaveConfig::apply for the two get_resource Some/None
  blocks.
- Hoist `use bevy_config::prelude::*` in tests/merge.rs; drop the
  per-fn `use Config` lines (already in the prelude).
- Cargo.toml: rust-version = "1.85" (matches edition 2024) and
  readme = "README.md".
- bevy_camera: never `use`d anywhere in src/ — was aspirational from
  the bootstrap. The types we actually need (Msaa) live in bevy_render.
- wasm-bindgen: never imported directly; web-sys pulls it transitively
  for the localStorage FFI it generates.

Both were also blockers for a 0.18 backport (bevy_camera doesn't exist
as a separate crate in 0.18, and wasm-bindgen would have to track
web-sys's pin) — the dep set is now version-portable.
@socket-security

socket-security Bot commented May 1, 2026

Copy link
Copy Markdown

bevy_winit on Linux pulls wayland-sys / alsa-sys / udev whose build
scripts need libwayland-dev / libasound2-dev / libudev-dev. macOS and
Windows aren't affected.
@stuartparmenter
stuartparmenter merged commit b21de97 into main May 1, 2026
8 checks passed
@stuartparmenter
stuartparmenter deleted the bootstrap-v0.1.0 branch May 1, 2026 18:54
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.

1 participant