Repository navigation
Releases
v0.91.0
Added
- Multi-segment hint authoring (🎯T179) —
makeContactClip/PhaseTiming/Player(Clip)for continuous multi-waypoint contact with independent approach/stroke/lift/exit timings; stockKinds route through the same builders - Articulating SDF pointing hand (🎯T180) — small motion is finger/wrist, large is body translate, over-reach pivots about the wrist; contact tip stays
PointerState.pos;hint.artic_*tweaks
Changed
- STABILITY snapshot for v0.91.0
Notes
- Library submodule — pin consumers to this tag;
homebrew_tap: disabled - 🎯T181 (prebuilts on GitHub Releases) is filed, not shipped in this release
- Primary modality remains direct
ge::run; control plane is spyder
v0.90.0
Added
- Hint-driven synthetic touch input (🎯T177) —
ge::hint::InputDriver(<ge/hint_input.h>): a strictly opt-in second consumer of a gesture-hint timeline that converts the same interpolated pointer states the hand renderer draws into synthetic SDL finger events (down/motion/up; pinch = two fingers), injected through the app's production event path. A demo therefore exercises real input handling — a driven tap presses an actualge::Button, a driven drag rotates an actualGlobeController— with zero game-side correlation code and no drift from the drawn gesture. Synthetic events carry a reserved touch id and finger-id range (isSyntheticFinger) so games can filter consequences;cancel()lifts held fingers cleanly; tag ordering guarantees snapshot-at-contact precedes the input applying. Presentation never implies driving. Demonstrated live in tiltbuggy (HINT=tap HINT_DRIVE=1). ge::spriteFromRgba(🎯T176) — the internal RGBA8→Sprite upload promoted to public API, with the game-thread-only contract documented in one place.
Changed
- Thread-safe text rasterisation (🎯T176) — architected from FreeType's documented contract: one shared
FT_Librarywith a mutex only around face create/destroy; lock-free glyph rendering on per-call faces; a write-once shared font-bytes cache thatFT_New_Memory_Facemaps without copying (theFontRefpath now reads each font from disk once per process instead of per call).rasterizeTextToPixelsis callable from any thread, concurrently — verified by an 8-thread byte-identical concurrency test — andrasterizeTextis a thin composition of it plusspriteFromRgba.
Notes
- 🎯T177's yourworld2 onboarding validation and the 🎯T178 scenario layer (steps, anchors, verdicts, interruption policy, per-sink opt-in coupling) are the tracked follow-ons.
v0.89.0
Changed
- Dev-plane session scoping (🎯T175) — everything session-varying in the dev plane is now per-session, completing the 🎯T174 globals-audit campaign tests-first: per-session app-channel stores (state slices, serializers, hit-target extras, time control, perf counters, game-thread task queues) with process-default registrations inherited by every session; stable session ids (
Context::sessionId()) advertised in the app-channel hello; dev RPCs address a session with an optional{"session": <id>}(sole-session default); per-session button hit-target registries (dead sessions pruned), cmdstream LiveCapture sinks (hot path unchanged via an engine-bound active cache), SensorControl accel authority, wire-fed viewer-backgrounded bit, and session-taggedmetrics::Scoperesolution. "Pause" now means one session, andframe_msmeans one session's frame time.
Notes
- Behaviour-preserving by construction: a characterization suite (🎯T175.12) locked every touched surface before surgery and stayed green throughout; 13 new isolation tests prove two sessions hold distinct state. 427/427 unit tests; render goldens unchanged.
docs/globals-audit.mdis now all-green: every accidental global is fixed, session-addressed, or has a written concurrency decision (sprite frame cursors — safe by serialisation, documented at the commit listener).- With 🎯T163's process-per-session architecture these were latent, not live, defects; this release keeps the in-process multi-world option genuinely open. 🎯T176 (FreeType thread safety) remains open.
v0.88.0
Changed
ge::debugstate is per-session (🎯T174) — the debug primitive queues, the debug-draw enable, and the perf HUD config (enable / placement / provider) are now carried by theContextrather than a process-global singleton. The host binds the active session around game callbacks andflush(ctx, …)re-binds from its Context, so a multi-session server keeps each stream's debug content and HUD strip separate. The free-function API is unchanged; direct-mode games behave identically. GPU pipelines and the monospace font remain process-global on the shared sokol device.
Notes
- Full process-globals audit in
docs/globals-audit.md: all 38 statics insrc/classified. Remaining latent multi-session items filed as 🎯T175 (app-channel registries, button hit-target registry, cmdstream LiveCapture, SensorControl, viewer-backgrounded bit, metrics addressing) and 🎯T176 (text.cppFreeType thread safety). All gate 🎯T163 true multi-session, not current behaviour. - Multi-session isolation doctests added; prebuilts recooked for all platforms + debug variants.
v0.87.0
Added
- Gesture-hint service (🎯T170) — hand-gesture hint animations as an engine service.
ge::hint::Player(<ge/hint.h>) compiles tap, double-tap, long-press, swipe, drag, pinch-zoom, and pinch-rotate into keyframed timelines over unit gesture space, with parametric trajectory (Params.from/to), display-rate-continuous motion, and event tags (contact,release,apex,hold-start,pinch-start/end) fired at exact timeline moments. Games consume the pointer states + tags with their own art (data-only tier) or callge::hint::drawHand(<ge/hint_hand.h>) — a white-fill / black-outline / sticker-halo cartoon hand re-derived every frame from the skeleton as a smooth-min capsule SDF in a fragment shader: fingers blend into the palm, fingertip squashes on contact, the pinch hand scales with fingertip spread, fwidth AA at any zoom, no textures or cooked assets. Look knobs arehint.*Tweaks. Demonstrated both ways insample/tiltbuggy(HINT=<kind>,HINT_STYLE=ring), locked by 10 new render-test goldens, unit-tested tag timing, verified on desktop Metal and the iOS simulator. - Perf HUD strip (🎯T173, engine side) — the dt/fps frame-stats box every ge game rebuilds is now
ge::debugmachinery with game-supplied segments:hudEnabled/setHudEnabled(independentGE_PERF_HUDlatch), imperative per-frame-safe placement (setHudPlacement— four corner anchors +HudAnchor::Customabsolute position),setHudProviderfor game segments appended after engine dt/fps, pure doctestedhudLabel, translucent backing box for legibility. yourworld2 adopts it in a follow-up (T173 converging).
Notes
- Prebuilt static libs recooked for all platforms + debug variants;
ge_hintshader added to the prebuild cook (kept in sync withModule.mk). - Follow-ups filed: 🎯T170.1 (device-pose track — hand-holding-phone tilt hint), 🎯T172 (verify-prebuilds blind to newly added sources).
v0.86.0
Added
- App-method advertise:
registerMethod(name, handler, exampleParams, doc)— optional discovery metadata rides in hello as mixedmethodsentries (bare string or{name, example_params?, doc?}) - Consumer handlers run on the game thread (same as state_query)
- TiltBuggy sample:
reset_posefor spyderapp_call
Docs
- agents-guide: registerMethod + spyder
app_methods/app_callloop
Note
Pair with spyder ≥ v0.74.0 for host discovery and generic invoke.
v0.85.0
🎯T169 — cmdstream image-recipe leak (critical)
Every direct-mode ge game leaked ~2.3 MB of native heap per rendered frame: rasterizeText registered a stream-only image recipe unconditionally, copying the full font file per rasterized string into a registry keyed by never-recycled sokol id generations, with no erasure. Changing HUD/clock text produced one registration per frame — 24 GB desktop RSS in ~80 s; foreground lmkd kill on 8 GB Android tablets within minutes.
Fixed
- Recipe registration is off by default (
cmdstream::setImageRecipesEnabled);LiveCapture::beginenables it for the stream/capture path. Direct mode pays nothing — the font file isn't even read. Sprite::destroynow unregisters its image, so an enabled registry mirrors live textures instead of growing per rasterization.- Font bytes are cached per path (one copy per font, no per-string disk reads).
Added
cmdstream::imageRecipesEnabled/unregisterImage/imageRecipeCount.
Known limitation (T128.2 spike scope): textures created before the first capture arm carry no recipes; the experimental SP2S replay should retro-register or fall back when it graduates.
Verification: yw2 desktop RSS flat over 30 s soaks on both render paths (was ~250 MB/s); 386/386 unit tests.
v0.84.0
🎯T168 — Cube-sphere tile pyramid
Globe-scale imagery for consumer games: one nested pack, fully-resident coarse-first loading, device-tier depth cap. Driven by yourworld2's 1 km/px Blue Marble globe.
Added
.getptile-pack format (TilePackFormat.h): per-face quadtree pyramid of compressed tiles, multiple planes per pack (imagery / country-ID / SDF), coarse→fine blob layout with a byte-prefix truncation property — a capped cook is byte-identical to a prefix of the full pack. Frozen on-disk structs; data-breaking to change.bin/ge-texpackcook (ge::cookTilePack): equirectangular master → gnomonic per-face reprojection with supersampled leaf sampling, box-filtered pyramid levels, gutters via continuous face extension, per-tile mips, parallel astcenc. JSON config; plane encodings Astc4x4, R8, and Rg8 (16-bit IDs as lo/hi bytes, for region sets that overflow u8).ge::TilePyramidloader (TilePack.h): fully-resident coarse-first loading — background reader thread, budgeted render-thread upload pump (tilepack.uploads_per_frametweak), ancestor-fallbackresolve(), capped/truncated-pack presence rule, defensive parsing, FAILED-state resource checks.ge::CubeSphere(CubeSphere.h): shared cube-sphere conventions — face basis matching sokol cubemap slice addressing, tile/patch math,tileAncestorRemap, equirect helpers. Pinned by convention-oracle tests.ge::queryDeviceTier(DeviceTier.h): Full / Capped / Legacy texture tier from physical RAM (sysctl / sysinfo) + live ASTC support, mapped to a pyramid load-depth cap. Logged and reported on the app channel.
Changed
- Apple-silicon macOS Metal now samples ASTC/ETC2/EAC (vendored sokol patch, runtime
MTLGPUFamilyApple7gate) — M-series desktops get dev parity with mobile compressed textures. sg_setupimage/view pools raised to 2048/4096 on all backends (tile fleets need more than sokol's 128 default).GeTilePlaneEncodinggainsRg8;.getex(GETX) format unchanged.
Fixed
- Cook gunzip path uses
gunzip -c(BSDzcatdemands.Zsuffixes on macOS).
Follow-ups filed: 🎯T168.4 (cook band-streaming — whole-image float loading currently peaks ~4× source bytes), 🎯T168.5 (pack size: per-tile mip redundancy, EacR11 SDF encoding).
v0.83.0
Added
- 🎯T167 compressed-texture pipeline (cook + load)
bin/ge-texenc+ Module.mk patterns:%.astc.getex/%.etc2.getex/%.png.getexfrom%.pngge::loadTexture/ge::loadCube— backend-aware encoding pick (ASTC → ETC2 → PNG getex → PNG)- Docs in AGENTS.md; path-resolution unit tests
Changed
- Recooked iOS / Android / web-wasm prebuilts to include
texture_load.cpp
v0.82.0
Changed
- SDL3 bumped to release-3.4.12; headers, vendor static libs/xcframeworks, and all platform prebuilts recooked
- SDL_image build pin aligned to 3.4.4 in
build-deps.sh - STABILITY snapshot for v0.82.0
Notes
- Library submodule — pin consumers to this tag;
homebrew_tap: disabled - Open stream WIP (#178) is not included
- Primary modality remains direct
ge::run; control plane is spyder