@connected-web/terrain-editor 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/dist/index.cjs +3265 -0
- package/dist/index.d.cts +409 -0
- package/dist/index.d.ts +409 -0
- package/dist/index.js +3213 -0
- package/package.json +34 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
type HeightSampler = {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
data: Float32Array;
|
|
7
|
+
};
|
|
8
|
+
declare function createHeightSampler(texture: THREE.Texture): HeightSampler | null;
|
|
9
|
+
declare function sampleHeightValue(sampler: HeightSampler, u: number, v: number): number;
|
|
10
|
+
declare function applyHeightField(geometry: THREE.PlaneGeometry, sampler: HeightSampler, options: {
|
|
11
|
+
seaLevel: number;
|
|
12
|
+
heightScale: number;
|
|
13
|
+
}): {
|
|
14
|
+
minY: number;
|
|
15
|
+
maxY: number;
|
|
16
|
+
};
|
|
17
|
+
declare function buildRimMesh(geometry: THREE.PlaneGeometry, floorY: number, material?: THREE.Material): THREE.Mesh<THREE.BufferGeometry<THREE.NormalBufferAttributes, THREE.BufferGeometryEventMap>, THREE.Material, THREE.Object3DEventMap>;
|
|
18
|
+
|
|
19
|
+
type MarkerSpriteStateStyle = {
|
|
20
|
+
textColor: string;
|
|
21
|
+
backgroundColor: string;
|
|
22
|
+
borderColor: string;
|
|
23
|
+
borderThickness: number;
|
|
24
|
+
opacity: number;
|
|
25
|
+
};
|
|
26
|
+
type MarkerSpriteTheme = {
|
|
27
|
+
fontFamily: string;
|
|
28
|
+
fontWeight: string;
|
|
29
|
+
maxFontSize: number;
|
|
30
|
+
minFontSize: number;
|
|
31
|
+
paddingX: number;
|
|
32
|
+
paddingY: number;
|
|
33
|
+
borderRadius: number;
|
|
34
|
+
states: {
|
|
35
|
+
default: MarkerSpriteStateStyle;
|
|
36
|
+
hover?: Partial<MarkerSpriteStateStyle>;
|
|
37
|
+
focus?: Partial<MarkerSpriteStateStyle>;
|
|
38
|
+
};
|
|
39
|
+
};
|
|
40
|
+
type MarkerStemStateStyle = {
|
|
41
|
+
color: string;
|
|
42
|
+
opacity: number;
|
|
43
|
+
};
|
|
44
|
+
type MarkerStemGeometryShape = 'cylinder' | 'triangle' | 'square' | 'pentagon' | 'hexagon';
|
|
45
|
+
type MarkerStemTheme = {
|
|
46
|
+
shape: MarkerStemGeometryShape;
|
|
47
|
+
radius: number;
|
|
48
|
+
scale?: number;
|
|
49
|
+
states: {
|
|
50
|
+
default: MarkerStemStateStyle;
|
|
51
|
+
hover?: Partial<MarkerStemStateStyle>;
|
|
52
|
+
focus?: Partial<MarkerStemStateStyle>;
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
type TerrainTheme = {
|
|
56
|
+
locationMarkers: {
|
|
57
|
+
sprite: MarkerSpriteTheme;
|
|
58
|
+
stem: MarkerStemTheme;
|
|
59
|
+
};
|
|
60
|
+
};
|
|
61
|
+
type DeepPartial<T> = {
|
|
62
|
+
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
|
|
63
|
+
};
|
|
64
|
+
type TerrainThemeOverrides = DeepPartial<TerrainTheme>;
|
|
65
|
+
declare function getDefaultTerrainTheme(): TerrainTheme;
|
|
66
|
+
declare function resolveTerrainTheme(...overrides: Array<TerrainTheme | TerrainThemeOverrides | undefined>): TerrainTheme;
|
|
67
|
+
|
|
68
|
+
type LayerToggleState = {
|
|
69
|
+
biomes: Record<string, boolean>;
|
|
70
|
+
overlays: Record<string, boolean>;
|
|
71
|
+
};
|
|
72
|
+
type LocationViewState = {
|
|
73
|
+
distance: number;
|
|
74
|
+
polar: number;
|
|
75
|
+
azimuth: number;
|
|
76
|
+
targetPixel?: {
|
|
77
|
+
x: number;
|
|
78
|
+
y: number;
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
type TerrainLocation = {
|
|
82
|
+
id: string;
|
|
83
|
+
name?: string;
|
|
84
|
+
icon?: string;
|
|
85
|
+
showBorder?: boolean;
|
|
86
|
+
pixel: {
|
|
87
|
+
x: number;
|
|
88
|
+
y: number;
|
|
89
|
+
};
|
|
90
|
+
uv?: {
|
|
91
|
+
u: number;
|
|
92
|
+
v: number;
|
|
93
|
+
};
|
|
94
|
+
world?: {
|
|
95
|
+
x: number;
|
|
96
|
+
y: number;
|
|
97
|
+
z: number;
|
|
98
|
+
};
|
|
99
|
+
view?: LocationViewState;
|
|
100
|
+
};
|
|
101
|
+
type LocationPickPayload = {
|
|
102
|
+
pixel: {
|
|
103
|
+
x: number;
|
|
104
|
+
y: number;
|
|
105
|
+
};
|
|
106
|
+
uv: {
|
|
107
|
+
u: number;
|
|
108
|
+
v: number;
|
|
109
|
+
};
|
|
110
|
+
world: {
|
|
111
|
+
x: number;
|
|
112
|
+
y: number;
|
|
113
|
+
z: number;
|
|
114
|
+
};
|
|
115
|
+
};
|
|
116
|
+
type ViewerLifecycleState = 'initializing' | 'loading-textures' | 'building-geometry' | 'first-render' | 'stabilizing' | 'ready';
|
|
117
|
+
type TerrainInitOptions = {
|
|
118
|
+
onReady?: () => void;
|
|
119
|
+
onLifecycleChange?: (state: ViewerLifecycleState) => void;
|
|
120
|
+
heightScale?: number;
|
|
121
|
+
waterLevelPercent?: number;
|
|
122
|
+
layers?: LayerToggleState;
|
|
123
|
+
interactive?: boolean;
|
|
124
|
+
onLocationPick?: (payload: LocationPickPayload) => void;
|
|
125
|
+
onLocationHover?: (locationId: string | null) => void;
|
|
126
|
+
onLocationClick?: (locationId: string) => void;
|
|
127
|
+
locations?: TerrainLocation[];
|
|
128
|
+
theme?: TerrainThemeOverrides;
|
|
129
|
+
cameraView?: LocationViewState;
|
|
130
|
+
};
|
|
131
|
+
type TerrainHandle = {
|
|
132
|
+
destroy: () => void;
|
|
133
|
+
updateLayers: (state: LayerToggleState) => Promise<void>;
|
|
134
|
+
setInteractiveMode: (enabled: boolean) => void;
|
|
135
|
+
updateLocations: (locations: TerrainLocation[], focusedId?: string) => void;
|
|
136
|
+
setFocusedLocation: (locationId?: string | null) => void;
|
|
137
|
+
navigateTo: (payload: {
|
|
138
|
+
pixel: {
|
|
139
|
+
x: number;
|
|
140
|
+
y: number;
|
|
141
|
+
};
|
|
142
|
+
locationId?: string;
|
|
143
|
+
world?: {
|
|
144
|
+
x: number;
|
|
145
|
+
y: number;
|
|
146
|
+
z: number;
|
|
147
|
+
};
|
|
148
|
+
view?: LocationViewState;
|
|
149
|
+
instant?: boolean;
|
|
150
|
+
}) => void;
|
|
151
|
+
setHoveredLocation: (id: string | null) => void;
|
|
152
|
+
setCameraOffset: (offset: number, focusId?: string) => void;
|
|
153
|
+
onCameraMove: (callback: (newState: LocationViewState) => void) => void;
|
|
154
|
+
getViewState: () => LocationViewState;
|
|
155
|
+
setTheme: (overrides?: TerrainThemeOverrides) => void;
|
|
156
|
+
setSeaLevel: (level: number) => void;
|
|
157
|
+
invalidateIconTextures: (paths?: string[]) => void;
|
|
158
|
+
invalidateLayerMasks: (paths?: string[]) => void;
|
|
159
|
+
enableFrameCaptureMode: (fps?: number) => {
|
|
160
|
+
fps: number;
|
|
161
|
+
};
|
|
162
|
+
disableFrameCaptureMode: () => void;
|
|
163
|
+
captureFrame: (frameNumber: number, fps?: number) => {
|
|
164
|
+
frameNumber: number;
|
|
165
|
+
time: number;
|
|
166
|
+
};
|
|
167
|
+
};
|
|
168
|
+
type Cleanup = () => void;
|
|
169
|
+
type Resolvable<T> = T | Promise<T>;
|
|
170
|
+
type LegendLayer = {
|
|
171
|
+
mask: string;
|
|
172
|
+
rgb: [number, number, number];
|
|
173
|
+
label?: string;
|
|
174
|
+
};
|
|
175
|
+
type TerrainLegend = {
|
|
176
|
+
size: [number, number];
|
|
177
|
+
sea_level?: number;
|
|
178
|
+
heightmap: string;
|
|
179
|
+
topology?: string;
|
|
180
|
+
biomes: Record<string, LegendLayer>;
|
|
181
|
+
overlays: Record<string, LegendLayer>;
|
|
182
|
+
};
|
|
183
|
+
type TerrainDataset = {
|
|
184
|
+
legend: TerrainLegend;
|
|
185
|
+
getHeightMapUrl: () => Resolvable<string>;
|
|
186
|
+
getTopologyMapUrl: () => Resolvable<string>;
|
|
187
|
+
resolveAssetUrl: (path: string) => Resolvable<string>;
|
|
188
|
+
cleanup?: () => void;
|
|
189
|
+
theme?: TerrainThemeOverrides;
|
|
190
|
+
};
|
|
191
|
+
declare function initTerrainViewer(container: HTMLElement, dataset: TerrainDataset, options?: TerrainInitOptions): Promise<TerrainHandle>;
|
|
192
|
+
|
|
193
|
+
type TerrainProjectFileEntry = {
|
|
194
|
+
path: string;
|
|
195
|
+
data: ArrayBuffer;
|
|
196
|
+
type?: string;
|
|
197
|
+
lastModified?: number;
|
|
198
|
+
sourceFileName?: string;
|
|
199
|
+
};
|
|
200
|
+
type TerrainProjectMetadata = {
|
|
201
|
+
label?: string;
|
|
202
|
+
author?: string;
|
|
203
|
+
source?: 'archive' | 'scratch';
|
|
204
|
+
};
|
|
205
|
+
type TerrainProjectSnapshot = {
|
|
206
|
+
legend?: TerrainLegend;
|
|
207
|
+
locations?: TerrainLocation[];
|
|
208
|
+
theme?: TerrainThemeOverrides;
|
|
209
|
+
metadata: TerrainProjectMetadata;
|
|
210
|
+
files: TerrainProjectFileEntry[];
|
|
211
|
+
dirty: boolean;
|
|
212
|
+
};
|
|
213
|
+
type TerrainProjectStore = {
|
|
214
|
+
getSnapshot: () => TerrainProjectSnapshot;
|
|
215
|
+
subscribe: (listener: (snapshot: TerrainProjectSnapshot) => void) => () => void;
|
|
216
|
+
loadFromArchive: (payload: {
|
|
217
|
+
legend: TerrainLegend;
|
|
218
|
+
locations?: TerrainLocation[];
|
|
219
|
+
theme?: TerrainThemeOverrides;
|
|
220
|
+
files?: TerrainProjectFileEntry[];
|
|
221
|
+
metadata?: TerrainProjectMetadata;
|
|
222
|
+
}) => void;
|
|
223
|
+
setLegend: (legend: TerrainLegend) => void;
|
|
224
|
+
setLocations: (locations?: TerrainLocation[]) => void;
|
|
225
|
+
setTheme: (theme?: TerrainThemeOverrides) => void;
|
|
226
|
+
updateMetadata: (metadata: Partial<TerrainProjectMetadata>) => void;
|
|
227
|
+
upsertFile: (entry: TerrainProjectFileEntry) => void;
|
|
228
|
+
removeFile: (path: string) => void;
|
|
229
|
+
reset: () => void;
|
|
230
|
+
markPersisted: () => void;
|
|
231
|
+
};
|
|
232
|
+
declare function createProjectStore(initial?: Partial<TerrainProjectSnapshot>): TerrainProjectStore;
|
|
233
|
+
|
|
234
|
+
type WynArchiveProgressEvent = {
|
|
235
|
+
type: 'network-download';
|
|
236
|
+
loadedBytes: number;
|
|
237
|
+
totalBytes?: number;
|
|
238
|
+
} | {
|
|
239
|
+
type: 'file-read';
|
|
240
|
+
loadedBytes: number;
|
|
241
|
+
totalBytes?: number;
|
|
242
|
+
};
|
|
243
|
+
type LoadWynArchiveOptions = {
|
|
244
|
+
onProgress?: (event: WynArchiveProgressEvent) => void;
|
|
245
|
+
includeFiles?: boolean;
|
|
246
|
+
};
|
|
247
|
+
type LoadedWynFile = {
|
|
248
|
+
dataset: TerrainDataset;
|
|
249
|
+
legend: TerrainLegend;
|
|
250
|
+
locations?: TerrainLocation[];
|
|
251
|
+
files?: TerrainProjectFileEntry[];
|
|
252
|
+
metadata?: TerrainProjectMetadata;
|
|
253
|
+
};
|
|
254
|
+
declare function loadWynArchive(url: string, options?: LoadWynArchiveOptions): Promise<LoadedWynFile>;
|
|
255
|
+
declare function loadWynArchiveFromArrayBuffer(data: ArrayBuffer, options?: LoadWynArchiveOptions): Promise<LoadedWynFile>;
|
|
256
|
+
declare function loadWynArchiveFromFile(file: File, options?: LoadWynArchiveOptions): Promise<LoadedWynFile>;
|
|
257
|
+
|
|
258
|
+
type TerrainViewMode = 'embed' | 'popout' | 'fullscreen';
|
|
259
|
+
type TerrainViewerHostOptions = {
|
|
260
|
+
viewerElement: HTMLElement;
|
|
261
|
+
embedTarget: HTMLElement;
|
|
262
|
+
title?: string;
|
|
263
|
+
subtitle?: string;
|
|
264
|
+
documentRoot?: Document;
|
|
265
|
+
onModeChange?: (mode: TerrainViewMode) => void;
|
|
266
|
+
};
|
|
267
|
+
type TerrainViewerHostHandle = {
|
|
268
|
+
openPopout: () => void;
|
|
269
|
+
closePopout: () => void;
|
|
270
|
+
toggleFullscreen: () => Promise<void>;
|
|
271
|
+
getMode: () => TerrainViewMode;
|
|
272
|
+
destroy: () => void;
|
|
273
|
+
};
|
|
274
|
+
declare function createTerrainViewerHost(options: TerrainViewerHostOptions): TerrainViewerHostHandle;
|
|
275
|
+
|
|
276
|
+
type ViewerOverlayButtonLocation = 'top-left' | 'top-right' | 'top-center' | 'bottom-left' | 'bottom-right' | 'bottom-center' | 'center';
|
|
277
|
+
type ViewerOverlayCustomButton = {
|
|
278
|
+
location: ViewerOverlayButtonLocation;
|
|
279
|
+
label: string;
|
|
280
|
+
description?: string;
|
|
281
|
+
callback?: () => void;
|
|
282
|
+
};
|
|
283
|
+
type ViewerOverlayStatusOptions = {
|
|
284
|
+
initialText: string;
|
|
285
|
+
};
|
|
286
|
+
type ViewerOverlaySelectFileOptions = {
|
|
287
|
+
enabled: boolean;
|
|
288
|
+
label: string;
|
|
289
|
+
callback?: (file: File) => void;
|
|
290
|
+
};
|
|
291
|
+
type ViewerOverlayPopoutOptions = {
|
|
292
|
+
enabled: boolean;
|
|
293
|
+
labelOpen: string;
|
|
294
|
+
labelClose: string;
|
|
295
|
+
onRequestOpen?: () => void;
|
|
296
|
+
onRequestClose?: () => void;
|
|
297
|
+
};
|
|
298
|
+
type ViewerOverlayFullscreenOptions = {
|
|
299
|
+
enabled: boolean;
|
|
300
|
+
labelEnter: string;
|
|
301
|
+
labelExit: string;
|
|
302
|
+
onToggle?: () => void;
|
|
303
|
+
displayInEmbed: boolean;
|
|
304
|
+
};
|
|
305
|
+
type ViewerOverlayOptions = {
|
|
306
|
+
status?: Partial<ViewerOverlayStatusOptions>;
|
|
307
|
+
selectFile?: Partial<Omit<ViewerOverlaySelectFileOptions, 'enabled' | 'label'>> & {
|
|
308
|
+
enabled?: boolean;
|
|
309
|
+
label?: string;
|
|
310
|
+
};
|
|
311
|
+
popout?: Partial<Omit<ViewerOverlayPopoutOptions, 'enabled' | 'labelOpen' | 'labelClose'>> & {
|
|
312
|
+
enabled?: boolean;
|
|
313
|
+
labelOpen?: string;
|
|
314
|
+
labelClose?: string;
|
|
315
|
+
};
|
|
316
|
+
fullscreen?: Partial<Omit<ViewerOverlayFullscreenOptions, 'enabled' | 'labelEnter' | 'labelExit' | 'displayInEmbed'>> & {
|
|
317
|
+
enabled?: boolean;
|
|
318
|
+
labelEnter?: string;
|
|
319
|
+
labelExit?: string;
|
|
320
|
+
displayInEmbed?: boolean;
|
|
321
|
+
};
|
|
322
|
+
customButtons?: ViewerOverlayCustomButton[];
|
|
323
|
+
};
|
|
324
|
+
type ViewerOverlayLoadingState = {
|
|
325
|
+
label: string;
|
|
326
|
+
loadedBytes: number;
|
|
327
|
+
totalBytes?: number;
|
|
328
|
+
};
|
|
329
|
+
type ViewerOverlayHandle = {
|
|
330
|
+
setStatus: (message: string) => void;
|
|
331
|
+
setStatusFade: (fade: boolean) => void;
|
|
332
|
+
setViewMode: (mode: TerrainViewMode) => void;
|
|
333
|
+
setLoadingProgress: (state: ViewerOverlayLoadingState | null) => void;
|
|
334
|
+
hideDropOverlay: () => void;
|
|
335
|
+
openFileDialog?: () => void;
|
|
336
|
+
destroy: () => void;
|
|
337
|
+
};
|
|
338
|
+
declare function createViewerOverlay(target: HTMLElement, optionsInput?: ViewerOverlayOptions): ViewerOverlayHandle;
|
|
339
|
+
|
|
340
|
+
type BuildWynArchiveOptions = {
|
|
341
|
+
pretty?: boolean;
|
|
342
|
+
};
|
|
343
|
+
declare function buildWynArchive(project: TerrainProjectSnapshot, options?: BuildWynArchiveOptions): Promise<Blob>;
|
|
344
|
+
|
|
345
|
+
type LayerBrowserEntry = {
|
|
346
|
+
id: string;
|
|
347
|
+
kind: 'biome' | 'overlay';
|
|
348
|
+
label: string;
|
|
349
|
+
mask: string;
|
|
350
|
+
color: [number, number, number];
|
|
351
|
+
visible: boolean;
|
|
352
|
+
};
|
|
353
|
+
type LayerBrowserState = {
|
|
354
|
+
legend?: TerrainLegend;
|
|
355
|
+
entries: LayerBrowserEntry[];
|
|
356
|
+
};
|
|
357
|
+
type LayerBrowserStore = {
|
|
358
|
+
getState: () => LayerBrowserState;
|
|
359
|
+
subscribe: (listener: (state: LayerBrowserState) => void) => () => void;
|
|
360
|
+
setLegend: (legend?: TerrainLegend) => void;
|
|
361
|
+
setVisibility: (id: string, visible: boolean) => void;
|
|
362
|
+
toggleVisibility: (id: string) => void;
|
|
363
|
+
setAll: (kind: 'biome' | 'overlay', visible: boolean) => void;
|
|
364
|
+
getLayerToggles: () => LayerToggleState;
|
|
365
|
+
};
|
|
366
|
+
declare function createLayerBrowserStore(legend?: TerrainLegend, initial?: Partial<LayerToggleState>): LayerBrowserStore;
|
|
367
|
+
|
|
368
|
+
type MaskStrokeMode = 'paint' | 'erase';
|
|
369
|
+
type MaskStrokePoint = {
|
|
370
|
+
x: number;
|
|
371
|
+
y: number;
|
|
372
|
+
};
|
|
373
|
+
type MaskStroke = {
|
|
374
|
+
points: MaskStrokePoint[];
|
|
375
|
+
radius: number;
|
|
376
|
+
strength?: number;
|
|
377
|
+
mode?: MaskStrokeMode;
|
|
378
|
+
};
|
|
379
|
+
type MaskImage = {
|
|
380
|
+
width: number;
|
|
381
|
+
height: number;
|
|
382
|
+
data: Uint8ClampedArray;
|
|
383
|
+
};
|
|
384
|
+
type MaskEditorState = {
|
|
385
|
+
width: number;
|
|
386
|
+
height: number;
|
|
387
|
+
dirty: boolean;
|
|
388
|
+
undoCount: number;
|
|
389
|
+
redoCount: number;
|
|
390
|
+
};
|
|
391
|
+
type MaskEditorHandle = {
|
|
392
|
+
getState: () => MaskEditorState;
|
|
393
|
+
subscribe: (listener: (state: MaskEditorState) => void) => () => void;
|
|
394
|
+
applyStroke: (stroke: MaskStroke) => void;
|
|
395
|
+
clear: () => void;
|
|
396
|
+
undo: () => void;
|
|
397
|
+
redo: () => void;
|
|
398
|
+
exportMask: () => MaskImage;
|
|
399
|
+
loadMask: (mask: MaskImage) => void;
|
|
400
|
+
markClean: () => void;
|
|
401
|
+
};
|
|
402
|
+
type MaskEditorOptions = {
|
|
403
|
+
width: number;
|
|
404
|
+
height: number;
|
|
405
|
+
initialMask?: MaskImage;
|
|
406
|
+
};
|
|
407
|
+
declare function createMaskEditor(options: MaskEditorOptions): MaskEditorHandle;
|
|
408
|
+
|
|
409
|
+
export { type BuildWynArchiveOptions, type Cleanup, type DeepPartial, type HeightSampler, type LayerBrowserEntry, type LayerBrowserState, type LayerBrowserStore, type LayerToggleState, type LegendLayer, type LoadWynArchiveOptions, type LoadedWynFile, type LocationPickPayload, type LocationViewState, type MarkerSpriteStateStyle, type MarkerSpriteTheme, type MarkerStemGeometryShape, type MarkerStemStateStyle, type MarkerStemTheme, type MaskEditorHandle, type MaskEditorState, type MaskImage, type MaskStroke, type MaskStrokeMode, type MaskStrokePoint, type TerrainDataset, type TerrainHandle, type TerrainLegend, type TerrainLocation, type TerrainProjectFileEntry, type TerrainProjectMetadata, type TerrainProjectSnapshot, type TerrainProjectStore, type TerrainTheme, type TerrainThemeOverrides, type TerrainViewMode, type TerrainViewerHostHandle, type TerrainViewerHostOptions, type ViewerLifecycleState, type ViewerOverlayCustomButton, type ViewerOverlayHandle, type ViewerOverlayLoadingState, type ViewerOverlayOptions, type WynArchiveProgressEvent, applyHeightField, buildRimMesh, buildWynArchive, createHeightSampler, createLayerBrowserStore, createMaskEditor, createProjectStore, createTerrainViewerHost, createViewerOverlay, getDefaultTerrainTheme, initTerrainViewer, loadWynArchive, loadWynArchiveFromArrayBuffer, loadWynArchiveFromFile, resolveTerrainTheme, sampleHeightValue };
|