@poe2-toolkit/tree-core 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/README.md +451 -0
- package/dist/geometry/centre.d.ts +17 -0
- package/dist/geometry/centre.d.ts.map +1 -0
- package/dist/geometry/centre.js +59 -0
- package/dist/geometry/centre.js.map +1 -0
- package/dist/geometry/framing.d.ts +27 -0
- package/dist/geometry/framing.d.ts.map +1 -0
- package/dist/geometry/framing.js +101 -0
- package/dist/geometry/framing.js.map +1 -0
- package/dist/geometry/orbit.d.ts +23 -0
- package/dist/geometry/orbit.d.ts.map +1 -0
- package/dist/geometry/orbit.js +28 -0
- package/dist/geometry/orbit.js.map +1 -0
- package/dist/geometry/project.d.ts +20 -0
- package/dist/geometry/project.d.ts.map +1 -0
- package/dist/geometry/project.js +149 -0
- package/dist/geometry/project.js.map +1 -0
- package/dist/ggg/normalize.d.ts +109 -0
- package/dist/ggg/normalize.d.ts.map +1 -0
- package/dist/ggg/normalize.js +279 -0
- package/dist/ggg/normalize.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/dist/scene/allocate.d.ts +61 -0
- package/dist/scene/allocate.d.ts.map +1 -0
- package/dist/scene/allocate.js +239 -0
- package/dist/scene/allocate.js.map +1 -0
- package/dist/scene/buildScene.d.ts +21 -0
- package/dist/scene/buildScene.d.ts.map +1 -0
- package/dist/scene/buildScene.js +212 -0
- package/dist/scene/buildScene.js.map +1 -0
- package/dist/scene/connections.d.ts +13 -0
- package/dist/scene/connections.d.ts.map +1 -0
- package/dist/scene/connections.js +75 -0
- package/dist/scene/connections.js.map +1 -0
- package/dist/scene/nodeSize.d.ts +26 -0
- package/dist/scene/nodeSize.d.ts.map +1 -0
- package/dist/scene/nodeSize.js +72 -0
- package/dist/scene/nodeSize.js.map +1 -0
- package/dist/types.d.ts +426 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data contracts for the engine.
|
|
3
|
+
*
|
|
4
|
+
* Two families of types live here:
|
|
5
|
+
* - `TreeData` + friends: the **source** shape, normalised from GGG's official
|
|
6
|
+
* skill-tree export (`data.json`). GGG bakes world `x`/`y` into every node;
|
|
7
|
+
* the engine consumes those positions directly.
|
|
8
|
+
* - `Scene` + friends: the **computed** shape the engine produces, with every
|
|
9
|
+
* node/effect already positioned and sized in world space.
|
|
10
|
+
*
|
|
11
|
+
* Sizes are still *derived* (Path of Building's `GetNodeTargetSize` cascade);
|
|
12
|
+
* only positions come baked, because GGG does not ship the orbit-radius
|
|
13
|
+
* constants needed to recompute them and instead pre-bakes the coordinates.
|
|
14
|
+
*/
|
|
15
|
+
export interface TreeData {
|
|
16
|
+
/** Tree/patch version, e.g. "0_5". */
|
|
17
|
+
version: string;
|
|
18
|
+
/** Geometry backbone shared by every node. */
|
|
19
|
+
constants: TreeConstants;
|
|
20
|
+
/** Orbit anchor clusters, keyed by group id. */
|
|
21
|
+
groups: Record<number, Group>;
|
|
22
|
+
/** Every node, keyed by skill id. */
|
|
23
|
+
nodes: Record<number, TreeNode>;
|
|
24
|
+
/** Central class art + ascendancy metadata. */
|
|
25
|
+
classes: ClassDef[];
|
|
26
|
+
/** Skill ids that are jewel sockets. */
|
|
27
|
+
jewelSlots: number[];
|
|
28
|
+
/** World-space extent of the whole tree (for fit-to-view). */
|
|
29
|
+
bounds: WorldRect;
|
|
30
|
+
}
|
|
31
|
+
export interface TreeConstants {
|
|
32
|
+
/**
|
|
33
|
+
* Radius of the central opening. PoB ships this as `PSSCentreInnerRadius`;
|
|
34
|
+
* GGG's export omits it, so normalisation supplies the (stable) game value.
|
|
35
|
+
*/
|
|
36
|
+
centreInnerRadius: number;
|
|
37
|
+
}
|
|
38
|
+
export interface Group {
|
|
39
|
+
/** World centre of the orbit cluster. */
|
|
40
|
+
x: number;
|
|
41
|
+
y: number;
|
|
42
|
+
/** Which orbits are populated in this group. */
|
|
43
|
+
orbits: number[];
|
|
44
|
+
/** Member skill ids. */
|
|
45
|
+
nodes: number[];
|
|
46
|
+
}
|
|
47
|
+
export interface TreeNode {
|
|
48
|
+
/** Canonical skill id (matches GGG `PassiveSkills.id`). */
|
|
49
|
+
skill: number;
|
|
50
|
+
/** Owning group id (direct index into {@link TreeData.groups}). */
|
|
51
|
+
group: number;
|
|
52
|
+
/** Orbit number within the group. */
|
|
53
|
+
orbit: number;
|
|
54
|
+
/** Slot index along the orbit. */
|
|
55
|
+
orbitIndex: number;
|
|
56
|
+
/** World x, baked by GGG's export. */
|
|
57
|
+
x: number;
|
|
58
|
+
/** World y, baked by GGG's export. */
|
|
59
|
+
y: number;
|
|
60
|
+
/** Edges to neighbouring nodes (GGG `in` + `out`, merged). */
|
|
61
|
+
connections: NodeConnection[];
|
|
62
|
+
name: string;
|
|
63
|
+
/** Atlas key into the {@link SpriteManifest}. */
|
|
64
|
+
icon: string;
|
|
65
|
+
stats: string[];
|
|
66
|
+
isNotable?: boolean;
|
|
67
|
+
isKeystone?: boolean;
|
|
68
|
+
isJewelSocket?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Special sockets (e.g. "Sinister Jewel Socket") that are not part of the base
|
|
71
|
+
* tree and are hidden from the normal render. Derived from the node name, as
|
|
72
|
+
* GGG carries no dedicated flag (PoB shipped this as `noRadius`).
|
|
73
|
+
*/
|
|
74
|
+
noRadius?: boolean;
|
|
75
|
+
/** GGG: `isMastery` (PoB: `isOnlyImage`). */
|
|
76
|
+
isMastery?: boolean;
|
|
77
|
+
isAscendancyStart?: boolean;
|
|
78
|
+
/** GGG: `isGenericAttribute`. */
|
|
79
|
+
isAttribute?: boolean;
|
|
80
|
+
/** Background pattern key (masteries AND notables). */
|
|
81
|
+
activeEffectImage?: string;
|
|
82
|
+
/**
|
|
83
|
+
* Ascendancy display name (e.g. "Deadeye"), translated from GGG's internal
|
|
84
|
+
* `ascendancyId` ("Ranger1") so it matches a build's chosen ascendancy.
|
|
85
|
+
*/
|
|
86
|
+
ascendancyName?: string;
|
|
87
|
+
/** Keystone lore. */
|
|
88
|
+
flavourText?: string;
|
|
89
|
+
recipe?: string[];
|
|
90
|
+
/** Attribute nodes: the interchangeable choices (e.g. Str / Dex / Int). */
|
|
91
|
+
options?: NodeOption[];
|
|
92
|
+
/**
|
|
93
|
+
* Conditional node (GGG `unlockConstraint`): not part of the base tree, shown
|
|
94
|
+
* only when unlocked (e.g. by an ascendancy). The official default tree hides
|
|
95
|
+
* these.
|
|
96
|
+
*/
|
|
97
|
+
conditional?: boolean;
|
|
98
|
+
/** Ascendancy id that unlocks this conditional node, when specified. */
|
|
99
|
+
unlockAscendancy?: string;
|
|
100
|
+
/** Present on class-start nodes: names of the classes that start here. */
|
|
101
|
+
classesStart?: string[];
|
|
102
|
+
}
|
|
103
|
+
/** One selectable variant of an attribute node. */
|
|
104
|
+
export interface NodeOption {
|
|
105
|
+
id: number;
|
|
106
|
+
name: string;
|
|
107
|
+
stats: string[];
|
|
108
|
+
/** Skill-icon path for this specific choice (e.g. plusintelligence.png). */
|
|
109
|
+
icon: string;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* An edge to a neighbouring node. GGG's top-level `edges` table marks which edges
|
|
113
|
+
* are arcs and gives the arc centre directly (`orbitX`/`orbitY`); that centre is
|
|
114
|
+
* carried here as {@link NodeConnection.arcCentre}. Edges without it draw as a
|
|
115
|
+
* straight line (or, as a fallback, an arc around the shared group centre — see
|
|
116
|
+
* {@link placeConnection}).
|
|
117
|
+
*/
|
|
118
|
+
export interface NodeConnection {
|
|
119
|
+
/** Skill id of the connected node. */
|
|
120
|
+
id: number;
|
|
121
|
+
/** World centre of the arc this edge follows (GGG `orbitX`/`orbitY`), if any. */
|
|
122
|
+
arcCentre?: Point;
|
|
123
|
+
}
|
|
124
|
+
export interface Size {
|
|
125
|
+
width: number;
|
|
126
|
+
height: number;
|
|
127
|
+
}
|
|
128
|
+
export interface ClassDef {
|
|
129
|
+
name: string;
|
|
130
|
+
/** Integer class id = index in GGG's `classes` array (Witch = 1). */
|
|
131
|
+
id: number;
|
|
132
|
+
baseStr: number;
|
|
133
|
+
baseDex: number;
|
|
134
|
+
baseInt: number;
|
|
135
|
+
/** Skill id of this class's start node (derived from `classStartIndex`). */
|
|
136
|
+
startNode: number;
|
|
137
|
+
/** Central art + ring geometry for this class. */
|
|
138
|
+
centre: CentreArt;
|
|
139
|
+
ascendancies: AscendancyDef[];
|
|
140
|
+
/**
|
|
141
|
+
* Per-class node display overrides: base node skill id -> the skill id whose
|
|
142
|
+
* name/stats/icon this class shows instead (e.g. the Witch sees the generic
|
|
143
|
+
* "Spell Damage" node as "Spell and Minion Damage"). Geometry is unchanged.
|
|
144
|
+
*/
|
|
145
|
+
overridePairs?: Record<number, number>;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* The three concentric layers drawn at the tree hub for a class. All share the
|
|
149
|
+
* same world centre (`x`/`y`, pinned at the origin).
|
|
150
|
+
*
|
|
151
|
+
* GGG's `data.json` carries no layer dimensions, so normalisation fills these
|
|
152
|
+
* from the stable atlas frame sizes: the class portrait (`background-<class>`)
|
|
153
|
+
* is 1500², the ornate + rotating rings (`group-background`) are 2000². World
|
|
154
|
+
* radius equals the native width (the DrawAsset 2× rule folds in downstream).
|
|
155
|
+
*/
|
|
156
|
+
export interface CentreArt {
|
|
157
|
+
/** Class portrait atlas key (e.g. `ClassesRanger`). */
|
|
158
|
+
image: string;
|
|
159
|
+
/** World centre of the hub (origin: 0,0). */
|
|
160
|
+
x: number;
|
|
161
|
+
y: number;
|
|
162
|
+
/** Static class-portrait layer native size (1500²). */
|
|
163
|
+
art: Size;
|
|
164
|
+
/** Rotating gold ring layer native size (2000²). */
|
|
165
|
+
active: Size;
|
|
166
|
+
/** Static ornate frame layer native size (2000²). */
|
|
167
|
+
frame: Size;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* An ascendancy disc as a relocatable block. GGG bakes each ascendancy's nodes
|
|
171
|
+
* at a far-flung cluster; `worldAnchor` is where that cluster sits. The renderer
|
|
172
|
+
* chooses where to draw it — translated into the hub (how the game shows it) or
|
|
173
|
+
* left at `worldAnchor` (the raw export layout).
|
|
174
|
+
*/
|
|
175
|
+
export interface AscendancyDef {
|
|
176
|
+
/** Display name, also the build's ascendancy key (e.g. "Deadeye"). */
|
|
177
|
+
id: string;
|
|
178
|
+
name: string;
|
|
179
|
+
/** GGG internal id, e.g. `Ranger1`. */
|
|
180
|
+
internalId: string;
|
|
181
|
+
/** Disc background atlas key. */
|
|
182
|
+
image: string;
|
|
183
|
+
/**
|
|
184
|
+
* World anchor of the disc: the centroid of its nodes (GGG bakes each
|
|
185
|
+
* ascendancy's nodes at a far-flung cluster). The renderer translates this
|
|
186
|
+
* onto the hub to draw the disc game-style.
|
|
187
|
+
*/
|
|
188
|
+
worldAnchor: Point;
|
|
189
|
+
/** Disc native size (1500²). */
|
|
190
|
+
size: Size;
|
|
191
|
+
}
|
|
192
|
+
export interface SpriteFrame {
|
|
193
|
+
/** Atlas id the render package resolves to a bitmap. */
|
|
194
|
+
atlas: string;
|
|
195
|
+
/** Native pixel sub-rect inside the atlas. */
|
|
196
|
+
x: number;
|
|
197
|
+
y: number;
|
|
198
|
+
w: number;
|
|
199
|
+
h: number;
|
|
200
|
+
}
|
|
201
|
+
export interface SpriteManifest {
|
|
202
|
+
/** Atlas key -> native pixel rect. */
|
|
203
|
+
frames: Record<string, SpriteFrame>;
|
|
204
|
+
}
|
|
205
|
+
export interface Point {
|
|
206
|
+
x: number;
|
|
207
|
+
y: number;
|
|
208
|
+
}
|
|
209
|
+
export interface WorldRect {
|
|
210
|
+
minX: number;
|
|
211
|
+
minY: number;
|
|
212
|
+
maxX: number;
|
|
213
|
+
maxY: number;
|
|
214
|
+
}
|
|
215
|
+
export interface Scene {
|
|
216
|
+
nodes: PlacedNode[];
|
|
217
|
+
connections: PlacedConnection[];
|
|
218
|
+
masteryEffects: PlacedEffect[];
|
|
219
|
+
centre: CentreLayout;
|
|
220
|
+
/** Extent of the whole tree, including the far-flung ascendancy discs. */
|
|
221
|
+
bounds: WorldRect;
|
|
222
|
+
/**
|
|
223
|
+
* Extent of the main tree only (ascendancy nodes excluded). Use this to fit
|
|
224
|
+
* the initial view: the ascendancy discs sit thousands of units out, so
|
|
225
|
+
* fitting `bounds` leaves the main tree tiny in the middle.
|
|
226
|
+
*/
|
|
227
|
+
mainBounds: WorldRect;
|
|
228
|
+
}
|
|
229
|
+
export interface PlacedNode {
|
|
230
|
+
skill: number;
|
|
231
|
+
/** Absolute world centre. */
|
|
232
|
+
x: number;
|
|
233
|
+
y: number;
|
|
234
|
+
kind: NodeKind;
|
|
235
|
+
/** Skill-icon atlas key (carried through from {@link TreeNode.icon}). */
|
|
236
|
+
icon: string;
|
|
237
|
+
/** World diameter of the skill icon. */
|
|
238
|
+
iconSize: number;
|
|
239
|
+
/** World diameter of the overlay frame (0 = none, e.g. masteries). */
|
|
240
|
+
frameSize: number;
|
|
241
|
+
/** Hit-test radius: half the larger of icon/frame. */
|
|
242
|
+
radius: number;
|
|
243
|
+
/** Allocated in the current build. */
|
|
244
|
+
allocated: boolean;
|
|
245
|
+
/** Owning ascendancy id, if this node belongs to an ascendancy. */
|
|
246
|
+
ascendancy?: string;
|
|
247
|
+
/** Jewel socketed into this node (jewel sockets only), if the build has one. */
|
|
248
|
+
jewel?: JewelInfo;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* A jewel socketed into a tree socket. Display-only metadata — the engine never
|
|
252
|
+
* applies a jewel's radius effect to nearby nodes (PoE2 jewels are global stats).
|
|
253
|
+
*/
|
|
254
|
+
export interface JewelInfo {
|
|
255
|
+
name: string;
|
|
256
|
+
/** Item rarity, upper-case PoB form: NORMAL / MAGIC / RARE / UNIQUE. */
|
|
257
|
+
rarity: string;
|
|
258
|
+
baseType: string;
|
|
259
|
+
/** Granted modifier lines. */
|
|
260
|
+
mods: string[];
|
|
261
|
+
/** Item-icon URL for the jewel's base type, when resolved. */
|
|
262
|
+
icon?: string;
|
|
263
|
+
}
|
|
264
|
+
export type NodeKind = 'normal' | 'notable' | 'keystone' | 'mastery' | 'jewel' | 'attribute' | 'classStart' | 'ascendancyStart' | 'ascendancyNormal' | 'ascendancyNotable';
|
|
265
|
+
export interface PlacedConnection {
|
|
266
|
+
from: number;
|
|
267
|
+
to: number;
|
|
268
|
+
/** Straight line, or an arc following an orbit. */
|
|
269
|
+
kind: 'line' | 'arc';
|
|
270
|
+
a: Point;
|
|
271
|
+
b: Point;
|
|
272
|
+
/** Both endpoints allocated — the edge is part of the build. */
|
|
273
|
+
active: boolean;
|
|
274
|
+
/** Owning ascendancy id, if this edge is inside an ascendancy. */
|
|
275
|
+
ascendancy?: string;
|
|
276
|
+
/** Arc only: centre, radius, signed sweep (radians), and the orbit it follows. */
|
|
277
|
+
arc?: {
|
|
278
|
+
cx: number;
|
|
279
|
+
cy: number;
|
|
280
|
+
radius: number;
|
|
281
|
+
startAngle: number;
|
|
282
|
+
endAngle: number;
|
|
283
|
+
clockwise: boolean;
|
|
284
|
+
orbit: number;
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
export interface PlacedEffect {
|
|
288
|
+
/** Node the effect pattern belongs to. */
|
|
289
|
+
skill: number;
|
|
290
|
+
x: number;
|
|
291
|
+
y: number;
|
|
292
|
+
/** World diameter of the pattern. */
|
|
293
|
+
size: number;
|
|
294
|
+
patternKey: string;
|
|
295
|
+
/** The mastery's cluster (group) has an allocated node — the pattern is lit. */
|
|
296
|
+
active: boolean;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* The hub layout: where the centre is, how big the opening is, and one anchor
|
|
300
|
+
* per class describing how its ring rotates and where it sits on the rim. All
|
|
301
|
+
* derived from the data — none of it eyeballed.
|
|
302
|
+
*/
|
|
303
|
+
export interface CentreLayout {
|
|
304
|
+
/** World centre of the hub (the origin). */
|
|
305
|
+
centre: Point;
|
|
306
|
+
/** Radius of the central opening. */
|
|
307
|
+
innerRadius: number;
|
|
308
|
+
/**
|
|
309
|
+
* World radii of the three hub layers (shared across classes). Each layer is
|
|
310
|
+
* drawn at `2 * width` centred on the hub, so the world radius equals the
|
|
311
|
+
* native `width` — already folded in here so the renderer just scales these.
|
|
312
|
+
*/
|
|
313
|
+
ring: {
|
|
314
|
+
artRadius: number;
|
|
315
|
+
activeRadius: number;
|
|
316
|
+
frameRadius: number;
|
|
317
|
+
};
|
|
318
|
+
classes: ClassAnchor[];
|
|
319
|
+
/** Every ascendancy disc (relocatable block: world anchor + size). */
|
|
320
|
+
ascendancies: AscendancyDef[];
|
|
321
|
+
}
|
|
322
|
+
export interface ClassAnchor {
|
|
323
|
+
classId: number;
|
|
324
|
+
name: string;
|
|
325
|
+
/** Class-start skill id. */
|
|
326
|
+
startNode: number;
|
|
327
|
+
/** Radians, direction centre -> start node: the class's spot on the rim. */
|
|
328
|
+
startAngle: number;
|
|
329
|
+
/** Radians to rotate the active ring onto this class: `π/2 + atan2(dy, dx)`. */
|
|
330
|
+
ringRotation: number;
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* A character's tree state, and the ONLY build input the engine needs. Whatever
|
|
334
|
+
* produces it — a POB code / `.build` decoder, the GGG OAuth API, a manual
|
|
335
|
+
* editor — is none of the engine's concern. Gems and items are irrelevant to
|
|
336
|
+
* drawing the tree and deliberately absent.
|
|
337
|
+
*/
|
|
338
|
+
export interface BuildAllocation {
|
|
339
|
+
/**
|
|
340
|
+
* Integer class id (matches `ClassDef.id`). Optional: a read-only allocation
|
|
341
|
+
* identifies its class by name at the call site (the imported PoB `classId`
|
|
342
|
+
* is not stable across versions), and only the editable planner needs the id
|
|
343
|
+
* — to find the class start node for pathing.
|
|
344
|
+
*/
|
|
345
|
+
classId?: number;
|
|
346
|
+
/** Active ascendancy id (matches `AscendancyDef.id`), if any. */
|
|
347
|
+
ascendId?: string;
|
|
348
|
+
/** Allocated skill ids. */
|
|
349
|
+
allocated: number[];
|
|
350
|
+
/**
|
|
351
|
+
* Chosen attribute per generic +attribute node (node id -> str/dex/int). Lets
|
|
352
|
+
* the renderer show the specific icon/stat instead of the generic "any".
|
|
353
|
+
*/
|
|
354
|
+
attributeChoices?: Record<number, AttributeChoice>;
|
|
355
|
+
/** Jewels socketed into the tree, keyed by socket node id. Display-only. */
|
|
356
|
+
jewels?: Record<number, JewelInfo>;
|
|
357
|
+
/** Tree/patch version the allocation was made against, e.g. "0_5". */
|
|
358
|
+
treeVersion?: string;
|
|
359
|
+
}
|
|
360
|
+
/** The attribute a generic +attribute node was assigned to. */
|
|
361
|
+
export type AttributeChoice = 'str' | 'dex' | 'int';
|
|
362
|
+
/** Inputs to {@link Scene} construction beyond the static tree data. */
|
|
363
|
+
export interface SceneOptions {
|
|
364
|
+
/** Current build state; omit for an unallocated tree. */
|
|
365
|
+
allocation?: BuildAllocation;
|
|
366
|
+
}
|
|
367
|
+
/** View transform: `screen = world * scale + (tx, ty)`. */
|
|
368
|
+
export interface Viewport {
|
|
369
|
+
tx: number;
|
|
370
|
+
ty: number;
|
|
371
|
+
scale: number;
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* A {@link Scene} projected to screen pixels and culled to the viewport. The
|
|
375
|
+
* renderer walks these arrays and blits — no `* scale`, no `+ offset`, no math.
|
|
376
|
+
*/
|
|
377
|
+
export interface ScreenScene {
|
|
378
|
+
/** The viewport scale, for line widths / LOD decisions in the renderer. */
|
|
379
|
+
scale: number;
|
|
380
|
+
nodes: ScreenNode[];
|
|
381
|
+
connections: ScreenConnection[];
|
|
382
|
+
masteryEffects: ScreenEffect[];
|
|
383
|
+
}
|
|
384
|
+
export interface ScreenNode {
|
|
385
|
+
skill: number;
|
|
386
|
+
/** Screen-pixel centre. */
|
|
387
|
+
x: number;
|
|
388
|
+
y: number;
|
|
389
|
+
kind: NodeKind;
|
|
390
|
+
icon: string;
|
|
391
|
+
/** Screen-pixel diameters. */
|
|
392
|
+
iconSize: number;
|
|
393
|
+
frameSize: number;
|
|
394
|
+
radius: number;
|
|
395
|
+
allocated: boolean;
|
|
396
|
+
/** Jewel socketed into this node (jewel sockets only), if the build has one. */
|
|
397
|
+
jewel?: JewelInfo;
|
|
398
|
+
}
|
|
399
|
+
export interface ScreenConnection {
|
|
400
|
+
from: number;
|
|
401
|
+
to: number;
|
|
402
|
+
kind: 'line' | 'arc';
|
|
403
|
+
a: Point;
|
|
404
|
+
b: Point;
|
|
405
|
+
active: boolean;
|
|
406
|
+
/** Arc only, in screen space (angles are unchanged by uniform scale). */
|
|
407
|
+
arc?: {
|
|
408
|
+
cx: number;
|
|
409
|
+
cy: number;
|
|
410
|
+
radius: number;
|
|
411
|
+
startAngle: number;
|
|
412
|
+
endAngle: number;
|
|
413
|
+
clockwise: boolean;
|
|
414
|
+
orbit: number;
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
export interface ScreenEffect {
|
|
418
|
+
skill: number;
|
|
419
|
+
x: number;
|
|
420
|
+
y: number;
|
|
421
|
+
size: number;
|
|
422
|
+
patternKey: string;
|
|
423
|
+
/** The mastery's cluster (group) has an allocated node — the pattern is lit. */
|
|
424
|
+
active: boolean;
|
|
425
|
+
}
|
|
426
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data contracts for the engine.
|
|
3
|
+
*
|
|
4
|
+
* Two families of types live here:
|
|
5
|
+
* - `TreeData` + friends: the **source** shape, normalised from GGG's official
|
|
6
|
+
* skill-tree export (`data.json`). GGG bakes world `x`/`y` into every node;
|
|
7
|
+
* the engine consumes those positions directly.
|
|
8
|
+
* - `Scene` + friends: the **computed** shape the engine produces, with every
|
|
9
|
+
* node/effect already positioned and sized in world space.
|
|
10
|
+
*
|
|
11
|
+
* Sizes are still *derived* (Path of Building's `GetNodeTargetSize` cascade);
|
|
12
|
+
* only positions come baked, because GGG does not ship the orbit-radius
|
|
13
|
+
* constants needed to recompute them and instead pre-bakes the coordinates.
|
|
14
|
+
*/
|
|
15
|
+
export {};
|
|
16
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@poe2-toolkit/tree-core",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Headless, framework-agnostic geometry engine for the Path of Exile 2 passive tree. Data in, game-accurate scene out. Positions and sizes derived from the source data, never hand-tuned.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"path-of-exile",
|
|
7
|
+
"poe2",
|
|
8
|
+
"passive-tree",
|
|
9
|
+
"skill-tree",
|
|
10
|
+
"geometry"
|
|
11
|
+
],
|
|
12
|
+
"license": "MIT",
|
|
13
|
+
"type": "module",
|
|
14
|
+
"sideEffects": false,
|
|
15
|
+
"exports": {
|
|
16
|
+
".": {
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"default": "./dist/index.js"
|
|
19
|
+
},
|
|
20
|
+
"./ggg": {
|
|
21
|
+
"types": "./dist/ggg/normalize.d.ts",
|
|
22
|
+
"default": "./dist/ggg/normalize.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"main": "./dist/index.js",
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"scripts": {
|
|
33
|
+
"clean": "node -e \"require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
34
|
+
"build": "npm run clean && tsc -p tsconfig.build.json",
|
|
35
|
+
"prepack": "npm run build",
|
|
36
|
+
"typecheck": "tsc --noEmit",
|
|
37
|
+
"test": "vitest run",
|
|
38
|
+
"test:watch": "vitest"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"typescript": "^5.7.0",
|
|
42
|
+
"vitest": "^3.0.0"
|
|
43
|
+
},
|
|
44
|
+
"engines": {
|
|
45
|
+
"node": ">=18"
|
|
46
|
+
},
|
|
47
|
+
"publishConfig": {
|
|
48
|
+
"access": "public"
|
|
49
|
+
}
|
|
50
|
+
}
|