@adatechnology/game-items-three 0.0.0-stage → 0.1.1
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/README.md +21 -2
- package/dist/index.d.ts +381 -0
- package/dist/index.global.js +2254 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1761 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -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/README.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @adatechnology/game-items-three
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
three.js presentation for `@adatechnology/game-items`. Everything is drawn at the **real size** of the item (metres, y up, origin at the bottom centre).
|
|
4
|
+
|
|
5
|
+
- **Models of the team:** the 24 builders of the Itens do Vale Cinzento showcase, ported as they are (their units, their materials by tag) and scaled to metres by the `scale` of its entry. A game adds or replaces one with `registerItemModel`.
|
|
6
|
+
- **Simple shapes:** 25 shapes (`can`, `bottle`, `box`, `bag`, `tool`, `blade`, `long_tool`, `garment`, `backpack`, `jerrycan`, `tank`, `book`, `key`, `battery`, `plank`, `device`...) drawn inside the `size` of any item, chosen by its `shape` hint refined by category and proportions (`shapeOf`).
|
|
7
|
+
- **Wear:** `setWear(object, 0 | 1 | 2)` takes the materials from new to used to spoiled, as the showcase does.
|
|
8
|
+
- **Budgets:** `mergeItem` joins an item by material, `buildItemLod` gives three levels (model or shape, half-detail shape, nothing past 30 m for a small item and 60 m for a large one), `ITEM_BUDGETS` and `checkBudget` hold the page's 30 draw calls and 400 / 1200 triangles.
|
|
9
|
+
|
|
10
|
+
```ts
|
|
11
|
+
import * as THREE from 'three'
|
|
12
|
+
import { createGoodsItems } from '@adatechnology/game-items-goods'
|
|
13
|
+
import { buildItem, buildItemLod, setWear } from '@adatechnology/game-items-three'
|
|
14
|
+
|
|
15
|
+
const items = createGoodsItems()
|
|
16
|
+
const can = buildItem(THREE, items.get('canned_beans')) // model or shape, real size
|
|
17
|
+
scene.add(can.root)
|
|
18
|
+
setWear(can.root, 2) // spoiled
|
|
19
|
+
scene.add(buildItemLod(THREE, items.get('hammer')).root) // merged, with LOD and cull
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
three.js is a peer dependency (`^0.160`). The global of the IIFE build is `GameItemsThree`.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
import * as THREE_NS from 'three';
|
|
2
|
+
import { Thumbnail, Vec3, AreaPlacement, TestableModule } from '@adatechnology/game-contracts';
|
|
3
|
+
import { FindStack, ItemsCatalog, FindsProvider } from '@adatechnology/game-items';
|
|
4
|
+
|
|
5
|
+
type Three = typeof THREE_NS;
|
|
6
|
+
/** The material tags the team's showcase wears: what `setWear` turns toward its spoiled colour. */
|
|
7
|
+
declare const WEAR_TAGS: readonly ["metal", "wood", "cloth", "plastic", "paper", "food", "glass"];
|
|
8
|
+
type WearTag = (typeof WEAR_TAGS)[number];
|
|
9
|
+
/** What a material of the kit remembers so that `setWear` can go back to new: the colour it was made with (as three read it, and as sRGB floats), its tag and its roughness. */
|
|
10
|
+
interface ItemMaterialData {
|
|
11
|
+
base: THREE_NS.Color;
|
|
12
|
+
baseRgb: readonly [number, number, number];
|
|
13
|
+
tag: string;
|
|
14
|
+
rough: number;
|
|
15
|
+
}
|
|
16
|
+
type Vec3Tuple = readonly [number, number, number];
|
|
17
|
+
/**
|
|
18
|
+
* The helpers the showcase page defines before its models (`M`, `mesh`, `cyl`, `bx`, `lathe`, `torus`, `extrude`, `G` and the seven material makers), so that the
|
|
19
|
+
* builders ported from the page read the same as the originals. `T` is the three.js the kit was made with; `materials` lists every material it made, in order.
|
|
20
|
+
*/
|
|
21
|
+
interface ItemKit {
|
|
22
|
+
readonly T: Three;
|
|
23
|
+
readonly materials: THREE_NS.MeshStandardMaterial[];
|
|
24
|
+
M(color: number, tag: string, options?: THREE_NS.MeshStandardMaterialParameters): THREE_NS.MeshStandardMaterial;
|
|
25
|
+
mesh(geometry: THREE_NS.BufferGeometry, material: THREE_NS.Material, position?: Vec3Tuple, rotation?: Vec3Tuple, scale?: Vec3Tuple): THREE_NS.Mesh;
|
|
26
|
+
cyl(radiusTop: number, radiusBottom: number, height: number, segments?: number): THREE_NS.CylinderGeometry;
|
|
27
|
+
bx(width: number, height: number, depth: number): THREE_NS.BoxGeometry;
|
|
28
|
+
lathe(points: ReadonlyArray<readonly [number, number]>, segments?: number): THREE_NS.LatheGeometry;
|
|
29
|
+
torus(radius: number, tube: number, arc?: number): THREE_NS.TorusGeometry;
|
|
30
|
+
extrude(points: ReadonlyArray<readonly [number, number]>, depth: number, bevel?: number): THREE_NS.ExtrudeGeometry;
|
|
31
|
+
G(...children: THREE_NS.Object3D[]): THREE_NS.Group;
|
|
32
|
+
metal(color: number): THREE_NS.MeshStandardMaterial;
|
|
33
|
+
wood(color: number): THREE_NS.MeshStandardMaterial;
|
|
34
|
+
cloth(color: number): THREE_NS.MeshStandardMaterial;
|
|
35
|
+
plastic(color: number): THREE_NS.MeshStandardMaterial;
|
|
36
|
+
paper(color: number): THREE_NS.MeshStandardMaterial;
|
|
37
|
+
food(color: number): THREE_NS.MeshStandardMaterial;
|
|
38
|
+
glass(color: number, opacity: number): THREE_NS.MeshStandardMaterial;
|
|
39
|
+
}
|
|
40
|
+
/** The helpers of the showcase page on a given three.js; every kit has its own list of materials. */
|
|
41
|
+
declare function createItemKit(T: Three): ItemKit;
|
|
42
|
+
|
|
43
|
+
/** 0 new, 1 used, 2 spoiled (the three stages of the showcase). */
|
|
44
|
+
type WearStage = 0 | 1 | 2;
|
|
45
|
+
/** The colour each material tag turns toward as it wears (`STAGE_TARGET` of the showcase). */
|
|
46
|
+
declare const WEAR_TARGET: Readonly<Record<string, number>>;
|
|
47
|
+
/** How far toward the target colour each stage goes (`AMT`). */
|
|
48
|
+
declare const WEAR_AMOUNT: readonly [number, number, number];
|
|
49
|
+
/** Every material under `root` that the kit made (with a tag), once each. */
|
|
50
|
+
declare function wearableMaterials(root: THREE_NS.Object3D): THREE_NS.MeshStandardMaterial[];
|
|
51
|
+
/**
|
|
52
|
+
* Sets the wear of an item (`setStage` of the showcase): each material goes from its own colour toward the target of its tag by `WEAR_AMOUNT[stage]`, gets rougher, and
|
|
53
|
+
* metal loses its shine. The colours are mixed in sRGB, as the page mixes them (three r128 had no colour management), so stage 0 is exactly the colour the material was made with.
|
|
54
|
+
* Takes the object or the list of materials of a kit.
|
|
55
|
+
*/
|
|
56
|
+
declare function setWear(target: THREE_NS.Object3D | readonly THREE_NS.MeshStandardMaterial[], stage: WearStage): void;
|
|
57
|
+
|
|
58
|
+
/** The simple shapes the kit draws at the real size of an item, by the `shape` hint of its definition. */
|
|
59
|
+
declare const SHAPES: readonly ["can", "bag", "box", "bottle", "tool", "roll", "dish", "cloth", "shoe", "jar", "paper", "fruit", "cup", "tube", "blade", "long_tool", "garment", "backpack", "jerrycan", "tank", "book", "key", "battery", "plank", "device"];
|
|
60
|
+
type ShapeId = (typeof SHAPES)[number];
|
|
61
|
+
/** What a shape drawer is given: the kit, the size in metres, the colour of the item and the level of detail (1 full, 0.5 half the segments). */
|
|
62
|
+
interface ShapeContext {
|
|
63
|
+
k: ItemKit;
|
|
64
|
+
w: number;
|
|
65
|
+
h: number;
|
|
66
|
+
d: number;
|
|
67
|
+
color: number;
|
|
68
|
+
detail: number;
|
|
69
|
+
}
|
|
70
|
+
/** The colour `factor` times lighter (above 1) or darker (below 1), per channel. */
|
|
71
|
+
declare function shade(color: number, factor: number): number;
|
|
72
|
+
/** The long axis of a size and the three sides in the frame where that axis is x: `L` long, `a` the next, `b` the shortest of the other two in their own order. */
|
|
73
|
+
declare function canonicalFrame(size: Vec3Tuple): {
|
|
74
|
+
axis: 0 | 1 | 2;
|
|
75
|
+
L: number;
|
|
76
|
+
a: number;
|
|
77
|
+
b: number;
|
|
78
|
+
};
|
|
79
|
+
declare const isShape: (value: string | undefined) => value is ShapeId;
|
|
80
|
+
/** The item fields the shape choice reads. */
|
|
81
|
+
interface ShapeSubject {
|
|
82
|
+
category: string;
|
|
83
|
+
size: Vec3Tuple;
|
|
84
|
+
shape?: string;
|
|
85
|
+
color?: number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* The shape an item is drawn with: its own `shape` when it names one of the 25, else a box. The hints the household catalog uses (`tool`, `cloth`, `bag`, `box`, `paper`) are
|
|
89
|
+
* refined by the category and the proportions, so that a rake is a long tool, a jacket a garment, a rucksack a backpack, a phone a device and a diary a book.
|
|
90
|
+
*/
|
|
91
|
+
declare function shapeOf(subject: ShapeSubject): ShapeId;
|
|
92
|
+
/** Draws the simple shape of an item at its real size, centred on the origin (the long side of long shapes lies on the long axis of `size`). */
|
|
93
|
+
declare function drawShape(k: ItemKit, shape: ShapeId, size: Vec3Tuple, options?: {
|
|
94
|
+
color?: number;
|
|
95
|
+
detail?: number;
|
|
96
|
+
}): THREE_NS.Group;
|
|
97
|
+
|
|
98
|
+
/** The fields of an item the drawing reads (an `ItemDef` of `game-items` has them all). */
|
|
99
|
+
interface DrawableItem extends ShapeSubject {
|
|
100
|
+
id: string;
|
|
101
|
+
size: Vec3Tuple;
|
|
102
|
+
/** Key of a showcase model; without one (or when the model is not registered) the simple shape is drawn. */
|
|
103
|
+
model?: string;
|
|
104
|
+
}
|
|
105
|
+
interface BuildItemOptions {
|
|
106
|
+
/** Wear of the materials, 0 new (default), 1 used, 2 spoiled. */
|
|
107
|
+
wear?: WearStage;
|
|
108
|
+
/** Draw the simple shape even when the item has a model (the second level of detail). */
|
|
109
|
+
simple?: boolean;
|
|
110
|
+
/** Level of detail of the simple shape, 1 (default) or 0.5 for half the segments. */
|
|
111
|
+
detail?: number;
|
|
112
|
+
/** A kit to draw with (and to collect the materials in); default a new one. */
|
|
113
|
+
kit?: ItemKit;
|
|
114
|
+
}
|
|
115
|
+
/** What `buildItem` returns. */
|
|
116
|
+
interface ItemModel {
|
|
117
|
+
/** The object to add to a scene: origin at the bottom centre of the item, y up, in metres. */
|
|
118
|
+
readonly root: THREE_NS.Group;
|
|
119
|
+
/** `model` when the showcase builder drew it, `shape` otherwise. */
|
|
120
|
+
readonly kind: 'model' | 'shape';
|
|
121
|
+
readonly shape?: ShapeId;
|
|
122
|
+
/** Size in metres the drawing was fitted to (the item's `size`). */
|
|
123
|
+
readonly size: Vec3Tuple;
|
|
124
|
+
/** The materials made for this item. */
|
|
125
|
+
readonly materials: readonly THREE_NS.MeshStandardMaterial[];
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Draws an item at its real size. An item whose `model` is registered gets the showcase builder, ported as it is (page units, scaled to metres by the scale of
|
|
129
|
+
* `models.json` on the root, so that the group inside is still the team's); every other item gets the simple shape of its `shape` hint (refined by category and
|
|
130
|
+
* proportions) at its `size`. Either way the origin is the bottom centre and y is up.
|
|
131
|
+
*/
|
|
132
|
+
declare function buildItem(T: typeof THREE_NS, item: DrawableItem, options?: BuildItemOptions): ItemModel;
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* The same item with its meshes joined by material: one mesh and one draw call per material instead of one per part (the "one material for all the items" of the page's
|
|
136
|
+
* budget, as far as the materials of the kit allow). The materials are the same objects, so `setWear` still reaches them. The model's scale stays on the root.
|
|
137
|
+
*/
|
|
138
|
+
declare function mergeItem(T: typeof THREE_NS, model: ItemModel): ItemModel;
|
|
139
|
+
|
|
140
|
+
type Vec3Like = readonly [number, number, number];
|
|
141
|
+
/** The draw budgets of the Itens do Vale Cinzento page (section "Desempenho com hordas"). */
|
|
142
|
+
interface ItemBudgets {
|
|
143
|
+
/** Draw calls of all the items in a frame. */
|
|
144
|
+
drawCalls: number;
|
|
145
|
+
/** A small item: at most this many triangles, and it disappears at `cullDistance`. */
|
|
146
|
+
small: {
|
|
147
|
+
triangles: number;
|
|
148
|
+
cullDistance: number;
|
|
149
|
+
};
|
|
150
|
+
/** A large item. */
|
|
151
|
+
large: {
|
|
152
|
+
triangles: number;
|
|
153
|
+
cullDistance: number;
|
|
154
|
+
};
|
|
155
|
+
/** The second level of detail has this share of the triangles of the first. */
|
|
156
|
+
lod1Ratio: number;
|
|
157
|
+
/** Longest side (m) from which an item counts as large: the page does not say where small ends, so this is the kit's reading and a game can change it. */
|
|
158
|
+
largeFrom: number;
|
|
159
|
+
}
|
|
160
|
+
declare const ITEM_BUDGETS: ItemBudgets;
|
|
161
|
+
type ItemSizeClass = 'small' | 'large';
|
|
162
|
+
declare const sizeClassOf: (size: Vec3Like, budgets?: ItemBudgets) => ItemSizeClass;
|
|
163
|
+
declare const triangleBudgetOf: (size: Vec3Like, budgets?: ItemBudgets) => number;
|
|
164
|
+
declare const cullDistanceOf: (size: Vec3Like, budgets?: ItemBudgets) => number;
|
|
165
|
+
/** Triangles under `root`: visible meshes only, indexed or not. */
|
|
166
|
+
declare function countTriangles(root: THREE_NS.Object3D): number;
|
|
167
|
+
/** Draw calls under `root`: one per visible mesh (a mesh with a material list counts once per group). */
|
|
168
|
+
declare function countDrawCalls(root: THREE_NS.Object3D): number;
|
|
169
|
+
interface BudgetReport {
|
|
170
|
+
triangles: number;
|
|
171
|
+
limit: number;
|
|
172
|
+
drawCalls: number;
|
|
173
|
+
sizeClass: ItemSizeClass;
|
|
174
|
+
ok: boolean;
|
|
175
|
+
}
|
|
176
|
+
/** How an item's model measures against its triangle budget (a model of the team above it is a known deviation, not an error). */
|
|
177
|
+
declare function checkBudget(root: THREE_NS.Object3D, size: Vec3Like, budgets?: ItemBudgets): BudgetReport;
|
|
178
|
+
|
|
179
|
+
interface ItemLodOptions extends Omit<BuildItemOptions, 'simple' | 'detail' | 'kit'> {
|
|
180
|
+
budgets?: ItemBudgets;
|
|
181
|
+
/** Join the meshes of each level by material (default true). */
|
|
182
|
+
merge?: boolean;
|
|
183
|
+
/** Distance of the second level in metres; default a third of the distance at which the item disappears. */
|
|
184
|
+
lod1Distance?: number;
|
|
185
|
+
}
|
|
186
|
+
interface ItemLod {
|
|
187
|
+
/** Add this to the scene and call `update(camera)` (or let the renderer do it). */
|
|
188
|
+
readonly root: THREE_NS.LOD;
|
|
189
|
+
/** Full detail: the showcase model, or the shape at full segments. */
|
|
190
|
+
readonly near: ItemModel;
|
|
191
|
+
/** The simple shape at half the segments. */
|
|
192
|
+
readonly far: ItemModel;
|
|
193
|
+
/** Metres from the camera at which the item is no longer drawn. */
|
|
194
|
+
readonly cullDistance: number;
|
|
195
|
+
readonly lod1Distance: number;
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Three levels of an item: the model (or the shape) up close, the simple shape at half the segments from `lod1Distance`, and nothing from the distance of its class
|
|
199
|
+
* (a small item goes at 30 m, a large one at 60 m).
|
|
200
|
+
*/
|
|
201
|
+
declare function buildItemLod(T: typeof THREE_NS, item: DrawableItem, options?: ItemLodOptions): ItemLod;
|
|
202
|
+
|
|
203
|
+
/** One model of the showcase as `data/models.json` keeps it: the item it draws, the id the team gave it, the box it has in the units of the page and the scale to metres. */
|
|
204
|
+
interface ItemModelEntry {
|
|
205
|
+
/** Catalog id of the item (`canned_beans`). */
|
|
206
|
+
readonly id: string;
|
|
207
|
+
/** The id in the team's `MODELS` (`feijao_lata`). */
|
|
208
|
+
readonly teamId: string;
|
|
209
|
+
/** Box of the builder's group in the page's units (`Box3.setFromObject`), x y z. */
|
|
210
|
+
readonly teamBox: readonly [number, number, number];
|
|
211
|
+
/** Metres per unit of the page, from one real measure of the object. */
|
|
212
|
+
readonly scale: number;
|
|
213
|
+
}
|
|
214
|
+
/** A builder of the showcase, ported as it is: it draws in the page's units and returns the group. */
|
|
215
|
+
type ItemModelBuilder = (kit: ItemKit) => THREE_NS.Group;
|
|
216
|
+
/** Adds (or replaces) the model of an item: `entry.id` is the catalog id the item's `model` field names. */
|
|
217
|
+
declare function registerItemModel(entry: ItemModelEntry, builder: ItemModelBuilder): void;
|
|
218
|
+
/** Takes a model out (a game that wants the simple shape instead). */
|
|
219
|
+
declare function unregisterItemModel(id: string): void;
|
|
220
|
+
declare const itemModelEntry: (id: string) => ItemModelEntry | undefined;
|
|
221
|
+
declare const itemModelBuilder: (id: string) => ItemModelBuilder | undefined;
|
|
222
|
+
declare const hasItemModel: (id: string) => boolean;
|
|
223
|
+
/** The ids of the models registered, in the order of registration (the order of the showcase for the ones the kit ships). */
|
|
224
|
+
declare const listItemModels: () => string[];
|
|
225
|
+
|
|
226
|
+
/** The 24 models of the showcase in the page's order: the entry of `data/models.json` (generated by `tools/items-catalog`) and the builder ported from the page. */
|
|
227
|
+
declare const SHIPPED_MODELS: ReadonlyArray<{
|
|
228
|
+
readonly entry: ItemModelEntry;
|
|
229
|
+
readonly builder: ItemModelBuilder;
|
|
230
|
+
}>;
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Models of the showcase that go over the triangle budget of their class (400 for a small item, 1200 for a large one) as the team drew them, with the count they have.
|
|
234
|
+
* The page set the budget for the game and drew the models for a showcase; the models stay as delivered (the builder is the team's) and a scene at a distance wears the
|
|
235
|
+
* simple shape of the second level of detail (`buildItemLod`), which is inside the budget. A model that changes its count is a drawing that changed: the test flags it.
|
|
236
|
+
*/
|
|
237
|
+
declare const MODEL_BUDGET_DEVIATIONS: Readonly<Record<string, number>>;
|
|
238
|
+
|
|
239
|
+
/** The SVG picture of a shape in the colour of an item: a 64 x 64 board with plain shapes, no script and no reference. */
|
|
240
|
+
declare function shapeThumbnailSvg(shape: ShapeId, color?: number): string;
|
|
241
|
+
/**
|
|
242
|
+
* The picture of an item for catalogues and inventories: an item that has a 3D model asks the host to draw it (`render: true`), every other gets the SVG of its shape in
|
|
243
|
+
* its colour.
|
|
244
|
+
*/
|
|
245
|
+
declare function itemThumbnail(item: DrawableItem): Thumbnail;
|
|
246
|
+
/** The SVG of an item whatever it has: its shape in its colour (what a host with no renderer shows for a modeled item). */
|
|
247
|
+
declare const itemThumbnailSvg: (item: DrawableItem) => string;
|
|
248
|
+
/** `{ id: { thumbnail } }` for `createItems({ patch })`, so that a catalog carries its pictures. */
|
|
249
|
+
declare function thumbnailPatch(items: Iterable<DrawableItem>): Record<string, {
|
|
250
|
+
thumbnail: Thumbnail;
|
|
251
|
+
}>;
|
|
252
|
+
interface ThumbnailRenderOptions {
|
|
253
|
+
/** Side of the picture in pixels (default 128). */
|
|
254
|
+
size?: number;
|
|
255
|
+
/** Turn of the item around y and the lift of the camera, radians (default a three-quarter view from above). */
|
|
256
|
+
yaw?: number;
|
|
257
|
+
pitch?: number;
|
|
258
|
+
/** Multiplies the distance that just fits the item (default 1). */
|
|
259
|
+
distance?: number;
|
|
260
|
+
wear?: WearStage;
|
|
261
|
+
}
|
|
262
|
+
interface ThumbnailScene {
|
|
263
|
+
scene: THREE_NS.Scene;
|
|
264
|
+
camera: THREE_NS.PerspectiveCamera;
|
|
265
|
+
}
|
|
266
|
+
/** The scene and camera that frame an item for its picture: the item at the origin, lit like the showcase (hemisphere, sun, rim), the camera far enough to fit all of it. */
|
|
267
|
+
declare function composeThumbnailScene(T: typeof THREE_NS, item: DrawableItem, options?: ThumbnailRenderOptions): ThumbnailScene;
|
|
268
|
+
/** What `renderItemThumbnail` needs of a renderer (a `WebGLRenderer`, or anything that draws a scene to a canvas). */
|
|
269
|
+
interface ThumbnailRenderer {
|
|
270
|
+
setSize(width: number, height: number): void;
|
|
271
|
+
setClearColor?(color: number, alpha?: number): void;
|
|
272
|
+
render(scene: THREE_NS.Scene, camera: THREE_NS.Camera): void;
|
|
273
|
+
domElement: {
|
|
274
|
+
toDataURL(type?: string): string;
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
/** Draws the item with the host's renderer and returns the PNG as a data URL (transparent background). */
|
|
278
|
+
declare function renderItemThumbnail(T: typeof THREE_NS, renderer: ThumbnailRenderer, item: DrawableItem, options?: ThumbnailRenderOptions): string;
|
|
279
|
+
|
|
280
|
+
/** What the layout needs of an item: its id, category and real size [width, height, depth] in metres. */
|
|
281
|
+
interface LayoutItem {
|
|
282
|
+
readonly id: string;
|
|
283
|
+
readonly category: string;
|
|
284
|
+
readonly size: readonly [number, number, number];
|
|
285
|
+
}
|
|
286
|
+
/** Height of the top of a shelf, metres. */
|
|
287
|
+
declare const SHELF_HEIGHT = 0.9;
|
|
288
|
+
/** Longest row of items on a shelf, metres. */
|
|
289
|
+
declare const ROW_LIMIT = 5;
|
|
290
|
+
/** One shelf: a category's items laid out in rows at real size, the shelf's footprint and where its items sit on its top. */
|
|
291
|
+
interface ShelfPlan {
|
|
292
|
+
category: string;
|
|
293
|
+
/** Item id of the shelf in the module (`shelf_<category>`). */
|
|
294
|
+
id: string;
|
|
295
|
+
/** Footprint on the floor: length along x, depth along z. */
|
|
296
|
+
length: number;
|
|
297
|
+
depth: number;
|
|
298
|
+
position: Vec3;
|
|
299
|
+
/** Where each item sits, in world coordinates. */
|
|
300
|
+
items: AreaPlacement[];
|
|
301
|
+
}
|
|
302
|
+
declare const SHELF_PREFIX = "shelf_";
|
|
303
|
+
declare const ITEM_PREFIX = "item_";
|
|
304
|
+
declare const SHOWCASE_PREFIX = "showcase_";
|
|
305
|
+
/**
|
|
306
|
+
* The shelves of the area: one per category, in the order the categories come, with every item of the category side by side at real size, wrapped in rows of at most
|
|
307
|
+
* `ROW_LIMIT` metres. Shelves stand in a grid of four columns; an item that is longer than the row limit gets a row to itself. Pure: the same items always land in the same spots.
|
|
308
|
+
*/
|
|
309
|
+
declare function shelvesLayout(items: readonly LayoutItem[], categories: readonly string[]): ShelfPlan[];
|
|
310
|
+
|
|
311
|
+
interface ItemsTestModuleOptions {
|
|
312
|
+
/** The catalog to lay out (for example `createGoodsItems()` of `game-items-goods`). The module knows no content of its own. */
|
|
313
|
+
catalog: ItemsCatalog;
|
|
314
|
+
/** `en` or `pt-BR` (default). */
|
|
315
|
+
locale?: string;
|
|
316
|
+
/** Text of a key such as `item.canned_beans`, `place.house`, `category.food`, `container.fridge`, `recipe.stew` (the goods package has them in `goodsText`); without it the module falls back to the id. */
|
|
317
|
+
translate?: (key: string, locale: string) => string | undefined;
|
|
318
|
+
/** Seed of the finds roll (default 1). */
|
|
319
|
+
seed?: number;
|
|
320
|
+
/** Wear the items start with: `new` (default), `used` or `spoiled`. */
|
|
321
|
+
wear?: string;
|
|
322
|
+
/** The finds provider; default the one of `game-items` over `catalog`. A game gives its own (floorplan bindings, pools). */
|
|
323
|
+
provider?: FindsProvider;
|
|
324
|
+
}
|
|
325
|
+
declare const SHOWCASE_STAND_ID = "stand_models";
|
|
326
|
+
declare const RULER_ID = "ruler_155";
|
|
327
|
+
declare const HUMAN_ID = "human_180";
|
|
328
|
+
declare const FINDS_TABLE_ID = "finds_table";
|
|
329
|
+
declare const RULER_HEIGHT = 1.55;
|
|
330
|
+
declare const HUMAN_HEIGHT = 1.8;
|
|
331
|
+
/** What the scenarios of the area ask of the module (and what a host or a test may read). */
|
|
332
|
+
interface ItemsAreaState {
|
|
333
|
+
readonly category: string;
|
|
334
|
+
readonly wear: string;
|
|
335
|
+
readonly ageDays: number;
|
|
336
|
+
readonly storage: string;
|
|
337
|
+
readonly powered: boolean;
|
|
338
|
+
readonly place: string;
|
|
339
|
+
readonly container: string;
|
|
340
|
+
readonly state: string;
|
|
341
|
+
readonly day: number;
|
|
342
|
+
readonly seed: number;
|
|
343
|
+
readonly recipe: string;
|
|
344
|
+
}
|
|
345
|
+
interface ItemsTestModule extends TestableModule {
|
|
346
|
+
/** Everything the module has put in the scene so far, with what was measured when it was drawn. */
|
|
347
|
+
placed(): ReadonlyArray<{
|
|
348
|
+
id: string;
|
|
349
|
+
itemId: string;
|
|
350
|
+
group: 'shelf' | 'showcase';
|
|
351
|
+
kind: 'model' | 'shape';
|
|
352
|
+
size: readonly [number, number, number];
|
|
353
|
+
root: THREE_NS.Object3D;
|
|
354
|
+
}>;
|
|
355
|
+
/** The stacks now on the finds table. */
|
|
356
|
+
finds(): readonly FindStack[];
|
|
357
|
+
/** The shelves of the layout. */
|
|
358
|
+
shelves(): readonly ShelfPlan[];
|
|
359
|
+
readonly state: ItemsAreaState;
|
|
360
|
+
/** The bench actions, callable without a host (what the buttons do). */
|
|
361
|
+
rollFinds(): readonly FindStack[];
|
|
362
|
+
craftSelected(): {
|
|
363
|
+
ok: boolean;
|
|
364
|
+
missing: readonly string[];
|
|
365
|
+
};
|
|
366
|
+
selectRecipe(id: string): void;
|
|
367
|
+
/** The box of a drawn object, metres [x, y, z] (needs the host's three.js namespace: null before the module is attached or an item built). */
|
|
368
|
+
measure(root: THREE_NS.Object3D): [number, number, number] | null;
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* The items test area as a `TestableModule` of @adatechnology/game-contracts: every item of a catalog on shelves by category at real size (the real model of the team where there is
|
|
372
|
+
* one, the simple shape of its category elsewhere), a stand where the 24 models turn, a ruler and a human figure to judge the scale, and a table where the finds of a container
|
|
373
|
+
* and the result of a recipe are laid. The bench sets wear, age and storage, the place, container, state, outbreak day and seed of the finds, and the recipe.
|
|
374
|
+
*/
|
|
375
|
+
declare function createItemsTestModule(options: ItemsTestModuleOptions): ItemsTestModule;
|
|
376
|
+
/** What the scenarios use of the context the test room passes (`ScenarioContext`). */
|
|
377
|
+
interface ScenarioLike {
|
|
378
|
+
expect(condition: boolean, label: string, data?: Record<string, unknown>): void;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export { type BudgetReport, type BuildItemOptions, type DrawableItem, FINDS_TABLE_ID, HUMAN_HEIGHT, HUMAN_ID, ITEM_BUDGETS, ITEM_PREFIX, type ItemBudgets, type ItemKit, type ItemLod, type ItemLodOptions, type ItemMaterialData, type ItemModel, type ItemModelBuilder, type ItemModelEntry, type ItemSizeClass, type ItemsAreaState, type ItemsTestModule, type ItemsTestModuleOptions, type LayoutItem, MODEL_BUDGET_DEVIATIONS, ROW_LIMIT, RULER_HEIGHT, RULER_ID, SHAPES, SHELF_HEIGHT, SHELF_PREFIX, SHIPPED_MODELS, SHOWCASE_PREFIX, SHOWCASE_STAND_ID, type ScenarioLike, type ShapeContext, type ShapeId, type ShapeSubject, type ShelfPlan, type ThumbnailRenderOptions, type ThumbnailRenderer, type ThumbnailScene, type Vec3Like, type Vec3Tuple, WEAR_AMOUNT, WEAR_TAGS, WEAR_TARGET, type WearStage, type WearTag, buildItem, buildItemLod, canonicalFrame, checkBudget, composeThumbnailScene, countDrawCalls, countTriangles, createItemKit, createItemsTestModule, cullDistanceOf, drawShape, hasItemModel, isShape, itemModelBuilder, itemModelEntry, itemThumbnail, itemThumbnailSvg, listItemModels, mergeItem, registerItemModel, renderItemThumbnail, setWear, shade, shapeOf, shapeThumbnailSvg, shelvesLayout, sizeClassOf, thumbnailPatch, triangleBudgetOf, unregisterItemModel, wearableMaterials };
|