[package] name = "benilla-app" version.workspace = true edition.workspace = true license.workspace = true description = "The Bevy app as a library: everything but the build-id stamp, which lives in the `benilla` launcher shim so a commit dirties ~30 lines instead of this crate (decision 0993)" [features] # **The dev/player seam** (decisions 0026 + 1173). Default-ON, so every ordinary `cargo run`, # capture, probe and gate builds exactly what it built before. `--no-default-features` compiles # the instruments — the debug panel, the perf HUD, the inspector, the capture harness and the # probe fleet — physically OUT: not dormant behind a runtime flag, absent. That is the whole # requirement a player client has of them, and a runtime toggle cannot meet it. # # The rule the seam enforces is one-directional: **dev may see anything; nothing may depend on # dev.** It is enforced by `cargo build -p benilla --no-default-features` in `scripts/gates.sh`, # not by anyone remembering it — 0026 adopted the rule in June 2026 with no failing build behind # it, and twenty-four couplings had accumulated by August (1173). default = ["dev"] # # The three benilla crates below are taken with `default-features = false` and their `dev` # re-exported here (1175). Their `dev` is default-on too, so without the round trip a # `--no-default-features` build gets the feature back through unification — and the binary # carries the build machine's source-tree path after all. Same trap as the shim's, one level down. dev = ["benilla-assets/dev", "benilla-formats/dev", "benilla-world/dev", "dep:bevy_egui", "dep:libc"] # Opt-in Tracy profiling: `cargo run --features tracy` streams per-system `info_span!` markers (on the # hot systems) + render-pass CPU timings to a Tracy capture (decision 0026 — the dev/player seam; # a `docs/howto/running.md` this once cited never landed). tracy = ["bevy/trace_tracy"] # Opt-in Chrome-trace profiling: `cargo run --features trace_chrome` writes a `trace-.json` of # every system's per-run span next to the working dir. Tracy's offline twin — it needs no GUI and no # live capture, so a per-system cost question is answerable from a terminal (and from a run someone # else recorded). Aggregate it with `scripts/tracesum.py`. trace_chrome = ["bevy/trace_chrome"] [dependencies] anyhow.workspace = true # OS clipboard access for the UI EditBox copy/cut/paste chords (chat input). Already in the tree via # bevy_egui; pinned to the same 3.x so there's one copy. Read on the main thread (the UI key feed is # a NonSend system) — required for the macOS NSPasteboard path. Covers macOS, Windows, and Linux/BSD # under X11; the Wayland backend is `smithay-clipboard` below (decision 0702). arboard = "3" benilla-ui = { path = "../benilla-ui" } bevy.workspace = true wgpu.workspace = true # Optional: the dev overlays are its only consumers (the panel, the perf pill, the inspector # card), so a player build does not link it at all (`dev` feature, decision 1173). bevy_egui = { version = "0.39", optional = true } # Zero-copy POD→bytes for the shared light storage buffer (one per-frame write_buffer). Already in # the tree transitively; pinned to the same version as the dev-dep below. bytemuck = { version = "1", features = ["derive"] } # `f16` decode for the booth-target dump (`WOW_BOOTH_DUMP`): the booth render targets are # `Rgba16Float` (decision 0804) and the PNG wants display bytes. Already in the tree via # wgpu/bevy_image; declared so the call site is an honest dependency. half = "2" # The shipped FrameXML tree, compiled into the binary (decision 1175 §2): 61 files, ~2.8 MB, so the # client cannot boot without its interface on a machine that has never seen our source. A proc # macro plus a no-dependency runtime shim — it adds nothing to the graph at runtime, and it is the # crate everyone uses for this. `assets/ui` is OUR content (MIT/Apache), not Blizzard's. include_dir = "0.7" # `getrusage` — whole-process CPU time (all threads), the perf probes' `cpu_ms`/`cpu_pct` metric # (`perf::process_cpu_secs`). Wall-clock fps is unusable as a regression instrument on a machine # running parallel sessions' builds; CPU-per-frame is, and it is also the number the Mac report # is about ("250 % CPU at 59 fps"). Already in the tree transitively; declared so the call site is # an honest dependency. libc = { version = "0.2", optional = true } # Resample varying-size layer BLPs to a uniform size for the terrain texture array; `png` so we can # encode the cursor image into data an NSImage can load (macOS hardware cursor). image = { version = "0.25", default-features = false, features = ["png"] } # The net↔ECS bridge: a background IO thread streams typed `SessionEvent`s to the ECS over a # channel, and outbound `ClientCommand`s back. crossbeam's Sender/Receiver are `Send + Sync + Clone` # (std's mpsc Sender is `!Sync`, so it can't be a Bevy resource without a mutex — the very thing this # bridge deletes). The canonical Bevy background-thread→channel→system idiom. See decision 0006. crossbeam-channel = "0.5" benilla-assets = { path = "../benilla-assets", default-features = false } benilla-formats = { path = "../benilla-formats", default-features = false } benilla-protocol = { path = "../benilla-protocol" } benilla-world = { path = "../benilla-world", default-features = false } # The CVar config diff (`benilla/config.toml`, decision 0954): serde derive on the persisted # shape, toml as its format. (serde_json left with the era manifest — 0978.) serde = { version = "1", features = ["derive"] } toml = "0.8" # ECS-native physics: collider storage + broadphase BVH + shape-casts, with a thin custom kinematic # character controller on top (decision 0009). Pinned 0.6: it targets Bevy 0.18 (verified single, # unified bevy 0.18.1 in the tree); 0.7.0 jumps to Bevy 0.19 and would duplicate bevy. avian wraps # parry under the hood, so adopting it lets us drop the *direct* parry3d dep once the bespoke # CollisionWorld is gone. See docs… (decision 0007 superseded by 0009). avian3d = "0.6" # The glyph shaper + rasterizer for `FontString` text (decision 0068 §2, probe-verified in # `probes/text-glyph`). Pinned to 0.16 — the exact version already in the tree transitively # (`bevy_text`'s own dependency, see `Cargo.lock`) — so this is the *same* `cosmic-text` the decision # already commits to, not a second copy. Used as a standalone shaper/rasterizer (`FontSystem` + # `Buffer` + `SwashCache`) in `ui_text.rs`, never `bevy_text`'s `Text2d`/ECS integration (that path # doesn't feed our custom z-ordered `UiQuad` stream). cosmic-text = "0.16" # The font database `cosmic-text` 0.16 uses (its `Source`/`ID`/`FaceInfo` appear in `ui_text.rs`'s # public-in-crate types). Pinned to the exact version `cosmic-text` 0.16 depends on so there's one # `fontdb` in the graph. fontdb = "0.23" # kira's own backend dependency, named directly so the mixer can hand cpal an explicit device buffer # size instead of accepting `BufferSize::Default` (decision 1026). `CpalBackendSettings`' fields ARE # cpal types, so this must stay the exact version kira resolves — one cpal in the graph. cpal = "0.17" kira = { version = "0.12", default-features = false, features = ["cpal", "mp3", "wav", "pcm", "adpcm"] } # kira's own decoder, named directly for one trait: the mixer feeds streams through its own # `MediaSource` so kira's per-stream decode thread runs OUR code and can promote its QoS (decision # 1109 — a bare-spawned decode thread starves under the world-entry burst and zero-fills the mix). # No codecs of its own (kira's features enable those); must stay the version kira resolves — one # symphonia in the graph, or the trait impl won't line up. symphonia = { version = "0.5", default-features = false } # The mix tap's audio-thread → writer-thread ring (decision 1112): the tap effect must never # block or allocate on the render path. kira's own SPSC ring crate; kept on the version kira # resolves so the graph carries one rtrb. rtrb = "0.3" mint = "0.5" # The gossip greeting is a weighted random DRAW per menu-open, not a fixed pick (wow-re # `gossip-npctext-law.md` — the reference re-rolls in its gossip handler), so the app needs a uniform # source. Pinned to 0.8: the version `benilla-srp` already depends on, so this adds no crate. rand = "0.8" [dev-dependencies] # The WMO portal-cull audit's raw-face instruments (`WOW_PIN_COL`): the pin probe compares the # filtered walking-collision set against the group file's FULL face list with per-face MOPY flags, # which only the raw parser exposes — benilla-formats' gathers are exactly the filtered views. benilla-wmo = { path = "../benilla-wmo" } # Linux/BSD: the Wayland clipboard (decision 0702). We build with bevy's `wayland` feature, so on a # Wayland session winit gives us a native Wayland window and `arboard` — X11-only without its # non-default `wayland-data-control` feature — finds no X11 CLIPBOARD owner and every paste fails. # smithay-clipboard is the right crate for a windowed app: it drives the *standard* `wl_data_device` # off our own `wl_display`/seat, which every compositor supports. arboard's own Wayland feature would # not do: it speaks `wlr-data-control`, a privileged manager protocol GNOME/Mutter deliberately # doesn't implement. `raw-window-handle` (pinned to the 0.6 already in the tree via bevy_window, so # this adds no crate) is only needed to read the `wl_display` out of bevy's `RawHandleWrapper`. [target.'cfg(all(unix, not(any(target_os = "macos", target_os = "android"))))'.dependencies] raw-window-handle = "0.6" smithay-clipboard = "0.7" # macOS: drive a native NSCursor for a crisp hardware cursor. winit drives the cursor via AppKit # cursor-rects, which our continuous Metal render loop doesn't honor on mouse-move (custom cursor / # hide revert to the arrow); we bypass it with NSCursor + NSWindow::disableCursorRects. See # docs/knowledge/camera-control.md. [target.'cfg(target_os = "macos")'.dependencies] objc2 = "0.5" objc2-app-kit = { version = "0.2", features = [ "NSApplication", "NSResponder", # NSApplicationActivationPolicy (bgwin's Accessory demotion) is declared in this header. "NSRunningApplication", "NSWindow", "NSView", "NSImage", "NSCursor", "NSEvent", ] } objc2-foundation = { version = "0.2", features = ["NSArray", "NSData", "NSGeometry"] }