@buley/hexgrid-3d 3.6.0 → 3.6.2

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.
@@ -0,0 +1,109 @@
1
+ function priorityForEvent(eventType) {
2
+ switch (eventType) {
3
+ case 'leaderboard_flip':
4
+ case 'unlock':
5
+ return 9;
6
+ case 'nexus_created':
7
+ case 'nexus_connected':
8
+ case 'alliance_surged':
9
+ return 8;
10
+ case 'territory_captured':
11
+ return 8;
12
+ case 'tick_surged':
13
+ case 'tick_entrenched':
14
+ return 8;
15
+ case 'rally_called':
16
+ case 'alliance_root_bound':
17
+ return 7;
18
+ case 'claim':
19
+ return 7;
20
+ case 'allied_border_held':
21
+ return 6;
22
+ case 'delegation_issued':
23
+ case 'delegation_revoked':
24
+ return 6;
25
+ case 'embed_set':
26
+ return 5;
27
+ default:
28
+ return 4;
29
+ }
30
+ }
31
+ function formatSingleEvent(event) {
32
+ const actor = event.actorName ? `${event.actorName} ` : '';
33
+ const cell = event.cellId ? ` ${event.cellId}` : '';
34
+ switch (event.eventType) {
35
+ case 'claim':
36
+ return `${actor}claimed root${cell}.`.trim();
37
+ case 'territory_captured':
38
+ return `${actor}captured frontier territory${cell}.`.trim();
39
+ case 'embed_set':
40
+ return `${actor}repointed the frontier payload${cell}.`.trim();
41
+ case 'delegation_issued':
42
+ return `${actor}delegated subhex control${cell}.`.trim();
43
+ case 'delegation_revoked':
44
+ return `${actor}revoked delegated control${cell}.`.trim();
45
+ case 'nexus_created':
46
+ return `${actor}founded a nexus${cell}.`.trim();
47
+ case 'nexus_connected':
48
+ return `${actor}connected a sovereign root into an alliance${cell}.`.trim();
49
+ case 'alliance_root_bound':
50
+ return `A sovereign root joined an allied phyle${cell}.`.trim();
51
+ case 'rally_called':
52
+ return `A new rally directive lit up${cell}.`.trim();
53
+ case 'allied_border_held':
54
+ return `Allied borders held firm${cell}.`.trim();
55
+ case 'alliance_surged':
56
+ return `Allied pressure pushed${cell} into surge state.`.trim();
57
+ case 'unlock':
58
+ return `A new latitude band unlocked${cell}.`.trim();
59
+ case 'tick_surged':
60
+ return `Hourly pressure pushed${cell} into surge state.`.trim();
61
+ case 'tick_entrenched':
62
+ return `${cell.trim()} entrenched after the latest tick.`.trim();
63
+ case 'leaderboard_flip':
64
+ return `The leaderboard flipped after the latest tick.`.trim();
65
+ default:
66
+ return 'Frontier activity updated.';
67
+ }
68
+ }
69
+ export function createHexwarNarrationAdapter(events) {
70
+ if (events.length === 0) {
71
+ return [];
72
+ }
73
+ const sorted = [...events].sort((left, right) => left.occurredAtMs - right.occurredAtMs);
74
+ const messages = [];
75
+ let currentBurst = [];
76
+ for (const event of sorted) {
77
+ const previous = currentBurst[currentBurst.length - 1];
78
+ const isBurstContinuation = previous &&
79
+ previous.eventType === event.eventType &&
80
+ event.occurredAtMs - previous.occurredAtMs <= 30000;
81
+ if (!isBurstContinuation && currentBurst.length > 0) {
82
+ const first = currentBurst[0];
83
+ messages.push({
84
+ generation: 0,
85
+ timestamp: new Date(first.occurredAtMs).toISOString(),
86
+ priority: priorityForEvent(first.eventType),
87
+ text: currentBurst.length === 1
88
+ ? formatSingleEvent(first)
89
+ : `${currentBurst.length} ${first.eventType.replace(/_/g, ' ')} events rippled across the frontier.`,
90
+ eventType: first.eventType,
91
+ });
92
+ currentBurst = [];
93
+ }
94
+ currentBurst.push(event);
95
+ }
96
+ if (currentBurst.length > 0) {
97
+ const first = currentBurst[0];
98
+ messages.push({
99
+ generation: 0,
100
+ timestamp: new Date(first.occurredAtMs).toISOString(),
101
+ priority: priorityForEvent(first.eventType),
102
+ text: currentBurst.length === 1
103
+ ? formatSingleEvent(first)
104
+ : `${currentBurst.length} ${first.eventType.replace(/_/g, ' ')} events rippled across the frontier.`,
105
+ eventType: first.eventType,
106
+ });
107
+ }
108
+ return messages;
109
+ }
package/dist/types.d.ts CHANGED
@@ -123,4 +123,169 @@ export interface WorkerDebug {
123
123
  batchPerFrame: number;
124
124
  [key: string]: any;
125
125
  }
126
+ /** Built-in 3D primitive shapes for game pieces */
127
+ export type PieceShape = 'sphere' | 'cube' | 'cone' | 'cylinder' | 'pyramid' | 'torus' | 'ring' | 'flag' | 'star' | 'diamond' | 'capsule' | 'octahedron' | 'dodecahedron' | 'icosahedron';
128
+ /** Animation presets that can be applied to game pieces */
129
+ export type PieceAnimation = 'none' | 'spin' | 'bob' | 'pulse' | 'wobble' | 'orbit' | 'glow';
130
+ /** Animation configuration */
131
+ export interface PieceAnimationConfig {
132
+ type: PieceAnimation;
133
+ speed?: number;
134
+ amplitude?: number;
135
+ axis?: [number, number, number];
136
+ phase?: number;
137
+ }
138
+ /**
139
+ * A game piece placed on a hex cell.
140
+ *
141
+ * Supports three rendering modes:
142
+ * 1. **Primitive shape** — set `shape` to a PieceShape string.
143
+ * 2. **Custom Three.js Object3D** — set `object3D` to any Object3D instance.
144
+ * The renderer will clone it and place it on the hex surface.
145
+ * 3. **GLTF/GLB model URL** — set `modelUrl` to a URL pointing to a .glb/.gltf.
146
+ * The renderer loads it asynchronously and caches the geometry.
147
+ */
148
+ export interface GamePiece {
149
+ id: string;
150
+ shape?: PieceShape;
151
+ /** Arbitrary Three.js Object3D (mesh, group, sprite, etc.) */
152
+ object3D?: unknown;
153
+ /** URL to a .glb / .gltf model */
154
+ modelUrl?: string;
155
+ color?: string;
156
+ emissive?: string;
157
+ emissiveIntensity?: number;
158
+ opacity?: number;
159
+ metalness?: number;
160
+ roughness?: number;
161
+ wireframe?: boolean;
162
+ scale?: number | [number, number, number];
163
+ offsetY?: number;
164
+ rotationY?: number;
165
+ animation?: PieceAnimation | PieceAnimationConfig;
166
+ label?: string;
167
+ labelColor?: string;
168
+ tooltip?: string;
169
+ count?: number;
170
+ stackStyle?: 'badge' | 'stack' | 'ring';
171
+ interactive?: boolean;
172
+ draggable?: boolean;
173
+ layer?: number;
174
+ group?: string;
175
+ }
176
+ /** Fog of war visibility levels */
177
+ export type FogLevel = 'visible' | 'explored' | 'dim' | 'hidden';
178
+ /** Cell highlight modes */
179
+ export type CellHighlight = 'none' | 'selected' | 'hover' | 'attack-target' | 'move-target' | 'great-circle' | 'path' | 'danger' | 'friendly' | 'contested' | string;
180
+ /** Border style for cell outlines */
181
+ export interface CellBorder {
182
+ color: string;
183
+ width?: number;
184
+ style?: 'solid' | 'dashed' | 'glow' | 'pulse';
185
+ emissive?: boolean;
186
+ }
187
+ /**
188
+ * Complete game state for a single cell on the sphere.
189
+ * Pass a `Map<number, CellGameState>` to GameSphere to overlay game state on the geodesic grid.
190
+ */
191
+ export interface CellGameState {
192
+ ownerId?: string;
193
+ ownerColor?: string;
194
+ ownerColorIntensity?: number;
195
+ pieces?: GamePiece[];
196
+ fogLevel?: FogLevel;
197
+ highlight?: CellHighlight;
198
+ highlightColor?: string;
199
+ highlightIntensity?: number;
200
+ border?: CellBorder;
201
+ terrainType?: string;
202
+ terrainColor?: string;
203
+ cellLabel?: string;
204
+ cellLabelColor?: string;
205
+ cellLabelSize?: number;
206
+ elevation?: number;
207
+ isPentagon?: boolean;
208
+ data?: Record<string, unknown>;
209
+ }
210
+ /**
211
+ * Configuration for the GameSphere's visual appearance.
212
+ */
213
+ export interface GameSphereConfig {
214
+ subdivisions?: number;
215
+ sphereRadius?: number;
216
+ cameraDistance?: number;
217
+ cameraFov?: number;
218
+ enableOrbitControls?: boolean;
219
+ autoRotate?: boolean;
220
+ autoRotateSpeed?: number;
221
+ ambientLightIntensity?: number;
222
+ directionalLightIntensity?: number;
223
+ directionalLightPosition?: [number, number, number];
224
+ hexBaseColor?: string;
225
+ hexBorderColor?: string;
226
+ hexBorderWidth?: number;
227
+ pentagonBaseColor?: string;
228
+ pentagonBorderColor?: string;
229
+ fogDimColor?: string;
230
+ fogHiddenColor?: string;
231
+ fogExploredColor?: string;
232
+ defaultPieceScale?: number;
233
+ defaultPieceColor?: string;
234
+ enableRaycasting?: boolean;
235
+ enableDragDrop?: boolean;
236
+ hoverHighlightColor?: string;
237
+ enableBloom?: boolean;
238
+ enableShadows?: boolean;
239
+ enableAntialias?: boolean;
240
+ enableInstancing?: boolean;
241
+ maxVisiblePieces?: number;
242
+ pixelRatio?: number;
243
+ }
244
+ /**
245
+ * Events emitted by the GameSphere component.
246
+ */
247
+ export interface GameSphereEvents {
248
+ /** Cell was clicked */
249
+ onCellClick?: (cellIndex: number, event: {
250
+ shiftKey: boolean;
251
+ ctrlKey: boolean;
252
+ }) => void;
253
+ /** Cell hover entered */
254
+ onCellHover?: (cellIndex: number | null) => void;
255
+ /** A piece was clicked */
256
+ onPieceClick?: (cellIndex: number, piece: GamePiece) => void;
257
+ /** A piece was dragged from one cell to another */
258
+ onPieceDrop?: (fromCell: number, toCell: number, piece: GamePiece) => void;
259
+ /** Camera moved (for syncing external UI) */
260
+ onCameraChange?: (position: [number, number, number], target: [number, number, number]) => void;
261
+ /** Render frame callback (for custom overlays) */
262
+ onFrame?: (deltaTime: number) => void;
263
+ }
264
+ /**
265
+ * Props for the GameSphere component — the 3D board game renderer.
266
+ */
267
+ export interface GameSphereProps {
268
+ /** Game state per cell. Key = cell index from GeodesicHexGrid. */
269
+ cellGameState?: Map<number, CellGameState>;
270
+ /** Visual and behavior configuration */
271
+ config?: GameSphereConfig;
272
+ /** Event callbacks */
273
+ events?: GameSphereEvents;
274
+ /** Width of the canvas (default '100%') */
275
+ width?: number | string;
276
+ /** Height of the canvas (default '100%') */
277
+ height?: number | string;
278
+ /** CSS class for the container */
279
+ className?: string;
280
+ /** Inline styles for the container */
281
+ style?: React.CSSProperties;
282
+ /** Optional ref to the Three.js renderer for external access */
283
+ rendererRef?: RefObject<unknown>;
284
+ /** Optional ref to the Three.js scene for injecting custom objects */
285
+ sceneRef?: RefObject<unknown>;
286
+ /** Pauses rendering when true (e.g. modal open) */
287
+ paused?: boolean;
288
+ /** Children rendered as React overlay on top of the canvas */
289
+ children?: React.ReactNode;
290
+ }
126
291
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAEtD;;;;;GAKG;AACH,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IAGd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IAGrB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IAGzB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IAGtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,QAAQ,CAAC,CAAC,GAAG,OAAO;IAEnC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IAGb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,IAAI,CAAC,EAAE,CAAC,CAAC;IAGT,gBAAgB,CAAC,EAAE;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;QAC/B,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACrC,UAAU,CAAC,EAAE;YACX,MAAM,EAAE,MAAM,CAAC;YACf,WAAW,EAAE,MAAM,CAAC;YACpB,UAAU,EAAE,MAAM,CAAC;SACpB,CAAC;KACH,CAAC;IAGF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IAGnB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAGjC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACpC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,SAAS,CAAC,iBAAiB,CAAC,CAAC;IACzC,mBAAmB,CAAC,EAAE,CAAC,WAAW,EAAE,GAAG,KAAK,IAAI,CAAC;IACjD,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,0BAA0B,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,mBAAmB,CAAC;IACnC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,cAAc,CAAC,EAAE;QACf,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,eAAe,CAAC,EAAE,OAAO,CAAC;QAC1B,eAAe,CAAC,EAAE,OAAO,CAAC;KAC3B,CAAC;IACF,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE;QACzB,IAAI,EAAE,UAAU,GAAG,OAAO,GAAG,OAAO,CAAC;QACrC,OAAO,EAAE,MAAM,CAAC;QAChB,SAAS,CAAC,EAAE,MAAM,CAAC;KACpB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,OAAO;IACtB,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,36 @@
3
3
  * These functions have NO side effects, NO logging, and NO mutable state access.
4
4
  * They are deterministic and testable in isolation.
5
5
  */
6
+ export interface ScreenGridMetadata {
7
+ isSpherical: false;
8
+ cols: number;
9
+ rows: number;
10
+ }
11
+ export interface SphericalScreenGridMetadata {
12
+ isSpherical: true;
13
+ cols: number;
14
+ rows: number;
15
+ rowColumnCounts: number[];
16
+ indexToRow: number[];
17
+ indexToColumn: number[];
18
+ }
19
+ export interface SphericalScreenGridLayout {
20
+ positions: [number, number, number][];
21
+ metadata: SphericalScreenGridMetadata;
22
+ }
23
+ /**
24
+ * Generate a screen-space hex grid that preserves local neighbor spacing while
25
+ * carrying enough metadata to project each row across the full spherical span.
26
+ */
27
+ export declare function generateScreenSpaceSphericalHexGrid(_targetCount: number, screenWidth: number, screenHeight: number, curveUDeg: number, curveVDeg: number, densityMultiplier: number | undefined, hexRadius: number): SphericalScreenGridLayout;
28
+ /**
29
+ * Convert a spherical grid index into normalized [0,1] coordinates used for
30
+ * longitude/latitude mapping, independent of the row's raw screen-space width.
31
+ */
32
+ export declare function getNormalizedScreenSpaceSphericalCoordinates(index: number, metadata: SphericalScreenGridMetadata, curveUDeg: number): {
33
+ u: number;
34
+ v: number;
35
+ } | null;
6
36
  /**
7
37
  * Calculate the bounding box of a set of 2D/3D positions.
8
38
  * @pure - No side effects, deterministic
@@ -1 +1 @@
1
- {"version":3,"file":"hexgrid-math.d.ts","sourceRoot":"","sources":["../../src/workers/hexgrid-math.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE;;;;;;;EAmBlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAC3B,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACzC,WAAW,EAAE,OAAO,GACnB,MAAM,CAeR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAalC;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EACrC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,GACxC,MAAM,CAgBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EACrC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,GACxC,MAAM,CAER;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,GACxC,MAAM,CAgBR"}
1
+ {"version":3,"file":"hexgrid-math.d.ts","sourceRoot":"","sources":["../../src/workers/hexgrid-math.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,KAAK,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,2BAA2B;IAC1C,WAAW,EAAE,IAAI,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,MAAM,WAAW,yBAAyB;IACxC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC;IACtC,QAAQ,EAAE,2BAA2B,CAAC;CACvC;AAED;;;GAGG;AACH,wBAAgB,mCAAmC,CACjD,YAAY,EAAE,MAAM,EACpB,WAAW,EAAE,MAAM,EACnB,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,iBAAiB,oBAAM,EACvB,SAAS,EAAE,MAAM,GAChB,yBAAyB,CAmE3B;AAED;;;GAGG;AACH,wBAAgB,4CAA4C,CAC1D,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,2BAA2B,EACrC,SAAS,EAAE,MAAM,GAChB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAkCjC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE;;;;;;;EAmBlE;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAC3B,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAC3B,MAAM,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,EACzC,WAAW,EAAE,OAAO,GACnB,MAAM,CAeR;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iCAAiC,CAC/C,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACb,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAalC;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EACrC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,GACxC,MAAM,CAgBR;AAED;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EACrC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,GACxC,MAAM,CAER;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EAAE,EACjB,SAAS,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,EACrC,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,MAAM,EAAE,GACxC,MAAM,CAgBR"}
@@ -3,6 +3,98 @@
3
3
  * These functions have NO side effects, NO logging, and NO mutable state access.
4
4
  * They are deterministic and testable in isolation.
5
5
  */
6
+ /**
7
+ * Generate a screen-space hex grid that preserves local neighbor spacing while
8
+ * carrying enough metadata to project each row across the full spherical span.
9
+ */
10
+ export function generateScreenSpaceSphericalHexGrid(_targetCount, screenWidth, screenHeight, curveUDeg, curveVDeg, densityMultiplier = 1.4, hexRadius) {
11
+ const positions = [];
12
+ const rowColumnCounts = [];
13
+ const indexToRow = [];
14
+ const indexToColumn = [];
15
+ if (!Number.isFinite(screenWidth) ||
16
+ !Number.isFinite(screenHeight) ||
17
+ !Number.isFinite(curveUDeg) ||
18
+ !Number.isFinite(curveVDeg) ||
19
+ !Number.isFinite(densityMultiplier) ||
20
+ !Number.isFinite(hexRadius) ||
21
+ screenWidth <= 0 ||
22
+ screenHeight <= 0 ||
23
+ hexRadius <= 0) {
24
+ return {
25
+ positions,
26
+ metadata: {
27
+ isSpherical: true,
28
+ cols: 0,
29
+ rows: 0,
30
+ rowColumnCounts,
31
+ indexToRow,
32
+ indexToColumn,
33
+ },
34
+ };
35
+ }
36
+ const sqrt3 = Math.sqrt(3);
37
+ const horizontalSpacing = sqrt3 * hexRadius;
38
+ const verticalSpacing = 1.5 * hexRadius;
39
+ const densityScale = Math.sqrt(Math.max(0.1, densityMultiplier));
40
+ const cols = Math.max(3, Math.ceil((screenWidth / horizontalSpacing) * densityScale));
41
+ const rows = Math.max(1, Math.ceil((screenHeight / verticalSpacing) * densityScale));
42
+ const deg2rad = Math.PI / 180;
43
+ for (let row = 0; row < rows; row += 1) {
44
+ const y = row * verticalSpacing;
45
+ const rowProgress = rows === 1 ? 0.5 : (row + 0.5) / rows;
46
+ const lat = (rowProgress - 0.5) * (curveVDeg * deg2rad);
47
+ const latFactor = Math.max(0.3, Math.abs(Math.cos(lat)));
48
+ const effectiveColsForRow = Math.max(3, Math.round(cols * latFactor));
49
+ const rowOffset = row % 2 === 0 ? 0 : 0.5;
50
+ rowColumnCounts.push(effectiveColsForRow);
51
+ for (let col = 0; col < effectiveColsForRow; col += 1) {
52
+ const x = (col + rowOffset) * horizontalSpacing;
53
+ positions.push([x, y, 0]);
54
+ indexToRow.push(row);
55
+ indexToColumn.push(col);
56
+ }
57
+ }
58
+ return {
59
+ positions,
60
+ metadata: {
61
+ isSpherical: true,
62
+ cols,
63
+ rows,
64
+ rowColumnCounts,
65
+ indexToRow,
66
+ indexToColumn,
67
+ },
68
+ };
69
+ }
70
+ /**
71
+ * Convert a spherical grid index into normalized [0,1] coordinates used for
72
+ * longitude/latitude mapping, independent of the row's raw screen-space width.
73
+ */
74
+ export function getNormalizedScreenSpaceSphericalCoordinates(index, metadata, curveUDeg) {
75
+ if (index < 0 ||
76
+ index >= metadata.indexToRow.length ||
77
+ metadata.rows <= 0) {
78
+ return null;
79
+ }
80
+ const row = metadata.indexToRow[index];
81
+ const column = metadata.indexToColumn[index];
82
+ const rowColumnCount = metadata.rowColumnCounts[row];
83
+ if (row === undefined ||
84
+ column === undefined ||
85
+ rowColumnCount === undefined ||
86
+ rowColumnCount <= 0) {
87
+ return null;
88
+ }
89
+ const rowOffset = row % 2 === 0 ? 0 : 0.5;
90
+ const isWrapped = Math.abs(curveUDeg) >= 359;
91
+ const rawU = (column + 0.5 + rowOffset) / rowColumnCount;
92
+ const u = isWrapped
93
+ ? ((rawU % 1) + 1) % 1
94
+ : Math.min(1, Math.max(0, rawU / Math.max(1, 1 + rowOffset / rowColumnCount)));
95
+ const v = metadata.rows === 1 ? 0.5 : (row + 0.5) / metadata.rows;
96
+ return { u, v };
97
+ }
6
98
  /**
7
99
  * Calculate the bounding box of a set of 2D/3D positions.
8
100
  * @pure - No side effects, deterministic
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@buley/hexgrid-3d",
3
- "version": "3.6.0",
3
+ "version": "3.6.2",
4
4
  "description": "3D hexagonal grid visualization component for React",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -65,6 +65,7 @@
65
65
  "three"
66
66
  ],
67
67
  "peerDependencies": {
68
+ "@react-three/fiber": "^9.4.2",
68
69
  "next": "^14.0.0",
69
70
  "react": "^18.0.0",
70
71
  "react-dom": "^18.0.0",
@@ -80,6 +81,7 @@
80
81
  "@types/react": "^18.3.27",
81
82
  "@types/three": "^0.183.1",
82
83
  "@types/react-dom": "^18.3.7",
84
+ "@react-three/fiber": "^9.4.2",
83
85
  "happy-dom": "^20.3.3",
84
86
  "jest": "^29.7.0",
85
87
  "jest-environment-jsdom": "^29.7.0",