@adatechnology/game-test-room 0.14.0 → 0.16.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 CHANGED
@@ -94,6 +94,22 @@ A `SceneryObject` is `{ spec, position?, rotationY?, colors?, build?, label?, to
94
94
 
95
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
96
 
97
+ ## Test table
98
+
99
+ `room.testTable` lays the catalogue on a table a page at a time, so every item can be tried one by one with the same hit. The table is a `scenery` piece with a `top` (id `test_table`, or `testTable: { scenery }`); the room never draws one of its own, the host passes its model (the example uses the long dining table of the furniture catalogue, `furnitureSpec` of `game-floorplan-three`). Without that piece the table lays nothing; `testTable: false` also leaves the panel out.
100
+
101
+ ```ts
102
+ createTestRoom({ ..., scenery: { test_table: { spec, build, top, position: [-8, 0, 3] } } })
103
+ room.testTable.open('Items') // clears the room and lays the first page of the group along the front edge of the table
104
+ room.testTable.next() // the next page (a page holds what fits on the table)
105
+ room.testTable.find('item_canned_beans') // the page that holds that item, with it picked
106
+ room.testTable.select(objectId) // the item the trials hit (the first one until another is picked)
107
+ room.testTable.trial('shot') // 'shot' | 'punch' | 'stab' | 'fire' | 'blast'
108
+ room.testTable.relay() // puts the table and the page back as they were
109
+ ```
110
+
111
+ A trial equips its tool, puts the player in front of the item, aims at its centre and uses the tool: a 9 mm pistol from 2.5 m, the fists and a knife up close, a flamethrower burst from 1.6 m, and a fragmentation grenade set off just behind the item (`DEFAULT_TRIALS`; `testTable: { trials: { shot: { weapon: 'rifle_5_56' } } }` changes one). What happens goes to the log like any other hit. With the UI on, the **Test table** panel (between the inspector and the log) has the group, the pages, a search that lays the page of an item, the items on the table (a click picks one) and a button per trial plus **Put back**.
112
+
97
113
  ## Models of thrown and placed explosives
98
114
 
99
115
  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)`.
@@ -186,7 +202,7 @@ interface RoomAvatar {
186
202
 
187
203
  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
204
 
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).
205
+ **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. The left click with bare hands (`hand`, the default tool) punches too (E or the right button grab). Punches alternate hands, right first (`punchHand`: `alternate`, `left`, `right`; `punchTools`, default `['hand', 'fists']`): the room calls `strike(clip, { hand })` and logs the hand, as the kick does with `kickLeg` and `{ leg }`. 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
206
 
191
207
  `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
208
 
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  import * as THREE_NS from 'three';
2
2
  import { AudioEngine } from '@adatechnology/game-audio';
3
- import { Vec3, DestructionWorld, BlastOptions, DestructibleSpec, DestructionOptions, DestructionEvent } from '@adatechnology/game-destruction';
3
+ import { Vec3 as Vec3$1, DestructionWorld, BlastOptions, DestructibleSpec, DestructionOptions, DestructionEvent } from '@adatechnology/game-destruction';
4
4
  export { DestructionEvent, Vec3 } from '@adatechnology/game-destruction';
5
- import { BusySink, HandTargets, ModuleControl, ControlValue, ModuleLayer, EnvironmentBus, BusyTask, BusyOptions, TestableModule, DestructibleImpl, AnimationClipSpec, BlastShoveOptions } from '@adatechnology/game-contracts';
5
+ import { BusySink, Vec3, HandTargets, ModuleControl, ControlValue, ModuleLayer, EnvironmentBus, BusyTask, BusyOptions, TestableModule, DestructibleImpl, AnimationClipSpec, BlastShoveOptions } from '@adatechnology/game-contracts';
6
6
  export { AnimationClipSpec, DestructibleImpl, ItemAnimationContract, ModuleScenario, TestableItem, TestableModule } from '@adatechnology/game-contracts';
7
7
  import { DestructionRenderer, SpecFromObjectOptions, Quality } from '@adatechnology/game-destruction-three';
8
8
  import { Arsenal, WeaponState, WeaponDef } from '@adatechnology/game-weapons';
@@ -63,6 +63,140 @@ interface LogOptions {
63
63
  }
64
64
  declare function createLog(options?: LogOptions): WritableLog;
65
65
 
66
+ /**
67
+ * What a trial does to one object: a shot, a punch, a knife blow, a flame on it or a blast beside it. The test table runs one on the object it has picked, so every item of the
68
+ * catalogue can be tried one by one with the same hit.
69
+ */
70
+ type TrialKind = 'shot' | 'punch' | 'stab' | 'fire' | 'blast';
71
+ declare const TRIAL_KINDS: readonly TrialKind[];
72
+ /**
73
+ * How the room runs a trial: the tool (an id of the arsenal), where the player stands and how long the trigger is held.
74
+ * `distance` is metres from the front face of the object (the side the player comes from) to the eye, `lift` metres the eye is above the object's centre, `hold` seconds the
75
+ * trigger stays down (a flame). For `blast` the explosive of `weapon` goes off `distance` metres behind the object, and the player watches from `watch` metres in front.
76
+ */
77
+ interface TrialTool {
78
+ readonly weapon: string;
79
+ readonly distance: number;
80
+ readonly lift: number;
81
+ readonly hold?: number;
82
+ readonly watch?: number;
83
+ }
84
+ /** The tools of the trials: a 9 mm pistol, the fists, a knife, a flamethrower and a fragmentation grenade, all of the default arsenal. */
85
+ declare const DEFAULT_TRIALS: Readonly<Record<TrialKind, TrialTool>>;
86
+ /** The test table: which piece of the arena it is, the gap between the things laid on it and the trial tools (each one replaces the default's fields it gives). */
87
+ interface TestTableOptions {
88
+ /** Id of the `scenery` piece with a `top` the items are laid on (default `test_table`). */
89
+ readonly scenery?: string;
90
+ /** Metres between two items on the table (default 0.12). */
91
+ readonly gap?: number;
92
+ /** Metres kept free at each end of the table (default 0.1). */
93
+ readonly margin?: number;
94
+ readonly trials?: Partial<Record<TrialKind, Partial<TrialTool>>>;
95
+ }
96
+ /** One item laid on the table. */
97
+ interface TestTableObject {
98
+ readonly objectId: string;
99
+ readonly itemId: string;
100
+ readonly name: string;
101
+ }
102
+ /** The page of a group that lies on the table now. */
103
+ interface TestTablePage {
104
+ /** The catalogue group (its translated name, as the catalogue tabs show it). */
105
+ readonly group: string;
106
+ /** Index of the page, from 0. */
107
+ readonly page: number;
108
+ /** Index in the group of the first item on the table, and how many the group has. */
109
+ readonly first: number;
110
+ readonly total: number;
111
+ readonly objects: readonly TestTableObject[];
112
+ /** The object the trials hit (the first one until another is picked). */
113
+ readonly selected: string | null;
114
+ readonly hasPrev: boolean;
115
+ readonly hasNext: boolean;
116
+ }
117
+ /** The test table of the room: lays a group of the catalogue on the table a page at a time, picks one object and runs the trials on it. */
118
+ interface TestTable {
119
+ /** The groups of the catalogue that can be laid (every group with items). */
120
+ groups(): string[];
121
+ /** Every item that can be laid, with its group (what a search looks in). */
122
+ items(): Array<{
123
+ id: string;
124
+ name: string;
125
+ group: string;
126
+ }>;
127
+ /** Clears the room and lays page `page` (default 0) of `group`; null when the room has no table or the group no items. */
128
+ open(group: string, page?: number): TestTablePage | null;
129
+ next(): TestTablePage | null;
130
+ prev(): TestTablePage | null;
131
+ /** Lays the page of the group that holds `itemId` and picks it; null when no group has it (or the room has no table). */
132
+ find(itemId: string): TestTablePage | null;
133
+ /** Puts the table and the page back as they were before the trials: everything is restored and laid again. */
134
+ relay(): TestTablePage | null;
135
+ state(): TestTablePage | null;
136
+ /** Picks the object the trials hit; false when it is not on the table. */
137
+ select(objectId: string): boolean;
138
+ /** Runs a trial on the picked object (or on `objectId`): the room equips the tool, puts the player in front of it, aims and uses it. False when there is nothing to hit. */
139
+ trial(kind: TrialKind, objectId?: string): boolean;
140
+ /** Follow the table: a page laid, an object picked, a trial run. Returns the unsubscribe function. */
141
+ on(listener: (page: TestTablePage | null) => void): () => void;
142
+ }
143
+ /**
144
+ * How many items, from `start`, fit side by side along a table of `length` metres with `gap` between them (`width(i)` is the width of item i). At least one, so an item longer
145
+ * than the table still gets a page of its own. Pure.
146
+ */
147
+ declare function fitRow(width: (index: number) => number, start: number, total: number, length: number, gap: number): number;
148
+ /** The x of the centre of each item of a row laid side by side, centred on `centreX`, with `gap` between them. Pure. */
149
+ declare function rowCentres(widths: readonly number[], centreX: number, gap: number): number[];
150
+ /**
151
+ * Where the player's eye goes for a trial on an object whose box is `min`..`max` (world), and where it looks. The player comes from +z (the side of the room the table faces),
152
+ * so a melee blow lands on the front face. A blast is watched from `watch` metres. Pure.
153
+ */
154
+ declare function trialView(tool: TrialTool, kind: TrialKind, min: Vec3, max: Vec3): {
155
+ eye: Vec3;
156
+ target: Vec3;
157
+ };
158
+ /** What the test table needs of the room. */
159
+ interface TestTableContext {
160
+ /** The catalogue by group: the ids and names of the items of each one. */
161
+ readonly groups: () => ReadonlyMap<string, ReadonlyArray<{
162
+ readonly id: string;
163
+ readonly name: string;
164
+ }>>;
165
+ /** The top of the table in the world (null: the room has no such piece, or its top is broken). */
166
+ readonly top: () => {
167
+ readonly minX: number;
168
+ readonly maxX: number;
169
+ readonly minZ: number;
170
+ readonly maxZ: number;
171
+ readonly top: number;
172
+ } | null;
173
+ /** Width (x) and depth (z) of an item's model at rotation 0, metres. */
174
+ readonly measure: (itemId: string) => {
175
+ readonly w: number;
176
+ readonly d: number;
177
+ };
178
+ readonly spawn: (itemId: string, position: Vec3) => {
179
+ readonly objectId: string;
180
+ };
181
+ readonly clear: () => void;
182
+ readonly resetAll: () => void;
183
+ /** The world box of an object still in the room, else null. */
184
+ readonly box: (objectId: string) => {
185
+ readonly min: Vec3;
186
+ readonly max: Vec3;
187
+ } | null;
188
+ /** Puts the tool in hand (added to the hotbar) and waits for its draw. False for an id the arsenal does not have. */
189
+ readonly equip: (weapon: string) => boolean;
190
+ readonly look: (eye: Vec3, target: Vec3) => void;
191
+ readonly use: (hold: number) => void;
192
+ /** Sets off the explosive of `weapon` at `point`. False when the weapon throws or places no explosive. */
193
+ readonly blastAt: (weapon: string, point: Vec3) => boolean;
194
+ readonly log: (type: string, text: string, data: Record<string, unknown>) => void;
195
+ readonly translate: (key: string, vars?: Record<string, string | number>) => string;
196
+ }
197
+ /** The test table over a room (see `TestTable`). */
198
+ declare function createTestTable(context: TestTableContext, options?: TestTableOptions): TestTable;
199
+
66
200
  /** Locales shipped with the package. Unknown locales fall back to `en`. */
67
201
  type TestRoomLocale = 'en' | 'pt-BR';
68
202
  interface RoomStrings {
@@ -214,10 +348,13 @@ interface RoomAvatar {
214
348
  */
215
349
  strike?(clipId: string, options?: {
216
350
  leg?: 'left' | 'right';
351
+ hand?: 'left' | 'right';
217
352
  }): number | null;
218
353
  }
219
354
  /** Which leg a kick uses: `alternate` swaps at each kick (right first). */
220
355
  type KickLeg = 'alternate' | 'left' | 'right';
356
+ /** Which hand a punch uses: `alternate` swaps at each punch (right first). */
357
+ type PunchHand = 'alternate' | 'left' | 'right';
221
358
  type CameraMode = 'first' | 'third';
222
359
  /** Which clip a melee tool plays before its blow lands (`TestRoomOptions.strikeClips`). */
223
360
  declare const DEFAULT_STRIKE_CLIPS: Readonly<Record<string, string>>;
@@ -289,7 +426,7 @@ interface TestRoomItem {
289
426
  container: ContainerSpec;
290
427
  part?: string;
291
428
  uses?: string[];
292
- offset?: Vec3;
429
+ offset?: Vec3$1;
293
430
  };
294
431
  /** The item is also a weapon the player can equip from the catalogue (e.g. a crowbar, a knife, a pistol on the table). */
295
432
  weapon?: string;
@@ -313,7 +450,7 @@ interface SceneryObject {
313
450
  /** What the destruction world is given. */
314
451
  spec: DestructibleSpec;
315
452
  /** World position of the spec's origin. Required for a new id; for a default id it defaults to the object it replaces. */
316
- position?: Vec3;
453
+ position?: Vec3$1;
317
454
  /** Turn about the vertical axis, radians (default 0). */
318
455
  rotationY?: number;
319
456
  /** Colour per part id, then per material id, for the default drawing (`buildFromSpec`). */
@@ -323,6 +460,15 @@ interface SceneryObject {
323
460
  * draws one plain mesh per part with `buildFromSpec`.
324
461
  */
325
462
  build?: (THREE: ThreeNamespace) => THREE_NS.Object3D;
463
+ /**
464
+ * Lets the drawing follow the object in the destruction world, for what the room's destruction renderer cannot draw on it (a house wall redraws its
465
+ * courses without the bricks that shots knock out). Called once the object is in the world as `objectId`; the room calls `restore` when it resets the
466
+ * object and `dispose` when it removes it.
467
+ */
468
+ follow?: (root: THREE_NS.Object3D, world: DestructionWorld, objectId: string) => {
469
+ restore?(): void;
470
+ dispose?(): void;
471
+ } | null | void;
326
472
  /** Name shown in the inspector and the log (default the translated name of a default id, else the id). */
327
473
  label?: string;
328
474
  /**
@@ -336,7 +482,12 @@ interface SceneryObject {
336
482
  /**
337
483
  * 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.
338
484
  */
339
- spout?: Vec3;
485
+ spout?: Vec3$1;
486
+ /**
487
+ * Stands free on the floor (a bookcase, a wardrobe), not fixed to the room: a blast, or shots whose push is enough to move its mass (a shotgun,
488
+ * not a pistol), make it a piece and shove it. Default false: the scenery stays put.
489
+ */
490
+ free?: boolean;
340
491
  }
341
492
  /** 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. */
342
493
  interface ProjectileQuery {
@@ -347,16 +498,16 @@ interface ProjectileQuery {
347
498
  /** 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). */
348
499
  interface ProjectileModel {
349
500
  model: THREE_NS.Object3D;
350
- axis?: Vec3;
501
+ axis?: Vec3$1;
351
502
  }
352
503
  /** The room's tap (a stream of water): how it is drawn and where the water leaves it. */
353
504
  interface SceneryTap {
354
505
  /** Draws the tap in its own space (the origin where it stands). */
355
506
  build: (THREE: ThreeNamespace) => THREE_NS.Object3D;
356
507
  /** Where the water leaves the spout, in the space of the model. */
357
- spout: Vec3;
508
+ spout: Vec3$1;
358
509
  /** World position of the model's origin. Default: standing on the `table` top, with the spout over its right half (no table, no tap). */
359
- position?: Vec3;
510
+ position?: Vec3$1;
360
511
  /** Turn about the vertical axis, radians (default 0). */
361
512
  rotationY?: number;
362
513
  }
@@ -416,7 +567,7 @@ interface TestRoomOptions {
416
567
  area?: string;
417
568
  /** Called for every destruction event (to log, play sounds, sync over LAN). Fluid events reach the log too. */
418
569
  onEvent?: (event: DestructionEvent) => void;
419
- onSound?: (key: string, point: Vec3, volume: number) => void;
570
+ onSound?: (key: string, point: Vec3$1, volume: number) => void;
420
571
  /**
421
572
  * The sound engine of the room (@adatechnology/game-audio): the destruction renderer's sound keys play on it, and modules get it as `host.audio`.
422
573
  * Default: a new engine of the room's own (it makes no AudioContext until the first sound); `false` for a silent room.
@@ -437,6 +588,10 @@ interface TestRoomOptions {
437
588
  strikeClips?: Readonly<Record<string, string>>;
438
589
  /** Which leg the kick uses: `alternate` (default) swaps at each kick starting with the right, or always `left` or `right`. */
439
590
  kickLeg?: KickLeg;
591
+ /** Which hand throws the one-handed strikes (`punchTools`): `alternate` (default) swaps at each punch starting with the right, or always `left` or `right`. */
592
+ punchHand?: PunchHand;
593
+ /** The tools whose strike is thrown with one hand, so `punchHand` picks it (default `['hand', 'fists']`); the shove and the kick are not. */
594
+ punchTools?: readonly string[];
440
595
  /** 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). */
441
596
  handStances?: Readonly<Record<string, string>>;
442
597
  /** The over-the-shoulder view of the `third` mode: distance, shoulder, height, wall probes. Defaults are the team game's. */
@@ -459,6 +614,11 @@ interface TestRoomOptions {
459
614
  readonly state?: Readonly<Record<string, string>>;
460
615
  readonly onChange?: (moduleId: string, encoded: string) => void;
461
616
  };
617
+ /**
618
+ * The test table (`room.testTable`): a `scenery` piece with a `top` (default id `test_table`) the room lays a group of the catalogue on, a page at a time, to try each item with a
619
+ * shot, a punch, a knife, a flame or a blast. Without that piece the table lays nothing; `false` leaves the panel out too.
620
+ */
621
+ testTable?: TestTableOptions | false;
462
622
  }
463
623
  /** Counters the room measures itself. `fps` and `frame_ms` use the real frame time, so slow motion does not change them. */
464
624
  type RoomMetricId = 'fps' | 'frame_ms' | 'draw_calls' | 'triangles' | 'objects' | 'fragments' | 'particles' | 'decals'
@@ -500,8 +660,10 @@ interface TestRoom {
500
660
  readonly renderer: DestructionRenderer;
501
661
  readonly scene: THREE_NS.Scene;
502
662
  readonly camera: THREE_NS.PerspectiveCamera;
663
+ /** The test table: lays the catalogue on the `test_table` piece a page at a time and runs the trials (shot, punch, knife, fire, blast) on one item. */
664
+ readonly testTable: TestTable;
503
665
  /** Spawn a catalogue item at a world position (default in front of the player). */
504
- spawn(itemId: string, position?: Vec3, rotationY?: number): SpawnedObject;
666
+ spawn(itemId: string, position?: Vec3$1, rotationY?: number): SpawnedObject;
505
667
  /** Remove every spawned object, fragment and particle. */
506
668
  clear(): void;
507
669
  /** Repair every spawned object in place. */
@@ -517,14 +679,14 @@ interface TestRoom {
517
679
  readonly tool: WeaponState;
518
680
  /** Play an item use on the held item (`drink`, `pour`...). Returns false when nothing is held or the use does not apply. */
519
681
  useItem(useId: string): boolean;
520
- /** Use the current tool once from the camera (tests and scripted demos). `hold` seconds for continuous tools. */
682
+ /** Use the current tool once from the camera (tests and scripted demos), as the click does: bare hands punch (or let go of what they hold). `hold` seconds for continuous tools. */
521
683
  use(hold?: number): void;
522
684
  /** Grab what the camera looks at (or drop what is held). */
523
685
  grab(): boolean;
524
686
  /** Throw what is held at `speed` m/s (default 9). */
525
687
  throwHeld(speed?: number): boolean;
526
688
  /** Point the camera (scripted demos and tests). */
527
- look(position: Vec3, target: Vec3): void;
689
+ look(position: Vec3$1, target: Vec3$1): void;
528
690
  /** Object and part the camera looks at, with its state, for the inspector. */
529
691
  inspect(): {
530
692
  objectId: string;
@@ -551,7 +713,7 @@ interface TestRoom {
551
713
  resume(): void;
552
714
  readonly paused: boolean;
553
715
  /** Walk the player in a straight line to the floor position `to` (x and z; y is ignored) over `seconds` of simulated time, during the next `step()` / frames. Colliders still block. 0 seconds moves at once. */
554
- walk(to: Vec3, seconds: number): void;
716
+ walk(to: Vec3$1, seconds: number): void;
555
717
  /** 0.25x simulation speed. */
556
718
  setSlowMotion(on: boolean): void;
557
719
  /** Run the simulation 10x per frame (fire, melting and drying take a tenth of the time). */
@@ -630,8 +792,8 @@ interface TestRoom {
630
792
  };
631
793
  /** 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. */
632
794
  setDebugCamera(view: {
633
- position: Vec3;
634
- target: Vec3;
795
+ position: Vec3$1;
796
+ target: Vec3$1;
635
797
  fov?: number;
636
798
  } | null): void;
637
799
  /** What the avatar was last given. */
@@ -773,7 +935,7 @@ interface ScenarioReport {
773
935
  declare function createTestRoom(options: TestRoomOptions): TestRoom;
774
936
 
775
937
  /** Spec of the brick target wall: `cols` x `rows` brick panels, the bottom row anchored, mortar joints between neighbours. */
776
- declare function brickWallSpec(cols?: number, rows?: number, panel?: Vec3): DestructibleSpec;
938
+ declare function brickWallSpec(cols?: number, rows?: number, panel?: Vec3$1): DestructibleSpec;
777
939
 
778
940
  /** Default look of each built-in destruction material (`0xRRGGBB`). */
779
941
  declare const MATERIAL_COLORS: Record<string, number>;
@@ -812,4 +974,4 @@ declare function encodeBenchState(controls: readonly BenchControl[], layers: rea
812
974
  /** Reads an encoded state as hostile input: unknown ids, NaN, options not offered and malformed pairs are dropped; numbers are clamped. */
813
975
  declare function decodeBenchState(encoded: string, controls: readonly ModuleControl[], layers: readonly ModuleLayer[]): Map<string, ControlValue>;
814
976
 
815
- 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 };
977
+ export { type AnimationInfo, type BenchControl, type BenchHandle, type BenchLayer, type BuildFromSpecOptions, type CameraMode, DEFAULT_HAND_STANCES, DEFAULT_STRIKE_CLIPS, DEFAULT_TRIALS, 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 PunchHand, type RoomAvatar, type RoomAvatarState, type RoomFirstPersonState, type RoomLoading, type RoomMetricId, type RoomStrings, type ScenarioContext, type ScenarioReport, type SceneryObject, type SceneryTap, type SpawnedObject, TRIAL_KINDS, type TestRoom, type TestRoomItem, type TestRoomLocale, type TestRoomLog, type TestRoomOptions, type TestRoomScenario, type TestTable, type TestTableContext, type TestTableObject, type TestTableOptions, type TestTablePage, type ThirdPersonOptions, type ThreeNamespace, type TrialKind, type TrialTool, type WritableLog, brickWallSpec, buildFromSpec, createLoading, createLog, createTestRoom, createTestTable, decodeBenchState, encodeBenchState, fitRow, loadingMarkup, locales, nextPaint, resolveStrings, rowCentres, trialView };