tosijs-3d 0.7.0 → 0.7.2

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.
Files changed (59) hide show
  1. package/CHANGELOG.md +78 -0
  2. package/dist/b3d-ambient.js +1 -1
  3. package/dist/b3d-biped.js +1 -1
  4. package/dist/b3d-clouds.d.ts.map +1 -1
  5. package/dist/b3d-clouds.js +13 -35
  6. package/dist/b3d-clouds.js.map +1 -1
  7. package/dist/b3d-death.d.ts.map +1 -1
  8. package/dist/b3d-death.js +12 -5
  9. package/dist/b3d-death.js.map +1 -1
  10. package/dist/b3d-destroyable.d.ts +12 -0
  11. package/dist/b3d-destroyable.d.ts.map +1 -1
  12. package/dist/b3d-destroyable.js +17 -2
  13. package/dist/b3d-destroyable.js.map +1 -1
  14. package/dist/b3d-exploder.js +1 -1
  15. package/dist/b3d-fog.js +1 -1
  16. package/dist/b3d-launcher.d.ts +14 -0
  17. package/dist/b3d-launcher.d.ts.map +1 -1
  18. package/dist/b3d-launcher.js +25 -5
  19. package/dist/b3d-launcher.js.map +1 -1
  20. package/dist/b3d-library.js +2 -2
  21. package/dist/b3d-light.js +1 -1
  22. package/dist/b3d-loader.js +1 -1
  23. package/dist/b3d-particles.js +1 -1
  24. package/dist/b3d-physics.js +1 -1
  25. package/dist/b3d-radar.js +2 -2
  26. package/dist/b3d-reflections.js +1 -1
  27. package/dist/b3d-shadows.js +1 -1
  28. package/dist/b3d-skybox.js +1 -1
  29. package/dist/b3d-sound.js +1 -1
  30. package/dist/b3d-svg-plane.d.ts +29 -0
  31. package/dist/b3d-svg-plane.d.ts.map +1 -1
  32. package/dist/b3d-svg-plane.js +136 -6
  33. package/dist/b3d-svg-plane.js.map +1 -1
  34. package/dist/b3d-trigger.js +1 -1
  35. package/dist/b3d-turret.js +1 -1
  36. package/dist/b3d-warhead.js +1 -1
  37. package/dist/b3d-water.js +1 -1
  38. package/dist/biome-chart.js +1 -1
  39. package/dist/cloud-shadows.js +2 -2
  40. package/dist/demo-utils.d.ts +166 -0
  41. package/dist/demo-utils.d.ts.map +1 -0
  42. package/dist/demo-utils.js +232 -0
  43. package/dist/demo-utils.js.map +1 -0
  44. package/dist/dialog-placement.d.ts +68 -0
  45. package/dist/dialog-placement.d.ts.map +1 -0
  46. package/dist/dialog-placement.js +130 -0
  47. package/dist/dialog-placement.js.map +1 -0
  48. package/dist/formations.js +1 -1
  49. package/dist/glass-gamepad.js +1 -1
  50. package/dist/make-mesh.js +2 -2
  51. package/dist/popup-surface.js +2 -2
  52. package/dist/shadow-decal.d.ts.map +1 -1
  53. package/dist/shadow-decal.js +12 -3
  54. package/dist/shadow-decal.js.map +1 -1
  55. package/dist/svg-texture.js +1 -1
  56. package/dist/tosi-b3d.d.ts.map +1 -1
  57. package/dist/tosi-b3d.js +6 -8
  58. package/dist/tosi-b3d.js.map +1 -1
  59. package/package.json +12 -2
@@ -25,7 +25,7 @@ keep up even when smart.
25
25
 
26
26
  ```js
27
27
  import { b3d, b3dTurret, b3dDestroyable, b3dLight, b3dSkybox, b3dGround, label3d, slider3d, sceneDelta } from 'tosijs-3d'
28
- import { orbitCam } from 'demo-utils'
28
+ import { orbitCam } from 'tosijs-3d/demo-utils'
29
29
  import { tosi } from 'tosijs'
30
30
 
31
31
  const { s } = tosi({ s: { traverseRate: 2.5, range: 30, fireRate: 2, muzzleSpeed: 24, smart: 0 } })
@@ -26,7 +26,7 @@ sight** off in the ⚙ panel and the wall stops mattering.
26
26
 
27
27
  ```js
28
28
  import { b3d, b3dController, b3dWarhead, b3dDestroyable, b3dLight, b3dSkybox, b3dGround, label3d, slider3d, toggle3d } from 'tosijs-3d'
29
- import { orbitCam } from 'demo-utils'
29
+ import { orbitCam } from 'tosijs-3d/demo-utils'
30
30
  import { tosi } from 'tosijs'
31
31
 
32
32
  const { s } = tosi({ s: { damage: 20, fullRadius: 1.5, blastRadius: 5, los: true } })
package/dist/b3d-water.js CHANGED
@@ -10,7 +10,7 @@ sky and the crates. Drag to orbit — dip the camera below the surface and the w
10
10
 
11
11
  ```js
12
12
  import { b3d, b3dSkybox, b3dWater, b3dReflections, b3dGround, sceneDelta } from 'tosijs-3d'
13
- import { demoSun, orbitCam, spinner } from 'demo-utils'
13
+ import { demoSun, orbitCam, spinner } from 'tosijs-3d/demo-utils'
14
14
 
15
15
  const scene = b3d(
16
16
  {
@@ -51,7 +51,7 @@ import {
51
51
  toggle3d, mesaProfile, beachProfile, cliffProfile, blendProfiles,
52
52
  profileField, LAVA_PALETTE, CRYOVOLCANIC_PALETTE, volcano,
53
53
  } from 'tosijs-3d'
54
- import { orbitCam } from 'demo-utils'
54
+ import { orbitCam } from 'tosijs-3d/demo-utils'
55
55
 
56
56
  // PINNED showcase vista — seed + scales chosen so this exact terrain shows
57
57
  // every spec transition at once. Change DELIBERATELY, with the page open: the
@@ -19,7 +19,7 @@ drift across the ground and the crates below. Drag to orbit; watch the dark patc
19
19
 
20
20
  ```js
21
21
  import { b3d, b3dClouds, b3dBox } from 'tosijs-3d'
22
- import { demoStage, orbitCam } from 'demo-utils'
22
+ import { demoStage, orbitCam } from 'tosijs-3d/demo-utils'
23
23
 
24
24
  const scene = b3d(
25
25
  {
@@ -36,7 +36,7 @@ const scene = b3d(
36
36
  // On the stage — cloud shadows are DARKENING, so the scene needs a fill light
37
37
  // to darken FROM. Sun alone put every unlit face at zero and the demo read as
38
38
  // black boxes on a black floor.
39
- ...demoStage({ size: 160, tiles: 26, pattern: true, timeOfDay: 11, sun: { x: -0.5, y: -1, z: -0.35 } }),
39
+ ...demoStage({ size: 160, tiles: 26, texture: '/tosi-warhol-testgrid.svg', timeOfDay: 11, sun: { x: -0.5, y: -1, z: -0.35 } }),
40
40
  b3dClouds({ model: '/cloud.glb', altitude: 115, thickness: 18, spread: 200, size: 38, coverage: 0.5, castShadows: true, shadowStrength: 0.7, seed: 3 }),
41
41
  ...Array.from({ length: 9 }, (_, i) =>
42
42
  b3dBox({ meshName: `crate-${i}`, size: 3, x: (i % 3) * 10 - 10, y: 1.5, z: Math.floor(i / 3) * 10 - 10, color: '#7a9b6e' })
@@ -0,0 +1,166 @@
1
+ import * as BABYLON from '@babylonjs/core';
2
+ /** The `<tosi-b3d>` element an example receives as `el` — just the parts these touch. */
3
+ export type DemoHost = {
4
+ scene: BABYLON.Scene;
5
+ setActiveCamera(camera: BABYLON.Camera): void;
6
+ querySelector(selector: string): Element | null;
7
+ register?(additions: {
8
+ meshes?: BABYLON.AbstractMesh[];
9
+ }): void;
10
+ };
11
+ export interface DemoSunOptions {
12
+ intensity?: number;
13
+ /** `0` (default) = the device-tier budget. Set a size only to override it. */
14
+ shadowTextureSize?: number;
15
+ shadowCascading?: boolean;
16
+ shadowMaxZ?: number;
17
+ y?: number;
18
+ }
19
+ /**
20
+ * A sun that CASTS shadows — the "when in doubt, add a shadow light" default.
21
+ *
22
+ * `shadowTextureSize` defaults to the **auto sentinel `0`**, not a hard-wired
23
+ * 2048. A fixed size overrode the device-tier budget for every demo including
24
+ * on a headset, which is 4× the shadow VRAM on the tier least able to pay it.
25
+ * Acne is handled by `shadowNormalBias` instead, which costs nothing.
26
+ */
27
+ export declare function demoSun(opts?: DemoSunOptions): import("./b3d-shadows").B3dSun;
28
+ export interface PatternGroundOptions {
29
+ size?: number;
30
+ tiles?: number;
31
+ color?: string;
32
+ /**
33
+ * Texture URL. Omitted = a generated checker, which needs no asset and so
34
+ * works in any project. (This replaces the old `pattern: boolean`, which
35
+ * pointed at a file that exists only on the doc site.)
36
+ */
37
+ texture?: string;
38
+ }
39
+ /**
40
+ * A ground that RECEIVES shadows. A test pattern reads the light far better
41
+ * than a flat colour — a flat ground hides the lighting, the shadows and the UV
42
+ * mapping at once, which is how a scene ends up looking broken when it is
43
+ * merely bland.
44
+ */
45
+ export declare function patternGround(opts?: PatternGroundOptions): import("./b3d-primitives").B3dGround;
46
+ export interface DemoStageOptions extends PatternGroundOptions {
47
+ timeOfDay?: number;
48
+ sun?: DemoSunOptions;
49
+ /** Hemispheric fill. `0` turns it off for a hard, airless look. */
50
+ fill?: number;
51
+ }
52
+ /**
53
+ * The whole "make it not look like a test harness" setup in one spread: a sun
54
+ * that casts, a sky to light and reflect, and a ground that shows both.
55
+ *
56
+ * ```js
57
+ * b3d({ ... }, ...demoStage({ texture: '/my-grid.png' }), myThing)
58
+ * ```
59
+ *
60
+ * The fill light is not optional-by-taste: a directional sun alone leaves every
61
+ * unlit face at ZERO, so objects read as black silhouettes rather than objects.
62
+ * Real outdoor light has sky bounce; a hemispheric light is the cheap stand-in.
63
+ */
64
+ export declare function demoStage(opts?: DemoStageOptions): (import("./b3d-primitives").B3dGround | import("./b3d-shadows").B3dSun | import("./b3d-skybox").B3dSkybox | import("./b3d-light").B3dLight)[];
65
+ export interface OrbitCamOptions {
66
+ /** Orbit angle around Y, in DEGREES. Default −90 (facing −Z). */
67
+ alphaDeg?: number;
68
+ /** Tilt from vertical, in DEGREES. Default 60. */
69
+ betaDeg?: number;
70
+ radius?: number;
71
+ target?: [number, number, number];
72
+ /** Keep the camera at least this far above horizontal. `null` opts out. */
73
+ minElevationDeg?: number | null;
74
+ /** Stop it going exactly top-down. `null` opts out. */
75
+ maxElevationDeg?: number | null;
76
+ /** @deprecated pre-0.7.1 radians — use `alphaDeg`. Converted if given. */
77
+ alpha?: number;
78
+ /** @deprecated pre-0.7.1 radians — use `betaDeg`. Converted if given. */
79
+ beta?: number;
80
+ }
81
+ /**
82
+ * The standard `ArcRotateCamera` every demo sets up — one call instead of six
83
+ * lines. Call it in `sceneCreated`.
84
+ *
85
+ * Clamps the tilt by DEFAULT so you cannot drag the view below the horizon and
86
+ * see the world from underneath (an `ArcRotateCamera` happily orbits under the
87
+ * floor otherwise — a long-standing demo papercut).
88
+ *
89
+ * **Degrees**, per the framework rule that a bare angle name is already
90
+ * degrees. The old radian `alpha`/`beta` are still accepted and converted, so
91
+ * existing snippets keep working; they are the one place in this module where
92
+ * radians appear at all.
93
+ */
94
+ export declare function orbitCam(el: DemoHost, opts?: OrbitCamOptions): BABYLON.ArcRotateCamera;
95
+ export interface SpinnerOptions {
96
+ size?: number;
97
+ x?: number;
98
+ y?: number;
99
+ z?: number;
100
+ /** Revolutions per second. */
101
+ spin?: number;
102
+ /** Texture URL. Omitted = an untextured box. */
103
+ texture?: string;
104
+ }
105
+ /**
106
+ * A slowly-rotating box — the "non-static object so you can see the shadow
107
+ * move" prop. Registers itself as a shadow caster so `demoSun`/`b3dSun` picks
108
+ * it up. Call in `sceneCreated`.
109
+ */
110
+ export declare function spinner(el: DemoHost, opts?: SpinnerOptions): BABYLON.Mesh;
111
+ export interface FlightStageOptions {
112
+ /**
113
+ * Builds a FRESH aircraft. A factory, not an instance — respawn has to
114
+ * construct a new one, and a demo that passed an instance was unrecoverable
115
+ * after the first crash.
116
+ */
117
+ plane: () => any;
118
+ /** Ground extent. Default 4000 — an aircraft needs somewhere to go. */
119
+ size?: number;
120
+ timeOfDay?: number;
121
+ /** GLB holding the vehicle library, if the plane uses `library:`. */
122
+ library?: string;
123
+ libraryType?: string;
124
+ /** Distance fog. `false` for a hard, airless look. */
125
+ fog?: boolean;
126
+ groundColor?: string;
127
+ /** Heading on the death panel. */
128
+ title?: string;
129
+ }
130
+ /**
131
+ * A setting an aircraft can actually operate in — the flight equivalent of
132
+ * {@link demoStage}, and the fix for three demos that each forgot a different
133
+ * piece of it.
134
+ *
135
+ * What it includes, and why each is here rather than left to the caller:
136
+ *
137
+ * - **A `b3dDeath` with a working respawn.** Without one, `crash()` releases
138
+ * input focus and leaves you holding nothing — no wreck to fly, no panel, no
139
+ * way back. That reads as the demo seizing up rather than as dying, and it is
140
+ * why `plane` is a factory.
141
+ * - **A sun configured for the ground it lights.** A 4000-unit ground with the
142
+ * default single shadow map puts the aircraft's shadow in a coarse far
143
+ * cascade where it is invisible, and `shadowMaxZ` at its default of 100 drops
144
+ * shadows entirely once you climb.
145
+ * - **Ground, sky and fog at flight scale**, which every flight demo otherwise
146
+ * retypes slightly differently.
147
+ *
148
+ * Returns an object rather than an array (unlike `demoStage`) because the stage
149
+ * owns an IDENTITY: the current aircraft changes on respawn, so a readout that
150
+ * captured the first one would go stale.
151
+ *
152
+ * ```js
153
+ * const stage = flightStage({
154
+ * plane: () => b3dAircraft({ library: 'vehicles', meshName: 'scout', player: true, y: 40 }),
155
+ * library: '/test-3.glb',
156
+ * })
157
+ * const scene = b3d({ gamepad: true }, ...stage.elements)
158
+ * // stage.aircraft is always the one you are flying NOW
159
+ * ```
160
+ */
161
+ export declare function flightStage(opts: FlightStageOptions): {
162
+ elements: (import("./b3d-primitives").B3dGround | import("./b3d-input-focus").B3dInputFocus | import("./b3d-death").B3dDeath | import("./b3d-shadows").B3dSun | import("./b3d-skybox").B3dSkybox | import("./b3d-fog").B3dFog | import("./b3d-library").B3dLibrary | import("./b3d-light").B3dLight)[];
163
+ /** The aircraft you are flying NOW — changes on respawn. */
164
+ readonly aircraft: any;
165
+ };
166
+ //# sourceMappingURL=demo-utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo-utils.d.ts","sourceRoot":"","sources":["../src/demo-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,232 @@
1
+ /*#
2
+ # demo-utils
3
+
4
+ **Scene-setup helpers for examples and prototypes** — the "when in doubt" defaults
5
+ that make a scene look like a scene instead of a test harness. Every live example
6
+ on this site uses them, which is why they are published: the code you copy off a
7
+ doc page should run in your project unchanged.
8
+
9
+ > ## ⚠️ These are DEV HELPERS. Do not build on them.
10
+ >
11
+ > They exist so examples run, and they are **not** covered by the care the main
12
+ > API gets:
13
+ >
14
+ > - **They can change or disappear in a patch release.** No deprecation period,
15
+ > no migration note.
16
+ > - **They are tuned for looking good in a doc page**, not for your game — the
17
+ > numbers are chosen to flatter a cube on a grey ground.
18
+ > - **They are not a design system.** `demoStage` is three components in a
19
+ > trench coat; when you outgrow it, inline what it does and delete the import.
20
+ >
21
+ > Production code should compose `b3dSun`/`b3dSkybox`/`b3dGround` directly. If
22
+ > you find yourself wanting a helper to be *stable*, that is the signal it
23
+ > belongs in the main API — open an issue rather than pinning a version.
24
+
25
+ ```js
26
+ import { b3d, b3dBox } from 'tosijs-3d'
27
+ import { demoStage, orbitCam } from 'tosijs-3d/demo-utils'
28
+
29
+ const scene = b3d(
30
+ { sceneCreated: (el) => orbitCam(el, { radius: 8 }) },
31
+ ...demoStage({ texture: '/tosi-warhol-testgrid.svg' }),
32
+ b3dBox({ y: 1 }),
33
+ )
34
+ preview.append(scene)
35
+ ```
36
+
37
+ ## What's here
38
+
39
+ | Helper | What it does |
40
+ | --- | --- |
41
+ | `demoStage(opts)` | Sun + fill + sky + ground, spread into a `b3d(...)` |
42
+ | `demoSun(opts)` | A sun that casts shadows, at the device's shadow budget |
43
+ | `patternGround(opts)` | A ground that RECEIVES shadows and shows the light |
44
+ | `orbitCam(el, opts)` | The standard orbit camera, tilt-clamped, in `sceneCreated` |
45
+ | `spinner(el, opts)` | A slowly-rotating textured box, so you can see shadows move |
46
+ | `flightStage(opts)` | A setting an **aircraft** can operate in — stage, library, and a death panel that respawns you |
47
+
48
+ ## Angles are DEGREES
49
+
50
+ `orbitCam` takes `alphaDeg`/`betaDeg`, per the framework rule: a bare angle name
51
+ is already degrees, and radians appear only where the maths needs them (see
52
+ CLAUDE.md → Angles). The pre-0.7.1 `alpha`/`beta` radian pair is still accepted
53
+ and converted, so old snippets keep working.
54
+
55
+ ## Textures
56
+
57
+ Helpers take a `texture` URL rather than exporting asset paths. The paths that
58
+ used to be exported (`/tosi-test-pattern.svg`) resolve only on **this** site, so
59
+ publishing them would have been a broken promise in your project. Pass your own,
60
+ or omit it for a generated checker that needs no asset at all.
61
+ */
62
+ /*{ "parent": "Utilities" }*/
63
+ import * as BABYLON from '@babylonjs/core';
64
+ import { b3dSun, b3dSkybox, b3dLight, b3dGround, b3dFog, b3dLibrary, b3dDeath, inputFocus, gameController, } from './index';
65
+ const DEG = Math.PI / 180;
66
+ /**
67
+ * A sun that CASTS shadows — the "when in doubt, add a shadow light" default.
68
+ *
69
+ * `shadowTextureSize` defaults to the **auto sentinel `0`**, not a hard-wired
70
+ * 2048. A fixed size overrode the device-tier budget for every demo including
71
+ * on a headset, which is 4× the shadow VRAM on the tier least able to pay it.
72
+ * Acne is handled by `shadowNormalBias` instead, which costs nothing.
73
+ */
74
+ export function demoSun(opts = {}) {
75
+ return b3dSun({ intensity: 0.9, shadowTextureSize: 0, ...opts });
76
+ }
77
+ /**
78
+ * A ground that RECEIVES shadows. A test pattern reads the light far better
79
+ * than a flat colour — a flat ground hides the lighting, the shadows and the UV
80
+ * mapping at once, which is how a scene ends up looking broken when it is
81
+ * merely bland.
82
+ */
83
+ export function patternGround(opts = {}) {
84
+ const { size = 40, tiles = 16, color = '#8a9b7e', texture } = opts;
85
+ return b3dGround({
86
+ width: size,
87
+ height: size,
88
+ texture: texture ?? 'checker',
89
+ textureTiles: texture ? Math.max(1, Math.round(tiles / 4)) : tiles,
90
+ color,
91
+ });
92
+ }
93
+ /**
94
+ * The whole "make it not look like a test harness" setup in one spread: a sun
95
+ * that casts, a sky to light and reflect, and a ground that shows both.
96
+ *
97
+ * ```js
98
+ * b3d({ ... }, ...demoStage({ texture: '/my-grid.png' }), myThing)
99
+ * ```
100
+ *
101
+ * The fill light is not optional-by-taste: a directional sun alone leaves every
102
+ * unlit face at ZERO, so objects read as black silhouettes rather than objects.
103
+ * Real outdoor light has sky bounce; a hemispheric light is the cheap stand-in.
104
+ */
105
+ export function demoStage(opts = {}) {
106
+ const { timeOfDay = 11, sun = {}, fill = 0.35, ...ground } = opts;
107
+ return [
108
+ demoSun(sun),
109
+ ...(fill > 0 ? [b3dLight({ y: 1, intensity: fill })] : []),
110
+ b3dSkybox({ timeOfDay }),
111
+ patternGround(ground),
112
+ ];
113
+ }
114
+ /**
115
+ * The standard `ArcRotateCamera` every demo sets up — one call instead of six
116
+ * lines. Call it in `sceneCreated`.
117
+ *
118
+ * Clamps the tilt by DEFAULT so you cannot drag the view below the horizon and
119
+ * see the world from underneath (an `ArcRotateCamera` happily orbits under the
120
+ * floor otherwise — a long-standing demo papercut).
121
+ *
122
+ * **Degrees**, per the framework rule that a bare angle name is already
123
+ * degrees. The old radian `alpha`/`beta` are still accepted and converted, so
124
+ * existing snippets keep working; they are the one place in this module where
125
+ * radians appear at all.
126
+ */
127
+ export function orbitCam(el, opts = {}) {
128
+ const { radius = 14, target = [0, 0.8, 0], minElevationDeg = 5, maxElevationDeg = 89, } = opts;
129
+ const alpha = opts.alpha ?? (opts.alphaDeg ?? -90) * DEG;
130
+ const beta = opts.beta ?? (opts.betaDeg ?? 60) * DEG;
131
+ const cam = new BABYLON.ArcRotateCamera('demo-cam', alpha, beta, radius, new BABYLON.Vector3(target[0], target[1], target[2]), el.scene);
132
+ cam.attachControl(el.querySelector('canvas'), true);
133
+ // beta is measured from straight-up (0) to straight-down (π); π/2 is level.
134
+ // Elevation ABOVE horizontal = π/2 − beta, so a MIN elevation is an UPPER
135
+ // beta limit.
136
+ if (minElevationDeg != null)
137
+ cam.upperBetaLimit = Math.PI / 2 - minElevationDeg * DEG;
138
+ if (maxElevationDeg != null)
139
+ cam.lowerBetaLimit = Math.PI / 2 - maxElevationDeg * DEG;
140
+ el.setActiveCamera(cam);
141
+ return cam;
142
+ }
143
+ /**
144
+ * A slowly-rotating box — the "non-static object so you can see the shadow
145
+ * move" prop. Registers itself as a shadow caster so `demoSun`/`b3dSun` picks
146
+ * it up. Call in `sceneCreated`.
147
+ */
148
+ export function spinner(el, opts = {}) {
149
+ const { size = 2, x = 0, y = 1.2, z = 0, spin = 0.12, texture } = opts;
150
+ const box = BABYLON.MeshBuilder.CreateBox('spinner', { size }, el.scene);
151
+ box.position.set(x, y, z);
152
+ const mat = new BABYLON.StandardMaterial('spinner-mat', el.scene);
153
+ if (texture)
154
+ mat.diffuseTexture = new BABYLON.Texture(texture, el.scene);
155
+ box.material = mat;
156
+ el.register?.({ meshes: [box] });
157
+ el.scene.onBeforeRenderObservable.add(() => {
158
+ box.rotation.y += spin * 0.016 * Math.PI * 2;
159
+ });
160
+ return box;
161
+ }
162
+ /**
163
+ * A setting an aircraft can actually operate in — the flight equivalent of
164
+ * {@link demoStage}, and the fix for three demos that each forgot a different
165
+ * piece of it.
166
+ *
167
+ * What it includes, and why each is here rather than left to the caller:
168
+ *
169
+ * - **A `b3dDeath` with a working respawn.** Without one, `crash()` releases
170
+ * input focus and leaves you holding nothing — no wreck to fly, no panel, no
171
+ * way back. That reads as the demo seizing up rather than as dying, and it is
172
+ * why `plane` is a factory.
173
+ * - **A sun configured for the ground it lights.** A 4000-unit ground with the
174
+ * default single shadow map puts the aircraft's shadow in a coarse far
175
+ * cascade where it is invisible, and `shadowMaxZ` at its default of 100 drops
176
+ * shadows entirely once you climb.
177
+ * - **Ground, sky and fog at flight scale**, which every flight demo otherwise
178
+ * retypes slightly differently.
179
+ *
180
+ * Returns an object rather than an array (unlike `demoStage`) because the stage
181
+ * owns an IDENTITY: the current aircraft changes on respawn, so a readout that
182
+ * captured the first one would go stale.
183
+ *
184
+ * ```js
185
+ * const stage = flightStage({
186
+ * plane: () => b3dAircraft({ library: 'vehicles', meshName: 'scout', player: true, y: 40 }),
187
+ * library: '/test-3.glb',
188
+ * })
189
+ * const scene = b3d({ gamepad: true }, ...stage.elements)
190
+ * // stage.aircraft is always the one you are flying NOW
191
+ * ```
192
+ */
193
+ export function flightStage(opts) {
194
+ const { plane, size = 4000, timeOfDay = 10, library, libraryType = 'vehicles', fog = true, groundColor = '#6b7f5e', title = 'DOWN', } = opts;
195
+ let current = plane();
196
+ const focus = inputFocus(gameController(), current);
197
+ const elements = [
198
+ b3dLight({ y: 1, intensity: 0.6 }),
199
+ // Cascaded, with a shadowMaxZ that still reaches the ground from cruising
200
+ // altitude. `shadowTextureSize` stays on the auto sentinel so the device
201
+ // tier decides — a hard-wired size is 4x the VRAM on the tier least able to
202
+ // pay for it.
203
+ b3dSun({ intensity: 0.9, shadowCascading: true, shadowMaxZ: 600 }),
204
+ b3dSkybox({ timeOfDay }),
205
+ ...(fog
206
+ ? [b3dFog({ start: size / 10, end: size * 0.75, color: '#bfd9f2' })]
207
+ : []),
208
+ b3dGround({
209
+ meshName: 'ground_nocast',
210
+ width: size,
211
+ height: size,
212
+ color: groundColor,
213
+ }),
214
+ ...(library ? [b3dLibrary({ url: library, type: libraryType })] : []),
215
+ b3dDeath({
216
+ title,
217
+ respawn() {
218
+ current = plane();
219
+ focus.appendChild(current);
220
+ },
221
+ }),
222
+ focus,
223
+ ];
224
+ return {
225
+ elements,
226
+ /** The aircraft you are flying NOW — changes on respawn. */
227
+ get aircraft() {
228
+ return current;
229
+ },
230
+ };
231
+ }
232
+ //# sourceMappingURL=demo-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demo-utils.js","sourceRoot":"","sources":["../src/demo-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,68 @@
1
+ /** Minimal vector — deliberately not Babylon's, so this module stays pure. */
2
+ export interface Vec3 {
3
+ x: number;
4
+ y: number;
5
+ z: number;
6
+ }
7
+ /** Unit vector, or `null` for a zero-length input (which has no direction). */
8
+ export declare function normalize(v: Vec3): Vec3 | null;
9
+ /**
10
+ * Angle in DEGREES between where the viewer looks and where the dialog is.
11
+ *
12
+ * Returns `0` when the dialog is exactly on the view axis and `180` when it is
13
+ * directly behind. A dialog at the viewer's own position has no direction, and
14
+ * is reported as `0` — on-axis — because "you are inside it" is not a reason to
15
+ * go and fetch it.
16
+ */
17
+ export declare function gazeOffAxisDeg(eye: Vec3, forward: Vec3, dialog: Vec3): number;
18
+ /** How long the dialog has been out of view, in seconds. */
19
+ export interface GazeState {
20
+ offAxisSec: number;
21
+ }
22
+ export declare const newGazeState: () => GazeState;
23
+ export interface GazeOptions {
24
+ /** Half-angle you may look away by before the clock starts. Default 55°. */
25
+ coneDeg?: number;
26
+ /** Seconds outside the cone before the dialog comes to you. Default 2. */
27
+ holdSec?: number;
28
+ }
29
+ /**
30
+ * Advance the look-away clock and say whether the dialog should re-place.
31
+ *
32
+ * The clock **resets** the moment the dialog is back inside the cone, so a
33
+ * glance away costs nothing — only sustained inattention moves it. Returns the
34
+ * next state alongside the decision rather than mutating, so the rule is
35
+ * testable and the caller owns the state.
36
+ */
37
+ export declare function gazeStep(state: GazeState, offAxisDeg: number, dt: number, opts?: GazeOptions): {
38
+ state: GazeState;
39
+ recover: boolean;
40
+ };
41
+ /**
42
+ * Pick the best of several candidate distances — the results of casting a ray
43
+ * along each candidate direction.
44
+ *
45
+ * `Infinity` means nothing was hit, i.e. fully clear. The winner is the
46
+ * candidate with the most room, preferring EARLIER candidates on a tie so a
47
+ * caller can order them by desirability (straight ahead first). Returns `-1`
48
+ * when every candidate is too cramped to use.
49
+ */
50
+ export declare function bestCandidate(clearances: number[], minClearance: number): number;
51
+ /**
52
+ * How far along a candidate direction to actually sit.
53
+ *
54
+ * Short of the obstruction by `margin` so the panel is not coplanar with a wall,
55
+ * never past the distance you asked for, and never closer than `minZ` — a panel
56
+ * at arm's length is uncomfortable in a headset, which is why "just use the near
57
+ * clip plane" is the wrong version of this idea.
58
+ */
59
+ export declare function placementDistance(clearance: number, desired: number, minZ?: number, margin?: number): number;
60
+ /**
61
+ * Ease a position toward a target — frame-rate independent.
62
+ *
63
+ * `smoothing` is the fraction of the remaining distance left after one second,
64
+ * so the result does not change when the frame rate does (the naive
65
+ * `lerp(a, b, 0.1)` per frame moves twice as fast at 120fps as at 60).
66
+ */
67
+ export declare function easeTo(current: Vec3, target: Vec3, dt: number, smoothing?: number): Vec3;
68
+ //# sourceMappingURL=dialog-placement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog-placement.d.ts","sourceRoot":"","sources":["../src/dialog-placement.ts"],"names":[],"mappings":"AAiCA,8EAA8E;AAC9E,MAAM,WAAW,IAAI;IACnB,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;IACT,CAAC,EAAE,MAAM,CAAA;CACV;AASD,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAI9C;AAED;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,MAAM,CAM7E;AAED,4DAA4D;AAC5D,MAAM,WAAW,SAAS;IACxB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,YAAY,QAAO,SAAgC,CAAA;AAEhE,MAAM,WAAW,WAAW;IAC1B,4EAA4E;IAC5E,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;GAOG;AACH,wBAAgB,QAAQ,CACtB,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,MAAM,EAClB,EAAE,EAAE,MAAM,EACV,IAAI,GAAE,WAAgB,GACrB;IAAE,KAAK,EAAE,SAAS,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAMxC;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,UAAU,EAAE,MAAM,EAAE,EACpB,YAAY,EAAE,MAAM,GACnB,MAAM,CAYR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,IAAI,SAAM,EACV,MAAM,SAAO,GACZ,MAAM,CAGR;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CACpB,OAAO,EAAE,IAAI,EACb,MAAM,EAAE,IAAI,EACZ,EAAE,EAAE,MAAM,EACV,SAAS,SAAQ,GAChB,IAAI,CAON"}