@adatechnology/game-animals-three 0.0.0-stage → 0.1.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 +21 -0
- package/dist/index.d.ts +251 -0
- package/dist/index.global.js +1415 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1160 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -3
- package/README.md +0 -3
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/dist/index.d.ts
ADDED
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import { AnimalSpecies, QuadrupedSpec, TextureMarker, AnimalVisualState } from '@adatechnology/game-animals';
|
|
2
|
+
import { NodeSkin } from '@adatechnology/game-props3d';
|
|
3
|
+
import * as THREE_NS from 'three';
|
|
4
|
+
import { TestableModule } from '@adatechnology/game-contracts';
|
|
5
|
+
|
|
6
|
+
/** What the animation needs each frame. */
|
|
7
|
+
type AnimateParams = {
|
|
8
|
+
/** Seconds since the start. */
|
|
9
|
+
readonly time: number;
|
|
10
|
+
/** Seconds since the last frame. */
|
|
11
|
+
readonly delta: number;
|
|
12
|
+
/** `idle`, `walk` or `run`; any other value stands in the walk pose without advancing the cycle, as the page does. */
|
|
13
|
+
readonly clip: string;
|
|
14
|
+
/** Snakes only: spread the body segments apart (the split view). */
|
|
15
|
+
readonly split?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type Three = typeof THREE_NS;
|
|
19
|
+
/** The slice of a canvas the texture painter uses; a stub works in tests. */
|
|
20
|
+
type CanvasLike = {
|
|
21
|
+
width: number;
|
|
22
|
+
height: number;
|
|
23
|
+
getContext(kind: '2d'): unknown;
|
|
24
|
+
};
|
|
25
|
+
/** The slice of `document` that creates canvases. */
|
|
26
|
+
type DocumentLike = {
|
|
27
|
+
createElement(tag: 'canvas'): CanvasLike;
|
|
28
|
+
};
|
|
29
|
+
type AnimalsThreeOptions = {
|
|
30
|
+
/** Where canvases for the coat textures (cat stripes, jaguar rosettes) come from; default `globalThis.document`. */
|
|
31
|
+
readonly document?: DocumentLike;
|
|
32
|
+
/** A stream of numbers in [0, 1) for the start phase of each step cycle; default a seeded stream of `seed`. */
|
|
33
|
+
readonly random?: () => number;
|
|
34
|
+
/** Seed of the default stream (the page uses 7). */
|
|
35
|
+
readonly seed?: number;
|
|
36
|
+
};
|
|
37
|
+
type AnimalPivot = {
|
|
38
|
+
readonly group: THREE_NS.Group;
|
|
39
|
+
readonly rest: THREE_NS.Vector3;
|
|
40
|
+
readonly offset: THREE_NS.Vector3;
|
|
41
|
+
};
|
|
42
|
+
type AnimalLeg = {
|
|
43
|
+
readonly hip: THREE_NS.Group;
|
|
44
|
+
readonly knee: THREE_NS.Group;
|
|
45
|
+
readonly foot: THREE_NS.Group;
|
|
46
|
+
readonly isFront: boolean;
|
|
47
|
+
readonly angle1: number;
|
|
48
|
+
readonly angle2: number;
|
|
49
|
+
readonly side: number;
|
|
50
|
+
};
|
|
51
|
+
type AnimalWing = {
|
|
52
|
+
readonly shoulder: THREE_NS.Group;
|
|
53
|
+
readonly elbow: THREE_NS.Group;
|
|
54
|
+
readonly side: number;
|
|
55
|
+
};
|
|
56
|
+
/** One animal: the tree to put in a scene (`root`) and the parts the animation drives. */
|
|
57
|
+
type AnimalRig = {
|
|
58
|
+
readonly species: AnimalSpecies;
|
|
59
|
+
readonly root: THREE_NS.Group;
|
|
60
|
+
readonly trunk: THREE_NS.Group;
|
|
61
|
+
readonly materials: THREE_NS.MeshStandardMaterial[];
|
|
62
|
+
readonly joints: THREE_NS.Mesh[];
|
|
63
|
+
readonly pivots: AnimalPivot[];
|
|
64
|
+
readonly legs: AnimalLeg[];
|
|
65
|
+
readonly tail: THREE_NS.Group[];
|
|
66
|
+
readonly ears: THREE_NS.Group[];
|
|
67
|
+
/** Parts that show only while infected (wounds, ribs). */
|
|
68
|
+
readonly infectionParts: THREE_NS.Object3D[];
|
|
69
|
+
readonly eyes: THREE_NS.Mesh[];
|
|
70
|
+
readonly wings: AnimalWing[];
|
|
71
|
+
readonly segments: {
|
|
72
|
+
readonly group: THREE_NS.Group;
|
|
73
|
+
readonly radius: number;
|
|
74
|
+
}[];
|
|
75
|
+
phase: number;
|
|
76
|
+
size: number;
|
|
77
|
+
segmentLength: number;
|
|
78
|
+
segmentCount: number;
|
|
79
|
+
home: THREE_NS.Vector3;
|
|
80
|
+
infected: boolean;
|
|
81
|
+
dead: boolean;
|
|
82
|
+
pool?: THREE_NS.Mesh;
|
|
83
|
+
eyeMaterial?: THREE_NS.MeshStandardMaterial;
|
|
84
|
+
woundMaterial?: THREE_NS.MeshStandardMaterial;
|
|
85
|
+
main?: THREE_NS.MeshStandardMaterial;
|
|
86
|
+
dark?: THREE_NS.MeshStandardMaterial;
|
|
87
|
+
bodyGroup?: THREE_NS.Group;
|
|
88
|
+
/** The mesh of a quadruped's trunk (it moves with the animation of the body, so a node skin keeps it as a node). */
|
|
89
|
+
body?: THREE_NS.Mesh;
|
|
90
|
+
neck?: THREE_NS.Group;
|
|
91
|
+
head?: THREE_NS.Group;
|
|
92
|
+
jaw?: THREE_NS.Group;
|
|
93
|
+
tailRoot?: THREE_NS.Group;
|
|
94
|
+
neckAngle: number;
|
|
95
|
+
headAngle: number;
|
|
96
|
+
tongue?: THREE_NS.Mesh;
|
|
97
|
+
/** Triangles of the whole tree. */
|
|
98
|
+
triangles: number;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
type MaterialExtras = Partial<THREE_NS.MeshStandardMaterialParameters>;
|
|
102
|
+
/** The part builders of the page's `Animal` (`M`, `ball`, `limb`, `joint`, `pivot`), bound to one rig. */
|
|
103
|
+
type RigTools = {
|
|
104
|
+
material(color: number, extras?: MaterialExtras): THREE_NS.MeshStandardMaterial;
|
|
105
|
+
ball(parent: THREE_NS.Object3D, radius: number, material: THREE_NS.Material, x?: number, y?: number, z?: number, sx?: number, sy?: number, sz?: number): THREE_NS.Mesh;
|
|
106
|
+
/** A cylinder hanging from the origin; `radius1` is the one the page calls the top, but the geometry takes it as the bottom (kept as the page has it). */
|
|
107
|
+
limb(parent: THREE_NS.Object3D, radius1: number, radius2: number, length: number, material: THREE_NS.Material): THREE_NS.Mesh;
|
|
108
|
+
joint(parent: THREE_NS.Object3D, radius: number, material: THREE_NS.Material, x?: number, y?: number, z?: number): THREE_NS.Mesh;
|
|
109
|
+
pivot(parent: THREE_NS.Object3D, x: number, y: number, z: number, offset?: THREE_NS.Vector3): THREE_NS.Group;
|
|
110
|
+
eyes(head: THREE_NS.Object3D, radius: number, x: number, y: number, z: number): void;
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
type HeadSpecOf = QuadrupedSpec['head'];
|
|
114
|
+
type NeckSpecOf = QuadrupedSpec['neck'];
|
|
115
|
+
|
|
116
|
+
type ExtraContext = {
|
|
117
|
+
readonly THREE: Three;
|
|
118
|
+
readonly rig: AnimalRig;
|
|
119
|
+
readonly tools: RigTools;
|
|
120
|
+
};
|
|
121
|
+
type QuadrupedParts = {
|
|
122
|
+
readonly bodyGroup: THREE_NS.Group;
|
|
123
|
+
readonly head: THREE_NS.Group;
|
|
124
|
+
readonly neck: THREE_NS.Group;
|
|
125
|
+
readonly main: THREE_NS.MeshStandardMaterial;
|
|
126
|
+
readonly belly: THREE_NS.MeshStandardMaterial;
|
|
127
|
+
readonly dark: THREE_NS.MeshStandardMaterial;
|
|
128
|
+
readonly L: number;
|
|
129
|
+
readonly Rb: number;
|
|
130
|
+
readonly bodyY: number;
|
|
131
|
+
readonly hd: HeadSpecOf;
|
|
132
|
+
readonly nk: NeckSpecOf;
|
|
133
|
+
};
|
|
134
|
+
type BirdParts = {
|
|
135
|
+
readonly bodyGroup: THREE_NS.Group;
|
|
136
|
+
readonly head: THREE_NS.Group;
|
|
137
|
+
readonly neck: THREE_NS.Group;
|
|
138
|
+
readonly main: THREE_NS.MeshStandardMaterial;
|
|
139
|
+
readonly dark: THREE_NS.MeshStandardMaterial;
|
|
140
|
+
};
|
|
141
|
+
type QuadrupedExtra = (context: ExtraContext, parts: QuadrupedParts) => void;
|
|
142
|
+
type BirdExtra = (context: ExtraContext, parts: BirdParts) => void;
|
|
143
|
+
/** The parts the page builds with code for five species (the page's `extra` closures), by species id. */
|
|
144
|
+
declare const QUADRUPED_EXTRAS: Readonly<Record<string, QuadrupedExtra>>;
|
|
145
|
+
declare const BIRD_EXTRAS: Readonly<Record<string, BirdExtra>>;
|
|
146
|
+
|
|
147
|
+
type LineUpOptions = {
|
|
148
|
+
/** X where the row starts (page: -19). */
|
|
149
|
+
readonly start?: number;
|
|
150
|
+
/** Gap between animals (page: 0.85). */
|
|
151
|
+
readonly gap?: number;
|
|
152
|
+
/** Heading of the animals, radians (page: 1.1; snakes 2.2). */
|
|
153
|
+
readonly yaw?: number;
|
|
154
|
+
readonly snakeYaw?: number;
|
|
155
|
+
};
|
|
156
|
+
/** Puts the animals in a row on the x axis, each given room by its length, the row centred on the origin, and keeps each place as `home` (page: the line-up). */
|
|
157
|
+
declare const lineUpAnimals: (rigs: readonly AnimalRig[], options?: LineUpOptions) => void;
|
|
158
|
+
|
|
159
|
+
/** A body of revolution whose radius follows `profile` along the length, rear to front, closed by a point at each end. */
|
|
160
|
+
declare const profileGeometry: (THREE: Three, length: number, profile: readonly number[], segments?: number) => THREE_NS.LatheGeometry;
|
|
161
|
+
|
|
162
|
+
/** The coat texture a species spec asks for (cat stripes, jaguar rosettes), painted on a canvas. */
|
|
163
|
+
declare const createCoatTexture: (THREE: Three, document: DocumentLike, marker: TextureMarker) => THREE_NS.CanvasTexture;
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Applies a visual state (page: `setInfected`, with the dead look for every species): infected greys the coat, glows the eyes, shows the wounds and hides
|
|
167
|
+
* the first ear; dead lets the animation lay the body down and shows a blood pool at `home`. The pool goes under `rig.root.parent`; with no parent yet,
|
|
168
|
+
* it is created hidden from the scene and `rig.pool` is for the caller to add.
|
|
169
|
+
*/
|
|
170
|
+
declare const applyVisualState: (THREE: Three, rig: AnimalRig, state: AnimalVisualState) => void;
|
|
171
|
+
|
|
172
|
+
/** The "joints" view (page: `setJoint`): the coat turns see-through and every joint ball shows in `jointMaterial`. */
|
|
173
|
+
declare const setJointView: (rig: AnimalRig, on: boolean, jointMaterial: THREE_NS.Material) => void;
|
|
174
|
+
/** The "split" view (page: `setSplit`): sets where each pivot should go, the rest position or the rest plus its offset; `updateSplit` moves it there. */
|
|
175
|
+
declare const setSplit: (rig: AnimalRig, on: boolean) => void;
|
|
176
|
+
/** Moves each pivot toward its split target (the page does it in the frame loop: a lerp of 5 per second). */
|
|
177
|
+
declare const updateSplit: (rig: AnimalRig, delta: number) => void;
|
|
178
|
+
|
|
179
|
+
/** The part of the outbreak rule the area uses (`createAnimalOutbreak` of game-characters-undead has all of it). */
|
|
180
|
+
type OutbreakLike = {
|
|
181
|
+
enabled: boolean;
|
|
182
|
+
bite(speciesId: string, random: () => number, now: number): {
|
|
183
|
+
readonly speciesId: string;
|
|
184
|
+
readonly outcome: 'turns' | 'dies';
|
|
185
|
+
readonly bittenAt: number;
|
|
186
|
+
readonly dueAt: number;
|
|
187
|
+
} | undefined;
|
|
188
|
+
stateOf(fate: {
|
|
189
|
+
readonly speciesId: string;
|
|
190
|
+
readonly outcome: 'turns' | 'dies';
|
|
191
|
+
readonly bittenAt: number;
|
|
192
|
+
readonly dueAt: number;
|
|
193
|
+
}, now: number): 'incubating' | 'turned' | 'dead';
|
|
194
|
+
carcass(speciesId: string, position: readonly [number, number, number], now: number): {
|
|
195
|
+
readonly lureRadiusMetres: number;
|
|
196
|
+
} | undefined;
|
|
197
|
+
lures(carcass: {
|
|
198
|
+
readonly lureRadiusMetres: number;
|
|
199
|
+
}, distance: number, now: number): boolean;
|
|
200
|
+
};
|
|
201
|
+
type AnimalsTestOptions = {
|
|
202
|
+
/** `en` or `pt-BR` (default). */
|
|
203
|
+
readonly locale?: string;
|
|
204
|
+
/** The species to lay out (the 13 of `@adatechnology/game-animals-species`). */
|
|
205
|
+
readonly species?: readonly AnimalSpecies[];
|
|
206
|
+
/** Builds the outbreak rule for the bench (`createAnimalOutbreak` from game-characters-undead): called again when the clock changes. Without it the bite actions do nothing. */
|
|
207
|
+
readonly createOutbreak?: (options: {
|
|
208
|
+
readonly species: readonly AnimalSpecies[];
|
|
209
|
+
readonly enabled: boolean;
|
|
210
|
+
readonly timeScale: number;
|
|
211
|
+
}) => OutbreakLike;
|
|
212
|
+
readonly document?: DocumentLike;
|
|
213
|
+
/** Seed of the draws of the area (default 7, the page's). */
|
|
214
|
+
readonly seed?: number;
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/** What a scenario needs of the room: the pass/fail line and time. The test room's `ScenarioContext` has both. */
|
|
218
|
+
type AnimalsContext = {
|
|
219
|
+
expect(condition: boolean, label: string, data?: Record<string, unknown>): void;
|
|
220
|
+
step(seconds: number): void;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
declare const ANIMALS_AREA_ID = "animals_area";
|
|
224
|
+
declare const ANIMAL_ITEM_PREFIX = "animal_";
|
|
225
|
+
/**
|
|
226
|
+
* The animals test area as a `TestableModule`: the species of the pack in a row, each drawn by the Bichos do Vale builders, with the alive / infected / dead looks, the gait,
|
|
227
|
+
* the joints and split views, the rings for how far its sound carries and how far a carcass lures, the outbreak rule with an accelerated bite clock, and a field of 40 animals
|
|
228
|
+
* drawn as node skins. The species and the outbreak rule come in by option, so this package knows no game.
|
|
229
|
+
*/
|
|
230
|
+
declare function createAnimalsTestModule(options?: AnimalsTestOptions): TestableModule<AnimalsContext> & {
|
|
231
|
+
readonly placed: ReadonlyMap<string, unknown>;
|
|
232
|
+
};
|
|
233
|
+
|
|
234
|
+
type AnimalsThree = {
|
|
235
|
+
/** Builds one animal from its species; consumes one number of the stream for the start phase unless `phase` is given. */
|
|
236
|
+
build(species: AnimalSpecies, buildOptions?: {
|
|
237
|
+
readonly phase?: number;
|
|
238
|
+
}): AnimalRig;
|
|
239
|
+
/** Advances the animation of one animal (steps, flight, wings, head, tail, a dead one lying down). */
|
|
240
|
+
animate(rig: AnimalRig, params: AnimateParams): void;
|
|
241
|
+
setVisualState(rig: AnimalRig, state: AnimalVisualState): void;
|
|
242
|
+
setJointView(rig: AnimalRig, on: boolean): void;
|
|
243
|
+
setSplit(rig: AnimalRig, on: boolean): void;
|
|
244
|
+
updateSplit(rig: AnimalRig, delta: number): void;
|
|
245
|
+
/** One mesh that stands for the whole tree, for crowds: call `skin.update()` each frame after `animate`. */
|
|
246
|
+
createSkin(rig: AnimalRig): NodeSkin;
|
|
247
|
+
readonly jointMaterial: THREE_NS.MeshStandardMaterial;
|
|
248
|
+
};
|
|
249
|
+
declare const createAnimalsThree: (THREE: Three, options?: AnimalsThreeOptions) => AnimalsThree;
|
|
250
|
+
|
|
251
|
+
export { ANIMALS_AREA_ID, ANIMAL_ITEM_PREFIX, type AnimalLeg, type AnimalPivot, type AnimalRig, type AnimalWing, type AnimalsContext, type AnimalsTestOptions, type AnimalsThree, type AnimalsThreeOptions, type AnimateParams, BIRD_EXTRAS, type BirdExtra, type BirdParts, type CanvasLike, type DocumentLike, type ExtraContext, type LineUpOptions, type OutbreakLike, QUADRUPED_EXTRAS, type QuadrupedExtra, type QuadrupedParts, type Three, applyVisualState, createAnimalsTestModule, createAnimalsThree, createCoatTexture, lineUpAnimals, profileGeometry, setJointView, setSplit, updateSplit };
|