Conversation
Headless regression test (auto-discovered by build_all.py, runs in CI on macOS/Linux/Windows): data-path root composition with an absolute root, absolute-path passthrough, Japanese filenames and directory names, spaces/parentheses, and round-trips through every C-library boundary (stb PNG, miniaudio WAV, nlohmann JSON, pugixml XML, FileWriter/Reader). On Windows this is the gate for UTF-8 -> wide conversion regressions.
All file-path parameters take const fs::path& (string literals and std::string still convert implicitly). getDataPath/getDataPathRoot are fs::path in/out: joining uses operator/, and the absolute-root check is fs::path::is_absolute(), fixing the old path[0]=='/' test that treated C:/... roots as relative on Windows. Paths cross into C libraries through new internal helpers (tcFileIO.h: pathToUtf8/utf8ToPath/openFile) at the last moment: - stb: STBI_WINDOWS_UTF8 / STBIW_WINDOWS_UTF8 + UTF-8 bytes at all call sites (incl. platform screenshot writers) - miniaudio: ma_decoder_init_file_w on Windows - stb_vorbis: openFile() + stb_vorbis_open_file (no UTF-8 mode exists) - pugixml: wide-path overloads on Windows - Media Foundation: path.wstring(); NSString/FFmpeg/GStreamer: UTF-8 Non-ASCII paths (Japanese names, spaces, parens) now work on Windows; covered by the new core/tests/filePath in CI. BREAKING: getDataPath()/getDataPathRoot() return fs::path (on Windows, assigning to std::string no longer compiles — use auto or .string()); string concatenation on the result must become operator/.
# Conflicts: # docs/FOR_AI_ASSISTANT.md
…rces New opt-in TC_DEPRECATED_ERRORS (cache var or env, read by core CMake and trussc_app.cmake) adds -Werror=deprecated-declarations PRIVATE to the core lib, bundled examples and tests. CI sets it workflow-wide (mac/linux/web/ android); user builds never see it, and without the flag deprecated use stays a plain warning. GCC/Clang only: MSVC folds CRT 'unsafe function' warnings into the same C4996, so /we4996 would misfire. Sweep fixes so the gate starts green (verified: all 107 example builds + 4 core tests pass with the flag; a deliberate deprecated call fails with it and warns without it): - tcxTls + tcxLua exampleFileReload: tcLogX -> logX (23 call sites) - tcxBox2d example-collision: old listen(listener, cb) -> listener = listen(cb) - tcxLua: PI binding value -> HALF_TAU; generated bindings TU is exempted via pragma (the Lua API deliberately keeps deprecated compat names) — luagen.js template updated so regeneration keeps the exemption
…-window phase 0) Every piece of state that is conceptually per-window — mouse/keyboard input, hover/grab/selection and the root node, camera and view/projection tracking, swapchain/FBO pass state, scissor stack, blend mode, clipboard size, and the RenderContext / CoreEvents instances — moves from scattered process globals into one internal::WindowContext (new tc/app/tcWindowContext.h). The active*() pipeline helpers and restoreCurrentPipeline() move with the state they select on; registerCameraContext() is declared in tcCameraContext.h and defined where the context is complete. internal::currentWindowContext() resolves the active context (a plain inline pointer, null = main window); mainWindowContext() is non-inline in tcGlobal.cpp so a hot-reload guest binds the host's instance — the same sharing pattern as events()/getDefaultContext(), whose accessors now wire their singletons into the context lazily, preserving the exact pre-context construction timing. Zero behavior change and no public API change: the app is still single-window and all free functions keep their signatures, now delegating through the current context. This is the seam Phase 1 uses to instantiate additional contexts (one per native secondary window) and switch them while dispatching each window's events and draw. Verified: all 107 examples + 4 core tests + HotReloadExample build green with TC_DEPRECATED_ERRORS=1 (macOS); threadSafety/filePath suites pass; graphicsExample renders and serves get_node_tree/save_screenshot over MCP.
WindowContext gains isMain/fbWidth/fbHeight/dpiScale and an acquireSwapchain provider; ensureSwapchainPass/resumeSwapchainPass use it (main window falls back to sglue_swapchain as before). All dimension-dependent code paths that can run under a secondary window's context (getWindowWidth/getFramebufferWidth/getDpiScale, internal::setupScreenFov, EasyCam, fullscreen-shader ortho, RectNode dpi, scissor reset) now read the ACTIVE context instead of sapp directly — a secondary window on a display with a different size or scale gets its own projection and mouse coordinate space. Node befriends Window for tree dispatch. Zero behavior change for single-window apps (main context still reads sapp).
Public API: createWindow(WindowSettings) -> shared_ptr<Window> with setRoot/events/close/setTitle; macOS only for now (stub elsewhere). Native glue: one NSWindow + CAMetalLayer + CADisplayLink per window, ticking on the main run loop at that display's own rate (120/60 mixed refresh works by construction). A fully occluded window skips drawable acquisition — the standalone PoC measured the alternative: acquiring while occluded blocks ~1s and drags the whole main thread to 9 fps (the known upstream sokol_app multi-window stall). Each window has its own sokol_gl context, MSAA + depth textures, mouse/key forwarding into its WindowContext, and draws its own Node tree; GPU resources are shared zero-copy through the single sokol_gfx context. Closing a secondary window (user or close()) leaves the app running.
NSTrackingActiveAlways + acceptsMouseMovedEvents (the default tracking only delivers mouseMoved to the key window, so an unfocused control-panel window froze its pointer). mouseExited parks the cursor offscreen so the window's own hoveredNode clears on the next tick.
Mirrors the main App contract (App is a RectNode resized on SAPP_EVENTTYPE_RESIZED): a RectNode root attached to a secondary window is resized at attach and on every resize/display change; a plain Node root is left untouched (documented convention). Example shows the synced bounds; resize the second window to see them follow.
setApp(shared_ptr<App>) is the only way to give a window content: the App's familiar lifecycle runs against THAT window — setup() once on the first tree update (standard Node lifecycle), update()/draw() on the window's tick, key/mouse virtuals from the window's event stream, and handleWindowResized() on resize (RectNode size sync, same path as the main window's SAPP_EVENTTYPE_RESIZED). One App per window, double-attach and main-App reuse rejected; close() runs exit()/cleanup() then releases. App's constructor now registers itself as the scene root only when the active window has none (previously constructing ANY App clobbered the main window's rootNode — a secondary-window App hijacked the main tree). setRoot(bare Node) is deleted: one way to do it; a minimal view is a trivial App subclass. runApp<T> untouched — 'runApp = create main window + setApp' unification is a future refactor. multiWindowExample: second window is now a SubApp demonstrating setup/update/draw/keyPressed/windowResized, keeping the shared-FBO proof. Verified live: setup x1, resize sync x1, per-window key routing, close teardown with the main window surviving.
…h WindowContext Move updateDeltaTime / lastUpdateCallTime / frame-rate buffer from process globals into WindowContext. The main loop writes the main window's context; a secondary window measures its own wall-clock delta per processed tick (first tick estimated from the display link interval). Fixes the latent slow-motion bug where a secondary window on a display with a different refresh rate (e.g. 60 Hz projector next to a 120 Hz main) read the MAIN window's delta. Verified: main pinned to setFps(10) reports avg dt 0.100 while the second window on a 120 Hz display reports 0.00833. Tween/TweenMod go through getDeltaTime() and are fixed by the same move.
Design for graduating from sokol_app: standalone sokol-style C header (fork lineage, zlib) with floooh's PR #437 API shape (sapp_window handles, window field on events, _window fn variants) revived on post-2024 per-pass sg_swapchain sokol_gfx with an event-driven per-window vsync tick loop. Inventory: 27 distinct sapp_* identifiers in core, tcxImGui the only addon consumer, 10 fork patches catalogued with carry-over flags.
New core/include/sokol/sokol_app_tc.h: a sokol-style single-header C API for additional native windows (fork lineage of sokol_app.h, zlib, API shape from floooh's multi-window sketch PR #437: sapp_window handle, sapp_window_desc, window-parameterized queries). The frame model is the new part: per-window vsync ticks (one CADisplayLink per window on the main run loop) with an occlusion gate before drawable acquisition, which makes the CAMetalLayer nextDrawable stall structurally impossible — an occluded window simply stops ticking (SUSPENDED/RESUMED at transitions). The macOS implementation absorbs everything native from tcWindowMac.mm and adds what the old glue lacked: the full sokol_app keycode table (arrows/ESC/F-keys now reach secondary windows, key == SAPP_KEYCODE_* identical to the main window), CHAR events, scroll wheel, and modifier keys via flagsChanged. Implemented for macOS in sokol_impl.mm (SOKOL_APP_TC_IMPL); other platforms get explicit stubs until their ports (Windows: DXGI flip + waitable ticks, Linux: X11 + shared GL). tcWindowMac.mm shrinks to a TrussC adapter: tick -> WindowContext switch + per-window dt + tree update/draw; sapp_event -> CoreEvents/App hooks/ tree dispatch (drag vs move split now matches the main window; scroll events delivered for the first time). Verified: multiWindowExample runs (main + second window, shared FBO), SAPP_KEYCODE_LEFT=263 received in the second window, occluded-at-launch window ticks zero times for 24s then resumes on visibility; 107/107 examples build against the worktree core; core tests pass.
…ndow = window #0) The header now owns [NSApp run] and the full app lifecycle on macOS; sokol_app.h is included declarations-only (its mac implementation is no longer compiled). TrussC.h / tcHotReloadHost.h are untouched -- all ~52 sapp_* call sites resolve to the header's window-#0 shims. - quit: upstream's cancellable performClose dance + NSApp terminate on main-window close (exits even with secondary windows open) - occlusion: main window keeps upstream's model (display link + 60Hz fallback timer); secondary windows keep the tick-gate model - drawable: lazy acquisition in sapp_get_swapchain() with per-tick cache - ported per docs/dev/sapp-mac-impl-spec.md: RGB10A2 (4 sites) + framebufferOnly=false, Cmd-keyup monitor, Cmd+V paste event, cursor table, drag&drop, clipboard, fullscreen tracking - deviation: pre-run sapp_dpi_scale() returns the main screen scale (upstream returned 0 -- fixes a latent pixelPerfect div-by-zero) Verified: 85/85 examples build, 4/4 core test suites pass (68 asserts), render/resize/fullscreen/quit/minimize/hot-reload E2E on macOS.
…D3D11 driver) - win32/D3D11 section in sokol_app_tc.h: main window = window #0 on the same wndproc/tick machinery as secondary windows; sapp_* shims mirror the mac P0b strategy (sokol_app.h included declarations-only on win, TrussC.h untouched) - per-window DXGI frame latency waitable ticks replace the upstream PeekMessage busy-render-loop (and the old WM_TIMER ~64Hz cap): the message loop blocks in MsgWaitForMultipleObjectsEx, each window ticks at its own display's rate; skipped presents hold a waitable credit and are timer-re-paced (no busy-spin, no waitable starvation) - flip-discard swapchains (main RGB10A2, secondary BGRA8), waitable flag carried through every ResizeBuffers, RTV-unbind+Flush before resize, MSAA via separate render target + resolve view - scancode-indexed keytable lifted from sokol_app.h, WM_CHAR with surrogate pairs, Ctrl+V CLIPBOARD_PASTED, refcounted mouse capture, borderless fullscreen, per-monitor-v2 DPI, clipboard/dnd/cursors, skip_present honored on Present (TrussC flicker patch) - WM_ENTERSIZEMOVE arms a WM_TIMER that keeps all windows ticking through modal drags; resize coalesced per tick (never in WM_SIZE) - NEW core/platform/win/tcWindowWin.cpp: TrussC adapter mirroring tcWindowMac.mm; tcWindow.h platform gates widened to macos,windows
The multi-window branch introduced trussc::Window, which shadows the X11 Window typedef inside namespace trussc. First CI run of this base exposed the collision (linux/web/android jobs).
dumpbin /LINKERMEMBER:1 member headers (' 10A2B4 size', mode/uid/gid)
match the hex-address symbol regex once an object file reaches 1 MB (the
size field grows to 6 hex digits). sokol_impl.obj crossed that line with
the win32 sokol_app_tc section, putting a bogus 'size' export in
trussc_exports.def (LNK4022 + LNK2001).
snappy 1.2.1 builds itself with -Werror on Clang; its '#pragma clang loop' vectorization hints cannot be honored under wasm, so the newer emsdk clang fails the build with -Wpass-failed. Pre-existing on main (full=true web job reproduces it there); surfaced by this branch's full CI runs.
Child-process stdout from trusscli-built test exes gets lost on the Windows CI runners (inherited handles), leaving failing tests with no diagnostics in the log. Capture the output and re-print it through the script's own flushed stdout, plus report the raw exit code and add a 600s timeout.
loadTextFile/saveTextFile/appendToFile used text-mode streams, so on
Windows every \n was written as \r\n: getFileSize() disagreed with the
saved string length while load/save round-trips still matched (both
sides converted). Binary mode makes the on-disk bytes identical across
platforms. Caught by core/tests/filePath on its first Windows CI run
('getFileSize: Japanese name' — the body contains a \n).
…mponent-wise ops BREAKING (0.7.0): Vec2/Vec3/Vec4(float) and IVec2/IVec3(int) fill constructors are now explicit. 'v + 2' no longer compiles — vector + scalar is not a mathematical operation; it only worked through the implicit splat conversion. Write v + Vec3(2) when component-wise adding is intended. Scalar multiply/divide (v * 2, v / 2, 2 * v) are real overloads and unaffected. Dimension-promoting constructors (Vec3(Vec2, z), Vec4(Vec3, w), ...) stay implicit. This also aligns the Vec family with Color, whose gray constructor was already explicit. Consistency: Vec4 gains component-wise operator*/operator/ (+ *=, /=), matching Vec2/Vec3. Impact measured: all 107 examples build clean against this core (build_all.py --clean, macOS). The Lua side never supported the splat conversion (sol2 has no implicit ctor knowledge), so no sketch breaks. NOTE for 0.7.0 landing: regenerate reference-data + luagen(-types) bindings then (Vec4's new operators change the AST); done at merge time to avoid conflicts with ongoing generated-file churn on dev.
…+ regen API index)
…t-conv audit tool emit-sketch-reference.js emits trussc.org/generated/trusssketch-ref.js: same schema and global (TrussCAPI) as trussc-api.js so the main reference renderer is reused unchanged, but filtered to the Lua-bound surface with Lua-flavored signatures (colon methods, dot statics, number/boolean/string type names, Lua-ified defaults) and a hand-written Tasks category (spawn/wait/forever, en/ja/ko). implicit-conv-audit.js cross-references reference-data args x type constructors (explicit recovered by header grep) to list every bound arg site relying on a C++ implicit conversion Lua cannot perform.
…ality) One screenshot tool instead of two: defaults unchanged (full-res lossless PNG), width gives a downscaled monitoring thumbnail (never upscales), format 'jpg' + quality for small payloads. The tool now always uses two-stage deferral, so even full-res PNG polling no longer stutters the frame loop (hammer-tested: 120 fps flat at ~12 req/s full-res PNG; the old synchronous encode dropped to ~46). tc_get_thumbnail is removed — it never shipped (born and merged away on this branch); pixelsToJpegJson generalized to pixelsToImageJson(format).
pid lets a supervisor confirm the reply comes from ITS child (two supervisors on one port could otherwise mask a dead app); rssBytes is whole-process resident memory (mach task_info / /proc/self/statm / K32GetProcessMemoryInfo) — the number to graph for leak hunting, next to which sokol-tracked memoryBytes is a deep-dive detail.
…ow stubs The stub error message claimed secondary windows work 'on Linux', which is wrong on Raspberry Pi (GLES3/EGL Linux is single-window; only desktop GLCORE Linux has the multi-window glue) -- reworded to name the backend. Also include iOS in the stub branch (it defines __APPLE__ but has no window glue; previously an iOS app calling createWindow() was a link error instead of the graceful runtime error every other single-window platform gets). Found during the RasPi P5.5 device pass.
The graduation is complete. sokol_app_tc.h absorbed sokol_app.h's public interface verbatim (documentation, types, enums, sapp_* declarations, self-guarded by SOKOL_APP_INCLUDED so sokol_glue.h / sokol_imgui.h keep working unchanged) and is now the single, self-contained application layer on every platform: macOS / Windows / desktop Linux (multi-window), Raspberry Pi / web / iOS / Android (single-window). - every includer switched to sokol_app_tc.h; the six platform sokol_impl shims dropped their declarations-only include - core/include/sokol/sokol_app.h DELETED - TRUSSC_MODIFICATIONS.md reframed: sokol_app_tc.h is a permanent fork (upstream changes are cherry-picked, never 3-way merged); the former sokol_app.h patches are recorded as native behavior - header banner rewritten (no more 'include AFTER sokol_app.h') Verified after deletion: mac core build + 4/4 core tests + multiWindowExample runtime (second window spawns), iOS simulator build/launch/render, Android core + AllFeaturesExample link, web wasm build. Windows/Linux via CI.
tc_get_screenshot / tc_get_status_image now answer with
[{type:'image', data, mimeType}, {type:'text', text:'{width,height}'}]
instead of base64 wrapped in a JSON text block. MCP clients (Claude Code
etc.) render the screenshot inline — no more base64 walls. Scripted
consumers read the metadata from the text block. Error results are
unchanged (plain text block). Breaking for anyone parsing the old shape;
lands inside the v0.7.0 breaking window alongside the tc_* rename.
Finishes what refactor/fs-path-unify started: every public API that
carries a file or directory path now speaks fs::path, including return
values and struct fields (breaking changes approved for v0.7).
- getExecutablePath()/getExecutableDir() return fs::path. The Windows
implementations now go GetModuleFileNameW -> fs::path natively (no
UTF-8 round trip), and getExecutableDir() feeds getDataPath() as a
path end to end -- non-ASCII install paths no longer get mangled at
the root of every asset load, which was the whole point of the unify.
(Directory results no longer carry a trailing slash; use operator/.)
- FileDialogResult.filePath/.fileName are fs::path; dialog defaultPath/
defaultName parameters are fs::path. The Windows dialog impls produce
paths from the native wide strings directly.
- getPath() family (SoundPlayer, VideoPlayer, VideoWriter,
ScreenRecorder, recordingPath()) returns fs::path -- display
conversion is the caller's .string() now. systemFontPath() returns
fs::path. The remaining std::string recorder overloads (fixed-duration
and Fbo variants) take fs::path.
- Serial device identifiers ("COM3", "/dev/ttyUSB0") and MCP JSON wire
strings deliberately stay std::string (not filesystem paths).
tcxLua: path adapter gains sol::is_container<path> = false and
sol::lua_type_of<path> = type::string -- without these, binding a
usertype FIELD of type fs::path (FileDialogResult.filePath) makes sol2
treat the path as a container / by-reference userdata and the generated
TU fails to compile. Bindings + types regenerated; bindcheck passes
(424 functions present, 0 missing; 153/153 usertypes; 31/31 call
checks). Reference + FOR_AI index regenerated (check.js --strict green).
Verified: mac core + 4/4 core tests + dialog/video examples, iOS sim,
Android core, web build all green.
Image/Pixels/SoundBuffer/Sound/SoundStream/VideoPlayer (and tcxHap's HapPlayer)/Font load APIs now return trussc::LoadResult instead of bool: a LoadError kind (None/FileNotFound/UnsupportedFormat/DecodeFailed/ Unknown) plus a human-readable message. explicit operator bool() keeps 'if (x.load(...))' working unchanged; 'bool ok = x.load(...)' needs .ok() now (the breaking part, hence the v0.7 window). Error filling is deliberately coarse for now and grows without breaking: fs::exists pre-checks classify FileNotFound uniformly (decoder error codes rarely distinguish missing-vs-corrupt), stb_image contributes stbi_failure_reason(), and native codes (OSStatus / HRESULT / ma_result / stb_vorbis error) ride along in the message. Internal helpers (loadPlatform, loadPosterFrame, decode*WithMiniaudio) stay bool. Shader has no path-based load in core -- nothing to convert (roadmap note updated; the remaining taxonomy enrichment is tracked there as non-breaking follow-up). Reference prose added (check.js --strict green); Lua bindings regenerated -- LoadResult/LoadError are Lua-visible usertypes now; bindcheck green (425 fns / 155 usertypes / 0 missing / 0 call failures). Verified: mac core + 4/4 core tests, iOS sim, Android, web builds all green.
# Conflicts: # core/include/tc/video/tcVideoRecorder.h
rpcndr.h (pulled in by windows.h for the RSS helper) defines small=char, which mangled the downscale buffer's name. Rename to 'scaled' and add NOMINMAX next to WIN32_LEAN_AND_MEAN while here. Also fix a stale tc_get_thumbnail mention in the tc_get_status_image description.
…nshots Multi-window Phase 4 (1/3). Adds a core open-window registry (creation order, non-inline storage in tcGlobal.cpp for hot-reload host/guest unity, RAII member so every ~Window() unregisters regardless of which platform adapter defines it) and Window::getTitle(). MCP gains list_windows (index 0 = main, then open secondaries with title/size) and an optional 'window' index on get_screenshot / save_screenshot: the afterFrame drain switches currentWindowCtx to the target so captureWindow reads that window's last presented drawable -- the per-window capture state existed since Phase 1, only the tool layer was hardwired to main. Verified live on macOS: multiWindowExample + MCP HTTP -- list_windows reports both windows, save_screenshot window=1 captures the secondary (480x320 @ dpi2, distinct content), window omitted captures main.
The single trussctype_generated.cpp instantiated ~100 sol2 usertypes in one TU: 7.86 GB peak compiler RSS / 92 s (clang, measured) — impossible to build on an 8 GB Raspberry Pi 5 even at -j1. luagen-types now takes --shards N --outdir DIR and greedy-bin-packs the usertype/enum blocks into N shard TUs plus an aggregator (constants + colors + the setGeneratedTypeBindings entry point calling each shard). One shard peaks at 1.27 GB / 8.4 s — a 6x memory drop, RPi-friendly. Legacy single-file stdout output remains the default (no flags). regen_expected.sh scans trussctype_generated*.cpp so bindcheck tracks the sharded layout: 423 fns / 152 usertypes / 31 call checks green.
# Conflicts: # addons/tcxLua/src/generated/trussctype_generated.cpp
Sharding is now the only output mode (constant SHARDS=16, outdir fixed to src/generated). Removes the legacy stdout mode and with it the footgun where the old '> trussctype_generated.cpp' redirect would overwrite the aggregator while shard files remained (duplicate registrations). To change the shard count, edit the constant and regenerate.
A static instance's destructor (e.g. a CLI tool that never called start()) used to announce 'TCP server stopped' at exit for a server that never existed. Cleanup stays unconditional and idempotent; only the log line is gated.
Multi-window Phase 4 (2/3). Dear ImGui now works in secondary windows: each window's App calls imguiSetup()/imguiBegin()/imguiEnd() as usual and gets its own fully independent ImGui (panels, input capture, rendering), driven by that window's events and sized by that window's framebuffer. sokol_imgui.h fork grows a multi-context API (simgui_tc_make_context / set_context / get_context / destroy_context): the global _simgui becomes a reference to the active instance (#define _simgui (*_simgui_cur)), so the whole vendored implementation compiles unchanged while every instance owns its ImGui context, font atlas, buffers and pipeline. Two root causes fixed on the way, found by driving the example through MCP + an ASan/validation build: 1. Secondary windows' swapchains are BGRA8/RGBA8 (only the main window is RGB10A2), but the imgui pipeline was created against the environment defaults -- silently corrupting rendering in release (channel-swizzled 'classic-looking' colors, delayed crashes) and failing sg validation in debug. WindowContext now carries swapchainColorFormat/-SampleCount (set by the platform adapters) and the per-window imgui instance is created against them. 2. Since Dear ImGui 1.90, CreateContext() RESTORES the previously current context before returning -- the second instance captured the FIRST window's context, every panel landed in one context and the invisible foreign panel stole hover (widgets unclickable). The fork now captures CreateContext()'s return value and makes it current explicitly. Window::close() now fires the window's own exit event so per-window resource holders (the imgui manager) tear down while the window's CoreEvents is still alive. New example: windowing/imguiWindowsExample (a panel in each window, open/close toggle, AI-drivable via registerDebuggerTools). Verified by hand on macOS: hover, sliders, checkbox, repeated open/close cycles in both windows; single-window colorExample regression + 4/4 core tests green; ASan + sg-validation build clean through close/reopen cycles. Known limitation (follow-up): the MCP imgui widget snapshot registry is still one global -- imgui_get_widgets/imgui_click see one window's widgets per frame.
Multi-window Phase 4 (3/3). EasyCam and the whole input layer were already context-routed (everything resolves through currentWindowContext()); what was missing is the CONTRACT: the enableMouseInput() listeners bind to whichever window's event stream is current at call time, so the camera must be enabled from within the lifecycle of the App that drives its window. Documented at enableMouseInput(), demonstrated end-to-end by the new windowing/easyCamWindowExample (an independent orbit camera per window).
…t-wise ops Regenerated from the merged tree (dev's 16-shard layout + this branch's tcMath.h changes). Vec4 gains vec*vec and vec/vec overloads in Lua. bindcheck: 425 functions / 155 usertypes / 31 call checks, all green. sweep_examples: 11/11 build + run.
…ors + Vec4 component-wise ops)
…en sharding) Conflict resolutions: - tcStandardTools.h: the window-targeting arg is woven into dev's new tc_get_screenshot (format/width/quality + two-stage deferral -- the context switch wraps only the readback stage); list_windows renamed tc_list_windows to match the new tool naming convention - AI_AUTOMATION.md: merged tool table (tc_* names + window args) - Lua bindings regenerated with the NEW 16-shard luagen-types tooling
One line in app code queues a message for the supervisor; anchorbolt drains tc_get_alerts on its health cadence and forwards each entry to its notification sinks (Slack etc.). Also logged at WARNING level so it survives locally with no supervisor attached. Thread-safe (sensor callbacks, async timers); bounded queue (100, oldest dropped). Named alert, not notify — for human-relevant events, not a message bus.
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.
Multi-window support
TrussC apps can now open multiple native windows — each with its own App,
its own input, its own ImGui, ticking at its own display's refresh rate:
camera, delta time, ImGui context.
getMouseX(),getDeltaTime(),imguiBegin()etc. just work inside each window's App — no new APIs tolearn beyond
createWindow()/Window::setApp().freely across windows (e.g. render once into an Fbo, show it in both).
skips rendering without stalling the others.
tc_list_windowslists open windows, andtc_get_screenshot/tc_save_screenshottake awindowindex — agentscan see every window, not just the main one.
(web / iOS / Android / Raspberry Pi)
createWindow()fails gracefullywith a log message.
windowing/multiWindowExample,windowing/imguiWindowsExample,windowing/easyCamWindowExample.Under the hood, upstream
sokol_app.hhas been retired in favor ofsokol_app_tc.h, a self-contained fork implementing the samesapp_*API(plus the window API) on all platforms — verified on real hardware:
mac, Windows 11, Linux, Chrome (WebGPU/WebGL2), iPhone, Pixel, Raspberry Pi 5.
Breaking changes
fs::pathend-to-end. Every path-carrying API now takes andreturns
fs::path. Passing strings keeps compiling (implicitconversion); code that assigns results to
std::stringneeds.string():getExecutablePath()/getExecutableDir()(the latter no longer has atrailing slash — join with
/)FileDialogResult.filePath/.fileNamegetPath()family (SoundPlayer, VideoPlayer, VideoWriter,ScreenRecorder,
recordingPath()),systemFontPath()paths now survive from the OS all the way through
getDataPath().LoadResult. Load APIs (Image,Pixels,SoundBuffer,Sound,SoundStream,VideoPlayer,Font, tcxHap) returntrussc::LoadResult— aLoadErrorkind plus a human-readable message —instead of
bool.if (img.load(...))works unchanged(
explicit operator bool);bool ok = img.load(...)becomesimg.load(...).ok(). Error taxonomy will grow without further breakage.tc_*/tcx_imgui_*(tc_get_screenshot,tc_save_screenshot,tc_quit, ...). MCP clients must switch to the newnames.
VecNsplat constructors (Vec3 v(1.0f)needs to beintentional) + Vec4 component-wise operators.
Also in this line
drops from ~8 GB (unbuildable on a Raspberry Pi 5) to ~1.3 GB per TU
metal_simshader variant) — iOS apps now run inthe simulator, so they are AI-verifiable via
simctltc_get_screenshotgainedformat/width/quality(JPEG thumbnails,encoding on the HTTP worker — polling doesn't stutter the app);
kiosk groundwork:
tc_get_health,tc_get_status(_image),TRUSSC_LOG_FILE-sGROWABLE_ARRAYBUFFERS=0)Verification
iOS compile, 108-example sweep, core tests, HotReload, reference check)
docs/dev/sokol_app_tc-design.md(per-platform behavioral contracts in
docs/dev/sapp-*-impl-spec.md)🤖 Generated with Claude Code