Phase 0 closeout: render, AccessKit, bevy_picking#28
Merged
Conversation
Phase 0 closeout: promote three deferred workspace deps from the speculative list to first-class entries, and enable the bevy_picking feature on the bevy workspace dep. - bevy: add bevy_picking to feature list - bytemuck 1 (derive): instance-buffer POD trait impls - accesskit 0.21 / accesskit_winit 0.29: pinned to match Bevy 0.18's vendored versions to keep a single copy in the dep graph (cargo tree -p accesskit → accesskit v0.21.1, single entry) - buiy_core: wire all three new deps via workspace = true Still deferred: image-compare (visual harness upgrade), thiserror (no error-typing pressure yet). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Close the Phase 0 deferred gap: the render-graph node now builds a per-frame instance buffer from ExtractedDraws (logical-px → clip-space via to_instance), binds the static unit-quad VBO held on BuiyPipeline, and issues an instanced draw(0..4, 0..n). Adds DrawData::new constructor (non_exhaustive struct requires it for external callers), window_size field on ExtractedDraws, and removes the resolved shader TODO block. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Critical: shader.wgsl was passing a *signed* half-extent into the SDF (rect_size.y is negative by design for the CPU-side y-flip), so q.y became `abs(p.y) + h/2 + r` for every interior fragment — alpha collapsed to 0 and rects rendered invisible. Fix: abs() the rect_size before halving in the vertex stage. The signed rect_size remains load-bearing for the `world` computation and for `local_uv * half_size` in the fragment stage, where both factors flip sign together. Also: - Pure-CPU regression tests (sdf_rounded_rect + shader_half_size port) pin the half_size-must-be-positive property and document the buggy signed-half_size path so a regression fails loudly. - Add to_instance_offsets_position_to_clip — the existing four tests all used position = Vec2::ZERO, leaving the offset arithmetic (`* inv_w - 1.0`, `1.0 - * inv_h`) un-exercised. - Drop the dead `Default` derive on InstanceData (Zeroable provides the only construction we use; Default was never invoked). - pipeline.rs: rewrite stale "Task 11 will fix winding" comment — that task IS this commit chain; the TL/BL/TR/BR strip already winds consistently and the deferred work is the cull_mode tightening. - node.rs: drop the duplicated clip-space-conversion paragraph that contradicted the closeout paragraph below it. - mod.rs: tighten ExtractedDraws doc comment — populated only by extract_buiy_draws, not externally constructed. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Split a11y.rs into a11y/{mod,translate,adapter}.rs. translate.rs adds
pure, winit-free A11yNodeView→AccessKit translation (build_tree_update,
to_accesskit_node, node_id_for). adapter.rs adds AccessKitAdapters
(NonSend resource) and AccessKitAdapterPlugin, which pushes TreeUpdate
payloads into bevy_winit's existing ACCESS_KIT_ADAPTERS thread-local each
frame rather than owning Adapter objects directly (Adapter::new requires
&ActiveEventLoop which is only accessible inside the winit runner callback
in Bevy 0.18). Fixes pre-existing rustdoc private-intra-doc-links warning
in render/mod.rs.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ee, drop dead AccessKitAdapters Three fixes from code review of 269be68: A. Always push TreeUpdate, even on empty snapshots. The previous early-return suppressed pushes when the last widget was removed, leaving the AT holding a stale tree. accesskit_unix's update_if_active correctly diffs a root-only update and emits ChildRemoved events; deleting the early return restores that contract. C. Order push_tree_updates .after(build_tree). Both lived in BuiySet::A11yUpdate without an explicit constraint; Bevy's default ambiguity-detection is LogLevel::Ignore, so the scheduler was free to reorder them. Without the .after() the push system could observe the previous frame's snapshot and permanently lag the AT by one frame. build_tree is now pub(crate) so adapter.rs can name it. B. Drop the AccessKitAdapters resource. It tracked which windows had been pushed to but no code read the map for any decision. bevy_winit's ACCESS_KIT_ADAPTERS thread-local is the source of truth; the resource was dead weight. Removed the struct, the NonSendMut parameter, the re-export from a11y/mod.rs, the re-export from buiy/src/lib.rs, and rewrote the smoke test to assert against bevy_winit's thread-local. Also added two translate-test gaps: description_round_trips and focusable_view_has_focus_action (covers Action::Focus add-action wiring). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace the AABB+window-cursor shim in update_hovered with a real bevy_picking backend. BuiyPickingBackendPlugin runs in PickingSystems::Backend (PreUpdate), reads PointerLocation components, and emits PointerHits messages sorted by area (smallest = topmost). PickingPlugin's update_hovered is rewired to consume those messages, making Hovered a thin aggregation layer over the backend. Bevy 0.18.1 API deviations from plan: - PointerHits is a Message (not Event); uses MessageWriter/MessageReader. - Location.target is NormalizedRenderTarget (not PointerTarget). - PickSet::Backend is PickingSystems::Backend. - BuiyPlugin now also composes bevy::picking::PickingPlugin to register PickingSystems sets and Messages<PointerHits> before the Buiy plugins. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ckend Two comment fixes flagged in code-quality review of 54d6073: - update_hovered: replace incorrect "cursor-leaving-window produces an empty picks event which clears it" with an accurate description of emit_picks's continue-on-empty behavior. Calls out the Phase 0 limitation (Hovered retains stale value when cursor leaves all Buiy nodes) and points to buiy-input-events-design for v0.x. - BuiyPlugin::build: update the inline order comment to acknowledge bevy::picking::PickingPlugin in the slot, and explain why it must precede the two Buiy picking plugins (registers PickingSystems sets + Messages<PointerHits>). No code changes; comments only. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Final-review feedback: the closeout plan's self-review row claimed "full HashMap<WindowId, Adapter>" but the actual implementation bridges into bevy_winit's ACCESS_KIT_ADAPTERS thread-local because Bevy 0.18 owns adapter creation (Adapter::* constructors require &ActiveEventLoop, only accessible from the winit runner callback). Update the self-review row to describe the bridge accurately and call out the AccessKitAdapters resource that was dropped during Task 4's review loop. Also tighten the CHANGELOG bullet so it doesn't imply Buiy owns the Adapter objects. No code changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes the three substantive deferrals from the Phase 0 self-review (
docs/plans/2026-05-07-buiy-phase-0-foundations.mdlines 2784–2790):BuiyNode::runbuilds a per-frame instance buffer fromExtractedDraws(logical-px → clip-space viato_instance), binds the static unit-quad VBO held onBuiyPipeline, and issuespass.draw(0..4, 0..n). Newcrates/buiy_core/src/render/instance.rsholds the POD + conversion. Shader's priorhalf_size = rect_size * 0.5was buggy with the y-flipped negativerect_size.y; fixed toabs(i.rect_size) * 0.5with regression tests.crates/buiy_core/src/a11y/gains puretranslate.rs(winit-free) +adapter.rs. Bevy 0.18'saccesskit_winit::Adapter::*constructors all require&ActiveEventLoop(only available inside the winit runner), so Buiy bridges intobevy::winit::accessibility::ACCESS_KIT_ADAPTERSrather than owningAdapterobjects directly.push_tree_updatesruns inBuiySet::A11yUpdate.after(build_tree)and pushesaccesskit::TreeUpdateto every existing adapter each frame, including empty trees so AT state clears correctly when widgets disappear.bevy_pickingbackend. NewBuiyPickingBackendPluginemitsPointerHitsfromPointerLocation×ResolvedLayoutAABBs inPreUpdate/PickingSystems::Backend.Hoveredrewired as a thin layer consumingMessageReader<PointerHits>. Composed intoBuiyPluginalong withbevy::picking::PickingPlugin(the sole registrar ofPickingSystemssets andMessages<PointerHits>).Plus: workspace deps (
bytemuck,accesskit,accesskit_winit;bevy_pickingfeature on bevy),[draft]→[landed]flips on the original Phase 0 plan + this closeout plan, CHANGELOG entries, plan indocs/plans/2026-05-08-buiy-phase-0-closeout.md.Architectural deviations from the plan body (forced by Bevy 0.18 reality)
accesskit_winitpinned to 0.29 (matches Bevy 0.18's vendored copy), not the plan's 0.31.PointerHitsis aMessagein Bevy 0.18, not anEvent; usesMessageWriter/MessageReader/Messages<T>.PickingSystems::Backend, notPickSet::Backend.HashMap<WindowId, Adapter>resource — see closeout plan self-review for the full rationale.Out of scope (explicit deferrals to v0.x sub-specs)
#[ignore]'d render-smoke tests stay ignored).buiy-render-pipeline-design.buiy-input-events-design.buiy-accessibility-design.Test plan
cargo fmt --all -- --check— cleancargo clippy --workspace --all-targets -- -D warnings— cleanRUSTDOCFLAGS='-D warnings' cargo doc --workspace --no-deps— cleancargo deny check— cleancargo test --workspace— all green (~50 tests pass, 2 expected#[ignore]'d GPU smokes)cargo run --example hello_button— opens window, paints button, no panicverification.md.)🤖 Generated with Claude Code