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.
- package/CHANGELOG.md +78 -0
- package/dist/b3d-ambient.js +1 -1
- package/dist/b3d-biped.js +1 -1
- package/dist/b3d-clouds.d.ts.map +1 -1
- package/dist/b3d-clouds.js +13 -35
- package/dist/b3d-clouds.js.map +1 -1
- package/dist/b3d-death.d.ts.map +1 -1
- package/dist/b3d-death.js +12 -5
- package/dist/b3d-death.js.map +1 -1
- package/dist/b3d-destroyable.d.ts +12 -0
- package/dist/b3d-destroyable.d.ts.map +1 -1
- package/dist/b3d-destroyable.js +17 -2
- package/dist/b3d-destroyable.js.map +1 -1
- package/dist/b3d-exploder.js +1 -1
- package/dist/b3d-fog.js +1 -1
- package/dist/b3d-launcher.d.ts +14 -0
- package/dist/b3d-launcher.d.ts.map +1 -1
- package/dist/b3d-launcher.js +25 -5
- package/dist/b3d-launcher.js.map +1 -1
- package/dist/b3d-library.js +2 -2
- package/dist/b3d-light.js +1 -1
- package/dist/b3d-loader.js +1 -1
- package/dist/b3d-particles.js +1 -1
- package/dist/b3d-physics.js +1 -1
- package/dist/b3d-radar.js +2 -2
- package/dist/b3d-reflections.js +1 -1
- package/dist/b3d-shadows.js +1 -1
- package/dist/b3d-skybox.js +1 -1
- package/dist/b3d-sound.js +1 -1
- package/dist/b3d-svg-plane.d.ts +29 -0
- package/dist/b3d-svg-plane.d.ts.map +1 -1
- package/dist/b3d-svg-plane.js +136 -6
- package/dist/b3d-svg-plane.js.map +1 -1
- package/dist/b3d-trigger.js +1 -1
- package/dist/b3d-turret.js +1 -1
- package/dist/b3d-warhead.js +1 -1
- package/dist/b3d-water.js +1 -1
- package/dist/biome-chart.js +1 -1
- package/dist/cloud-shadows.js +2 -2
- package/dist/demo-utils.d.ts +166 -0
- package/dist/demo-utils.d.ts.map +1 -0
- package/dist/demo-utils.js +232 -0
- package/dist/demo-utils.js.map +1 -0
- package/dist/dialog-placement.d.ts +68 -0
- package/dist/dialog-placement.d.ts.map +1 -0
- package/dist/dialog-placement.js +130 -0
- package/dist/dialog-placement.js.map +1 -0
- package/dist/formations.js +1 -1
- package/dist/glass-gamepad.js +1 -1
- package/dist/make-mesh.js +2 -2
- package/dist/popup-surface.js +2 -2
- package/dist/shadow-decal.d.ts.map +1 -1
- package/dist/shadow-decal.js +12 -3
- package/dist/shadow-decal.js.map +1 -1
- package/dist/svg-texture.js +1 -1
- package/dist/tosi-b3d.d.ts.map +1 -1
- package/dist/tosi-b3d.js +6 -8
- package/dist/tosi-b3d.js.map +1 -1
- package/package.json +12 -2
package/dist/b3d-turret.js
CHANGED
|
@@ -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 } })
|
package/dist/b3d-warhead.js
CHANGED
|
@@ -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
|
{
|
package/dist/biome-chart.js
CHANGED
|
@@ -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
|
package/dist/cloud-shadows.js
CHANGED
|
@@ -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,
|
|
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"}
|