@adatechnology/game-vehicles-three 0.0.0-stage → 0.2.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Anderson Fernandes
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,26 @@
1
- # Temporary Holding Version
1
+ # @adatechnology/game-vehicles-three
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ A vehicle of `@adatechnology/game-vehicles` in a game frame, at full detail or fused into six meshes. A literal port of the team's Frota Leve (`FrotaLeve.criar(...).construir`).
4
+
5
+ ```ts
6
+ import { createVehicleKit } from '@adatechnology/game-vehicles'
7
+ import { installFleet } from '@adatechnology/game-vehicles-fleet'
8
+ import { createVehiclesThree } from '@adatechnology/game-vehicles-three'
9
+
10
+ const kit = createVehicleKit({ THREE })
11
+ installFleet(kit)
12
+ const vehicles = createVehiclesThree(THREE, { kit })
13
+ const car = vehicles.build('midsize_sedan', { quality: 'lite', seed: 42 })
14
+ scene.add(car.group) // front on +z, right on -x, centred, wheels on y = 0
15
+ car.triangles // 19286 · car.drawCalls // 6 · car.damageables // metal, glass, rubber, fuel boxes in the game frame
16
+ ```
17
+
18
+ - `quality: 'high'` is the kit's vehicle (the context stays in `car.context` for damage), `'lite'` fuses it into `paint`, `trim`, `metal`, `glass`, `light` and `plate`, dropping interiors and pieces under 3 cm.
19
+ - The colour comes from `color` or from `seed` through the palette of the vehicle's group (`colorFromSeed`).
20
+ - Tested against the team's page on three r160 (triangles, draw calls, size, per-class vertices, damageable boxes) and against `DIMS` for the 69 vehicles.
21
+
22
+ ## Test area
23
+
24
+ `createVehiclesTestModule({ locale, document?, three?, vehicles?, effects? })` is a `TestableModule` for the shared test room (`room.loadModule`, or `loadVehiclesTestModule(room)`, which learns the room's three.js to compute the door, hood and trunk clips). It lays the eight vehicles of the Frota test, each with its own `DestructibleImpl`, and brings 13 scenarios: the eleven of the team's test page, literal (`vehicles_9mm_windshield`, `vehicles_shotgun_door`, `vehicles_ram_front`, `vehicles_engine_fire`, `vehicles_fuel_tank`, `vehicles_unbolt_wheel`, `vehicles_tear_bumper`, `vehicles_break_mirror`, `vehicles_kill_battery`, `vehicles_rollover`, `vehicles_melt`; the page ids are in `PAGE_SCENARIO_ALIASES`), plus `vehicles_drive_arcade` and `vehicles_drive_semi` for `@adatechnology/game-vehicles-driving`.
25
+
26
+ The bench sets the quality (full or light mode), the paint by seed and palette, the driving mode and the surface, and drives a car down a lane; its layers show the damageable boxes by material, the zones by type and the axes of the output frame; its metrics read triangles, draw calls, the size against `DIMS` and the boxes by material. The module draws no particles: fire, explosion, glass, sparks, leaks and exhaust are requested by id through `host.effects` when the host has one (`defaultEffectIds`, replaceable by option). A pierced tank asks for `leak` (`vehicle_leak`: the pool and the drips only); when the leak catches fire (a spark, an incendiary round, a fire near, a blast) the `ignite` event of the tank asks for `leakIgnited` (`vehicle_leak_ignited`: the Garagem's whole sequence, the fire along the pool and then the blast). `examples/vehicles-test-area` loads it.
@@ -0,0 +1,217 @@
1
+ import { Damageable, VehicleContext, VehicleKit } from '@adatechnology/game-vehicles';
2
+ import { FleetDims } from '@adatechnology/game-vehicles-fleet';
3
+ import { EffectSink, Vec3, TestableModule } from '@adatechnology/game-contracts';
4
+
5
+ type VehicleQuality = 'high' | 'lite';
6
+ interface BuildVehicleOptions {
7
+ /** `high`: the kit's vehicle at full detail. `lite`: fused into six meshes. Default `high`. */
8
+ quality?: VehicleQuality;
9
+ /** Body colour as a CSS colour. Wins over `seed`. */
10
+ color?: string;
11
+ /** Picks the body colour from the palette of the vehicle's group. */
12
+ seed?: number | string;
13
+ /** State of the vehicle. Default `intact`. */
14
+ state?: 'intact' | 'damaged' | 'modified';
15
+ }
16
+ interface BuiltVehicle {
17
+ key: string;
18
+ quality: VehicleQuality;
19
+ /** The colour the body ended up with, or null when the vehicle keeps its own paint. */
20
+ color: string | null;
21
+ seed: number | string | null;
22
+ /** Group in the game frame: front on +z, right on -x, centred on x and z, wheels on y = 0. */
23
+ group: any;
24
+ /** Damageable boxes in the game frame. */
25
+ damageables: Damageable[];
26
+ triangles: number;
27
+ drawCalls: number;
28
+ /** Measured size of the group in metres: length along z, width along x, height along y. */
29
+ length: number;
30
+ width: number;
31
+ height: number;
32
+ /** Pieces dropped for being smaller than 3 cm (lite only). */
33
+ pruned: number;
34
+ /** The measured size the team recorded for this vehicle, when the fleet knows it. */
35
+ expected: FleetDims | undefined;
36
+ /** The kit's context, for damage and animation (full detail only). */
37
+ context: VehicleContext | null;
38
+ dispose(): void;
39
+ }
40
+ interface VehiclesThree {
41
+ readonly THREE: any;
42
+ readonly kit: VehicleKit;
43
+ build(key: string, options?: BuildVehicleOptions): BuiltVehicle;
44
+ }
45
+ interface VehiclesThreeOptions {
46
+ kit: VehicleKit;
47
+ /** Vehicle id to the group id whose palette paints it. Defaults to the fleet group of the vehicle (`military` for the military ones). */
48
+ groupOf?: (key: string) => string;
49
+ }
50
+ /**
51
+ * Builds vehicles in a game frame. Port of `FrotaLeve.criar(...).construir` (frota-leve.js 14311-14442): the kit builds with +x to the front
52
+ * and +z to the right; the game wants +z to the front and -x to the right, the vehicle centred on x and z and standing on y = 0.
53
+ */
54
+ declare function createVehiclesThree(THREE: any, options: VehiclesThreeOptions): VehiclesThree;
55
+
56
+ /**
57
+ * The light mode of the team's Frota Leve (frota-leve.js 14202-14310): a built vehicle fused into six meshes, one per class of material,
58
+ * with the meshes nobody sees from outside left out. A literal port: the classes, the thresholds (3 cm prune, 0.99 opacity, 0.5 metalness,
59
+ * 0.25 and 0.45 emissive) and the colours are the team's.
60
+ */
61
+ /** The six classes of a fused vehicle, in the order they are added to the group. */
62
+ declare const LITE_CLASSES: readonly ["paint", "trim", "metal", "glass", "light", "plate"];
63
+ type LiteClass = (typeof LITE_CLASSES)[number];
64
+ /** Smallest extent in metres a piece needs to survive the fusion (the plate is always kept). */
65
+ declare const PRUNE_BELOW = 0.03;
66
+ interface Accumulator {
67
+ P: number[];
68
+ N: number[];
69
+ C: number[];
70
+ U: number[];
71
+ I: number[];
72
+ nv: number;
73
+ alpha: boolean;
74
+ uv: boolean;
75
+ map: any;
76
+ }
77
+ interface LiteFusion {
78
+ acc: Record<LiteClass, Accumulator>;
79
+ pruned: number;
80
+ }
81
+ /** Which class a material belongs to, or `null` when it is left out. */
82
+ declare function classify(mat: any, mesh: any, c: any): LiteClass | null;
83
+ /** The vertex colour of a piece of a class. `paintColor` replaces the primary paint. */
84
+ declare function classColor(mat: any, cls: LiteClass, primary: any, paintColor: any, out: any): any;
85
+ /** The material of each class (vertex colours; glass blends; light is unlit; the plate keeps its canvas texture). */
86
+ declare function liteMaterials(THREE: any, environment: any): Record<LiteClass, any>;
87
+ /**
88
+ * Walks the built vehicle and collects every visible mesh, in the frame of `pivot`, into one set of arrays per class.
89
+ * `hidden` is the set of materials nobody sees from outside (`kit.lodHiddenMaterials()`).
90
+ */
91
+ declare function fuse(THREE: any, c: any, pivot: any, paintColor: any, primary: any, hidden: ReadonlySet<any>): LiteFusion;
92
+ /** One mesh per class that has triangles. */
93
+ declare function liteMeshes(THREE: any, fusion: LiteFusion, materials: Record<LiteClass, any>): any[];
94
+
95
+ /** What the module needs of a document (canvas textures of the kit): a real `document`, or a stub in Node. */
96
+ type DocumentLike = {
97
+ createElement(tag: string): unknown;
98
+ };
99
+ /** The host's effects (`host.effects`, an `EffectSink` of the contracts: `game-vfx-three` is one): the module asks by id and writes no particle code. */
100
+ type EffectsLike = EffectSink;
101
+ /** The events the module turns into effect requests, and the effect id each one asks for. A game maps its own ids over these. */
102
+ type VehicleEffectIds = {
103
+ readonly ignite: string;
104
+ readonly explode: string;
105
+ readonly glass: string;
106
+ readonly sparks: string;
107
+ readonly leak: string;
108
+ /** The leak of a pierced tank caught fire: the whole sequence (fire along the pool, then the blast). `leak` is only the pool and the drips. */
109
+ readonly leakIgnited: string;
110
+ readonly exhaust: string;
111
+ };
112
+ declare const defaultEffectIds: VehicleEffectIds;
113
+ /** The sounds the module asks of `host.audio`, by id of the host's banks. `engine` is a loop (the game's saw through a 400 Hz low-pass), `horn` and `crash` one-shots. */
114
+ type VehicleSoundIds = {
115
+ readonly engine: string;
116
+ readonly horn: string;
117
+ readonly crash: string;
118
+ };
119
+ declare const defaultSoundIds: VehicleSoundIds;
120
+ type VehiclesTestOptions = {
121
+ /** `en` or `pt-BR` (default). */
122
+ readonly locale?: string;
123
+ /** The kit the vehicles are built with, per three.js namespace. Default: `createVehicleKit` with the fleet installed (`installFleet`). */
124
+ readonly createKit?: (THREE: unknown) => VehicleKit;
125
+ readonly document?: DocumentLike;
126
+ /** The three.js namespace the door, hood and trunk clips are computed with (they are plain numbers, so any copy works). Default: the global `THREE`; without either the items bring no clips. */
127
+ readonly three?: unknown;
128
+ /** The vehicles to lay out, as fleet ids (default the 8 of the Frota test: hatch, sedan, pickup, sport bike, box truck, city bus, battle tank, attack helicopter). */
129
+ readonly vehicles?: readonly string[];
130
+ /** Effect ids requested through `host.effects` (the defaults are ids of `game-vfx`: the Garagem's `car_fuel_tank` blast, the `vehicle_fire`, `vehicle_leak` (pool and drips only), `vehicle_leak_ignited` (the whole sequence) and `vehicle_exhaust` recipes written around a car from `engine_smoke` and `fuel_leak`, and the point-based `glass_burst` and `impact_metal`). */
131
+ readonly effects?: Partial<VehicleEffectIds>;
132
+ /** Sound ids requested through `host.audio` (the defaults are the `game-audio` ones: `engine_saw`, `horn`, `sfx_impact`). */
133
+ readonly sounds?: Partial<VehicleSoundIds>;
134
+ };
135
+ /** The part of the test room the scenarios use (the room's `ScenarioContext.room` has all of it). */
136
+ type PartView = {
137
+ holes: {
138
+ through?: boolean;
139
+ }[];
140
+ cracks: unknown[];
141
+ dents: unknown[];
142
+ status: string;
143
+ hp: number;
144
+ maxHp: number;
145
+ temperature: number;
146
+ burning: boolean;
147
+ liters: number;
148
+ melt: number;
149
+ };
150
+ type SpawnedVehicle = {
151
+ objectId: string;
152
+ root: {
153
+ userData: Record<string, unknown>;
154
+ };
155
+ };
156
+ type VehiclesRoom = {
157
+ spawn(item: string, position?: Vec3, rotationY?: number): SpawnedVehicle;
158
+ setTool(weaponId: string): void;
159
+ /** Lets the tool in hand finish its draw time (the room's rule: a weapon cannot fire the moment it is taken). */
160
+ waitUntilReady(): void;
161
+ look(position: Vec3, target: Vec3): void;
162
+ use(hold?: number): void;
163
+ playAnimation(clipId: string, objectId?: string): boolean;
164
+ world: {
165
+ part(object: string, part: string): PartView;
166
+ hit(object: string, hit: Record<string, unknown>): unknown;
167
+ disassemble(object: string, joint: string, tool: string, dt: number): number;
168
+ state(object: string): {
169
+ joints: {
170
+ id: string;
171
+ open: boolean;
172
+ }[];
173
+ groups: unknown[][];
174
+ };
175
+ };
176
+ log: {
177
+ entries(filter: {
178
+ type?: string;
179
+ objectId?: string;
180
+ }): readonly unknown[];
181
+ };
182
+ };
183
+ /** What a scenario needs of the room: the pass/fail line, time, and the room for the ones that shoot and hit. */
184
+ type VehiclesContext = {
185
+ room: VehiclesRoom;
186
+ expect(condition: boolean, label: string, data?: Record<string, unknown>): void;
187
+ step(seconds: number): void;
188
+ };
189
+
190
+ declare const VEHICLES_AREA_ID = "vehicles_area";
191
+ /** The eight vehicles of the Frota test page, in its order, and the item id each one has in the area. */
192
+ declare const DEFAULT_TEST_VEHICLES: readonly string[];
193
+ /**
194
+ * The vehicles test area as a `TestableModule`: the vehicles of the Frota test (hatch, sedan, pickup, sport bike, box truck, city bus, battle tank, attack helicopter), each with its own
195
+ * `DestructibleImpl` and its door, hood and trunk clips, the eleven scenarios of that page (literal) and two for the drivers. The bench sets the quality (full or light mode), the paint
196
+ * by seed and palette, the driving mode and the surface, and shows the damageable boxes by material, the zones by type and the axes of the output frame. Effects (fire, glass, sparks,
197
+ * exhaust) are requested by id through `host.effects` when the host has it; this module draws none.
198
+ */
199
+ declare function createVehiclesTestModule(options?: VehiclesTestOptions): TestableModule<VehiclesContext> & {
200
+ readonly placed: ReadonlyMap<string, unknown>;
201
+ };
202
+ /** What `loadVehiclesTestModule` needs of a room: `TestRoom.loadModule` has it. */
203
+ type ModuleRoomLike = {
204
+ loadModule(module: never): unknown;
205
+ };
206
+ /**
207
+ * Loads the vehicles module into a room. The door, hood and trunk clips of the items are computed when the room reads the items, before the module is lent the room's three.js
208
+ * (`attach`), so this first lends an empty module to learn the namespace and then loads the real one with it. Pass `three` to skip that.
209
+ */
210
+ declare function loadVehiclesTestModule<Room extends ModuleRoomLike>(room: Room, options?: VehiclesTestOptions): ReturnType<Room['loadModule']>;
211
+
212
+ declare const VEHICLE_SCENARIO_IDS: readonly string[];
213
+ /** The ids of the Frota test page, for whoever keeps a report or a link made against it. */
214
+ declare const PAGE_SCENARIO_ALIASES: Readonly<Record<string, string>>;
215
+ declare const PAGE_ITEM_ALIASES: Readonly<Record<string, string>>;
216
+
217
+ export { type BuildVehicleOptions, type BuiltVehicle, DEFAULT_TEST_VEHICLES, type DocumentLike, type EffectsLike, LITE_CLASSES, type LiteClass, type LiteFusion, type ModuleRoomLike, PAGE_ITEM_ALIASES, PAGE_SCENARIO_ALIASES, PRUNE_BELOW, VEHICLES_AREA_ID, VEHICLE_SCENARIO_IDS, type VehicleEffectIds, type VehicleQuality, type VehicleSoundIds, type VehiclesContext, type VehiclesRoom, type VehiclesTestOptions, type VehiclesThree, type VehiclesThreeOptions, classColor, classify, createVehiclesTestModule, createVehiclesThree, defaultEffectIds, defaultSoundIds, fuse, liteMaterials, liteMeshes, loadVehiclesTestModule };