Update portal port from 80 to 8900 across deployment files. Adjust the CLI status message in deployment/cli/stack.py to print http://localhost:8900, update access URLs in deployment/metabuilder/compose.yml comments to include :8900, and change the nginx service port mapping from "80:80" to "8900:80" so the gateway is exposed on a non-privileged localhost port.
- 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.
Add scripts/push-images-to-desktop.sh: a Bash utility (set -euo pipefail) to transfer local Docker images to a remote via Tailscale SSH. The script groups images by image ID so shared layers are only sent once, queries the remote for existing image IDs to skip duplicates, and streams docker save | tailscale ssh <remote> "docker load". It emits progress, tracks transferred/skipped counts, and writes a timestamped log to /tmp/docker-push-<timestamp>.log. Remote target and log path are configurable via REMOTE and LOG variables.
- 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>
When Conan's build output layout changes (e.g. build/generators/ vs
build/Release/generators/), CMakeUserPresets.json accumulates includes
that define the same preset names, causing CMake to fail with
"Duplicate preset". The fix detects preset name collisions across
included files and keeps only the newest, in addition to pruning
missing files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add explicit search paths for python.org installer (%APPDATA%\Python),
Chocolatey, macOS system Python (~/Library/Python), and ~/.local/bin.
Document coverage matrix for Windows (Store/python.org/Chocolatey),
macOS (Homebrew/system/pyenv), and Linux (apt/dnf/pip --user).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Searches PATH, interpreter/user Scripts dirs, site-packages sibling
dirs, and falls back to module invocation. Covers system Python,
Homebrew, Windows Store Python, pyenv, conda, pip --user, and venvs.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Windows Store Python installs packages without adding Scripts to PATH,
causing FileNotFoundError when invoking conan directly.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After moving compose.yml into metabuilder/ subfolder, all .././ context
paths were one level short — updated to ../../ to correctly resolve from
deployment/metabuilder/ to the project root siblings (dbal, frontends,
services).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- actions/checkout@v6 → @v4 (v6 does not exist) in both workflows
- actions/cache@v6 → @v4 and actions/upload-artifact@v6 → @v4 in dbal-tests.yml
- gate-2-complete: add if:always() guard so skip_tests=true no longer
kills Gate 3/4/5/6 by leaving gate-2-complete in skipped state
- deployment: move nexus-init.py and artifactory-init.py into metabuilder/
subfolder; update compose.yml volume paths from ../ to ./
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Gives the stack a clean name in Portainer ("metabuilder") instead of
the directory name. Updated all relative paths inside compose.yml and
COMPOSE_FILE references in CLI helpers.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Merge docker-compose.nexus.yml into compose.yml as --profile registry
- Drop docker-compose.smoke.yml, docker-compose.test.yml (deprecated), and docker-compose.stack.yml
- Rename to compose.yml (Docker Compose default; no -f flag needed)
- build apps / deploy now derive buildable services from compose.yml directly instead of hardcoded all_apps/service_map in commands.json — covers all 29 buildable services automatically
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
run = run_cmd alias at module level shadowed the imported subprocess
helper, causing recursive calls and TypeError on input kwarg.
Renamed import to run_proc to match the pattern used in deploy.py.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
package-lock.json is gitignored (**/package-lock.json) so it never
exists in the build context. npm install on line 41 handles deps fine.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Three QML syntax errors introduced by the a11y agents:
- CommentsDBAL.js:25 — string literal split across lines by line-wrapper
- LuaEditor.qml:50 — semicolon between sibling QML elements (invalid)
- SMTPConfigEditor.qml:48 — same semicolon issue
generate_cmake.py: list .hpp files in qt_add_executable so AUTOMOC
scans them for Q_OBJECT — required for header-only Qt classes to link
(signals/vtable are generated by moc, not the compiler).
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
generate_cmake.py now includes *.hpp alongside *.h when building
the header list. CMakeLists.txt regenerated — src/ now has 2 .cpp
sources (DBALClient, PackageLoader) after ModPlayer, NodeRegistry,
and PackageRegistry were converted to header-only .hpp files.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Move ModPlayer, NodeRegistry, PackageRegistry from .cpp/.h pairs to
single .hpp files. Add DBALRequest.hpp and DBALTypes.hpp. Update
DBALClient and main.cpp for new structure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Selected email card: add secondary-container bg + left accent border
- Unread email cards: add primary left border accent
- StarButton: sync local state with parent via useEffect([isStarred])
- Initial dark mode: useEffect applies data-theme on mount
- Star active color: amber #f9a825 via .star-button--active CSS rule
- Unread count badge: styled as pill with primary-container background
- Empty state: add inbox/folder_open material icon
- Folder toolbar label: capitalize + replace underscores with spaces
- ComposeWindow: CC/BCC hidden by default, revealed via Cc/Bcc button
- Email header: flex layout for .header-top, column gap for .header-details
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Extract ctx alias for rootContext() calls and wrap long string
literals to stay within the 80-character line margin.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Second-pass a11y work across all 12 component groups. Every interactive
element now has activeFocusOnTab, Keys.onReturnPressed/SpacePressed, and
context-aware Accessible.name/description bindings.
Highlights:
- Dialogs: keyboard handlers with enabled-guard on confirm buttons
- CDropdownMenu: full keyboard nav (Up/Down/Enter/Escape)
- CLoginForm: explicit KeyNavigation.tab chain (username→password→submit)
- CNotificationBell: dynamic "3 notifications"/"No notifications" name
- CJobProgressBar: Accessible.minimumValue/maximumValue/currentValue
- CExecutionStatusDot: "Execution status: Running/Passed/Failed" binding
- CKeyboardShortcuts: invisible Repeater exposes all shortcuts to a11y tree
- CDataTable rows: "Row N of M" descriptions
- Canvas elements: Accessible.Canvas role + keyboard zoom (+/- keys)
- DropdownExpandedList: focus-highlight extended to :activeFocus
- Dynamic names reflect loading state (e.g. "Signing in, please wait")
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Continues the a11y pass from the previous commit — adds objectName,
Accessible.role, Accessible.name to all remaining qml/MetaBuilder/,
qml/qt6/, and qml/widgets/ files. Widget files also get activeFocusOnTab
on interactive elements and dynamic Accessible.name bindings.
Cleans up redundant addImportPath(projectRoot) call in main.cpp.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Folders and emails constants extracted to folders.json and emails.json.
The TS loader hydrates relative hoursAgo into absolute timestamps.
Follows the 95% JSON / 5% code principle.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
SMTPConfigEditor: split property declarations + handler bodies
DatabaseManager: break long strings + property chains
FrontPage: split Layout properties onto separate lines
CCard: trim section comment rulers
Result: 0 lines over 80 chars across all qml/**/*.qml and qml/**/*.js
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace all emoji with Material Symbols Outlined (self-hosted woff2)
- Softer dark mode palette (blue-purple surface tones instead of near-black)
- Header: burger menu, notifications bell with badge, theme switcher,
language selector, settings, avatar
- Folder nav icons render via Material Symbols font ligatures
- Fix Dockerfile to copy public/ dir for font serving
- Improved padding and spacing throughout
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
88 files reformatted — zero logic changes:
- All views, components, and JS modules wrapped to 80-char margin
- Long property bindings, ternaries, and strings broken at natural points
- Theme.qml theme definitions expanded to multi-line
- StyleVariables tokens wrapped
- Section comment rulers trimmed to 80 chars
Trade-off: LOC increases from line wrapping (compact single-line properties
now span 2-3 lines). Content unchanged.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
No symlinks, no QmlComponents directory. main.cpp adds qml/
as import path — Qt finds QmlComponents module via qml/qmldir
and MetaBuilder via qml/MetaBuilder/qmldir.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
WorkflowEditor (325→80): CWorkflowState.qml + WorkflowConnectionState.js
DashboardView (121→95): DashboardDBAL.js + config/dashboard-config.json
Storybook (114→78): StorybookSidebar + config/storybook-components.json
+ 7 components compacted to under 100 via formatting (no logic changes)
+ Multiple view/component splits across all remaining 100+ LOC files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Moves inline JSX from EmailClientContent into proper FakeMUI email
components in components/fakemui/email/layout/. All styling uses M3
CSS custom properties (--mat-sys-*) from the FakeMUI token system.
New components:
- MailboxHeader: top bar with search, avatar, settings
- MailboxSidebar: compose button + folder navigation
- EmailDetail: reading pane with toolbar, header, body, reply bar
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Register all new components in qml/MetaBuilder/qmldir
- Fix backgroundColor → bgColor in 18 PackageView files
- Fix SMTP signal handlers: onHostChanged → onHostEdited (matching actual signals)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>