Crafter.Graphics/examples/README.md
catbot b645746c8c test(webgpu-rt): RayQueryPick example exercising the rayQuery TLAS shim (#25)
Adds an 8^3 = 512-instance TLAS pick test that shoots one analytically
determined ray through a rayQuery=true PlainComputeShader and checks the
read-back committed hit (customIndex 484, t 40.75). 512 instances sit in
the < 8193 regime that the hardcoded 16384-leaf start used to miss, so the
example fails fast if the shim regresses. Verified in Firefox/WebGPU:
"[RayQueryPick] PASS".

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-04 13:33:04 +00:00

4 KiB

Examples

Each example is a self-contained crafter-build project that depends on the parent Crafter.Graphics via LocalProject. To build and run any of them:

cd examples/<name>
crafter-build -r

Index

HelloWindow

Minimum viable program: open a window, run the event loop. No Vulkan rendering. Useful as a smoke test for Device::Initialize + Window + the platform backend.

VulkanTriangle

Ray-traced single triangle through vkCmdTraceRaysKHR. Shows the full ray-tracing setup: DescriptorHeapVulkan with image and buffer slots, PipelineRTVulkan from raygen / miss / closesthit SPIR-V, BLAS via Mesh::Build, TLAS via RenderingElement3D::BuildTLAS, direct vkWriteResourceDescriptorsEXT for swapchain views, RTPass on window.passes. Smallest test of the bindless ray-tracing path.

HelloUI

Compute-shader UI demo using all three UI tiers:

  • Tier 3 components: DrawButton, DrawSlider, DrawProgressBar, composed via Rect::SubRect for resize-safe layout.
  • Tier 2 standard shaders: DispatchQuads for the background and components, DispatchCircles for a cursor-tracking dot, DispatchText for the button label (with the FontAtlas wired up to UIRenderer).
  • Tier 1 is available too — any custom ComputeShader registered on the same heap can be dispatched alongside the standard ones.

Hit-testing and animation are user code (see the EventListener subscriptions on window.onMouseMove / onMouseLeftClick); the library does not track widgets or focus.

Drop a TTF in this directory as font.ttf before running (the example loads it via Font("font.ttf")).

InputSystem

Guided tour of Crafter::Input: name actions ("Jump", "Move", "Fire", "Look", "Zoom"), bind them to keys / mouse / gamepad (with composite bindings for WASD-as-Vector2 and analog sticks), and consume them as events. Demonstrates:

  • The compile-time Key(CrafterKeys::Space) helper that folds to a per-platform raw scancode — bindings stay cross-platform-readable in source while runtime data stores raw codes only.
  • All four action types (Button, Axis1D, Vector2) with multiple bindings per action (any-of semantics).
  • Map::StartRebind — press R, then press any input to remap "Jump" at runtime. Captured input is filtered out for that frame.
  • BindingToString / BindingFromString round-trip — print the default bindings as the on-disk format.
  • Gamepad hot-plug events: plug a controller in mid-run and the bindings start firing immediately.

Console-driven (no UI rendering needed); focus the window and watch stdout.

CustomShader

Tier 1 demo: a user-authored compute shader (inverse-circle.comp.glsl) running alongside the shipped drawQuads. The custom shader inverts RGB under each item-circle — exactly the kind of effect attempt #2's closed shader couldn't express. Shows:

  • Defining your own item POD struct in C++ + matching std430 struct in GLSL.
  • #include "../../shaders/ui-shared.glsl" for the bindless heap declarations + UIDispatchHeader push-constant contract.
  • ComputeShader::Load for the .spv, UIRenderer::RegisterBuffer for your SSBO, FillHeader to populate the standard prefix, and UIRenderer::Dispatch to launch — the same pattern the standard shaders use under the hood.
  • The inter-dispatch SHADER_WRITE → SHADER_READ|WRITE barrier is inserted automatically, so the custom shader sees the colored stripes drawn by the prior DispatchQuads and reads/writes the swapchain image safely.

RayQueryPick

Regression test for the WebGPU software ray-query shim. Builds a 512-instance TLAS and shoots one ray through a rayQuery=true PlainComputeShader, reading the committed hit back to the host and checking it against the analytically-known answer. Guards against the hardcoded-leaf-start TLAS-traversal bug (issue #25) that made every rayQuery pick miss for realistic instance counts. WebGPU/DOM only.