From 24dec6af59741662edecf8ba64be6b94fecc7f3e Mon Sep 17 00:00:00 2001 From: Daniel McCoy Stephenson Date: Thu, 29 Oct 2026 08:19:47 -0600 Subject: [PATCH] Move Strata to v0.7.0 (web kit 1.1 loader) strata.ref and the vendored loading shell move from v0.6.0 (c2d7ee4) and the kit 1.0 loader (901e6c9) to the v0.7.0 tag (20827c3). The engine and C ABI are unchanged (ABI 1.12, same pixels); the loader gains StrataLoader.progress()/show() and an idempotent slow(), and its reduced-motion and data-saver notices are reworded. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LYNeuo5Ry76i84tz6WXQSE --- README.md | 2 +- docs/STRATA.md | 2 +- strata/CMakeLists.txt | 2 +- strata/strata.ref | 2 +- strata/web/strata-kit/PIN | 2 +- strata/web/strata-kit/SHA256SUMS | 2 +- strata/web/strata-kit/strata-loader.js | 82 ++++++++++++++++++++++---- 7 files changed, 75 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 8336b7b..a67a7ad 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ This C++ library provides base classes for creating 2D virtual worlds. *A larger demo world (`--world meadow`): sheep graze and wander, wolves stalk the nearest sheep, flowers stay put. The grass under each location is the demo's own state, shown as the floor colour.* -The frontend reads an `Environment` and draws it with the [Strata](https://github.com/Preponderous-Software/strata) engine (v0.6.0). It never changes the world: CI runs each demo with and without drawing and compares the results. A consumer writes one callback that turns an `Entity` into a shape, colour and size; everything else (floor, camera, tweening, picking a location with the mouse, a HUD) is provided. It is opt-in and built separately with CMake, so the library above still needs nothing but a C++ compiler. See [docs/STRATA.md](docs/STRATA.md). +The frontend reads an `Environment` and draws it with the [Strata](https://github.com/Preponderous-Software/strata) engine (v0.7.0). It never changes the world: CI runs each demo with and without drawing and compares the results. A consumer writes one callback that turns an `Entity` into a shape, colour and size; everything else (floor, camera, tweening, picking a location with the mouse, a HUD) is provided. It is opt-in and built separately with CMake, so the library above still needs nothing but a C++ compiler. See [docs/STRATA.md](docs/STRATA.md). ``` cmake -S strata -B build-strata -DCMAKE_BUILD_TYPE=Release diff --git a/docs/STRATA.md b/docs/STRATA.md index 1ca4543..ea7e933 100644 --- a/docs/STRATA.md +++ b/docs/STRATA.md @@ -14,7 +14,7 @@ Nothing in the library depends on it. `make`, `run_tests.sh` and the top-level CMake 3.24 or newer (Strata's minimum), a C++17 compiler, and the SDL3 build dependencies Strata needs on Linux (X11 development headers, EGL). Strata is -fetched at the commit in `strata/strata.ref`, which is the `v0.6.0` release. +fetched at the commit in `strata/strata.ref`, which is the `v0.7.0` release. ``` cmake -S strata -B build-strata -DCMAKE_BUILD_TYPE=Release diff --git a/strata/CMakeLists.txt b/strata/CMakeLists.txt index da99d93..6dfa760 100644 --- a/strata/CMakeLists.txt +++ b/strata/CMakeLists.txt @@ -7,7 +7,7 @@ # cmake --build build-strata -j4 # ctest --test-dir build-strata --output-on-failure # -# Strata is fetched at the commit in strata.ref (the v0.6.0 release), or taken +# Strata is fetched at the commit in strata.ref (the v0.7.0 release), or taken # from a local checkout with -DFETCHCONTENT_SOURCE_DIR_STRATA=. # See docs/STRATA.md. # diff --git a/strata/strata.ref b/strata/strata.ref index 5f3d703..0e9c8c8 100644 --- a/strata/strata.ref +++ b/strata/strata.ref @@ -1 +1 @@ -c2d7ee4c1102726c654c90d8361383d9ba3590b3 +20827c3d67e71c1f942c29e7cf8adfa4801188a8 diff --git a/strata/web/strata-kit/PIN b/strata/web/strata-kit/PIN index 28beecb..0e9c8c8 100644 --- a/strata/web/strata-kit/PIN +++ b/strata/web/strata-kit/PIN @@ -1 +1 @@ -901e6c97bc70c86c0e7dfbf857bb87ec405e0164 +20827c3d67e71c1f942c29e7cf8adfa4801188a8 diff --git a/strata/web/strata-kit/SHA256SUMS b/strata/web/strata-kit/SHA256SUMS index a5be9e6..2e484d6 100644 --- a/strata/web/strata-kit/SHA256SUMS +++ b/strata/web/strata-kit/SHA256SUMS @@ -1,2 +1,2 @@ -7da2a43f932f63e5ae86273a7675b55180dbde4d61dc6e0c5fcd048026879946 strata-loader.js +fa03e8ed92759359359f29f40668c947e63b0c9f3eabafcce2f911110637f5c3 strata-loader.js 8e3fc647b4775773eabc147e564ffbddd0653b252eff96c5432213ee362798df LICENSE diff --git a/strata/web/strata-kit/strata-loader.js b/strata/web/strata-kit/strata-loader.js index f7d1d46..3ac65ee 100644 --- a/strata/web/strata-kit/strata-loader.js +++ b/strata/web/strata-kit/strata-loader.js @@ -17,6 +17,21 @@ // ... create the scene with StrataKit.create({module: mod, ...}), then: StrataLoader.done(); + A host whose own loader already knows how far it has got (a .NET or + Unity-style boot that fetches its own files) shows the same overlay and + drives its bar itself: + + if (StrataLoader.show({title: "the game", poster: "/poster.jpg"})) { + StrataLoader.progress(0.4, "Loading assemblies"); // 0..1, label optional + // ... boot; then: + StrataLoader.done(); + } + + show() takes load()'s display options (title, poster, trailer, fallback, + mount) and returns false, with the fallback showing, when WebGL 2 is + missing. progress(fraction, label) clamps the fraction to 0..1 and never + moves the bar back; the label (or the percentage) replaces the size line. + What it shows, in an overlay it adds to the page (class sk-loader): - the poster (if any) as a blurred backdrop, and the title; @@ -73,7 +88,7 @@ @media (prefers-reduced-motion: reduce){.sk-loader,.sk-loader .sk-fill{transition:none} .sk-loader .sk-bar.sk-indeterminate .sk-fill{animation:none;width:100%;opacity:.5}}`; - let root = null, opts = {}, state = "idle"; + let root = null, opts = {}, state = "idle", shown = 0; function el(tag, cls, text) { const e = document.createElement(tag); @@ -115,12 +130,14 @@ return root; } - function progress(got, total) { + // Sets the bar to `fraction` (0..1), or to indeterminate when it is null, + // and the line under it to `text`. Both progress paths draw through here. + function setBar(fraction, text) { if (!root) return; const bar = root.querySelector(".sk-bar"), fill = root.querySelector(".sk-fill"); if (!bar) return; - if (total) { - const pct = Math.min(100, Math.round(got / total * 100)); + if (fraction != null) { + const pct = Math.min(100, Math.round(fraction * 100)); bar.classList.remove("sk-indeterminate"); fill.style.width = pct + "%"; bar.setAttribute("aria-valuenow", String(pct)); @@ -128,7 +145,42 @@ bar.classList.add("sk-indeterminate"); bar.removeAttribute("aria-valuenow"); } - root.querySelector(".sk-size").textContent = sizeText(got, total); + root.querySelector(".sk-size").textContent = text; + } + + // load()'s byte progress: `got` of `total` bytes (total 0 when unknown). + function byteProgress(got, total) { + setBar(total ? got / total : null, sizeText(got, total)); + } + + // A host's own progress: `fraction` of the way (clamped to 0..1, and never + // lower than the last call's), with an optional label for the line under + // the bar (else the percentage). Mounts the overlay if show() or load() has + // not; does nothing once the shell is done or showing the fallback. + function progress(fraction, label) { + if (state === "done" || state === "fallback") return; + const f = Number(fraction); + if (Number.isNaN(f)) return; + shown = Math.max(shown, Math.min(1, Math.max(0, f))); + if (state === "idle") state = "loading"; + mount(); + setBar(shown, label != null && label !== "" ? String(label) : `${Math.round(shown * 100)}%`); + const bar = root.querySelector(".sk-bar"); + if (bar) { + if (label) bar.setAttribute("aria-valuetext", String(label)); + else bar.removeAttribute("aria-valuetext"); + } + } + + // The overlay without load()'s fetch, for a host that boots its own way. + // Returns false (the fallback showing) when WebGL 2 is missing. + function show(o) { + opts = Object.assign({}, o); + state = "loading"; + shown = 0; + mount(); + if (!hasWebGL2()) { fallback("no-webgl2"); return false; } + return true; } function hasWebGL2() { @@ -219,25 +271,25 @@ let total = (!enc || enc === "identity") && header > 0 ? header : (statedBytes || 0); if (!res.body || !res.body.getReader) { const buf = await res.arrayBuffer(); - progress(buf.byteLength, buf.byteLength); + byteProgress(buf.byteLength, buf.byteLength); return buf; } const reader = res.body.getReader(); const chunks = []; let got = 0; - progress(0, total); + byteProgress(0, total); for (;;) { const {done, value} = await reader.read(); if (done) break; chunks.push(value); got += value.byteLength; if (total && got > total) total = 0; // the stated size was wrong: say bytes only - progress(got, total); + byteProgress(got, total); } const out = new Uint8Array(got); let o = 0; for (const c of chunks) { out.set(c, o); o += c.byteLength; } - progress(got, got); + byteProgress(got, got); return out.buffer; } @@ -247,8 +299,9 @@ const keep = [...box.childNodes]; box.textContent = ""; const msg = reason === "save-data" ? "Data saver is on." - : reason === "low-memory" ? "This device has little memory." : "Motion is reduced on this device."; - box.appendChild(el("p", "sk-msg", `${msg} The live view downloads ${opts.bytes ? mb(opts.bytes) + " MB" : "its engine"} and animates.`)); + : reason === "low-memory" ? "This device has little memory." : "This device asks for reduced motion."; + const size = opts.bytes ? `a ${mb(opts.bytes)} MB download` : "a download"; + box.appendChild(el("p", "sk-msg", `${msg} The live view is ${size} and is animated.`)); const go = el("button", "", "Start the live view"); go.type = "button"; go.addEventListener("click", () => { box.textContent = ""; keep.forEach((n) => box.appendChild(n)); resolve(); }); @@ -267,6 +320,7 @@ async function load(o) { opts = Object.assign({}, o); state = "loading"; + shown = 0; mount(); if (!hasWebGL2()) { fallback("no-webgl2"); @@ -311,9 +365,11 @@ } // The kit could not go any lower and frames are still slow: offer the clip - // (or the fallback link) without taking the live view away. + // (or the fallback link) without taking the live view away. Once: a second + // call while the bar is up does nothing. function slow() { if (state === "fallback" || (!opts.trailer && !(opts.fallback && opts.fallback.href))) return; + if (document.querySelector(".sk-slow")) return; const bar = el("div", "sk-slow"); bar.setAttribute("role", "status"); bar.style.cssText = "position:fixed;left:50%;transform:translateX(-50%);bottom:max(12px,env(safe-area-inset-bottom));" + @@ -337,5 +393,5 @@ document.body.appendChild(bar); } - window.StrataLoader = {load, done, fallback, slow, hasWebGL2, get state() { return state; }}; + window.StrataLoader = {load, show, progress, done, fallback, slow, hasWebGL2, get state() { return state; }}; })();