@rydr/game-sdk 9.10.0 → 9.11.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.
package/dist/index.d.ts CHANGED
@@ -11,4 +11,5 @@ export * from "./protocol/index.js";
11
11
  export * from "./client/index.js";
12
12
  export * from "./host/index.js";
13
13
  export * from "./world-runtime.js";
14
+ export * from "./world-lighting.js";
14
15
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -11,4 +11,5 @@ export * from "./protocol/index.js";
11
11
  export * from "./client/index.js";
12
12
  export * from "./host/index.js";
13
13
  export * from "./world-runtime.js";
14
+ export * from "./world-lighting.js";
14
15
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,mBAAmB,CAAC;AAClC,cAAc,iBAAiB,CAAC;AAChC,cAAc,oBAAoB,CAAC;AACnC,cAAc,qBAAqB,CAAC"}
@@ -9,5 +9,5 @@
9
9
  export declare const RYDR_PROTOCOL_VERSION: 42;
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 = "9.10.0";
12
+ export declare const RYDR_SDK_VERSION = "9.11.0";
13
13
  //# sourceMappingURL=version.d.ts.map
@@ -398,5 +398,5 @@
398
398
  export const RYDR_PROTOCOL_VERSION = 42;
399
399
  /** Semver of this SDK build. Sent in the handshake for telemetry/debugging.
400
400
  * (Bumped to 2.0.0 by `npm version major` on release — see CHANGELOG [Unreleased].) */
401
- export const RYDR_SDK_VERSION = "9.10.0";
401
+ export const RYDR_SDK_VERSION = "9.11.0";
402
402
  //# sourceMappingURL=version.js.map
@@ -62,6 +62,157 @@ export interface WorldMapDelta {
62
62
  * Applied by `applyWorld`; absent on worlds saved before it existed.
63
63
  */
64
64
  worldTransform?: WorldTransform;
65
+ /**
66
+ * Lights placed in the world (lamps, spots, extra suns, area lights). Optional: absent on worlds
67
+ * saved before lights existed. The SUN is not here: it belongs to a lighting preset
68
+ * ({@link WorldLightingPreset.sun}), because Day and Night each have their own.
69
+ *
70
+ * These are authored in the platform world editor and exist so a bake can light the world with
71
+ * them. A game renders them LIVE only when it opts in (`createWorldLights`, capped), since dozens of
72
+ * real-time lights are unplayable in WebGL; in a baked scene their light is already in the lightmap.
73
+ */
74
+ lights?: WorldLight[];
75
+ }
76
+ /** The kinds of light a world can hold. `area` is bake-only: glTF and live three.js have no match. */
77
+ export type WorldLightType = "directional" | "point" | "spot" | "area";
78
+ /**
79
+ * One light placed in a world.
80
+ *
81
+ * **Units are three.js's physical units**, so a light looks the same live and baked:
82
+ * `directional` in lux-like irradiance (a noon sun is ~3), `point`/`spot` in candela (a street lamp is
83
+ * ~40-150 at a few metres), `area` in Blender watts (it has no live counterpart). The bake script
84
+ * converts them to Cycles once, in one place.
85
+ *
86
+ * **Transforms are absolute, in world (map) space, like `WorldAddedObject`.** To make a lamp move with
87
+ * its post, group the two in the editor (object groups are editor metadata); the light is still
88
+ * stored with its own absolute transform.
89
+ */
90
+ export interface WorldLight {
91
+ id: string;
92
+ type: WorldLightType;
93
+ /** Shown in the editor's outliner. */
94
+ name?: string;
95
+ position: [number, number, number];
96
+ /**
97
+ * Orientation quaternion `[x, y, z, w]`. The light shines down its local -Y axis (a lamp hanging
98
+ * from its post points down with the identity rotation). Ignored by `point`.
99
+ */
100
+ rotation?: [number, number, number, number];
101
+ /** `#rrggbb`, sRGB — the same string `THREE.Color.set` takes. */
102
+ color: string;
103
+ intensity: number;
104
+ /** Metres; the light has no effect past it. Absent or 0 = physically unbounded (inverse square). */
105
+ range?: number;
106
+ /** Spot only: outer cone half-angle, radians. */
107
+ angle?: number;
108
+ /** Spot only: 0 (hard edge) .. 1 (fully soft). */
109
+ penumbra?: number;
110
+ /** Area: side of the square emitter (m). Point/spot: radius of the emitter for soft shadows (m). */
111
+ size?: number;
112
+ /** Default true. */
113
+ castShadow?: boolean;
114
+ /**
115
+ * The light group a preset scales ({@link WorldLightingPreset.groups}), e.g. `"street-lamps"`: Night
116
+ * sets it to 1, Day to 0. Absent = always on at full intensity.
117
+ */
118
+ group?: string;
119
+ }
120
+ /**
121
+ * One way of lighting a world — "Day", "Dusk", "Night". A world holds several; a game (or one track of
122
+ * it) picks one, and a bake is made per preset.
123
+ *
124
+ * The fields are exactly a live rig's, so a game can light itself from a preset with no translation:
125
+ * sun + unshadowed fill opposite it + hemisphere + flat ambient + a gradient sky used as both the
126
+ * background and the environment probe, then fog and exposure. Colours are sRGB `#rrggbb`.
127
+ */
128
+ export interface WorldLightingPreset {
129
+ id: string;
130
+ name: string;
131
+ /** The shadow-casting sun (or moon). `intensity: 0` for none. Degrees; azimuth is measured from +X toward +Z. */
132
+ sun: {
133
+ azimuthDeg: number;
134
+ elevationDeg: number;
135
+ color: string;
136
+ intensity: number;
137
+ };
138
+ /** Unshadowed rim light from the sun's opposite side. */
139
+ fill?: {
140
+ color: string;
141
+ intensity: number;
142
+ };
143
+ /**
144
+ * Gradient sky, straight up → horizon → below it. It is the background AND the environment light
145
+ * (`scene.environment`, scaled by `intensity`), which is also how the bake lights the world with it.
146
+ */
147
+ sky: {
148
+ zenith: string;
149
+ horizon: string;
150
+ ground: string;
151
+ intensity: number;
152
+ };
153
+ hemisphere?: {
154
+ sky: string;
155
+ ground: string;
156
+ intensity: number;
157
+ };
158
+ ambient?: {
159
+ color: string;
160
+ intensity: number;
161
+ };
162
+ fog?: {
163
+ color: string;
164
+ near: number;
165
+ far: number;
166
+ };
167
+ /** Tone-mapping exposure (ACES filmic). Default 1. */
168
+ exposure?: number;
169
+ /** Multiplier per {@link WorldLight.group}. A group not listed is at 1. */
170
+ groups?: Record<string, number>;
171
+ }
172
+ /** A world's lighting: its presets, and which one a game gets when it asks for none. */
173
+ export interface WorldLighting {
174
+ presets: WorldLightingPreset[];
175
+ defaultPresetId: string;
176
+ }
177
+ /**
178
+ * A baked scene: a scene's lighting cooked into lightmaps by Blender (see the platform's
179
+ * `docs/baked-lighting.md`), stored as ONE self-contained glb whose materials carry the
180
+ * `RYDR_lightmap` extension.
181
+ *
182
+ * It is a derived output, never a source: it records the fingerprints of what it was built from, and
183
+ * the moment either changes (a prop moved, a lamp added, a route re-drawn) it is **stale** and a game
184
+ * ignores it and renders live. `isBakeFresh` / `pickBake` decide that.
185
+ *
186
+ * Where it is stored says what it covers: on the world (`CoreWorld.bakes`) it covers the world alone;
187
+ * in a game's own document (a racing track) it also covers that game's layer — the road, barriers and
188
+ * kerbs the game generates — and `layer` identifies it.
189
+ */
190
+ export interface SceneBake {
191
+ /** Format of the baked glb. 1 = `RYDR_lightmap` v1. */
192
+ format: 1;
193
+ id: string;
194
+ /** The {@link WorldLightingPreset.id} it was lit with. */
195
+ presetId: string;
196
+ glbUrl: string;
197
+ /** The {@link CoreWorld.id} it was built on. */
198
+ worldId: string;
199
+ /** `worldFingerprint(world, presetId)` at export time. */
200
+ worldFingerprint: string;
201
+ /** The game layer baked with it, when there is one. `fingerprint` is the game's own `layerFingerprint`. */
202
+ layer?: {
203
+ game: string;
204
+ docId: string;
205
+ fingerprint: string;
206
+ };
207
+ bakedAt: number;
208
+ stats?: {
209
+ atlases?: number;
210
+ atlasSize?: number;
211
+ bytes?: number;
212
+ samples?: number;
213
+ minutes?: number;
214
+ blender?: string;
215
+ };
65
216
  }
66
217
  /** Optional lighting/fog for a world. */
67
218
  export interface WorldEnv {
@@ -86,6 +237,13 @@ export interface CoreWorld {
86
237
  name: string;
87
238
  env?: WorldEnv;
88
239
  map: WorldMapDelta;
240
+ /**
241
+ * Lighting presets (Day, Night…). Optional: a world without it has at most the legacy `env`, which
242
+ * `lightingPresets()` reads as an implicit `"default"` preset.
243
+ */
244
+ lighting?: WorldLighting;
245
+ /** World-only bakes, one per preset (see {@link SceneBake}). A game's own layer keeps its bakes itself. */
246
+ bakes?: SceneBake[];
89
247
  createdAt: number;
90
248
  updatedAt: number;
91
249
  }
@@ -100,4 +258,27 @@ export interface CatalogItem {
100
258
  }
101
259
  /** The objectName used for the root of a baked single-object catalog glb. */
102
260
  export declare const CATALOG_ROOT_OBJECT = "root";
261
+ /**
262
+ * The shared-content collection a game publishes its **reference layers** to (one doc per layer, in the
263
+ * game's own `shared` scope, which every client can read).
264
+ *
265
+ * A reference layer is a lightweight glb of what a GAME builds on top of a world — racing's road,
266
+ * barriers and kerbs — so the platform world editor can show it as a read-only ghost. That is what
267
+ * lets a world author place street lamps along a road that otherwise exists only in the game's code.
268
+ */
269
+ export declare const WORLD_REFERENCES_COLLECTION = "world-references";
270
+ /** One doc in {@link WORLD_REFERENCES_COLLECTION}. */
271
+ export interface WorldReferenceLayer {
272
+ /** The {@link CoreWorld.id} it sits on. */
273
+ coreWorldId: string;
274
+ /** The publishing game's slug. */
275
+ game: string;
276
+ /** The game document it comes from (a racing track id). */
277
+ docId: string;
278
+ /** Shown in the editor's layer list, e.g. "Racing · Paris GP". */
279
+ label: string;
280
+ /** World-space glb (same frame as the world's own geometry). */
281
+ glbUrl: string;
282
+ updatedAt: number;
283
+ }
103
284
  //# sourceMappingURL=worlds.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"worlds.d.ts","sourceRoot":"","sources":["../../src/protocol/worlds.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,0DAA0D;AAC1D,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,kGAAkG;AAClG,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5C,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3C,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;CACjC;AAED;;;;;GAKG;AACH,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,cAAc;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,yCAAyC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,iGAAiG;AACjG,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,cAAc,EAAE,CAAC;IAChC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,iFAAiF;IACjF,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B;;;OAGG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,yCAAyC;AACzC,MAAM,WAAW,QAAQ;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED;;;GAGG;AACH,MAAM,WAAW,SAAS;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,aAAa,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,kGAAkG;AAClG,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,6EAA6E;AAC7E,eAAO,MAAM,mBAAmB,SAAS,CAAC"}
1
+ {"version":3,"file":"worlds.d.ts","sourceRoot":"","sources":["../../src/protocol/worlds.ts"],"names":[],"mappings":"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"}
@@ -7,4 +7,13 @@
7
7
  */
8
8
  /** The objectName used for the root of a baked single-object catalog glb. */
9
9
  export const CATALOG_ROOT_OBJECT = "root";
10
+ /**
11
+ * The shared-content collection a game publishes its **reference layers** to (one doc per layer, in the
12
+ * game's own `shared` scope, which every client can read).
13
+ *
14
+ * A reference layer is a lightweight glb of what a GAME builds on top of a world — racing's road,
15
+ * barriers and kerbs — so the platform world editor can show it as a read-only ghost. That is what
16
+ * lets a world author place street lamps along a road that otherwise exists only in the game's code.
17
+ */
18
+ export const WORLD_REFERENCES_COLLECTION = "world-references";
10
19
  //# sourceMappingURL=worlds.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"worlds.js","sourceRoot":"","sources":["../../src/protocol/worlds.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAoGH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC"}
1
+ {"version":3,"file":"worlds.js","sourceRoot":"","sources":["../../src/protocol/worlds.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AA2OH,6EAA6E;AAC7E,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAE1C;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,kBAAkB,CAAC"}
@@ -166,6 +166,31 @@ dispose();
166
166
  Handles GLB loading, DRACO decompression, placement transforms, and a shared cache so the same world
167
167
  isn't re-downloaded. Prefer this over a per-game `GLTFLoader`. `clearWorldCache(id?)` evicts.
168
168
 
169
+ ## Baked lighting — `loadBakedScene`, presets, shadow catcher
170
+
171
+ A platform world can carry lights and lighting presets (Day, Night…), and a scene baked from it in Blender
172
+ (the platform's `docs/baked-lighting.md`). Show the bake while it still matches, live otherwise:
173
+
174
+ ```ts
175
+ import { pickBake, resolvePreset, layerFingerprint } from "@rydr/game-sdk";
176
+ import { loadBakedScene, createShadowCatcher, applyLightingPreset, loadWorld } from "@rydr/game-sdk/three";
177
+
178
+ const preset = resolvePreset(world, myPresetId);
179
+ const bake = pickBake(myBakes, { world, presetId: preset?.id, layerFingerprint: layerFingerprint(myLayer) });
180
+ if (bake) {
181
+ const baked = await loadBakedScene(bake); // unlit albedo × lightmap, cached by URL
182
+ baked.attach(scene);
183
+ createShadowCatcher(baked.receivers); // moving things' live shadows on the baked road
184
+ } else {
185
+ (await loadWorld(world)).attach(scene);
186
+ }
187
+ if (preset) applyLightingPreset(scene, preset, { renderer, shadows: true }); // lights the moving things
188
+ ```
189
+
190
+ A baked material ignores live lights, so `createWorldLights(world, preset, { max, near })` can light a car
191
+ with the world's lamps at no cost to the world. `RydrLightmapPlugin` is the `RYDR_lightmap` GLTFLoader
192
+ plugin, for a loader of your own.
193
+
169
194
  ## `mergeByMaterial` — cut draw calls
170
195
 
171
196
  ```ts
@@ -0,0 +1,144 @@
1
+ /**
2
+ * baked-lighting — load a BAKED scene ({@link SceneBake}) and render it with its lightmaps.
3
+ *
4
+ * A baked scene is one self-contained glb produced by the platform's bake pipeline (Blender, see the
5
+ * platform repo's `docs/baked-lighting.md`): the world plus whatever a game baked with it, every static
6
+ * mesh carrying a second UV set (`TEXCOORD_1`) and a material extension, `RYDR_lightmap`, that points at
7
+ * the lightmap atlas it was baked into.
8
+ *
9
+ * ## What a lightmap holds, and how it is shown
10
+ *
11
+ * The light each surface RECEIVES (sun, sky, lamps, bounce) — not its colour. So a baked material is
12
+ * `albedo × lightmap`, which keeps the full detail of the colour textures at a low lightmap resolution,
13
+ * and it is a `MeshBasicMaterial`: the scene's live lights must not light it a second time. That is
14
+ * also why a baked world is CHEAPER than a live one — no per-pixel lighting at all.
15
+ *
16
+ * The atlas is an 8-bit sRGB PNG: the bake divides the light by a per-atlas `scale` before encoding,
17
+ * the GPU's sRGB decode undoes the curve for free, and `intensity` (= π × scale, the π cancelling
18
+ * `MeshBasicMaterial`'s Lambert term) puts the range back. No custom shader, no alpha channel for
19
+ * a browser to premultiply.
20
+ *
21
+ * ## What stays live
22
+ *
23
+ * Anything that moves. A car is still lit by the game's own sun + environment, and its shadow is put
24
+ * on the baked ground by a SHADOW CATCHER ({@link createShadowCatcher}): a `ShadowMaterial` overlay on
25
+ * the meshes the export marked as receivers (the road, the ground around it). Everything else in the
26
+ * baked scene casts and receives nothing live — its shadows are in the lightmap.
27
+ */
28
+ import * as THREE from "three";
29
+ import { GLTFLoader, type GLTFLoaderPlugin, type GLTFParser } from "three/addons/loaders/GLTFLoader.js";
30
+ import { type GlbLoaderOptions } from "./world-loader.js";
31
+ import type { SceneBake } from "../protocol/worlds.js";
32
+ /** The glTF material extension a baked glb carries. */
33
+ export declare const RYDR_LIGHTMAP_EXTENSION = "RYDR_lightmap";
34
+ /** `materials[i].extensions.RYDR_lightmap`. */
35
+ export interface RydrLightmapDef {
36
+ /** Index into the glb's `textures`. */
37
+ index: number;
38
+ /** Which UV set samples it. Always 1 from the pipeline. */
39
+ texCoord?: number;
40
+ /** `lightMapIntensity`: π × the atlas's encode scale. */
41
+ intensity: number;
42
+ }
43
+ /** Node extras the export writes and the bake carries through (see the platform's bake docs). */
44
+ export declare const BAKE_EXTRAS: {
45
+ /** `"static"` (gets a lightmap) or `"occluder"` (casts in the bake, then dropped). */
46
+ readonly role: "rydr_role";
47
+ /** true on meshes a moving object's live shadow must land on (a road). */
48
+ readonly receiveShadow: "rydr_receive_shadow";
49
+ /** Texels per metre wanted for this mesh. */
50
+ readonly density: "rydr_lm_density";
51
+ /** Atlas preference, e.g. `"near-road"`. */
52
+ readonly atlasHint: "rydr_atlas_hint";
53
+ /** Written BY the bake: the atlas a mesh ended up in. */
54
+ readonly lightmap: "rydr_lightmap";
55
+ /**
56
+ * `"world"` (the platform world's geometry) or `"game"` (what the game added: a road, walls). Lets a
57
+ * game tell the two apart in a baked scene — racing probes the drivable height off the WORLD alone.
58
+ */
59
+ readonly layer: "rydr_layer";
60
+ };
61
+ /** Name of the empty node carrying the bake manifest (a JSON string in its extras). */
62
+ export declare const BAKE_MANIFEST_NODE = "RYDR_BAKE_MANIFEST";
63
+ /** The extras key on {@link BAKE_MANIFEST_NODE}. */
64
+ export declare const BAKE_MANIFEST_KEY = "rydr_bake_manifest";
65
+ /**
66
+ * GLTFLoader plugin for `RYDR_lightmap`: assigns the atlas as the material's `lightMap` on UV channel 1
67
+ * with the extension's intensity. Register it on any GLTFLoader that may meet a baked glb:
68
+ * `loader.register((parser) => new RydrLightmapPlugin(parser))`.
69
+ */
70
+ export declare class RydrLightmapPlugin implements GLTFLoaderPlugin {
71
+ private readonly parser;
72
+ readonly name = "RYDR_lightmap";
73
+ constructor(parser: GLTFParser);
74
+ extendMaterialParams(materialIndex: number, materialParams: Record<string, unknown>): Promise<unknown>;
75
+ }
76
+ /** Add the {@link RydrLightmapPlugin} to a loader (idempotent per loader instance is the caller's job). */
77
+ export declare function registerBakedLighting(loader: GLTFLoader): GLTFLoader;
78
+ /**
79
+ * The material a baked mesh renders with: `albedo × lightmap`, unlit by the live rig.
80
+ *
81
+ * Returns `src` untouched when it has no lightmap (a mesh the bake skipped stays lit live, rather than
82
+ * turning black). Emissive surfaces keep their glow — a lit window IS its emission — via a two-line
83
+ * shader addition, since `MeshBasicMaterial` has no emissive of its own.
84
+ */
85
+ export declare function toBakedMaterial(src: THREE.Material): THREE.Material;
86
+ export interface LoadBakedSceneOptions extends GlbLoaderOptions {
87
+ /** Merge the static meshes by material (≈ one draw per material), as `loadWorld({ mergeStatics })`. */
88
+ mergeStatics?: boolean;
89
+ }
90
+ /** A loaded baked scene. Same lifecycle contract as `LoadedWorld`. */
91
+ export interface LoadedBakedScene {
92
+ /** The glb's path — the cache key. */
93
+ readonly id: string;
94
+ readonly group: THREE.Group;
95
+ /** Meshes the export marked `rydr_receive_shadow` — hand them to {@link createShadowCatcher}. */
96
+ readonly receivers: THREE.Mesh[];
97
+ /** The manifest the export embedded (fingerprints, preset…), or null for a glb without one. */
98
+ readonly manifest: BakeManifest | null;
99
+ attach(parent: THREE.Object3D): void;
100
+ detach(): void;
101
+ dispose(): void;
102
+ }
103
+ /** What the export embeds in {@link BAKE_MANIFEST_NODE}. Parsed as-is; fields may grow. */
104
+ export interface BakeManifest {
105
+ format: number;
106
+ worldId?: string;
107
+ presetId?: string;
108
+ worldFingerprint?: string;
109
+ layer?: {
110
+ game: string;
111
+ docId: string;
112
+ fingerprint: string;
113
+ };
114
+ [key: string]: unknown;
115
+ }
116
+ /**
117
+ * Load (and cache by glb path) a baked scene, with every lightmapped material swapped for its
118
+ * {@link toBakedMaterial}. Pass the {@link SceneBake} (or its url). Rejects if the glb fails to load —
119
+ * the caller falls back to rendering live.
120
+ */
121
+ export declare function loadBakedScene(bake: SceneBake | string, opts?: LoadBakedSceneOptions): Promise<LoadedBakedScene>;
122
+ /** Drop cached baked scenes (all, or one glb path) and free them. */
123
+ export declare function clearBakedSceneCache(url?: string): void;
124
+ export interface ShadowCatcherOptions {
125
+ /** How dark a live shadow gets on the baked ground. Default 0.45. */
126
+ opacity?: number;
127
+ }
128
+ /** A shadow-catcher overlay; `dispose` removes and frees it. */
129
+ export interface ShadowCatcher {
130
+ readonly meshes: THREE.Mesh[];
131
+ setOpacity(opacity: number): void;
132
+ dispose(): void;
133
+ }
134
+ /**
135
+ * Put a moving object's LIVE shadow on baked ground: one `ShadowMaterial` overlay per receiver, sharing
136
+ * its geometry and parented to it (so it follows exactly, at zero extra memory), drawn just in front
137
+ * of it with a polygon offset.
138
+ *
139
+ * It only darkens, which is the point — the receiver's own lighting is the lightmap and must not
140
+ * change. The catcher needs the game's sun to cast shadows as it already does; nothing else about the
141
+ * live rig changes.
142
+ */
143
+ export declare function createShadowCatcher(receivers: readonly THREE.Mesh[], opts?: ShadowCatcherOptions): ShadowCatcher;
144
+ //# sourceMappingURL=baked-lighting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"baked-lighting.d.ts","sourceRoot":"","sources":["../../src/three/baked-lighting.ts"],"names":[],"mappings":"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"}