@aethervtt/shard-terrain 0.0.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.
Files changed (47) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -0
  3. package/dist/biomes.d.ts +65 -0
  4. package/dist/biomes.js +163 -0
  5. package/dist/chunk.d.ts +99 -0
  6. package/dist/chunk.js +304 -0
  7. package/dist/colliders.d.ts +86 -0
  8. package/dist/colliders.js +356 -0
  9. package/dist/components.d.ts +49 -0
  10. package/dist/components.js +137 -0
  11. package/dist/cube.d.ts +51 -0
  12. package/dist/cube.js +87 -0
  13. package/dist/frame.d.ts +21 -0
  14. package/dist/frame.js +63 -0
  15. package/dist/heights.d.ts +51 -0
  16. package/dist/heights.js +137 -0
  17. package/dist/index.d.ts +19 -0
  18. package/dist/index.js +193 -0
  19. package/dist/kernel.d.ts +47 -0
  20. package/dist/kernel.js +243 -0
  21. package/dist/lod.d.ts +22 -0
  22. package/dist/lod.js +44 -0
  23. package/dist/material.d.ts +14 -0
  24. package/dist/material.js +426 -0
  25. package/dist/methods.d.ts +12 -0
  26. package/dist/methods.js +259 -0
  27. package/dist/nav.d.ts +14 -0
  28. package/dist/nav.js +114 -0
  29. package/dist/overlays.d.ts +6 -0
  30. package/dist/overlays.js +67 -0
  31. package/dist/planet.d.ts +106 -0
  32. package/dist/planet.js +313 -0
  33. package/dist/plugin.d.ts +23 -0
  34. package/dist/plugin.js +98 -0
  35. package/dist/points.d.ts +62 -0
  36. package/dist/points.js +207 -0
  37. package/dist/quadtree.d.ts +153 -0
  38. package/dist/quadtree.js +587 -0
  39. package/dist/render.d.ts +179 -0
  40. package/dist/render.js +1222 -0
  41. package/dist/test-planet.d.ts +59 -0
  42. package/dist/test-planet.js +189 -0
  43. package/dist/testing.d.ts +42 -0
  44. package/dist/testing.js +96 -0
  45. package/dist/view.d.ts +12 -0
  46. package/dist/view.js +61 -0
  47. package/package.json +50 -0
@@ -0,0 +1,59 @@
1
+ /**
2
+ * Test helpers (not a test): a planet app on a GPU (Dawn in Node) or headless, a camera placed in
3
+ * the planet's frame, and a loop that runs frames until the terrain stops generating.
4
+ */
5
+ import type { Entity, World } from '@aethervtt/shard-core';
6
+ import type { GpuContext } from '@aethervtt/shard-gpu';
7
+ import { type NoiseGraph } from '@aethervtt/shard-noise';
8
+ import { App, type Plugin } from '@aethervtt/shard-runtime';
9
+ import type { PlanetRuntime } from './planet.js';
10
+ export interface PlanetOptions {
11
+ radius: number;
12
+ heightScale?: number;
13
+ height?: NoiseGraph;
14
+ climate?: NoiseGraph;
15
+ seed?: number;
16
+ ocean?: boolean;
17
+ seaLevel?: number;
18
+ skirts?: boolean;
19
+ errorPixels?: number;
20
+ /** MSAA samples (default 1). */
21
+ msaa?: 1 | 4;
22
+ /** Planet.vertexPixels (default: the component's). */
23
+ vertexPixels?: number;
24
+ minSpacing?: number;
25
+ width?: number;
26
+ heightPx?: number;
27
+ /** The target's pixels per CSS pixel (a Retina display is 2). Default 1. */
28
+ pixelRatio?: number;
29
+ fovY?: number;
30
+ clearColor?: [number, number, number, number];
31
+ physics?: boolean;
32
+ extra?: Plugin[];
33
+ /** Chunk generations per frame (TerrainBudget.chunksPerFrame). */
34
+ chunksPerFrame?: number;
35
+ }
36
+ export interface PlanetApp {
37
+ app: App;
38
+ world: World;
39
+ planet: Entity;
40
+ camera: Entity;
41
+ /** The sun (a DirectionalLight), when there's a GPU. */
42
+ sun: Entity;
43
+ view: string;
44
+ runtime(): PlanetRuntime;
45
+ }
46
+ export declare function planetApp(gpu: GpuContext | undefined, o: PlanetOptions): Promise<PlanetApp>;
47
+ /** Puts the camera at `eye` (planet frame, f64) looking at `target`, up roughly radial. */
48
+ export declare function placeCamera(p: PlanetApp, eye: ArrayLike<number>, target: ArrayLike<number>): void;
49
+ /** Runs frames (awaiting pipelines) until nothing is requested, queued, or compiling. */
50
+ export declare function settleTerrain(p: PlanetApp, maxFrames?: number): Promise<number>;
51
+ /** Renders one more frame and captures the camera's view. */
52
+ export declare function capture(p: PlanetApp): Promise<import("@aethervtt/shard-render").CapturedImage>;
53
+ /** Points the sun at a spot on the planet (planet frame direction) from `elevation` degrees up. */
54
+ export declare function sunOver(p: PlanetApp, direction: ArrayLike<number>, elevation?: number): void;
55
+ /**
56
+ * Pixels that show sky where the ray from the camera must hit the planet: anything inside the
57
+ * sphere of the lowest possible surface (radius − heightScale) is terrain whatever the LOD.
58
+ */
59
+ export declare function holes(data: Uint8Array, W: number, H: number, FOV: number, eye: ArrayLike<number>, right: number[], up: number[], forward: number[], lowest: number): number;
@@ -0,0 +1,189 @@
1
+ import { quat } from "@aethervtt/shard-core";
2
+ import { NoiseGraphs } from "@aethervtt/shard-noise";
3
+ import { GravitySource, PhysicsConfig, physics3dPlugin } from "@aethervtt/shard-physics";
4
+ import {
5
+ Camera3d,
6
+ captureView,
7
+ DirectionalLight,
8
+ Exposure,
9
+ forwardPlugin,
10
+ Gpu,
11
+ OffscreenTarget,
12
+ RenderTargets,
13
+ renderPlugin,
14
+ Shaders,
15
+ Tonemapping
16
+ } from "@aethervtt/shard-render";
17
+ import { App } from "@aethervtt/shard-runtime";
18
+ import {
19
+ FloatingOrigin,
20
+ Grid,
21
+ placeInGrid,
22
+ Transform,
23
+ TransformPlugin
24
+ } from "@aethervtt/shard-transform";
25
+ import { Planet, TerrainBudget } from "./components.js";
26
+ import { Terrain } from "./heights.js";
27
+ import { terrainPlugin } from "./plugin.js";
28
+ async function planetApp(gpu, o) {
29
+ const app = new App().addPlugin(TransformPlugin);
30
+ if (gpu)
31
+ app.addPlugin(renderPlugin({ gpu, windowView: false }), forwardPlugin({ msaa: o.msaa ?? 1 }));
32
+ if (o.physics) app.addPlugin(physics3dPlugin);
33
+ app.addPlugin(terrainPlugin(), ...o.extra ?? []);
34
+ await app.init();
35
+ const world = app.world;
36
+ if (o.physics) world.resource(PhysicsConfig).gravity = [0, 0, 0];
37
+ if (o.chunksPerFrame !== void 0)
38
+ world.resource(TerrainBudget).chunksPerFrame = o.chunksPerFrame;
39
+ const graphs = world.initResource(NoiseGraphs);
40
+ const planet = world.spawn(
41
+ [Grid, { cellSize: 2e3 }],
42
+ [
43
+ Planet,
44
+ {
45
+ radius: o.radius,
46
+ heightScale: o.heightScale ?? 0,
47
+ height: o.height ? graphs.add(o.height, "height") : null,
48
+ climate: o.climate ? graphs.add(o.climate, "climate") : null,
49
+ seed: o.seed ?? 1,
50
+ ocean: o.ocean ?? false,
51
+ seaLevel: o.seaLevel ?? 0,
52
+ skirts: o.skirts ?? true,
53
+ errorPixels: o.errorPixels ?? 2,
54
+ ...o.vertexPixels !== void 0 ? { vertexPixels: o.vertexPixels } : {},
55
+ minSpacing: o.minSpacing ?? 0.4
56
+ }
57
+ ],
58
+ [GravitySource, { strength: 9.81, radius: o.radius }],
59
+ Transform
60
+ );
61
+ let view = "";
62
+ let camera = -1;
63
+ let sun = -1;
64
+ if (gpu) {
65
+ const target = new OffscreenTarget(gpu, {
66
+ label: "terrain-test",
67
+ width: o.width ?? 96,
68
+ height: o.heightPx ?? 64,
69
+ pixelRatio: o.pixelRatio ?? 1
70
+ });
71
+ const targetRef = world.resource(RenderTargets).add(target, "terrain-test");
72
+ camera = world.spawn(
73
+ [
74
+ Camera3d,
75
+ {
76
+ target: targetRef,
77
+ fovY: o.fovY ?? 60,
78
+ near: 0.05,
79
+ clearColor: o.clearColor ?? [1, 0, 1, 1]
80
+ }
81
+ ],
82
+ [Exposure, { ev100: 14 }],
83
+ [Tonemapping, { curve: "none", dither: false }],
84
+ Transform,
85
+ FloatingOrigin
86
+ );
87
+ view = `camera:${camera}`;
88
+ sun = world.spawn(
89
+ [DirectionalLight, { illuminance: 5e4, shadows: false }],
90
+ [
91
+ Transform,
92
+ {
93
+ rotation: quat.fromEuler([0, 0, 0, 1], -0.8, 0.4, 0)
94
+ }
95
+ ]
96
+ );
97
+ }
98
+ app.update(1 / 60);
99
+ return {
100
+ app,
101
+ world,
102
+ planet,
103
+ camera,
104
+ sun,
105
+ view,
106
+ runtime: () => world.resource(Terrain).planets.get(planet)
107
+ };
108
+ }
109
+ function placeCamera(p, eye, target) {
110
+ const f = [target[0] - eye[0], target[1] - eye[1], target[2] - eye[2]];
111
+ const l = Math.hypot(eye[0], eye[1], eye[2]) || 1;
112
+ const upv = [eye[0] / l, eye[1] / l, eye[2] / l];
113
+ const rotation = quat.lookRotation([0, 0, 0, 1], f, upv);
114
+ placeInGrid(p.world, p.camera, p.planet, eye);
115
+ p.world.set(p.camera, Transform, { rotation });
116
+ }
117
+ async function settleTerrain(p, maxFrames = 400) {
118
+ const gpu = p.world.tryResource(Gpu);
119
+ let quiet = 0;
120
+ for (let f = 0; f < maxFrames; f++) {
121
+ p.app.update(1 / 60);
122
+ const rt = p.runtime();
123
+ const pr = rt?.parts.get("render");
124
+ if (gpu) {
125
+ await p.world.resource(Shaders).whenIdle();
126
+ await gpu.pipelines.whenIdle();
127
+ await new Promise((r) => setTimeout(r, 0));
128
+ for (let k = 0; pr && pr.stats.readbacks < pr.stats.generated && k < 500; k++) {
129
+ await new Promise((r) => setTimeout(r, 1));
130
+ }
131
+ }
132
+ const busy = !rt?.ready || rt.selection.requestedCount > 0 || rt.oceanSelection.requestedCount > 0 || (pr?.jobs.length ?? 0) > 0 || // Bounds from generation readbacks still on the way would change culling.
133
+ (pr ? pr.stats.readbacks < pr.stats.generated : false) || (gpu ? gpu.pipelines.pending > 0 : false);
134
+ quiet = busy ? 0 : quiet + 1;
135
+ if (quiet >= 3) return f;
136
+ }
137
+ return maxFrames;
138
+ }
139
+ async function capture(p) {
140
+ const shot = captureView(p.world, p.view);
141
+ p.app.update(1 / 60);
142
+ return shot;
143
+ }
144
+ function sunOver(p, direction, elevation = 35) {
145
+ const l = Math.hypot(direction[0], direction[1], direction[2]);
146
+ const up = [direction[0] / l, direction[1] / l, direction[2] / l];
147
+ const side = Math.abs(up[1]) < 0.9 ? [0, 1, 0] : [1, 0, 0];
148
+ const h = [
149
+ side[1] * up[2] - side[2] * up[1],
150
+ side[2] * up[0] - side[0] * up[2],
151
+ side[0] * up[1] - side[1] * up[0]
152
+ ];
153
+ const hl = Math.hypot(h[0], h[1], h[2]);
154
+ const e = elevation * Math.PI / 180;
155
+ const travel = [0, 1, 2].map((k) => h[k] / hl * Math.cos(e) - up[k] * Math.sin(e));
156
+ const rotation = quat.lookRotation([0, 0, 0, 1], travel, up);
157
+ p.world.set(p.sun, Transform, { rotation });
158
+ }
159
+ function holes(data, W, H, FOV, eye, right, up, forward, lowest) {
160
+ let count = 0;
161
+ const ty = Math.tan(FOV / 2 * Math.PI / 180);
162
+ const tx = ty * (W / H);
163
+ for (let py = 0; py < H; py++) {
164
+ for (let px = 0; px < W; px++) {
165
+ const a = (px + 0.5) / W * 2 - 1;
166
+ const b = 1 - (py + 0.5) / H * 2;
167
+ const d = [0, 1, 2].map((k) => forward[k] + right[k] * a * tx + up[k] * b * ty);
168
+ const dl = Math.hypot(d[0], d[1], d[2]);
169
+ const dx = d[0] / dl;
170
+ const dy = d[1] / dl;
171
+ const dz = d[2] / dl;
172
+ const bq = eye[0] * dx + eye[1] * dy + eye[2] * dz;
173
+ const c = eye[0] ** 2 + eye[1] ** 2 + eye[2] ** 2 - lowest * lowest;
174
+ const disc = bq * bq - c;
175
+ if (disc <= lowest * lowest * 0.02 || -bq - Math.sqrt(disc) < 0) continue;
176
+ const o = (py * W + px) * 4;
177
+ if (data[o] > 200 && data[o + 1] < 60 && data[o + 2] > 200) count++;
178
+ }
179
+ }
180
+ return count;
181
+ }
182
+ export {
183
+ capture,
184
+ holes,
185
+ placeCamera,
186
+ planetApp,
187
+ settleTerrain,
188
+ sunOver
189
+ };
@@ -0,0 +1,42 @@
1
+ /** The Earth-sized planet the walk checksum runs on. */
2
+ export declare const WALK_PLANET: {
3
+ output: string;
4
+ nodes: {
5
+ continents: {
6
+ fbm: {
7
+ source: string;
8
+ octaves: number;
9
+ frequency: number;
10
+ seed: number;
11
+ };
12
+ };
13
+ hills: {
14
+ fbm: {
15
+ source: string;
16
+ octaves: number;
17
+ frequency: number;
18
+ seed: number;
19
+ };
20
+ };
21
+ h: {
22
+ add: (string | {
23
+ multiply: (string | number)[];
24
+ })[];
25
+ };
26
+ };
27
+ };
28
+ export interface WalkResult {
29
+ /** FNV-1a over the characters' final planet-frame positions (f64 bytes) and the collider count. */
30
+ checksum: string;
31
+ /** Metres each character walked. */
32
+ walked: number[];
33
+ colliders: number;
34
+ ms: number;
35
+ }
36
+ /**
37
+ * Drops `characters` capsules at deterministic points on an Earth-radius planet and walks each
38
+ * for `seconds` headless (no GPU). Node (packages/terrain tests) and Chrome (the playground's
39
+ * #terrain page) must print the same checksum: the noise kernel, collider meshes, and physics are
40
+ * all deterministic.
41
+ */
42
+ export declare function walkChecksum(characters?: number, seconds?: number): Promise<WalkResult>;
@@ -0,0 +1,96 @@
1
+ import { hash32 } from "@aethervtt/shard-core";
2
+ import { loadNoiseKernel, NoiseGraph, NoiseGraphs } from "@aethervtt/shard-noise";
3
+ import {
4
+ CharacterController,
5
+ CharacterIntent,
6
+ CharacterState,
7
+ GravitySource,
8
+ PhysicsConfig,
9
+ physics3dPlugin
10
+ } from "@aethervtt/shard-physics";
11
+ import { App } from "@aethervtt/shard-runtime";
12
+ import {
13
+ FloatingOrigin,
14
+ Grid,
15
+ placeInGrid,
16
+ Transform,
17
+ TransformPlugin,
18
+ worldPosition64
19
+ } from "@aethervtt/shard-transform";
20
+ import { collidersOf } from "./colliders.js";
21
+ import { Planet } from "./components.js";
22
+ import { planetHeightAt, Terrain } from "./heights.js";
23
+ import { terrainPlugin } from "./plugin.js";
24
+ const WALK_PLANET = {
25
+ output: "h",
26
+ nodes: {
27
+ continents: { fbm: { source: "simplex", octaves: 5, frequency: 2e-6, seed: 1 } },
28
+ hills: { fbm: { source: "simplex", octaves: 6, frequency: 2e-3, seed: 2 } },
29
+ h: { add: ["continents", { multiply: ["hills", 0.05] }] }
30
+ }
31
+ };
32
+ async function walkChecksum(characters = 4, seconds = 3) {
33
+ const t0 = performance.now();
34
+ await loadNoiseKernel();
35
+ const graph = NoiseGraph.fromJson(WALK_PLANET);
36
+ const app = new App().addPlugin(TransformPlugin, physics3dPlugin, terrainPlugin());
37
+ await app.init();
38
+ const w = app.world;
39
+ const R = 6371e3;
40
+ w.resource(PhysicsConfig).gravity = [0, 0, 0];
41
+ const height = w.initResource(NoiseGraphs).add(graph, "walk");
42
+ const planet = w.spawn(
43
+ [Grid, { cellSize: 2e3 }],
44
+ [Planet, { radius: R, height, heightScale: 400, seed: 11, ocean: false }],
45
+ [GravitySource, { strength: 9.81, radius: R }],
46
+ Transform
47
+ );
48
+ app.update(1 / 60);
49
+ const walked = [];
50
+ const bytes = new Uint8Array(characters * 24 + 4);
51
+ const f64 = new Float64Array(bytes.buffer, 0, characters * 3);
52
+ const p0 = new Float64Array(3);
53
+ const p = new Float64Array(3);
54
+ for (let k = 0; k < characters; k++) {
55
+ const u = hash32(77, k) / 2 ** 32 * 2 - 1;
56
+ const a = hash32(76, k) / 2 ** 32 * Math.PI * 2;
57
+ const s = Math.sqrt(1 - u * u);
58
+ const dir = [s * Math.cos(a), u, s * Math.sin(a)];
59
+ const h = planetHeightAt(w, planet, dir);
60
+ const c = w.spawn(
61
+ [CharacterController, { up: "gravity", radius: 0.35, height: 1.8 }],
62
+ [CharacterIntent, {}],
63
+ [CharacterState, {}],
64
+ Transform,
65
+ FloatingOrigin
66
+ );
67
+ placeInGrid(
68
+ w,
69
+ c,
70
+ planet,
71
+ dir.map((v) => v * (R + h + 1.2))
72
+ );
73
+ for (let f = 0; f < 30; f++) app.update(1 / 60);
74
+ worldPosition64(w, c, p0, planet);
75
+ w.set(c, CharacterIntent, { move: [0, 0, -5] });
76
+ for (let f = 0; f < seconds * 60; f++) app.update(1 / 60);
77
+ worldPosition64(w, c, p, planet);
78
+ walked.push(Math.hypot(p[0] - p0[0], p[1] - p0[1], p[2] - p0[2]));
79
+ f64.set(p, k * 3);
80
+ w.despawn(c);
81
+ }
82
+ const colliders = collidersOf(w.resource(Terrain).planets.get(planet)).chunks.size;
83
+ new DataView(bytes.buffer).setUint32(characters * 24, colliders, true);
84
+ let hash = 2166136261;
85
+ for (let i = 0; i < bytes.length; i++) hash = Math.imul(hash ^ bytes[i], 16777619);
86
+ return {
87
+ checksum: (hash >>> 0).toString(16).padStart(8, "0"),
88
+ walked,
89
+ colliders,
90
+ ms: performance.now() - t0
91
+ };
92
+ }
93
+ export {
94
+ WALK_PLANET,
95
+ walkChecksum
96
+ };
package/dist/view.d.ts ADDED
@@ -0,0 +1,12 @@
1
+ import type { SelectionView } from './quadtree.js';
2
+ /** A selection view with room for four side planes. */
3
+ export declare function createView(): SelectionView;
4
+ /**
5
+ * Fills a selection view for a perspective camera at `position` (planet frame, f64) with unit axes
6
+ * `right`, `up`, and `forward` (the direction it looks): the four side planes through the camera
7
+ * (near and far are left out; the horizon culls far terrain), and pixels per radian for a viewport
8
+ * `height` pixels tall.
9
+ */
10
+ export declare function perspectiveView(out: SelectionView, position: ArrayLike<number>, right: ArrayLike<number>, up: ArrayLike<number>, forward: ArrayLike<number>, fovY: number, aspect: number, height: number): SelectionView;
11
+ /** A view that sees in every direction (no side planes): selection culls by the horizon only. */
12
+ export declare function omniView(out: SelectionView, position: ArrayLike<number>, pixelsPerRadian: number): SelectionView;
package/dist/view.js ADDED
@@ -0,0 +1,61 @@
1
+ function createView() {
2
+ return {
3
+ position: new Float64Array(3),
4
+ frustum: new Float64Array(16),
5
+ wide: new Float64Array(16),
6
+ planes: 0,
7
+ pixelsPerRadian: 1e3
8
+ };
9
+ }
10
+ function perspectiveView(out, position, right, up, forward, fovY, aspect, height) {
11
+ out.position[0] = position[0];
12
+ out.position[1] = position[1];
13
+ out.position[2] = position[2];
14
+ const hy = fovY / 2;
15
+ const hx = Math.atan(Math.tan(hy) * aspect);
16
+ const cx = Math.cos(hx);
17
+ const sx = Math.sin(hx);
18
+ const cy = Math.cos(hy);
19
+ const sy = Math.sin(hy);
20
+ const f = out.frustum;
21
+ plane(f, 0, right, forward, cx, sx, position);
22
+ plane(f, 1, right, forward, -cx, sx, position);
23
+ plane(f, 2, up, forward, cy, sy, position);
24
+ plane(f, 3, up, forward, -cy, sy, position);
25
+ const wx = Math.min(1.45, hx * 1.5);
26
+ const wy = Math.min(1.45, hy * 1.5);
27
+ const w = out.wide;
28
+ plane(w, 0, right, forward, Math.cos(wx), Math.sin(wx), position);
29
+ plane(w, 1, right, forward, -Math.cos(wx), Math.sin(wx), position);
30
+ plane(w, 2, up, forward, Math.cos(wy), Math.sin(wy), position);
31
+ plane(w, 3, up, forward, -Math.cos(wy), Math.sin(wy), position);
32
+ out.planes = 4;
33
+ out.pixelsPerRadian = height / (2 * Math.tan(hy));
34
+ return out;
35
+ }
36
+ function plane(f, i, side, forward, a, b, p) {
37
+ let nx = side[0] * a + forward[0] * b;
38
+ let ny = side[1] * a + forward[1] * b;
39
+ let nz = side[2] * a + forward[2] * b;
40
+ const len = Math.sqrt(nx * nx + ny * ny + nz * nz);
41
+ nx /= len;
42
+ ny /= len;
43
+ nz /= len;
44
+ f[i * 4] = nx;
45
+ f[i * 4 + 1] = ny;
46
+ f[i * 4 + 2] = nz;
47
+ f[i * 4 + 3] = -(nx * p[0] + ny * p[1] + nz * p[2]);
48
+ }
49
+ function omniView(out, position, pixelsPerRadian) {
50
+ out.position[0] = position[0];
51
+ out.position[1] = position[1];
52
+ out.position[2] = position[2];
53
+ out.planes = 0;
54
+ out.pixelsPerRadian = pixelsPerRadian;
55
+ return out;
56
+ }
57
+ export {
58
+ createView,
59
+ omniView,
60
+ perspectiveView
61
+ };
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@aethervtt/shard-terrain",
3
+ "version": "0.0.1",
4
+ "license": "MIT",
5
+ "type": "module",
6
+ "sideEffects": false,
7
+ "exports": {
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./testing": {
13
+ "types": "./dist/testing.d.ts",
14
+ "default": "./dist/testing.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "LICENSE",
20
+ "README.md"
21
+ ],
22
+ "dependencies": {
23
+ "@aethervtt/shard-assets": "0.0.1",
24
+ "@aethervtt/shard-core": "0.0.1",
25
+ "@aethervtt/shard-gpu": "0.0.1",
26
+ "@aethervtt/shard-mesh": "0.0.1",
27
+ "@aethervtt/shard-nav": "0.0.1",
28
+ "@aethervtt/shard-noise": "0.0.1",
29
+ "@aethervtt/shard-physics": "0.0.1",
30
+ "@aethervtt/shard-platform": "0.0.1",
31
+ "@aethervtt/shard-protocol": "0.0.1",
32
+ "@aethervtt/shard-render": "0.0.1",
33
+ "@aethervtt/shard-runtime": "0.0.1",
34
+ "@aethervtt/shard-shader": "0.0.1",
35
+ "@aethervtt/shard-texture": "0.0.1",
36
+ "@aethervtt/shard-transform": "0.0.1"
37
+ },
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "git+https://github.com/aethervtt/shard.git",
41
+ "directory": "packages/terrain"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "provenance": true
46
+ },
47
+ "shard": {
48
+ "buildSha": "d6c5c6aef4675575c878b02cf2c8f738b4190229"
49
+ }
50
+ }