- Add workflow_q3_md3_load_step: load MD3 models from PK3 with correct
CCW winding, 1/64 xyz scale + 0.03125 world scale, and per-frame VBs
- Add workflow_q3_md3_draw_step: viewmodel (weapon) + world-space MD3
drawing; barrel oriented along model X → world forward
- Add workflow_q3_bots_draw_step: 3-part bot model chain
(lower→upper→head via MD3 tags) + weapon attachment
- Add workflow_q3_bots_spawn_step: spawn bots at indices 1+ so they
never overlap the player's spawn point (index 0)
- Add workflow_q3_bots_update_step: bot AI (idle/chase/shoot/dead FSM)
- Fix workflow_q3_menu_update_step: menu starts closed (was open)
- Fix workflow_postfx_composite_step: GPU readback via
SDL_DownloadFromGPUTexture captures full 3D scene for screenshots
- Fix Metal GPU validation: always bind 2 sampler slots; reuse albedo
as dummy shadow map when no shadow texture is available
- Reorder q3_frame.json: screenshot trigger nodes run before
postfx_composite so screenshot_output_path is set in time
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Introduce a new Quake3 pickups draw workflow step to render in-world pickup icons and register it: add WorkflowQ3PickupsDrawStep (header + implementation), register the step in WorkflowRegistrar, and include the source in CMakeLists. Update the q3_frame workflow JSON to insert a draw_pickups node into the frame graph. Enhance the overlay to show weapon damage in the HUD and draw weapon/hit visuals, and update weapon logic to mark hits and accumulate damage (q3.last_shot_hit, q3.hit_marker_until_frame, q3.damage_done). Also fix trailing newline in CMakeUserPresets.json.
- overlay.fps: SDL software renderer → GPU texture quad, top-right corner,
yellow EMA-smoothed FPS counter; LOADOP_LOAD preserves scene beneath it
- debug.screenshot: one-shot step that writes status txt + BMP then pushes
SDL_EVENT_QUIT for automated visual feedback loop
- Adaptive vsync: graphics.gpu.init "auto" present_mode queries actual monitor
refresh rate via SDL_GetCurrentDisplayMode; ≥120 Hz → VSYNC, <120 Hz → MAILBOX
Fixes vsync cap on 165/170 Hz monitors reporting as 240 Hz in settings
- Fixed present_mode wiring: q3_game.json gpu_init_viewport node now passes
present_mode as a direct parameter (workflow variables are not seeded into
context by the executor, so the variable section was dead data)
- Stair climbing: probeReach 0.45→0.70 for earlier detection, jam detection
nudges player up after 100 ms of horizontal blockage, step_height tuned to 0.6
- Physics dt: real wall-clock delta clamped to [1/600, 1/30] so 240 Hz displays
don't run physics 4× faster than intended
- GUI smart search paths: _candidate_build_dirs() scans all generator dirs ×
build types × flat and Conan-nested layouts, sorted by CMakeCache.txt mtime;
_find_binary() picks freshest sdl3_app.exe; packages loaded relative to
__file__ so gui works from any working directory
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Replace held-jump-extends-height (Mario-style) with a Q3-style impulse
jump: set vel.y once on press, gravity does the rest. Apply per-player
gravity scaling symmetrically in air (rising and falling) so jumps don't
feel floaty going up but heavy coming down.
Tune q3_frame for a fun, floaty feel rather than authentic Q3 numbers:
gravity_scale 0.55 (≈55% Earth) + jump_velocity 5.5 → ~2.8m apex,
~2s airtime. Trades rocket-dodge utility for hang-time enjoyment.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
physics.fps.move was directly setting linearVelocity each frame on the
ground, producing the classic "no inertia" snap-stop feel. Replace with
a CalcFriction-style ramp: velocity accelerates toward target by
ground_accel * dt, decelerates to zero by ground_friction * dt when
input is released.
Tune the quake3 frame loop to match a modern shooter rather than vanilla
Q3 arcade speeds:
- walk 4.5 m/s (was 8.0 — ~30 km/h is a sprint, not a walk)
- sprint 1.5x (was 2.0x — 6.75 m/s top speed)
- jump 0.9m / 0.22s (was 2.0m / 0.4s — Halo-ish hop, not a moon jump)
- air control 0.15 (was 0.5 — less floaty mid-jump)
- gravity_scale 1.6 (was 0.3 — was actually pushing the player UP
when falling because of how the (gravityScale - 1.0) extra-force
multiplier worked)
Defaults for the new ground_accel (35) / ground_friction (30) params
keep other workflows that use physics.fps.move feeling snappy without
having to update them.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Quake 3 package was missing GPU shaders entirely. With these in place,
the engine boots quake3 successfully: pak0 loads, BSP parses, lightmap
atlas and geometry build, and shaders compile/bind correctly on the
Vulkan path.
bsp.vert: matches BspRenderVertex layout (position/uv/lmuv/normal) and
re-uses the existing VertexUniformData uniform block from the seed
pipeline so no C++ changes are needed.
bsp.frag: classic Q3 model — albedo × lightmap × overbright + ambient.
Skips PBR / shadow mapping entirely; Q3's baked lightmaps already encode
direct + bounce lighting and shadowing. Q3 shader-script effects
(animated sky, scrolling water, env-mapped chrome) render flat — adding
them is a follow-up.
SPIR-V only for now (Windows/Vulkan/D3D12 via SDL3 cross-compile). MSL
and DXIL still missing for Mac/native-D3D12 paths.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Workflow JSON params can now reference environment variables (e.g.
${env:QUAKE3_PAK0}) which are expanded at JSON load time. A new Python
detector reads the Windows registry and parses libraryfolders.vdf to
locate Steam libraries, then resolves known-game files into env vars
that dev_commands.py exports before launching the engine. Lets users
with legitimate Steam-owned game data run packages like quake3 without
hardcoded paths.
Also fixes os.execv on Windows (Invalid argument with spaced paths) by
falling back to subprocess.call.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Fix CW→CCW winding bug on polygon/mesh faces (types 1,3) that caused
backface culling to discard half the geometry. Decompose the monolithic
bsp.load step (1028 lines) into atomic workflow steps chainable via
JSON connections — each step only runs when connected:
- bsp.load: open pk3, read + validate BSP, store raw data in context
- bsp.lightmap_atlas: build lightmap atlas, upload to GPU
- bsp.parse_spawn: parse entity lump for spawn point
- bsp.build_geometry: build face geometry with CW→CCW winding fix
- bsp.extract_textures: load textures from pk3 with mipmaps
- bsp.upload_geometry: upload merged VB/IB to GPU
- bsp.build_collision: create Bullet physics convex hull collision
Shared BSP structs extracted to bsp_types.hpp. Workflow JSON updated
to chain: load → lightmap → geometry → textures → upload → collision → spawn.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- postfx.taa: temporal anti-aliasing with Halton jitter, neighborhood clamping,
Karis tonemap for stable history, configurable blend_factor from JSON
- Texture loader: auto-generate full mipmap chain via SDL_GenerateMipmapsForGPUTexture
- 16x anisotropic filtering on all textures
- LOD bias 0.5 to reduce moire patterns on high-frequency textures at distance
- TAA shader: 3x3 neighborhood clamp with expanded bbox to reduce flicker
- Ping-pong history buffers for temporal accumulation
- Sub-pixel jitter via Halton(2,3) sequence, 16-frame cycle
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- map.load: Assimp-based glTF/GLB scene loader with auto physics generation
- draw.map: renders all map meshes with JSON-driven texture-to-mesh mapping
- export_room_gltf.py: exports seed workflow physics bodies to GLB
- Seed demo room exported as map.glb (14 static meshes)
- Texture mapping configurable per mesh name pattern in workflow JSON
- Maps can be edited in Blender and re-exported
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Shift to sprint (1.8x speed), Ctrl to crouch (0.4x speed + lower camera)
- Smooth animated crouch via eye height lerp (no snap)
- Variable-height jump: hold space longer = jump higher, release for short hop
- Raycast ground detection for reliable jump triggering
- Air control for mid-air strafing (Quake-style)
- Configurable gravity scale for floaty/snappy feel
- All parameters driven from workflow JSON (no hardcoded values)
- Ctrl polled in input.poll step
- Camera reads crouch height override from physics.fps.move context
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- spotlight.setup: generic parameter passthrough, no hardcoded defaults
- spotlight.update: all values from spotlight.state JSON, zero fallbacks
- aim_distance now explicit in workflow JSON (was hardcoded 50.0f)
- C++ steps are pure executors, all config lives in workflow definitions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Extract spotlight logic from render.prepare into dedicated spotlight.update step
- render.prepare now only handles camera, shadow, and lighting uniforms
- spotlight.update runs per-frame after render.prepare, reads spotlight.state from context
- Aim distance configurable via JSON (aim_distance parameter)
- Camera-local offset for spotlight origin (matches viewmodel position)
- Direction computed from torch position toward camera aim point (natural beam alignment)
- Add distance fog to whole room (exponential, dark blue-grey)
- Volumetric beam: 48 steps, UE4 interleaved gradient noise, cubic cone falloff
- Fog density increased for visible beam effect
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Build system:
- Fix generate_cmake.py backslash paths and UTF-8 encoding for Windows
- Auto C++20 in conan deps, auto-detect VS install location
- dev_commands.py: add generate, all --run commands, platform-aware bootstrap
- Add assimp to cmake_config.json link libraries
- Fix CMakeUserPresets.json duplicate preset issue
Cross-platform C++:
- UUID generation: Windows rpc.h/UuidCreate with #ifdef _WIN32
- HOME env var fallback to USERPROFILE on Windows
- Shader format detection for D3D12/DXIL Vulkan driver
Shader pipeline (12 new SPIRV shaders):
- Port all Metal shaders to Vulkan GLSL (PBR, shadows, post-FX, compute)
- SDL3 GPU descriptor set convention (set 0-3)
- Combined image samplers for Vulkan compatibility
- Bootstrap-driven shader path rewriting (msl↔spirv automatic per platform)
Rendering features:
- spotlight.setup: generic atomic workflow step, attach to camera or static
- PBR spotlight with cone attenuation, distance falloff, wrap lighting
- Volumetric light beam (16-step ray march through dust/fog in spotlight cone)
- geometry.create_flashlight: procedural flashlight mesh (cylinder + head + lens)
- draw.viewmodel: FPS weapon-style rendering locked to camera view
- model.load: Assimp-based 3D model loader (OBJ/GLB/FBX/BLEND)
- Indoor ambient lighting fix, SSAO bypass for Vulkan clip-space
Performance:
- Frame loop logging suppressed via _in_frame_loop context flag
Assets:
- Real PBR textures from ambientCG (CC0): wood floor, concrete ceiling
- Seed demo: dark room + flashlight beam + Quake-style viewmodel
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove stale dirs/files superseded by metabuilder-small's reorganization:
- Old YAML entity/seed files (migrated to JSON)
- Root-level workflowui/ (moved to frontends/workflowui/)
- Prisma, Pyodide, old hooks, bun.lock artifacts
- Legacy scratch docs (txt/, docs/, deployment/*.md)
- Stale CI workflows consolidated in small
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Import SDL3CPlusPlus C++ game engine with:
- SDL3 + bgfx rendering backend
- Vulkan/Metal/DirectX shader support
- MaterialX material system
- Scene framework with ECS architecture
- Comprehensive test suite (TDD approach)
- Conan package management
- CMake build system
This provides the native C++ foundation for the Universal Platform's
Game and 3D capability modules.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>