@adatechnology/game-test-room 0.11.0 → 0.12.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/README.md +80 -7
- package/dist/index.d.ts +291 -29
- package/dist/index.global.js +4843 -1998
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1535 -1640
- package/dist/index.js.map +1 -1
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -18,13 +18,13 @@ pnpm add @adatechnology/game-test-room three
|
|
|
18
18
|
|
|
19
19
|
```ts
|
|
20
20
|
import * as THREE from 'three'
|
|
21
|
-
import { createTestRoom
|
|
21
|
+
import { createTestRoom } from '@adatechnology/game-test-room'
|
|
22
22
|
|
|
23
23
|
const room = createTestRoom({
|
|
24
24
|
THREE,
|
|
25
25
|
container: document.getElementById('app')!,
|
|
26
26
|
locale: 'en', // 'en' or 'pt-BR'
|
|
27
|
-
catalog:
|
|
27
|
+
catalog: [], // the room ships no items: load modules (`room.loadModule`) or pass your own
|
|
28
28
|
})
|
|
29
29
|
room.runScenarios().then((report) => console.log(report.passed, report.failed))
|
|
30
30
|
console.log(room.log.toNDJSON())
|
|
@@ -39,7 +39,6 @@ const room = createTestRoom({
|
|
|
39
39
|
THREE,
|
|
40
40
|
container,
|
|
41
41
|
catalog: [
|
|
42
|
-
...demoItems('en'),
|
|
43
42
|
{ id: 'my_crate', name: 'My crate', group: 'Mine', build: (T) => buildMyCrate(T), specOptions: { /* material per mesh name */ } },
|
|
44
43
|
],
|
|
45
44
|
scenarios: [
|
|
@@ -56,8 +55,48 @@ const room = createTestRoom({
|
|
|
56
55
|
})
|
|
57
56
|
```
|
|
58
57
|
|
|
59
|
-
`
|
|
60
|
-
|
|
58
|
+
`buildFromSpec` turns a `DestructibleSpec` into meshes, and `brickWallSpec` (the arena's target wall) is exported to reuse.
|
|
59
|
+
|
|
60
|
+
## Breaking: the demo catalogue and the built-in scenarios are gone
|
|
61
|
+
|
|
62
|
+
The room used to ship 19 procedural box/cylinder items (`demoItems`, `DEMO_ITEMS`, `DEMO_MATERIALS`: chair, sofa, crate, jerrycan...) and its built-in scenarios (`SCENARIOS`, `scenariosFor`, `makeScenarios`) built on them. They were not the game's items, so they were removed: the room now holds only the generic contracts and the arena. Migrate:
|
|
63
|
+
|
|
64
|
+
- `catalog: demoItems(locale)` becomes `catalog: []`, and the items come from the SDK modules loaded with `room.loadModule` (weapons, items, household furniture, vehicles, characters...). `examples/interactables-test-area` loads all of them; `examples/test-room` opens with that set.
|
|
65
|
+
- `room.scenarios` is empty until the host passes `scenarios` or a module brings its own. The destruction checks the removed ones made (steel sheet, glass, concrete, fire, collapse) are covered by the tests of `game-destruction`, `game-fluids` and the module scenarios of the content packages.
|
|
66
|
+
- A test that needs a throwaway item should define it in its own fixture (see `tests/fixtures/demo-items.ts`, not exported).
|
|
67
|
+
|
|
68
|
+
## Scenery
|
|
69
|
+
|
|
70
|
+
The arena holds three destructible pieces by default, hand-made from boxes: `target_wall` (a brick wall of 48 panels at z = -11), `table` (with the water tap on a post beside it, at x = 3.5) and `shelf` (x = -3.5). `scenery` is a registry keyed by arena object id, so a host can use its own pieces without touching the room:
|
|
71
|
+
|
|
72
|
+
| `scenery[id]` | Effect |
|
|
73
|
+
|---|---|
|
|
74
|
+
| a key of a default (`target_wall`, `table`, `shelf`) | replaces that piece; `position` defaults to the replaced one's |
|
|
75
|
+
| `null` | removes the piece (no table: no tap either) |
|
|
76
|
+
| a new key | adds a piece; `position` is required |
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
createTestRoom({ ..., scenery: {
|
|
80
|
+
target_wall: { spec: wallSpec, position: [0, 0, -11], build: (THREE) => drawWall(THREE) },
|
|
81
|
+
table: { spec: tableSpec, build: drawTable, top: { part: 'wood_0', y: 0.78 } },
|
|
82
|
+
crate: { spec: crateSpec, position: [0, 0, -4], rotationY: 0.4, label: 'Crate' },
|
|
83
|
+
shelf: null,
|
|
84
|
+
} })
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
A `SceneryObject` is `{ spec, position?, rotationY?, colors?, build?, label?, top? }`:
|
|
88
|
+
|
|
89
|
+
- `spec`: the `DestructibleSpec` the world is given. The player collider is the footprint of its parts (what lies lower than 10 cm is walked over); the `target_wall` collider also closes the arena behind the wall.
|
|
90
|
+
- `build(THREE)`: draws the piece as a group whose meshes are named by part id (`userData.destructionPart` too), like `buildFromSpec` does. Without it the room draws one plain mesh per part with `buildFromSpec` and `colors`.
|
|
91
|
+
- `top: { part, y }`: loose things rest on that part's footprint at height `y` while the part stands (`room.groundAt`), and liquids pool on it. The tap stands beside the `table` top.
|
|
92
|
+
- `spout`: where a water tap of the piece pours (a sink, a tub), in the spec's space. The room's tap pours from the first piece that has one, so the piece's own model is the tap; without one the tap stands on the `table` top (see `tap` below).
|
|
93
|
+
- `label`: the name in the inspector and the log (the defaults are translated).
|
|
94
|
+
|
|
95
|
+
`tap` is the room's water tap: omitted, the room draws a post with an arm beside the table; `{ build(THREE), spout, position?, rotationY? }` puts the host's model there (the origin where it stands, `spout` where the water leaves it; by default it stands on the table top with the spout over its right half); `null` removes it.
|
|
96
|
+
|
|
97
|
+
## Models of thrown and placed explosives
|
|
98
|
+
|
|
99
|
+
The room knows the arsenal's ids, not the weapons' models. `projectileModel({ weapon, explosive, kind })` (`kind`: `grenade`, `molotov`, `rocket` or `charge`) is the host's hook: it answers `{ model, axis? }` (`axis`: the length of the model, default +y; a rocket points it along its flight) or `null`, and the room draws a plain primitive (a sphere, a cylinder, a box) only where it answers nothing. `@adatechnology/game-weapons-three` has one: `projectileModel(THREE, query)`.
|
|
61
100
|
|
|
62
101
|
## Loading a module
|
|
63
102
|
|
|
@@ -67,7 +106,17 @@ A game module hands the room a `TestableModule` from `@adatechnology/game-contra
|
|
|
67
106
|
const report = room.loadModule(RENTAL_CARS) // { module, items, scenarios, ok, problems }
|
|
68
107
|
```
|
|
69
108
|
|
|
70
|
-
The items join the catalogue under the module's group and its scenarios become buttons. The contract checks run at once and write one line per result to the log: `checkDestructible` for every item with an `impl`, `checkAnimation` for every clip (`✓ Rental car: destructible contract ok (4 parts...)` or `✗ ...: <problem>`). The animations panel lists the clips of the aimed or held item; `room.playAnimation(clipId)` plays one (poses are offsets from the rest pose, events go to the log and `sound` events to `onSound`). The example (`examples/test-room`) loads
|
|
109
|
+
The items join the catalogue under the module's group and its scenarios become buttons. The contract checks run at once and write one line per result to the log: `checkDestructible` for every item with an `impl`, `checkAnimation` for every clip (`✓ Rental car: destructible contract ok (4 parts...)` or `✗ ...: <problem>`). The animations panel lists the clips of the aimed or held item; `room.playAnimation(clipId)` plays one (poses are offsets from the rest pose, events go to the log and `sound` events to `onSound`). The example (`examples/test-room`) loads the SDK's content modules (the same set as `examples/interactables-test-area`).
|
|
110
|
+
|
|
111
|
+
## Loading indicator
|
|
112
|
+
|
|
113
|
+
Anything slow shows a spinner or a bar with a line of text over the room, so the page never looks frozen. `room.loading` (`RoomLoading`) is the component and `room.busy(label, work)` its shortcut: `busy` shows the indicator, waits for it to be painted (a synchronous job cannot paint it itself), runs `work` and takes it down, even when `work` throws. For a job in steps use `const task = room.loading.begin(label, { total })`, `task.step(text, done)`, `await task.paint()` and `task.end()`; tasks nest and the last one to end hides the card. `await room.loading.idle()` resolves when no task is open: the way for a scenario or a test to wait for a rebuild that runs behind the indicator. `room.openAreaAsync(area)` is `openArea` behind it. The text follows the room's `locale`, a room with `ui: false` draws nothing and tells the state through `room.loading.on(...)`.
|
|
114
|
+
|
|
115
|
+
A module declares what is slow and the room does the rest: `ModuleControl.slow` (an action or a control that takes a third of a second or more) and `TestableItem.slow` (a vehicle) make the room's own panel and catalogue run the press or the spawn behind the indicator (`bench().act/set` and `spawn` stay synchronous for scenarios). A module with a job of its own (a house rebuilt after a seed change) calls `host.loading.busy(...)`. `LOADING_CSS` and `loadingMarkup` are the same card as static HTML, for a page that must show it before its scripts run (the default test room's first frame does).
|
|
116
|
+
|
|
117
|
+
## Blasts shove what is around them
|
|
118
|
+
|
|
119
|
+
An `explosion` moves the loose items, the heavy furniture that is not fixed, and the bodies of the modules that answer it. One rule, `blastShove` of `@adatechnology/game-contracts`: `min(maxSpeed, sqrt(2 * energy * coupling / mass)) * (1 - d / r)^2` away from the centre with some lift, and nothing under `minSpeed`. The room's `blastShove` option sets the numbers (`coupling` 0.02, `maxSpeed` 20 m/s, `lift` 0.3, `minSpeed` 0.3, `falloffPower` 2) for the renderer's pieces and, as `host.blastShove`, for modules such as the characters area, which slide and knock their people down.
|
|
71
120
|
|
|
72
121
|
## Module bench
|
|
73
122
|
|
|
@@ -116,11 +165,33 @@ when a body (the player, an object of the room) crosses it; whatever was already
|
|
|
116
165
|
| E | grab / drop |
|
|
117
166
|
| R | rotate the held item |
|
|
118
167
|
| Right button or G | throw |
|
|
119
|
-
| F | use a fluid item (drink); Z tilt; C fill from the tap; V pour (holding a fluid item)
|
|
168
|
+
| F | use a fluid item (drink); Z tilt; C fill from the tap; V pour (holding a fluid item); otherwise V toggles 1st/3rd person when a body is set (`setAvatar`), and kicks when there is none (Shift+V kicks with a body too; the `kick` tool whatever is selected) |
|
|
120
169
|
| Tab | show / hide the panels |
|
|
121
170
|
|
|
122
171
|
Panels: catalogue tabs (spawn, Clear, Reset all), slow motion 0.25x, time x10, quality select, inspector (material, state, hp, temperature, char, marks, joints, load and stress) and the behaviour log with filters.
|
|
123
172
|
|
|
173
|
+
## The player's body and the third-person camera
|
|
174
|
+
|
|
175
|
+
The room is a bare first-person camera until you give it a body. `room.setAvatar(avatar | null)` takes anything shaped like `RoomAvatar` (the room imports no character code):
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
interface RoomAvatar {
|
|
179
|
+
root: Object3D
|
|
180
|
+
update(dt: number, state: { speed: number; running: boolean; crouch: boolean; down: boolean; armed: boolean; pitch: number }): void
|
|
181
|
+
hand?(side: 'R' | 'L'): Object3D
|
|
182
|
+
firstPerson?: { root: Object3D; update(dt: number, state: { camera: Object3D; targets: HandTargets | null; stance: string; speed: number; running: boolean; crouch: boolean }): void }
|
|
183
|
+
strike?(clipId: string): number | null
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Every frame the room puts `root` at the player's feet turned to where the player looks (the body's front is +z, as the catalogue items'; `rotation.y` is the yaw plus pi) and calls `update` with the ground speed of the player's movement, Shift, `armed` (a firearm is the tool in hand) and the camera `pitch` (radians, positive looking up). `crouch` and `down` are not known to the room: a player module sets them with `room.setAvatarState({ crouch, down })` (`avatarState()` reads them back). `@adatechnology/game-characters-three` has such a body: `toRoomAvatar(createPlayerAvatar(THREE))`.
|
|
188
|
+
|
|
189
|
+
**First-person arms and strikes.** An avatar may carry `firstPerson` (arms drawn in the camera's space; the room shows them only in the first person, updates them every frame after the modules' frame hooks and hands them where the tool in the hands asks the hands to be) and `strike(clipId)`. The hand targets come from the module that places the tool (`host.setHandTargets(source)`, `HandTargets` of `@adatechnology/game-contracts`: world-space poses of the right and left hand plus the grip closure and the size of the hands), else from the carried item, else null; the stance is `hold` when there are targets, else `handStances[toolId]` (default `{ fists: 'fists' }`) or `relaxed`. A melee strike (`fists`, `shove`, Shift+V kick) no longer lands at the click: the room calls `avatar.strike(strikeClips[toolId])` (default `{ fists: 'punch_right', shove: 'shove_two_hands', kick: 'front_kick' }`), which plays the clip on the arms and on the body and answers the seconds to its impact, writes a `strike` line to the log, and calls the existing `meleeUse` at that second with the aim read again. A tool without a clip, or an avatar that answers null, keeps the instant blow; a strike pending blocks the same tool. `toRoomAvatar(createPlayerAvatar(THREE))` already gives all of it (`firstPerson: false` for no arms).
|
|
190
|
+
|
|
191
|
+
`room.setCameraMode('first' | 'third')` (option `cameraMode`, property `cameraMode`, event `room.on('camera', fn)`; every change is a `camera` action in the log). V toggles it when a body is set. In `first` the body is hidden; in `third` it is shown, the camera stands over the shoulder, and a carried item rides `avatar.hand('R')` instead of the camera frame. Option `thirdPerson` changes the view; the defaults are the team game's shoulder camera (`zombiada-modo-livre.html`, `cameraUpdate`, line 76546): `back` 3.8 m, `side` 0.9 m to the right, `up` 1.95 m (`crouchUp` 1.4 m), `lift` 0.1 m, three probe rays (`probes` 0 and +-0.2 m) that pull the camera in `margin` 0.3 m short of a wall (never closer than `minDistance` 0.2 m) and let it out at `recover` 4 per second.
|
|
192
|
+
|
|
193
|
+
The simulation always sees the eye: tools, grabs, scripted walks and the listener work as in first person. Only the render moves the camera (`applyCamera()` does it, a host that renders by itself calls it around its `render`). A shot or grab leaves the eye toward the point the camera ray hits, so the crosshair stays true.
|
|
194
|
+
|
|
124
195
|
## Log format
|
|
125
196
|
|
|
126
197
|
One JSON object per line (`log.toNDJSON()`, "Baixar NDJSON"):
|
|
@@ -150,6 +221,8 @@ automáticos conferem o resultado e gravam aprovado/reprovado no mesmo registro.
|
|
|
150
221
|
Um módulo que declara controles, camadas ou contadores ganha um painel de bancada genérico; o estado vai para a URL do exemplo (`?bench.<idDoMódulo>=`) e
|
|
151
222
|
`room.bench()` / `room.metrics()` dirigem e leem a bancada por script.
|
|
152
223
|
|
|
224
|
+
Corpo do jogador: `room.setAvatar(corpo)` põe um corpo (qualquer objeto no formato `RoomAvatar`) nos pés do jogador; `room.setCameraMode('first' | 'third')` e a tecla V alternam entre 1ª e 3ª pessoa (câmera sobre o ombro com os números do jogo da equipe, puxada para perto de paredes). `room.setAvatarState({ crouch, down })` deixa um módulo de jogador agachar e derrubar o corpo. Com corpo, V alterna a câmera e Shift+V chuta. Em primeira pessoa o corpo pode trazer braços e mãos (`avatar.firstPerson`) que seguram a arma onde o módulo manda (`host.setHandTargets`): mão direita no punho, esquerda no guarda-mão, as duas na pistola, esquerda ao carregador na recarga; sem nada na mão ficam relaxadas, e `fists` levanta os punhos. Soco, empurrão e chute tocam o clipe (`avatar.strike`, opção `strikeClips`) e o efeito só acontece no instante do impacto, não no clique; um golpe pendente bloqueia a mesma ferramenta.
|
|
225
|
+
|
|
153
226
|
## Known limitations
|
|
154
227
|
|
|
155
228
|
The quality select does not recreate the destruction renderer; it only changes the room's own settings. Unit tests use an injected stub renderer (no WebGL).
|
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,54 @@
|
|
|
1
1
|
import * as THREE_NS from 'three';
|
|
2
2
|
import { AudioEngine } from '@adatechnology/game-audio';
|
|
3
|
-
import {
|
|
3
|
+
import { Vec3, DestructionWorld, BlastOptions, DestructibleSpec, DestructionOptions, DestructionEvent } from '@adatechnology/game-destruction';
|
|
4
4
|
export { DestructionEvent, Vec3 } from '@adatechnology/game-destruction';
|
|
5
|
-
import {
|
|
5
|
+
import { BusySink, HandTargets, ModuleControl, ControlValue, ModuleLayer, EnvironmentBus, BusyTask, BusyOptions, TestableModule, DestructibleImpl, AnimationClipSpec, BlastShoveOptions } from '@adatechnology/game-contracts';
|
|
6
|
+
export { AnimationClipSpec, DestructibleImpl, ItemAnimationContract, ModuleScenario, TestableItem, TestableModule } from '@adatechnology/game-contracts';
|
|
7
|
+
import { DestructionRenderer, SpecFromObjectOptions, Quality } from '@adatechnology/game-destruction-three';
|
|
6
8
|
import { Arsenal, WeaponState, WeaponDef } from '@adatechnology/game-weapons';
|
|
7
9
|
import { VfxWorld } from '@adatechnology/game-vfx';
|
|
8
10
|
import { FilmBridge, FluidRenderer } from '@adatechnology/game-fluids-three';
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
import { FluidWorld, ContainerSpec, LiquidDef, ItemUseDef, SurfaceSpec } from '@adatechnology/game-fluids';
|
|
12
|
+
|
|
13
|
+
/** What the indicator shows now: the label of the task on top, its line of text, and how far it is (the bar) when it knows. */
|
|
14
|
+
interface LoadingState {
|
|
15
|
+
readonly label: string;
|
|
16
|
+
readonly text: string;
|
|
17
|
+
readonly done: number;
|
|
18
|
+
readonly total: number | undefined;
|
|
19
|
+
/** The task hides what is behind the indicator. */
|
|
20
|
+
readonly opaque: boolean;
|
|
21
|
+
/** Tasks open at once (an area that builds a house inside a slow action counts two). */
|
|
22
|
+
readonly depth: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The loading indicator of the room: an overlay with a spinner or a bar and a line of text, shown for any slow job so that the page never looks frozen. `begin` shows it at once, `busy` also waits for the
|
|
26
|
+
* paint before it runs the work (the only way to show a bar before a heavy synchronous job), and the last task to end takes it down. The room lends it to modules as `ModuleHost.loading`.
|
|
27
|
+
*/
|
|
28
|
+
interface RoomLoading extends BusySink {
|
|
29
|
+
/** True while a task is open. */
|
|
30
|
+
readonly active: boolean;
|
|
31
|
+
/** Resolves once no task is open (at once when none is): a scenario or test awaits it after a change that rebuilds behind the indicator, instead of sleeping. */
|
|
32
|
+
idle(): Promise<void>;
|
|
33
|
+
/** What it shows now, or undefined when nothing is open. */
|
|
34
|
+
state(): LoadingState | undefined;
|
|
35
|
+
/** Follows it: called whenever a task opens, steps or ends, with `undefined` once none is left. Returns the function that stops following. */
|
|
36
|
+
on(listener: (state: LoadingState | undefined) => void): () => void;
|
|
37
|
+
/** The overlay element (undefined in a room with `ui: false`, where the page draws its own from `on`). */
|
|
38
|
+
readonly element: HTMLElement | undefined;
|
|
39
|
+
dispose(): void;
|
|
40
|
+
}
|
|
41
|
+
interface LoadingOptions {
|
|
42
|
+
/** The room's container: the overlay covers it. */
|
|
43
|
+
readonly container: HTMLElement;
|
|
44
|
+
/** False for a room with `ui: false`: the state is kept and told through `on`, nothing is drawn. Default true. */
|
|
45
|
+
readonly draw?: boolean;
|
|
46
|
+
/** Text of a task that has none yet (already translated). */
|
|
47
|
+
readonly working: string;
|
|
48
|
+
}
|
|
49
|
+
/** Resolves once the browser has painted a frame (a frame callback, then a timer), or after a short wait when frames are not running (a hidden tab, a test). */
|
|
50
|
+
declare const nextPaint: () => Promise<void>;
|
|
51
|
+
declare function createLoading(options: LoadingOptions): RoomLoading;
|
|
12
52
|
|
|
13
53
|
type NewEntry = NewLogEntry;
|
|
14
54
|
/** The log the room writes to (a `TestRoomLog` plus the write side). */
|
|
@@ -26,7 +66,7 @@ declare function createLog(options?: LogOptions): WritableLog;
|
|
|
26
66
|
/** Locales shipped with the package. Unknown locales fall back to `en`. */
|
|
27
67
|
type TestRoomLocale = 'en' | 'pt-BR';
|
|
28
68
|
interface RoomStrings {
|
|
29
|
-
/** Display name per
|
|
69
|
+
/** Display name per item id the room itself names (none: the items come from the modules). */
|
|
30
70
|
items: Record<string, string>;
|
|
31
71
|
/** Display name per demo catalogue group. */
|
|
32
72
|
groups: Record<string, string>;
|
|
@@ -107,6 +147,98 @@ interface HudState {
|
|
|
107
147
|
};
|
|
108
148
|
quality: string;
|
|
109
149
|
objects: number;
|
|
150
|
+
/** The view when the room has a body (`null`: no body, no shortcut). */
|
|
151
|
+
camera: 'first' | 'third' | null;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* The player's body in the room and the third-person camera. Generic: the room knows an avatar only by this interface (a body from any package
|
|
156
|
+
* that fits it, such as `createPlayerAvatar` of `@adatechnology/game-characters-three`), and no character code is imported here.
|
|
157
|
+
*/
|
|
158
|
+
|
|
159
|
+
/** What the room tells the avatar every frame. */
|
|
160
|
+
interface RoomAvatarState {
|
|
161
|
+
/** Ground speed of the player, m/s (from the movement of the feet, jumps ignored). */
|
|
162
|
+
speed: number;
|
|
163
|
+
/** Shift held. */
|
|
164
|
+
running: boolean;
|
|
165
|
+
crouch: boolean;
|
|
166
|
+
down: boolean;
|
|
167
|
+
/** A firearm is the tool in hand. */
|
|
168
|
+
armed: boolean;
|
|
169
|
+
/** Camera pitch, radians, positive looking up (the room's own convention). */
|
|
170
|
+
pitch: number;
|
|
171
|
+
}
|
|
172
|
+
/** What the room tells the first-person arms every frame, after the modules have placed the tool in the hands. */
|
|
173
|
+
interface RoomFirstPersonState {
|
|
174
|
+
/** The player's eye: the arms are drawn in its space. */
|
|
175
|
+
camera: THREE_NS.Object3D;
|
|
176
|
+
/** Where the tool in the hands asks them to be (world space): the module's, else the carried item's, else null. */
|
|
177
|
+
targets: HandTargets | null;
|
|
178
|
+
/** `hold` when something is held (targets), else the rest stance of the tool in hand (`relaxed`, `fists`...; `RoomOptions.handStances`). */
|
|
179
|
+
stance: string;
|
|
180
|
+
/** How far the index finger of the shooting hand is curled, 0 extended along the frame to 1 pulled on the trigger; null when no tool asks for it. */
|
|
181
|
+
triggerFinger: number | null;
|
|
182
|
+
speed: number;
|
|
183
|
+
running: boolean;
|
|
184
|
+
crouch: boolean;
|
|
185
|
+
/** The distance along a ray (world space) to the first thing in the room, or null: what the arms use to stop at a wall or a wardrobe. */
|
|
186
|
+
contact(origin: [number, number, number], direction: [number, number, number], maxDistance: number): number | null;
|
|
187
|
+
}
|
|
188
|
+
/** A body the room can show. The room puts `root` at the player's feet turned to where the player looks: the body's front is +z (as the catalogue items'), so `rotation.y` is the player's yaw plus pi. */
|
|
189
|
+
interface RoomAvatar {
|
|
190
|
+
root: THREE_NS.Object3D;
|
|
191
|
+
update(dt: number, state: RoomAvatarState): void;
|
|
192
|
+
/** A socket at a hand: the carried item follows `hand('R')` in third person. */
|
|
193
|
+
hand?(side: 'R' | 'L'): THREE_NS.Object3D;
|
|
194
|
+
/**
|
|
195
|
+
* The arms of the first-person view. The room shows `root` only in first person (the body only in third), updates it every frame after the modules'
|
|
196
|
+
* frame hooks (so the tool in the hands is already placed) and before the render.
|
|
197
|
+
*/
|
|
198
|
+
firstPerson?: {
|
|
199
|
+
root: THREE_NS.Object3D;
|
|
200
|
+
update(dt: number, state: RoomFirstPersonState): void;
|
|
201
|
+
};
|
|
202
|
+
/**
|
|
203
|
+
* Plays the strike `clipId` (on the body and on the arms) and answers the seconds until its impact, or null when this avatar has no such clip. The room then waits that long
|
|
204
|
+
* before the blow lands (`strikeClips`); an avatar without `strike`, or one that answers null, gets the blow at the click.
|
|
205
|
+
*/
|
|
206
|
+
strike?(clipId: string, options?: {
|
|
207
|
+
leg?: 'left' | 'right';
|
|
208
|
+
}): number | null;
|
|
209
|
+
}
|
|
210
|
+
/** Which leg a kick uses: `alternate` swaps at each kick (right first). */
|
|
211
|
+
type KickLeg = 'alternate' | 'left' | 'right';
|
|
212
|
+
type CameraMode = 'first' | 'third';
|
|
213
|
+
/** Which clip a melee tool plays before its blow lands (`TestRoomOptions.strikeClips`). */
|
|
214
|
+
declare const DEFAULT_STRIKE_CLIPS: Readonly<Record<string, string>>;
|
|
215
|
+
/** The first-person stance of the tools that choose one (`TestRoomOptions.handStances`). */
|
|
216
|
+
declare const DEFAULT_HAND_STANCES: Readonly<Record<string, string>>;
|
|
217
|
+
/**
|
|
218
|
+
* The over-the-shoulder view, metres. Defaults are the numbers of the team game's shoulder camera
|
|
219
|
+
* (`site/pages/jogo/zombiada-modo-livre.html`, `cameraUpdate`, line 76546): `view.cb` 3.8 back, `view.cs` 0.9 to the side, `view.cu` 1.95 high
|
|
220
|
+
* (1.4 crouched), the `+ 0.1` lift of the camera at line 76551, and three probe rays (centre and +-0.2 m, line 76557) that pull the camera in
|
|
221
|
+
* 0.3 m short of a wall (`h.t - 0.3`, never closer than 0.2 m) and let it out again slowly (`dt * 4`, line 76558).
|
|
222
|
+
*/
|
|
223
|
+
interface ThirdPersonOptions {
|
|
224
|
+
/** Distance behind the pivot. Default 3.8. */
|
|
225
|
+
back?: number;
|
|
226
|
+
/** Pivot offset to the right of the player (negative: left shoulder). Default 0.9. */
|
|
227
|
+
side?: number;
|
|
228
|
+
/** Pivot height above the feet. Default 1.95. */
|
|
229
|
+
up?: number;
|
|
230
|
+
/** Pivot height above the feet while crouched. Default 1.4. */
|
|
231
|
+
crouchUp?: number;
|
|
232
|
+
/** Extra height of the camera over the line from the pivot. Default 0.1. */
|
|
233
|
+
lift?: number;
|
|
234
|
+
/** How far short of a wall the camera stops. Default 0.3. */
|
|
235
|
+
margin?: number;
|
|
236
|
+
/** Closest the camera comes to the pivot. Default 0.2. */
|
|
237
|
+
minDistance?: number;
|
|
238
|
+
/** Sideways offsets of the probe rays. Default `[0, 0.2, -0.2]`. */
|
|
239
|
+
probes?: readonly number[];
|
|
240
|
+
/** Per second rate at which the camera returns after a wall is gone. Default 4. */
|
|
241
|
+
recover?: number;
|
|
110
242
|
}
|
|
111
243
|
|
|
112
244
|
/**
|
|
@@ -138,6 +270,8 @@ interface TestRoomItem {
|
|
|
138
270
|
movable?: boolean;
|
|
139
271
|
/** Short note shown in the inspector. */
|
|
140
272
|
note?: string;
|
|
273
|
+
/** Building it takes a noticeable time (a vehicle): the catalogue shows the loading indicator while it spawns one. `true`, or the text to show. */
|
|
274
|
+
slow?: boolean | string;
|
|
141
275
|
/**
|
|
142
276
|
* The item holds a liquid (a cup of coffee, a bottle, a jerrycan, a fuel tank). `part` is the destruction part that is the container (a
|
|
143
277
|
* bullet hole in it makes it leak). `uses` are the item uses offered while it is held (`drink`, `pour`...; defaults from `ITEM_USES`).
|
|
@@ -162,6 +296,61 @@ interface TestRoomItem {
|
|
|
162
296
|
/** Author and licence of the thumbnail, shown as the tooltip of the picture in the inspector. */
|
|
163
297
|
thumbnailCredit?: string;
|
|
164
298
|
}
|
|
299
|
+
/**
|
|
300
|
+
* One piece of destructible scenery of the arena (the target wall, the table, the shelf, or any piece the host adds): a spec, where it stands and how it is drawn.
|
|
301
|
+
* Keyed by arena object id in `TestRoomOptions.scenery`.
|
|
302
|
+
*/
|
|
303
|
+
interface SceneryObject {
|
|
304
|
+
/** What the destruction world is given. */
|
|
305
|
+
spec: DestructibleSpec;
|
|
306
|
+
/** World position of the spec's origin. Required for a new id; for a default id it defaults to the object it replaces. */
|
|
307
|
+
position?: Vec3;
|
|
308
|
+
/** Turn about the vertical axis, radians (default 0). */
|
|
309
|
+
rotationY?: number;
|
|
310
|
+
/** Colour per part id, then per material id, for the default drawing (`buildFromSpec`). */
|
|
311
|
+
colors?: Record<string, number>;
|
|
312
|
+
/**
|
|
313
|
+
* Draws the object: a group whose meshes are named by part id (and carry `userData.destructionPart`), in the space of the spec. Without it the room
|
|
314
|
+
* draws one plain mesh per part with `buildFromSpec`.
|
|
315
|
+
*/
|
|
316
|
+
build?: (THREE: ThreeNamespace) => THREE_NS.Object3D;
|
|
317
|
+
/** Name shown in the inspector and the log (default the translated name of a default id, else the id). */
|
|
318
|
+
label?: string;
|
|
319
|
+
/**
|
|
320
|
+
* A top that loose things rest on (and liquids pool on) while that part stands: the part id and the height of its upper face in the spec's space.
|
|
321
|
+
* The rectangle is the part's footprint. Without it nothing rests on the object.
|
|
322
|
+
*/
|
|
323
|
+
top?: {
|
|
324
|
+
part: string;
|
|
325
|
+
y: number;
|
|
326
|
+
};
|
|
327
|
+
/**
|
|
328
|
+
* Where a water tap of the piece pours (a sink, a tub), in the spec's space: the room's tap (its stream and its HUD button) pours there, and the piece's own model is the tap. The first piece with a `spout` wins over the table tap.
|
|
329
|
+
*/
|
|
330
|
+
spout?: Vec3;
|
|
331
|
+
}
|
|
332
|
+
/** What the room asks when something thrown or set down needs a model: the tool in the hand, the explosive it carries (an id of the arsenal) and how it is used. */
|
|
333
|
+
interface ProjectileQuery {
|
|
334
|
+
weapon: string;
|
|
335
|
+
explosive?: string;
|
|
336
|
+
kind: 'grenade' | 'molotov' | 'rocket' | 'charge';
|
|
337
|
+
}
|
|
338
|
+
/** A model for a projectile: the object, and the axis along its length (default +y, what the room's own primitives use; a rocket points that axis along its flight). */
|
|
339
|
+
interface ProjectileModel {
|
|
340
|
+
model: THREE_NS.Object3D;
|
|
341
|
+
axis?: Vec3;
|
|
342
|
+
}
|
|
343
|
+
/** The room's tap (a stream of water): how it is drawn and where the water leaves it. */
|
|
344
|
+
interface SceneryTap {
|
|
345
|
+
/** Draws the tap in its own space (the origin where it stands). */
|
|
346
|
+
build: (THREE: ThreeNamespace) => THREE_NS.Object3D;
|
|
347
|
+
/** Where the water leaves the spout, in the space of the model. */
|
|
348
|
+
spout: Vec3;
|
|
349
|
+
/** World position of the model's origin. Default: standing on the `table` top, with the spout over its right half (no table, no tap). */
|
|
350
|
+
position?: Vec3;
|
|
351
|
+
/** Turn about the vertical axis, radians (default 0). */
|
|
352
|
+
rotationY?: number;
|
|
353
|
+
}
|
|
165
354
|
interface TestRoomOptions {
|
|
166
355
|
THREE: ThreeNamespace;
|
|
167
356
|
/** Element the bench fills (canvas + HUD). */
|
|
@@ -195,6 +384,19 @@ interface TestRoomOptions {
|
|
|
195
384
|
maxCarryKg?: number;
|
|
196
385
|
/** Arena half size in metres (default 14). */
|
|
197
386
|
arenaSize?: number;
|
|
387
|
+
/**
|
|
388
|
+
* The destructible scenery of the arena, by object id. The defaults are `target_wall` (a brick wall of panels 11 m ahead of the start), `table` (with the
|
|
389
|
+
* water tap beside it) and `shelf`. A key that matches a default replaces it (the position defaults to the replaced one), `null` removes it, a new key adds
|
|
390
|
+
* a piece (its `position` is required). The player cannot walk through any of them: the collider is the footprint of the spec's parts.
|
|
391
|
+
*/
|
|
392
|
+
scenery?: Record<string, SceneryObject | null>;
|
|
393
|
+
/** The tap of the room. Omitted: a tap drawn from primitives on a post beside the table; an object: that model (see `SceneryTap`); `null`: no tap. */
|
|
394
|
+
tap?: SceneryTap | null;
|
|
395
|
+
/**
|
|
396
|
+
* The model of something thrown (a grenade, a molotov, a rocket) or set down (a charge). The room only knows the arsenal's ids, so the host's weapons package
|
|
397
|
+
* supplies the real model; where it answers nothing the room draws a plain primitive (a sphere, a cylinder, a box).
|
|
398
|
+
*/
|
|
399
|
+
projectileModel?: (query: ProjectileQuery) => ProjectileModel | null | undefined;
|
|
198
400
|
/** Spawn these catalogue ids on start, in a row in front of the player. */
|
|
199
401
|
initial?: string[];
|
|
200
402
|
/** Open on one catalogue group (`furniture`, `structure`, `weapons`…): see `TestRoom.openArea`. */
|
|
@@ -211,10 +413,30 @@ interface TestRoomOptions {
|
|
|
211
413
|
environment?: EnvironmentBus;
|
|
212
414
|
/** Show the built-in HUD and panels (default true). */
|
|
213
415
|
ui?: boolean;
|
|
416
|
+
/** The player's body (see `TestRoom.setAvatar`). */
|
|
417
|
+
avatar?: RoomAvatar;
|
|
418
|
+
/** The view the room starts in (default `first`; the V key and `TestRoom.setCameraMode` change it). */
|
|
419
|
+
cameraMode?: CameraMode;
|
|
420
|
+
/**
|
|
421
|
+
* The strike clip each melee tool plays before its blow lands, by tool id. The blow (`meleeUse`, with the aim read again) falls at the clip's impact second, which
|
|
422
|
+
* the avatar's `strike` answers; a tool that is not here, or an avatar that cannot play the clip, strikes at the click. Default `{ fists: 'punch_right', shove: 'shove_two_hands', kick: 'front_kick' }`.
|
|
423
|
+
*/
|
|
424
|
+
strikeClips?: Readonly<Record<string, string>>;
|
|
425
|
+
/** Which leg the kick uses: `alternate` (default) swaps at each kick starting with the right, or always `left` or `right`. */
|
|
426
|
+
kickLeg?: KickLeg;
|
|
427
|
+
/** The first-person stance of the arms by tool id, for the tools that hold nothing the module places (default `{ fists: 'fists' }`; any other tool holds, or is `relaxed` with nothing to hold). */
|
|
428
|
+
handStances?: Readonly<Record<string, string>>;
|
|
429
|
+
/** The over-the-shoulder view of the `third` mode: distance, shoulder, height, wall probes. Defaults are the team game's. */
|
|
430
|
+
thirdPerson?: ThirdPersonOptions;
|
|
214
431
|
/** Room counters the bench panel shows and `TestRoom.metrics()` returns (default all); `false` for none. */
|
|
215
432
|
metrics?: readonly RoomMetricId[] | false;
|
|
216
433
|
/** Blast options every explosion of the room starts with (`shelter`, `fragmentHits`, `confinement`; default all off). The HUD toggles them and `TestRoom.setBlast` changes them. */
|
|
217
434
|
blast?: BlastOptions;
|
|
435
|
+
/**
|
|
436
|
+
* The numbers of the shove an explosion gives to what is around it: loose items, furniture, and the bodies of the modules (people), which read them from `ModuleHost.blastShove`.
|
|
437
|
+
* Default: the SDK's (`DEFAULT_BLAST_SHOVE` of game-contracts: 2 % of the energy becomes speed, 20 m/s at most, falloff `(1 - d / r)^2`).
|
|
438
|
+
*/
|
|
439
|
+
blastShove?: BlastShoveOptions;
|
|
218
440
|
/**
|
|
219
441
|
* Module bench state. `state` maps a module id to its encoded state, restored when that module is first loaded (a module reloaded
|
|
220
442
|
* keeps its live state instead) before its first changes are sent; ids are per module, so two modules may share a control id.
|
|
@@ -303,7 +525,7 @@ interface TestRoom {
|
|
|
303
525
|
update(dt: number): void;
|
|
304
526
|
/** Advance frames until the tool in hand has no phase left (the draw `setTool` plays, a reload, a cycle) or `maxSeconds` pass; plus one frame so the next pull is not inside the phase; returns the seconds waited. */
|
|
305
527
|
waitUntilReady(maxSeconds?: number): number;
|
|
306
|
-
on(type: 'spawn' | 'tool' | 'grab' | 'throw' | 'event', fn: (data: unknown) => void): () => void;
|
|
528
|
+
on(type: 'spawn' | 'tool' | 'grab' | 'throw' | 'event' | 'camera', fn: (data: unknown) => void): () => void;
|
|
307
529
|
/** Tilt the held item by `rad` radians around its own x axis (hold Z in the room). Pouring and spilling follow from the tilt. */
|
|
308
530
|
tilt(rad: number): void;
|
|
309
531
|
/** Open or close the tap over the table (default: toggle). Returns whether it is open. */
|
|
@@ -328,6 +550,15 @@ interface TestRoom {
|
|
|
328
550
|
* that brings an `area` is laid out by it; any other group is laid in rows (small items in front, fixed big ones behind). Unknown: nothing.
|
|
329
551
|
*/
|
|
330
552
|
openArea(group: string): SpawnedObject[];
|
|
553
|
+
/**
|
|
554
|
+
* `openArea` with the loading indicator: shows "Opening <area>…", waits for it to be painted and then lays the area (an area with hundreds of items takes a second or more and would
|
|
555
|
+
* otherwise look frozen). Resolves with the spawned objects. Use it where a person waits for the result (a page that opens an area on load); scenarios call `openArea`, which is synchronous.
|
|
556
|
+
*/
|
|
557
|
+
openAreaAsync(group: string): Promise<SpawnedObject[]>;
|
|
558
|
+
/** The loading indicator of the room: `begin`, `busy`, `state`, `on` (see `RoomLoading`); modules get it as `ModuleHost.loading`. */
|
|
559
|
+
readonly loading: RoomLoading;
|
|
560
|
+
/** `loading.busy`: shows the indicator, waits for it to be painted, runs `work` and takes it down. The way to run a slow, synchronous job. */
|
|
561
|
+
busy<T>(label: string, work: (task: BusyTask) => T | Promise<T>, options?: BusyOptions): Promise<T>;
|
|
331
562
|
/** The scenarios the panel offers: the built-in `SCENARIOS` in the room locale plus `TestRoomOptions.scenarios`. */
|
|
332
563
|
readonly scenarios: TestRoomScenario[];
|
|
333
564
|
/** The liquid renderer of `@adatechnology/game-fluids-three` (containers, streams, stains). */
|
|
@@ -342,6 +573,12 @@ interface TestRoom {
|
|
|
342
573
|
* clip) writing a check line (pass or fail) per result to the log. Loading the same module twice replaces its items and scenarios.
|
|
343
574
|
*/
|
|
344
575
|
loadModule(module: TestableModule<ScenarioContext>): ModuleReport;
|
|
576
|
+
/**
|
|
577
|
+
* Compiles the shader programs that the first hit, decal or effect would otherwise compile in the middle of a frame, then draws a throw-away blast (its particle materials
|
|
578
|
+
* and lights make the materials recompile the first time they appear) and a fire and clears them, so a loading screen can pay those first-frame costs. Nothing of it stays
|
|
579
|
+
* in the world, the log or the sound. Call it once the lights of the scene are set (a module that adds lights changes the programs).
|
|
580
|
+
*/
|
|
581
|
+
warmUp(): void;
|
|
345
582
|
/** Animations of the aimed (or held) item: what the animations panel shows. */
|
|
346
583
|
animations(): AnimationInfo | null;
|
|
347
584
|
/**
|
|
@@ -351,6 +588,37 @@ interface TestRoom {
|
|
|
351
588
|
playAnimation(clipId: string, objectId?: string): boolean;
|
|
352
589
|
/** The bench of a loaded module (default the active one: the module of the last `openArea`, else the last loaded with a bench), or null. */
|
|
353
590
|
bench(moduleId?: string): BenchHandle | null;
|
|
591
|
+
/**
|
|
592
|
+
* Show a body for the player (or none with null). The room adds `root` to the scene, puts it at the player's feet with the player's yaw every
|
|
593
|
+
* frame and calls `update` with the speed of the player's movement, Shift, the crouch/down set by `setAvatarState`, whether a firearm is in hand
|
|
594
|
+
* and the camera pitch. Hidden in first person, shown in third. In third person the carried item follows `avatar.hand('R')`. The previous
|
|
595
|
+
* avatar is taken out of the scene, not disposed.
|
|
596
|
+
*/
|
|
597
|
+
setAvatar(avatar: RoomAvatar | null): void;
|
|
598
|
+
readonly avatar: RoomAvatar | null;
|
|
599
|
+
/** Crouch and knocked-down state a player module drives (merged over what is set; the room fills the rest). `armed` forces the armed arms (`null`: follow the tool in hand again). */
|
|
600
|
+
setAvatarState(state: {
|
|
601
|
+
crouch?: boolean;
|
|
602
|
+
down?: boolean;
|
|
603
|
+
armed?: boolean | null;
|
|
604
|
+
}): void;
|
|
605
|
+
/** What the first-person arms were last given: the stance, how far the trigger finger is curled (0 extended to 1 pulled) and the targets. Read it on each shot to see the finger. */
|
|
606
|
+
handState(): {
|
|
607
|
+
stance: string;
|
|
608
|
+
triggerFinger: number | null;
|
|
609
|
+
targets: HandTargets | null;
|
|
610
|
+
};
|
|
611
|
+
/** Draws the room from another camera (a debug view: the player's camera, the arms and the tool stay as they are) until it is given null. Look at the arms from the side or at a hand from 25 cm. */
|
|
612
|
+
setDebugCamera(view: {
|
|
613
|
+
position: Vec3;
|
|
614
|
+
target: Vec3;
|
|
615
|
+
fov?: number;
|
|
616
|
+
} | null): void;
|
|
617
|
+
/** What the avatar was last given. */
|
|
618
|
+
avatarState(): RoomAvatarState;
|
|
619
|
+
/** `first` (the camera is the eye) or `third` (over the shoulder). V toggles it when a body is set. Logged as a `camera` action. */
|
|
620
|
+
setCameraMode(mode: CameraMode): void;
|
|
621
|
+
readonly cameraMode: CameraMode;
|
|
354
622
|
/** Room counters and the active module's metrics, read now. */
|
|
355
623
|
/**
|
|
356
624
|
* Shakes the camera for the render that follows, by the shake of the effects world, and answers the function that puts it back. The room's own loop
|
|
@@ -484,29 +752,8 @@ interface ScenarioReport {
|
|
|
484
752
|
*/
|
|
485
753
|
declare function createTestRoom(options: TestRoomOptions): TestRoom;
|
|
486
754
|
|
|
487
|
-
/**
|
|
488
|
-
* Extra materials the demo items need on top of the core ones. None any more (the bottle uses the core `glass`, which now breaks from a drop);
|
|
489
|
-
* kept so that code passing it to `worldOptions.materials` keeps working.
|
|
490
|
-
*/
|
|
491
|
-
declare const DEMO_MATERIALS: MaterialDef[];
|
|
492
755
|
/** Spec of the brick target wall: `cols` x `rows` brick panels, the bottom row anchored, mortar joints between neighbours. */
|
|
493
756
|
declare function brickWallSpec(cols?: number, rows?: number, panel?: Vec3): DestructibleSpec;
|
|
494
|
-
/**
|
|
495
|
-
* The generic demo catalogue, names and groups translated for `locale` (`en` or `pt-BR`). Every item is a procedural low-poly build (one mesh per
|
|
496
|
-
* destruction part, drawn by `buildFromSpec`) plus an explicit destruction spec. Containers carry a fluid container where it makes sense.
|
|
497
|
-
*/
|
|
498
|
-
declare function demoItems(locale?: string, extra?: TestRoomItem[]): TestRoomItem[];
|
|
499
|
-
/** The demo catalogue in English (see `demoItems` for other locales). */
|
|
500
|
-
declare const DEMO_ITEMS: TestRoomItem[];
|
|
501
|
-
|
|
502
|
-
type T = (key: string, vars?: Record<string, string | number>) => string;
|
|
503
|
-
type Num = (n: number, digits?: number) => string;
|
|
504
|
-
/** Built-in scripted checks over the generic `DEMO_ITEMS`. Names and check texts come from the room locale. */
|
|
505
|
-
declare function makeScenarios(t: T, num: Num, _locale?: string): TestRoomScenario[];
|
|
506
|
-
/** The built-in scenarios for a locale (`en` or `pt-BR`), standalone: no room needed to list them. */
|
|
507
|
-
declare function scenariosFor(locale?: string): TestRoomScenario[];
|
|
508
|
-
/** The built-in scenarios in English. The room offers them in its own locale. */
|
|
509
|
-
declare const SCENARIOS: TestRoomScenario[];
|
|
510
757
|
|
|
511
758
|
/** Default look of each built-in destruction material (`0xRRGGBB`). */
|
|
512
759
|
declare const MATERIAL_COLORS: Record<string, number>;
|
|
@@ -525,9 +772,24 @@ interface BuildFromSpecOptions {
|
|
|
525
772
|
*/
|
|
526
773
|
declare function buildFromSpec(THREE: typeof THREE_NS, spec: DestructibleSpec, options?: BuildFromSpecOptions): THREE_NS.Group;
|
|
527
774
|
|
|
775
|
+
/**
|
|
776
|
+
* The look of the loading indicator, with no dependency: a card with a title, a bar and a line of text over a dim backdrop. The room draws it (`createLoading`), and a page that must show it before any
|
|
777
|
+
* script has run (the default test room's first frame) writes the same markup and styles from `loadingMarkup` and `LOADING_CSS`, so the screen the page starts with and the one the room shows later are one.
|
|
778
|
+
*/
|
|
779
|
+
declare const LOADING_CLASS = "tr-loading";
|
|
780
|
+
declare const LOADING_CSS: string;
|
|
781
|
+
/** The markup of the indicator as a string, for a page that writes it into its HTML. `solid` is the opaque backdrop of a first screen, `fixed` covers the window instead of the room. */
|
|
782
|
+
declare function loadingMarkup(options: {
|
|
783
|
+
title: string;
|
|
784
|
+
step?: string;
|
|
785
|
+
solid?: boolean;
|
|
786
|
+
fixed?: boolean;
|
|
787
|
+
id?: string;
|
|
788
|
+
}): string;
|
|
789
|
+
|
|
528
790
|
/** `id=value;id=value`, values with `encodeURIComponent`, booleans and layers as `1` / `0`. */
|
|
529
791
|
declare function encodeBenchState(controls: readonly BenchControl[], layers: readonly BenchLayer[]): string;
|
|
530
792
|
/** Reads an encoded state as hostile input: unknown ids, NaN, options not offered and malformed pairs are dropped; numbers are clamped. */
|
|
531
793
|
declare function decodeBenchState(encoded: string, controls: readonly ModuleControl[], layers: readonly ModuleLayer[]): Map<string, ControlValue>;
|
|
532
794
|
|
|
533
|
-
export { type AnimationInfo, type BenchControl, type BenchHandle, type BenchLayer, type BuildFromSpecOptions,
|
|
795
|
+
export { type AnimationInfo, type BenchControl, type BenchHandle, type BenchLayer, type BuildFromSpecOptions, type CameraMode, DEFAULT_HAND_STANCES, DEFAULT_STRIKE_CLIPS, type HudState, type InspectInfo, type KickLeg, LOADING_CLASS, LOADING_CSS, type LoadingOptions, type LoadingState, type LogEntry, MATERIAL_COLORS, type ModuleReport, type NewEntry, type NewLogEntry, type ProjectileModel, type ProjectileQuery, type RoomAvatar, type RoomAvatarState, type RoomFirstPersonState, type RoomLoading, type RoomMetricId, type RoomStrings, type ScenarioContext, type ScenarioReport, type SceneryObject, type SceneryTap, type SpawnedObject, type TestRoom, type TestRoomItem, type TestRoomLocale, type TestRoomLog, type TestRoomOptions, type TestRoomScenario, type ThirdPersonOptions, type ThreeNamespace, type WritableLog, brickWallSpec, buildFromSpec, createLoading, createLog, createTestRoom, decodeBenchState, encodeBenchState, loadingMarkup, locales, nextPaint, resolveStrings };
|