@rydr/game-sdk 8.16.0 → 8.17.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,5 +9,5 @@
9
9
  export declare const RYDR_PROTOCOL_VERSION: 32;
10
10
  /** Semver of this SDK build. Sent in the handshake for telemetry/debugging.
11
11
  * (Bumped to 2.0.0 by `npm version major` on release — see CHANGELOG [Unreleased].) */
12
- export declare const RYDR_SDK_VERSION = "8.16.0";
12
+ export declare const RYDR_SDK_VERSION = "8.17.0";
13
13
  //# sourceMappingURL=version.d.ts.map
@@ -217,5 +217,5 @@
217
217
  export const RYDR_PROTOCOL_VERSION = 32;
218
218
  /** Semver of this SDK build. Sent in the handshake for telemetry/debugging.
219
219
  * (Bumped to 2.0.0 by `npm version major` on release — see CHANGELOG [Unreleased].) */
220
- export const RYDR_SDK_VERSION = "8.16.0";
220
+ export const RYDR_SDK_VERSION = "8.17.0";
221
221
  //# sourceMappingURL=version.js.map
@@ -22,6 +22,8 @@ import { loadWorld, mergeByMaterial, PerfOverlay, ScreenAnchor } from "@rydr/gam
22
22
  | `createGlbLoader` | fn | A configured GLB→`Object3D` loader (DRACO, caching) when you load assets yourself. |
23
23
  | `applyPlacement` | fn | Apply a `WorldPlacement` (position/rotation/scale) to a group. |
24
24
  | `clearWorldCache` | fn | Drop cached loaded worlds (by id, or all). |
25
+ | `createGlbCache` | fn | The **persistent** GLB byte store (Cache Storage) that survives the shell destroying the game's iframe. On by default inside `loadWorld`/`createGlbLoader`; call it directly to show or clear the store. |
26
+ | `requestPersistentStorage` | fn | Ask the browser to exempt this origin's storage from eviction. For the **shell** to call, not a guest game. |
25
27
  | `mergeByMaterial` | fn | Merge a subtree's meshes by shared material → far fewer draw calls. |
26
28
  | `ScreenAnchor` | class | Hover a DOM UI element a fixed height above the **top** of a 3D object, projected to screen px. |
27
29
  | `WaypointBeacon` | class | A "go here" glow beacon (column + base + expanding ground waves) that gracefully fades out when reached. |
@@ -35,6 +37,51 @@ import { loadWorld, mergeByMaterial, PerfOverlay, ScreenAnchor } from "@rydr/gam
35
37
 
36
38
  ---
37
39
 
40
+ ## Worlds are cached across the iframe being destroyed
41
+
42
+ `loadWorld` already keeps a world in memory (GPU resources by `CoreWorld.id`, decoded GLBs by URL
43
+ path), but the shell **destroys the game's iframe** when the rider leaves — and every in-memory cache
44
+ goes with it. Under those two sits a third: the raw GLB bytes in Cache Storage, which survives the
45
+ document. A rider who comes back re-decodes the map instead of re-downloading it.
46
+
47
+ It is **on by default** and there is nothing to wire up:
48
+
49
+ ```ts
50
+ const world = await loadWorld(coreWorld, { mergeStatics: true });
51
+ // first ever visit: downloads the map (a base map is 3-73 MB today)
52
+ // after the iframe is killed: same call, no download
53
+ ```
54
+
55
+ Measured on a real platform world (73 MB base map, HTTP cache disabled so only Cache Storage can
56
+ serve it): **2889 ms → 41 ms, 0 bytes over the wire** in a fresh document.
57
+
58
+ The store is keyed by the asset URL's **path**, which is safe because a world upload mints a fresh
59
+ uuid per object key (`worlds/<kind>/<uuid>-<file>.glb`) — re-uploading a map produces a new path,
60
+ never new bytes at an old one. It holds 512 MB by default and evicts **least-recently-used** past
61
+ that.
62
+
63
+ ```ts
64
+ import { createGlbCache, requestPersistentStorage } from "@rydr/game-sdk/three";
65
+
66
+ await loadWorld(coreWorld, { cache: { maxBytes: 256 * 1024 * 1024 } }); // smaller budget
67
+ await loadWorld(coreWorld, { cache: false }); // off (a cold-load bench)
68
+
69
+ const store = createGlbCache();
70
+ await store.stats(); // { entries, bytes } — for a dev panel
71
+ await store.clear(); // drop the lot
72
+ ```
73
+
74
+ Two things worth knowing:
75
+
76
+ - **The HTTP cache is not a substitute.** Platform assets are served with no `Cache-Control` at all,
77
+ so a browser is free to re-fetch whenever it likes; what it does instead is apply *heuristic*
78
+ freshness, and a 73 MB entry is the first thing evicted when a real profile fills up.
79
+ - **`requestPersistentStorage()` is the shell's to call,** not a guest game's — some browsers prompt,
80
+ and the decision is scored against the first-party origin. Without it the store is merely
81
+ best-effort (still evicted long after the HTTP cache would be).
82
+
83
+ ---
84
+
38
85
  ## `ScreenAnchor` — float UI above a 3D object
39
86
 
40
87
  The canonical "name tag / button prompt / health bar hovering over a thing" placement. **Do not
@@ -0,0 +1,87 @@
1
+ /**
2
+ * glb-cache — a **persistent** byte cache for GLB assets, in the browser's Cache Storage.
3
+ *
4
+ * ## Why this exists
5
+ *
6
+ * A game runs in a cross-origin iframe that the shell **destroys** when the rider leaves it. Every
7
+ * in-memory cache dies with it: the per-world handle cache in {@link import("./world-loader.js").loadWorld}
8
+ * and the per-URL dedup inside {@link import("./world-loader.js").createGlbLoader} both start empty on
9
+ * the next visit. So a rider who plays, leaves, and comes back downloads the whole map again — and a
10
+ * platform world's base map is 3–73 MB today.
11
+ *
12
+ * The HTTP cache is not an answer to this. Platform assets are served from R2 with **no
13
+ * `Cache-Control` header at all**, so a browser is free to re-fetch at will; what it does instead is
14
+ * apply *heuristic* freshness, which happens to work on an empty profile and is exactly what gets
15
+ * evicted first on a full one (a 73 MB entry is the cheapest thing a browser can throw away). Cache
16
+ * Storage is a promise rather than a hint: it is origin-scoped, survives the document, and is only
17
+ * cleared under real storage pressure — and never before the HTTP cache (see
18
+ * {@link requestPersistentStorage} to take it off the eviction list entirely).
19
+ *
20
+ * ## The key is the URL PATH
21
+ *
22
+ * Same rule as the in-memory dedup in `createGlbLoader`: platform assets can arrive with per-request
23
+ * query strings, so the path is the asset's identity. That is safe *because* a world upload mints a
24
+ * fresh uuid per object key (`worlds/<kind>/<uuid>-<filename>.glb`) — re-uploading a map produces a
25
+ * new path, never new bytes at an old one. A cached path can therefore never be stale.
26
+ *
27
+ * ## Degrading
28
+ *
29
+ * Everything here is best-effort by construction: no Cache Storage (an insecure context, a browser
30
+ * with storage disabled, a quota refusal) means {@link GlbCache.bytes} still fetches and still
31
+ * resolves — it just doesn't remember. A caller never needs to branch on availability.
32
+ */
33
+ export interface GlbCacheOptions {
34
+ /** Cache Storage bucket name. Default `"rydr-glb-v1"`. */
35
+ name?: string;
36
+ /**
37
+ * Byte budget. Once a write takes the store past it, least-recently-USED entries are deleted
38
+ * until it fits again. Default 512 MB.
39
+ */
40
+ maxBytes?: number;
41
+ }
42
+ /** What the store currently holds. */
43
+ export interface GlbCacheStats {
44
+ entries: number;
45
+ bytes: number;
46
+ }
47
+ /**
48
+ * A persistent GLB byte store. Created by {@link createGlbCache}; wired into
49
+ * {@link import("./world-loader.js").createGlbLoader} by default, so most games never touch it
50
+ * directly — reach for it when you load GLBs yourself, or to show/clear the store in a dev panel.
51
+ */
52
+ export interface GlbCache {
53
+ /**
54
+ * The bytes for `url` — from the store when it has them, otherwise fetched and stored.
55
+ *
56
+ * Rejects exactly when a plain `fetch` would: a network failure or a non-2xx response. A storage
57
+ * failure never rejects (the bytes are returned uncached).
58
+ */
59
+ bytes(url: string): Promise<ArrayBuffer>;
60
+ /** Entry count + total bytes held. `{ entries: 0, bytes: 0 }` where Cache Storage is unavailable. */
61
+ stats(): Promise<GlbCacheStats>;
62
+ /** Delete every entry in this bucket. */
63
+ clear(): Promise<void>;
64
+ }
65
+ /** Whether this context can persist anything at all (Cache Storage needs a secure context). */
66
+ export declare function glbCacheAvailable(): boolean;
67
+ /**
68
+ * The cache key for an asset URL: its origin + path, with the query string and fragment dropped.
69
+ * Exported because it is the identity the whole store is keyed on — a dev panel listing entries
70
+ * wants the same answer.
71
+ */
72
+ export declare function glbCacheKey(url: string): string;
73
+ /**
74
+ * Ask the browser to make this origin's storage **persistent** — exempt from eviction under disk
75
+ * pressure, instead of merely best-effort.
76
+ *
77
+ * Not called automatically, and deliberately: some browsers surface a permission prompt, which is
78
+ * the shell's call to make (and the shell is the first-party origin whose engagement the decision is
79
+ * scored on), not a guest game's. Resolves `false` when the browser declines or doesn't support it.
80
+ */
81
+ export declare function requestPersistentStorage(): Promise<boolean>;
82
+ /**
83
+ * Open (lazily) a persistent GLB byte store. Cheap to call — nothing touches storage until the first
84
+ * {@link GlbCache.bytes}.
85
+ */
86
+ export declare function createGlbCache(opts?: GlbCacheOptions): GlbCache;
87
+ //# sourceMappingURL=glb-cache.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glb-cache.d.ts","sourceRoot":"","sources":["../../src/three/glb-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAcH,MAAM,WAAW,eAAe;IAC9B,0DAA0D;IAC1D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,sCAAsC;AACtC,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;IACzC,qGAAqG;IACrG,KAAK,IAAI,OAAO,CAAC,aAAa,CAAC,CAAC;IAChC,yCAAyC;IACzC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACxB;AAED,+FAA+F;AAC/F,wBAAgB,iBAAiB,IAAI,OAAO,CAI3C;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG/C;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,IAAI,OAAO,CAAC,OAAO,CAAC,CAQjE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,eAAoB,GAAG,QAAQ,CA6FnE"}
@@ -0,0 +1,272 @@
1
+ /**
2
+ * glb-cache — a **persistent** byte cache for GLB assets, in the browser's Cache Storage.
3
+ *
4
+ * ## Why this exists
5
+ *
6
+ * A game runs in a cross-origin iframe that the shell **destroys** when the rider leaves it. Every
7
+ * in-memory cache dies with it: the per-world handle cache in {@link import("./world-loader.js").loadWorld}
8
+ * and the per-URL dedup inside {@link import("./world-loader.js").createGlbLoader} both start empty on
9
+ * the next visit. So a rider who plays, leaves, and comes back downloads the whole map again — and a
10
+ * platform world's base map is 3–73 MB today.
11
+ *
12
+ * The HTTP cache is not an answer to this. Platform assets are served from R2 with **no
13
+ * `Cache-Control` header at all**, so a browser is free to re-fetch at will; what it does instead is
14
+ * apply *heuristic* freshness, which happens to work on an empty profile and is exactly what gets
15
+ * evicted first on a full one (a 73 MB entry is the cheapest thing a browser can throw away). Cache
16
+ * Storage is a promise rather than a hint: it is origin-scoped, survives the document, and is only
17
+ * cleared under real storage pressure — and never before the HTTP cache (see
18
+ * {@link requestPersistentStorage} to take it off the eviction list entirely).
19
+ *
20
+ * ## The key is the URL PATH
21
+ *
22
+ * Same rule as the in-memory dedup in `createGlbLoader`: platform assets can arrive with per-request
23
+ * query strings, so the path is the asset's identity. That is safe *because* a world upload mints a
24
+ * fresh uuid per object key (`worlds/<kind>/<uuid>-<filename>.glb`) — re-uploading a map produces a
25
+ * new path, never new bytes at an old one. A cached path can therefore never be stale.
26
+ *
27
+ * ## Degrading
28
+ *
29
+ * Everything here is best-effort by construction: no Cache Storage (an insecure context, a browser
30
+ * with storage disabled, a quota refusal) means {@link GlbCache.bytes} still fetches and still
31
+ * resolves — it just doesn't remember. A caller never needs to branch on availability.
32
+ */
33
+ /** Cache Storage bucket name. Bump the suffix to orphan every previous entry at once. */
34
+ const DEFAULT_CACHE_NAME = "rydr-glb-v1";
35
+ /** Default byte budget for the store — a handful of maps, at 3–73 MB each. */
36
+ const DEFAULT_MAX_BYTES = 512 * 1024 * 1024;
37
+ /** Where the recency index is parked. Never fetched — it is a Cache Storage key, not a real URL. */
38
+ const INDEX_URL = "https://rydr-glb-cache.invalid/index.json";
39
+ /** Response header carrying an entry's byte length, so a trim needn't read bodies. */
40
+ const BYTES_HEADER = "x-rydr-bytes";
41
+ /** Whether this context can persist anything at all (Cache Storage needs a secure context). */
42
+ export function glbCacheAvailable() {
43
+ // `!== false` rather than a truthiness test: a runtime that doesn't define `isSecureContext` at all
44
+ // (a worker in an older browser) still has a usable `caches`.
45
+ return typeof caches !== "undefined" && globalThis.isSecureContext !== false;
46
+ }
47
+ /**
48
+ * The cache key for an asset URL: its origin + path, with the query string and fragment dropped.
49
+ * Exported because it is the identity the whole store is keyed on — a dev panel listing entries
50
+ * wants the same answer.
51
+ */
52
+ export function glbCacheKey(url) {
53
+ const cut = url.search(/[?#]/);
54
+ return cut === -1 ? url : url.slice(0, cut);
55
+ }
56
+ /**
57
+ * Ask the browser to make this origin's storage **persistent** — exempt from eviction under disk
58
+ * pressure, instead of merely best-effort.
59
+ *
60
+ * Not called automatically, and deliberately: some browsers surface a permission prompt, which is
61
+ * the shell's call to make (and the shell is the first-party origin whose engagement the decision is
62
+ * scored on), not a guest game's. Resolves `false` when the browser declines or doesn't support it.
63
+ */
64
+ export async function requestPersistentStorage() {
65
+ try {
66
+ if (!navigator.storage?.persist)
67
+ return false;
68
+ if (await navigator.storage.persisted())
69
+ return true;
70
+ return await navigator.storage.persist();
71
+ }
72
+ catch {
73
+ return false;
74
+ }
75
+ }
76
+ /**
77
+ * Open (lazily) a persistent GLB byte store. Cheap to call — nothing touches storage until the first
78
+ * {@link GlbCache.bytes}.
79
+ */
80
+ export function createGlbCache(opts = {}) {
81
+ const name = opts.name ?? DEFAULT_CACHE_NAME;
82
+ const maxBytes = opts.maxBytes ?? DEFAULT_MAX_BYTES;
83
+ /**
84
+ * Fetches in flight, by key, so two loaders in one document can't both pull 73 MB.
85
+ *
86
+ * `taken` is which caller gets the buffer ITSELF: the first one. A second caller awaiting the same
87
+ * load is handed a copy, because a consumer is free to detach the buffer it is given (transferring
88
+ * it to a worker), which would empty the one the other is holding. Copying for everyone would mean
89
+ * a 73 MB allocation on the common path, where there is only ever one caller.
90
+ */
91
+ const inFlight = new Map();
92
+ let opened = null;
93
+ /**
94
+ * Every mutation runs on ONE chain.
95
+ *
96
+ * The recency index is a read-modify-write of a single cache entry, and world loads are
97
+ * concurrent by nature (a map plus its props, two screens booting). Interleaved writes lose each
98
+ * other's timestamps, and a trim running on a stale index evicts the entry that was just used —
99
+ * which is precisely the case the cache exists for. Serializing costs nothing: writes are already
100
+ * off the critical path (`bytes` resolves before them).
101
+ */
102
+ let writes = Promise.resolve();
103
+ const enqueue = (task) => {
104
+ const next = writes.then(task, task).catch(() => { });
105
+ writes = next;
106
+ return next;
107
+ };
108
+ /**
109
+ * Uses recorded the INSTANT they happen, flushed to the persisted index by the write queue.
110
+ *
111
+ * A read is not queued (it must not wait behind a 73 MB write), so a hit can land while a trim is
112
+ * already queued behind it. Stamping only on the queue would let that trim evict the entry the
113
+ * rider is using right now — the one thing an LRU must never do. Recording here, synchronously,
114
+ * is what makes the use visible to a trim that has not run yet.
115
+ */
116
+ const recent = new Map();
117
+ const open = () => {
118
+ if (!opened) {
119
+ opened = glbCacheAvailable()
120
+ ? caches.open(name).catch(() => null)
121
+ : Promise.resolve(null);
122
+ }
123
+ return opened;
124
+ };
125
+ const load = async (url, key) => {
126
+ const cache = await open();
127
+ if (cache) {
128
+ const hit = await cache.match(key).catch(() => undefined);
129
+ if (hit) {
130
+ recent.set(key, Date.now());
131
+ void enqueue(() => stamp(cache, recent, maxBytes));
132
+ return await hit.arrayBuffer();
133
+ }
134
+ }
135
+ const res = await fetch(url);
136
+ if (!res.ok)
137
+ throw new Error(`[rydr-sdk] glb fetch failed (${res.status}) — ${key}`);
138
+ const buf = await res.arrayBuffer();
139
+ if (cache) {
140
+ recent.set(key, Date.now());
141
+ void enqueue(() => store(cache, recent, key, buf, res.headers.get("content-type"), maxBytes));
142
+ }
143
+ return buf;
144
+ };
145
+ return {
146
+ bytes(url) {
147
+ const key = glbCacheKey(url);
148
+ let entry = inFlight.get(key);
149
+ if (!entry) {
150
+ entry = { bytes: load(url, key).finally(() => inFlight.delete(key)), taken: false };
151
+ inFlight.set(key, entry);
152
+ }
153
+ const mine = entry;
154
+ const first = !mine.taken;
155
+ mine.taken = true;
156
+ return mine.bytes.then((buf) => (first ? buf : buf.slice(0)));
157
+ },
158
+ async stats() {
159
+ const cache = await open();
160
+ if (!cache)
161
+ return { entries: 0, bytes: 0 };
162
+ const entries = await assetEntries(cache);
163
+ return { entries: entries.length, bytes: entries.reduce((n, e) => n + e.bytes, 0) };
164
+ },
165
+ async clear() {
166
+ opened = null;
167
+ if (glbCacheAvailable())
168
+ await caches.delete(name).catch(() => { });
169
+ },
170
+ };
171
+ }
172
+ // ==================== storage ====================
173
+ /**
174
+ * Write `buf` under `key`, then bring the bucket back inside its budget. Never throws.
175
+ *
176
+ * Always run through the caller's write queue — see `enqueue` in {@link createGlbCache}.
177
+ */
178
+ async function store(cache, recent, key, buf, contentType, maxBytes) {
179
+ try {
180
+ await cache.put(key, new Response(buf, {
181
+ headers: {
182
+ "content-type": contentType || "model/gltf-binary",
183
+ [BYTES_HEADER]: String(buf.byteLength),
184
+ },
185
+ }));
186
+ await stamp(cache, recent, maxBytes);
187
+ }
188
+ catch {
189
+ // Quota refusal, a private-mode browser, a storage policy — the bytes are already in hand and
190
+ // the load succeeds either way. Trim so the next write has a chance of landing.
191
+ await stamp(cache, recent, maxBytes).catch(() => { });
192
+ }
193
+ }
194
+ /**
195
+ * Flush the uses recorded since the last flush into the persisted index, then trim. Never throws.
196
+ *
197
+ * Always run through the caller's write queue — see `enqueue` in {@link createGlbCache}.
198
+ */
199
+ async function stamp(cache, recent, maxBytes) {
200
+ try {
201
+ const used = await readIndex(cache);
202
+ for (const [key, at] of recent)
203
+ used[key] = at;
204
+ await trim(cache, used, maxBytes);
205
+ await writeIndex(cache, used);
206
+ }
207
+ catch {
208
+ /* recency is a hint; losing it costs eviction ORDER, never correctness */
209
+ }
210
+ }
211
+ /**
212
+ * Delete least-recently-used entries until the bucket fits `maxBytes`.
213
+ *
214
+ * The index is reconciled against what the cache actually holds first, so it is self-healing: an
215
+ * entry with no timestamp (written by an older build, or a lost index) is stamped now and survives
216
+ * this round rather than being evicted as "oldest".
217
+ */
218
+ async function trim(cache, used, maxBytes) {
219
+ const entries = await assetEntries(cache);
220
+ const now = Date.now();
221
+ let total = 0;
222
+ for (const e of entries) {
223
+ if (used[e.key] === undefined)
224
+ used[e.key] = now;
225
+ total += e.bytes;
226
+ }
227
+ for (const key of Object.keys(used)) {
228
+ if (!entries.some((e) => e.key === key))
229
+ delete used[key];
230
+ }
231
+ if (total > maxBytes) {
232
+ for (const e of [...entries].sort((a, b) => (used[a.key] ?? 0) - (used[b.key] ?? 0))) {
233
+ if (total <= maxBytes)
234
+ break;
235
+ if (await cache.delete(e.key)) {
236
+ total -= e.bytes;
237
+ delete used[e.key];
238
+ }
239
+ }
240
+ }
241
+ }
242
+ /** Every ASSET entry (the recency index itself excluded) with its stored byte length. */
243
+ async function assetEntries(cache) {
244
+ const out = [];
245
+ for (const req of await cache.keys()) {
246
+ if (req.url === INDEX_URL)
247
+ continue;
248
+ const res = await cache.match(req);
249
+ if (!res)
250
+ continue;
251
+ const stamped = Number(res.headers.get(BYTES_HEADER) ?? res.headers.get("content-length"));
252
+ out.push({ key: req.url, bytes: Number.isFinite(stamped) ? stamped : 0 });
253
+ }
254
+ return out;
255
+ }
256
+ /** The recency index: cache key → last-used epoch ms. `{}` when absent or unreadable. */
257
+ async function readIndex(cache) {
258
+ try {
259
+ const res = await cache.match(INDEX_URL);
260
+ if (!res)
261
+ return {};
262
+ const parsed = await res.json();
263
+ return parsed && typeof parsed === "object" ? parsed : {};
264
+ }
265
+ catch {
266
+ return {};
267
+ }
268
+ }
269
+ async function writeIndex(cache, used) {
270
+ await cache.put(INDEX_URL, new Response(JSON.stringify(used), { headers: { "content-type": "application/json" } }));
271
+ }
272
+ //# sourceMappingURL=glb-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glb-cache.js","sourceRoot":"","sources":["../../src/three/glb-cache.ts"],"names":[],"mappings":"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"}
@@ -6,6 +6,7 @@
6
6
  * `GLTFLoader` + DRACO + caching per game.
7
7
  */
8
8
  export * from "./world-loader.js";
9
+ export * from "./glb-cache.js";
9
10
  export * from "./merge.js";
10
11
  export * from "./perf-marks.js";
11
12
  export * from "./perf-overlay.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
@@ -6,6 +6,7 @@
6
6
  * `GLTFLoader` + DRACO + caching per game.
7
7
  */
8
8
  export * from "./world-loader.js";
9
+ export * from "./glb-cache.js";
9
10
  export * from "./merge.js";
10
11
  export * from "./perf-marks.js";
11
12
  export * from "./perf-overlay.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/three/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,cAAc,mBAAmB,CAAC;AAClC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,sBAAsB,CAAC;AACrC,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC"}
@@ -11,9 +11,14 @@
11
11
  *
12
12
  * A platform world is a static environment, so it is fetched, DRACO-decoded, uploaded to the GPU and
13
13
  * shader-compiled **once** ({@link loadWorld}, cached by {@link CoreWorld.id}) and then reused — a game
14
- * that tears down and rebuilds gameplay on every restart still gets an instant world. Two caches back
15
- * this: a per-URL GLB dedup inside {@link createGlbLoader} (repeated props clone shared
16
- * geometry/material instead of re-downloading), and the per-world {@link LoadedWorld} handle cache.
14
+ * that tears down and rebuilds gameplay on every restart still gets an instant world. THREE caches back
15
+ * this, and they survive different things:
16
+ * - the per-world {@link LoadedWorld} handle cache — GPU resources, per document;
17
+ * - a per-URL GLB decode dedup inside {@link createGlbLoader} — repeated props clone shared
18
+ * geometry/material instead of re-downloading, per document;
19
+ * - the raw bytes in Cache Storage ({@link import("./glb-cache.js").createGlbCache}) — which
20
+ * **outlives the document**, so a rider returning to a game the shell already tore down re-decodes
21
+ * its map instead of re-downloading 3–73 MB of it.
17
22
  *
18
23
  * ## The handle owns the GPU resources — disposal is safe
19
24
  *
@@ -23,12 +28,19 @@
23
28
  * no "remember to detach, never dispose the shared group" rule to get wrong.
24
29
  */
25
30
  import * as THREE from "three";
31
+ import type { GlbCacheOptions } from "./glb-cache.js";
26
32
  import type { CoreWorld } from "../protocol/worlds.js";
27
33
  /** DRACO decoder — pinned to the same version the platform world editor uses. */
28
34
  export declare const DRACO_DECODER_PATH = "https://www.gstatic.com/draco/versioned/decoders/1.5.6/";
29
35
  export interface GlbLoaderOptions {
30
36
  /** Override the DRACO decoder directory (defaults to {@link DRACO_DECODER_PATH}). */
31
37
  dracoDecoderPath?: string;
38
+ /**
39
+ * The **persistent** byte cache (see {@link import("./glb-cache.js").GlbCache}), which is what
40
+ * makes a world survive the shell destroying the game's iframe. On by default; pass options to
41
+ * size it, or `false` to fetch every time (a bench measuring cold loads, say).
42
+ */
43
+ cache?: GlbCacheOptions | false;
32
44
  }
33
45
  /** A transform applied to a loaded world group: translate · Y-rotation · uniform scale. */
34
46
  export interface WorldPlacement {
@@ -85,6 +97,13 @@ export interface LoadedWorld {
85
97
  * R2 URLs whose signature/expiry query string varies per request, so the same prop placed N times
86
98
  * arrives as N distinct full URLs. Keying by path (the R2 object identity) collapses them to one
87
99
  * decode; without it every placement re-fetches and re-DRACO-decodes the same glb (slow level loads).
100
+ *
101
+ * **Two caches, and they answer different questions.** The decode map above is per-document and dies
102
+ * with the iframe; under it, {@link import("./glb-cache.js").createGlbCache} keeps the raw BYTES in
103
+ * Cache Storage, which does not — so a rider who leaves the game and comes back re-decodes a map
104
+ * instead of re-downloading it. That is why this fetches and calls `parse` itself rather than
105
+ * `loader.loadAsync(url)`: the bytes have to pass through our hands to be stored. Disable it with
106
+ * `cache: false`.
88
107
  */
89
108
  export declare function createGlbLoader(opts?: GlbLoaderOptions): (url: string) => Promise<THREE.Object3D>;
90
109
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"world-loader.d.ts","sourceRoot":"","sources":["../../src/three/world-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAK/B,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,4DAA4D,CAAC;AAE5F,MAAM,WAAW,gBAAgB;IAC/B,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACxD,kGAAkG;IAClG,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uGAAuG;IACvG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IAC5B,6GAA6G;IAC7G,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACrC,2GAA2G;IAC3G,MAAM,IAAI,IAAI,CAAC;IACf,iGAAiG;IACjG,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,gBAAqB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAgBrG;AAKD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAcjG;AAwBD,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,cAAc,GAAG,IAAI,CAIrF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAWjD"}
1
+ {"version":3,"file":"world-loader.d.ts","sourceRoot":"","sources":["../../src/three/world-loader.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAM/B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACtD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD,iFAAiF;AACjF,eAAO,MAAM,kBAAkB,4DAA4D,CAAC;AAE5F,MAAM,WAAW,gBAAgB;IAC/B,qFAAqF;IACrF,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,KAAK,CAAC,EAAE,eAAe,GAAG,KAAK,CAAC;CACjC;AAED,2FAA2F;AAC3F,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,gCAAgC;IAChC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qBAAqB;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,gBAAiB,SAAQ,gBAAgB;IACxD,kGAAkG;IAClG,SAAS,CAAC,EAAE,cAAc,CAAC;IAC3B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,oDAAoD;IACpD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,uGAAuG;IACvG,QAAQ,CAAC,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC;IAC5B,6GAA6G;IAC7G,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,QAAQ,GAAG,IAAI,CAAC;IACrC,2GAA2G;IAC3G,MAAM,IAAI,IAAI,CAAC;IACf,iGAAiG;IACjG,OAAO,IAAI,IAAI,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,eAAe,CAAC,IAAI,GAAE,gBAAqB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,CAmBrG;AAmBD;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,SAAS,EAAE,SAAS,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,WAAW,CAAC,CAcjG;AAwBD,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,EAAE,SAAS,EAAE,cAAc,GAAG,IAAI,CAIrF;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAWjD"}
@@ -11,9 +11,14 @@
11
11
  *
12
12
  * A platform world is a static environment, so it is fetched, DRACO-decoded, uploaded to the GPU and
13
13
  * shader-compiled **once** ({@link loadWorld}, cached by {@link CoreWorld.id}) and then reused — a game
14
- * that tears down and rebuilds gameplay on every restart still gets an instant world. Two caches back
15
- * this: a per-URL GLB dedup inside {@link createGlbLoader} (repeated props clone shared
16
- * geometry/material instead of re-downloading), and the per-world {@link LoadedWorld} handle cache.
14
+ * that tears down and rebuilds gameplay on every restart still gets an instant world. THREE caches back
15
+ * this, and they survive different things:
16
+ * - the per-world {@link LoadedWorld} handle cache — GPU resources, per document;
17
+ * - a per-URL GLB decode dedup inside {@link createGlbLoader} — repeated props clone shared
18
+ * geometry/material instead of re-downloading, per document;
19
+ * - the raw bytes in Cache Storage ({@link import("./glb-cache.js").createGlbCache}) — which
20
+ * **outlives the document**, so a rider returning to a game the shell already tore down re-decodes
21
+ * its map instead of re-downloading 3–73 MB of it.
17
22
  *
18
23
  * ## The handle owns the GPU resources — disposal is safe
19
24
  *
@@ -27,6 +32,7 @@ import { GLTFLoader } from "three/addons/loaders/GLTFLoader.js";
27
32
  import { DRACOLoader } from "three/addons/loaders/DRACOLoader.js";
28
33
  import { applyWorld } from "../world-runtime.js";
29
34
  import { mergeByMaterial } from "./merge.js";
35
+ import { createGlbCache } from "./glb-cache.js";
30
36
  /** DRACO decoder — pinned to the same version the platform world editor uses. */
31
37
  export const DRACO_DECODER_PATH = "https://www.gstatic.com/draco/versioned/decoders/1.5.6/";
32
38
  /**
@@ -42,6 +48,13 @@ export const DRACO_DECODER_PATH = "https://www.gstatic.com/draco/versioned/decod
42
48
  * R2 URLs whose signature/expiry query string varies per request, so the same prop placed N times
43
49
  * arrives as N distinct full URLs. Keying by path (the R2 object identity) collapses them to one
44
50
  * decode; without it every placement re-fetches and re-DRACO-decodes the same glb (slow level loads).
51
+ *
52
+ * **Two caches, and they answer different questions.** The decode map above is per-document and dies
53
+ * with the iframe; under it, {@link import("./glb-cache.js").createGlbCache} keeps the raw BYTES in
54
+ * Cache Storage, which does not — so a rider who leaves the game and comes back re-decodes a map
55
+ * instead of re-downloading it. That is why this fetches and calls `parse` itself rather than
56
+ * `loader.loadAsync(url)`: the bytes have to pass through our hands to be stored. Disable it with
57
+ * `cache: false`.
45
58
  */
46
59
  export function createGlbLoader(opts = {}) {
47
60
  const loader = new GLTFLoader();
@@ -49,17 +62,33 @@ export function createGlbLoader(opts = {}) {
49
62
  draco.setDecoderPath(opts.dracoDecoderPath ?? DRACO_DECODER_PATH);
50
63
  loader.setDRACOLoader(draco);
51
64
  const decoded = new Map();
65
+ const bytes = opts.cache === false ? null : createGlbCache(opts.cache);
52
66
  return (url) => {
53
67
  const cut = url.search(/[?#]/); // dedup by asset path; presigned query strings vary per placement
54
68
  const key = cut === -1 ? url : url.slice(0, cut);
55
69
  let p = decoded.get(key);
56
70
  if (!p) {
57
- p = loader.loadAsync(url).then((g) => g.scene);
71
+ p = bytes
72
+ ? bytes.bytes(url).then((buf) => parseGlb(loader, buf, key))
73
+ : loader.loadAsync(url).then((g) => g.scene);
58
74
  decoded.set(key, p);
59
75
  }
60
76
  return p.then((scene) => scene.clone());
61
77
  };
62
78
  }
79
+ /**
80
+ * Decode glb bytes with the shared loader, resolving to the asset's root scene.
81
+ *
82
+ * `path` is the asset's own directory, which is what a `.gltf` referencing a sibling `.bin` or a
83
+ * texture resolves against. Platform assets are self-contained `.glb`s, so nothing is fetched
84
+ * through it today — passing it anyway costs nothing and keeps a non-embedded asset working.
85
+ */
86
+ function parseGlb(loader, buf, url) {
87
+ const path = url.slice(0, url.lastIndexOf("/") + 1);
88
+ return new Promise((resolve, reject) => {
89
+ loader.parse(buf, path, (gltf) => resolve(gltf.scene), reject);
90
+ });
91
+ }
63
92
  /** Loaded worlds, keyed by {@link CoreWorld.id}. See the module doc for the lifecycle contract. */
64
93
  const worldCache = new Map();
65
94
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"world-loader.js","sourceRoot":"","sources":["../../src/three/world-loader.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"world-loader.js","sourceRoot":"","sources":["../../src/three/world-loader.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rydr/game-sdk",
3
- "version": "8.16.0",
3
+ "version": "8.17.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/bdefrenne/rydr-game-sdk.git"