@netforge/engine 0.0.0-stage → 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.
Files changed (244) hide show
  1. package/GAME-DESIGN.md +195 -0
  2. package/LICENSE +21 -0
  3. package/NOTICE +30 -0
  4. package/README.md +147 -2
  5. package/dist/api/appearance.d.ts +37 -0
  6. package/dist/api/appearance.js +41 -0
  7. package/dist/api/cards.d.ts +105 -0
  8. package/dist/api/cards.js +133 -0
  9. package/dist/api/collector.d.ts +114 -0
  10. package/dist/api/collector.js +204 -0
  11. package/dist/api/dungeon.d.ts +58 -0
  12. package/dist/api/dungeon.js +216 -0
  13. package/dist/api/harness.d.ts +149 -0
  14. package/dist/api/harness.js +549 -0
  15. package/dist/api/idle.d.ts +71 -0
  16. package/dist/api/idle.js +104 -0
  17. package/dist/api/race-harness.d.ts +3 -0
  18. package/dist/api/race-harness.js +148 -0
  19. package/dist/api/registry.d.ts +241 -0
  20. package/dist/api/registry.js +394 -0
  21. package/dist/api/scheduler.d.ts +56 -0
  22. package/dist/api/scheduler.js +160 -0
  23. package/dist/api/schemas.d.ts +958 -0
  24. package/dist/api/schemas.js +859 -0
  25. package/dist/api/tower.d.ts +127 -0
  26. package/dist/api/tower.js +183 -0
  27. package/dist/game/adapter.d.ts +69 -0
  28. package/dist/game/adapter.js +341 -0
  29. package/dist/game/arena-bot.d.ts +66 -0
  30. package/dist/game/arena-bot.js +188 -0
  31. package/dist/game/bot.d.ts +95 -0
  32. package/dist/game/bot.js +285 -0
  33. package/dist/game/compile.d.ts +97 -0
  34. package/dist/game/compile.js +476 -0
  35. package/dist/game/director.d.ts +42 -0
  36. package/dist/game/director.js +179 -0
  37. package/dist/game/earn-source.d.ts +122 -0
  38. package/dist/game/earn-source.js +386 -0
  39. package/dist/game/earn.d.ts +49 -0
  40. package/dist/game/earn.js +55 -0
  41. package/dist/game/index.d.ts +37 -0
  42. package/dist/game/index.js +25 -0
  43. package/dist/game/platformer.d.ts +156 -0
  44. package/dist/game/platformer.js +619 -0
  45. package/dist/game/profile.d.ts +97 -0
  46. package/dist/game/profile.js +140 -0
  47. package/dist/game/race.d.ts +177 -0
  48. package/dist/game/race.js +386 -0
  49. package/dist/game/racer.d.ts +98 -0
  50. package/dist/game/racer.js +379 -0
  51. package/dist/game/runner.d.ts +286 -0
  52. package/dist/game/runner.js +824 -0
  53. package/dist/game/threats.d.ts +23 -0
  54. package/dist/game/threats.js +49 -0
  55. package/dist/game/view.d.ts +47 -0
  56. package/dist/game/view.js +123 -0
  57. package/dist/index.d.ts +33 -0
  58. package/dist/index.js +24 -0
  59. package/dist/net/bits.d.ts +33 -0
  60. package/dist/net/bits.js +135 -0
  61. package/dist/net/client.d.ts +75 -0
  62. package/dist/net/client.js +151 -0
  63. package/dist/net/index.d.ts +23 -0
  64. package/dist/net/index.js +23 -0
  65. package/dist/net/input.d.ts +49 -0
  66. package/dist/net/input.js +112 -0
  67. package/dist/net/interpolation.d.ts +37 -0
  68. package/dist/net/interpolation.js +97 -0
  69. package/dist/net/netsim.d.ts +22 -0
  70. package/dist/net/netsim.js +52 -0
  71. package/dist/net/prediction.d.ts +31 -0
  72. package/dist/net/prediction.js +101 -0
  73. package/dist/net/profile-client.d.ts +75 -0
  74. package/dist/net/profile-client.js +173 -0
  75. package/dist/net/protocol.d.ts +208 -0
  76. package/dist/net/protocol.js +8 -0
  77. package/dist/net/room-client.d.ts +57 -0
  78. package/dist/net/room-client.js +144 -0
  79. package/dist/net/schema.d.ts +78 -0
  80. package/dist/net/schema.js +121 -0
  81. package/dist/net/sim-adapter.d.ts +134 -0
  82. package/dist/net/sim-adapter.js +22 -0
  83. package/dist/net/snapshot.d.ts +61 -0
  84. package/dist/net/snapshot.js +301 -0
  85. package/dist/rules/adapter.d.ts +53 -0
  86. package/dist/rules/adapter.js +261 -0
  87. package/dist/rules/cards.d.ts +115 -0
  88. package/dist/rules/cards.js +547 -0
  89. package/dist/rules/collector.d.ts +161 -0
  90. package/dist/rules/collector.js +732 -0
  91. package/dist/rules/genres.d.ts +13 -0
  92. package/dist/rules/genres.js +38 -0
  93. package/dist/rules/harness.d.ts +16 -0
  94. package/dist/rules/harness.js +127 -0
  95. package/dist/rules/idle.d.ts +115 -0
  96. package/dist/rules/idle.js +370 -0
  97. package/dist/rules/index.d.ts +16 -0
  98. package/dist/rules/index.js +14 -0
  99. package/dist/rules/kit.d.ts +171 -0
  100. package/dist/rules/kit.js +88 -0
  101. package/dist/rules/tower.d.ts +214 -0
  102. package/dist/rules/tower.js +655 -0
  103. package/dist/runtime/arena.d.ts +86 -0
  104. package/dist/runtime/arena.js +269 -0
  105. package/dist/runtime/assets.d.ts +26 -0
  106. package/dist/runtime/assets.js +35 -0
  107. package/dist/runtime/camera.d.ts +113 -0
  108. package/dist/runtime/camera.js +247 -0
  109. package/dist/runtime/crowd.d.ts +18 -0
  110. package/dist/runtime/crowd.js +62 -0
  111. package/dist/runtime/feel/audio.d.ts +150 -0
  112. package/dist/runtime/feel/audio.js +327 -0
  113. package/dist/runtime/feel/clock.d.ts +52 -0
  114. package/dist/runtime/feel/clock.js +80 -0
  115. package/dist/runtime/feel/flash.d.ts +28 -0
  116. package/dist/runtime/feel/flash.js +60 -0
  117. package/dist/runtime/feel/index.d.ts +27 -0
  118. package/dist/runtime/feel/index.js +16 -0
  119. package/dist/runtime/feel/kit.d.ts +159 -0
  120. package/dist/runtime/feel/kit.js +226 -0
  121. package/dist/runtime/feel/knockback.d.ts +41 -0
  122. package/dist/runtime/feel/knockback.js +70 -0
  123. package/dist/runtime/feel/noise.d.ts +6 -0
  124. package/dist/runtime/feel/noise.js +30 -0
  125. package/dist/runtime/feel/numbers.d.ts +91 -0
  126. package/dist/runtime/feel/numbers.js +172 -0
  127. package/dist/runtime/feel/rumble.d.ts +40 -0
  128. package/dist/runtime/feel/rumble.js +58 -0
  129. package/dist/runtime/feel/sound.d.ts +96 -0
  130. package/dist/runtime/feel/sound.js +176 -0
  131. package/dist/runtime/feel/spring.d.ts +42 -0
  132. package/dist/runtime/feel/spring.js +95 -0
  133. package/dist/runtime/feel/trauma.d.ts +48 -0
  134. package/dist/runtime/feel/trauma.js +76 -0
  135. package/dist/runtime/feel/tween.d.ts +66 -0
  136. package/dist/runtime/feel/tween.js +180 -0
  137. package/dist/runtime/feel/types.d.ts +30 -0
  138. package/dist/runtime/feel/types.js +5 -0
  139. package/dist/runtime/index.d.ts +28 -0
  140. package/dist/runtime/index.js +26 -0
  141. package/dist/runtime/input.d.ts +38 -0
  142. package/dist/runtime/input.js +159 -0
  143. package/dist/runtime/interpolate.d.ts +6 -0
  144. package/dist/runtime/interpolate.js +13 -0
  145. package/dist/runtime/render/animation.d.ts +63 -0
  146. package/dist/runtime/render/animation.js +128 -0
  147. package/dist/runtime/render/atmosphere.d.ts +32 -0
  148. package/dist/runtime/render/atmosphere.js +59 -0
  149. package/dist/runtime/render/crowd-motion.d.ts +68 -0
  150. package/dist/runtime/render/crowd-motion.js +163 -0
  151. package/dist/runtime/render/decals.d.ts +64 -0
  152. package/dist/runtime/render/decals.js +222 -0
  153. package/dist/runtime/render/highlight.d.ts +29 -0
  154. package/dist/runtime/render/highlight.js +110 -0
  155. package/dist/runtime/render/index.d.ts +35 -0
  156. package/dist/runtime/render/index.js +22 -0
  157. package/dist/runtime/render/lighting.d.ts +50 -0
  158. package/dist/runtime/render/lighting.js +142 -0
  159. package/dist/runtime/render/particles.d.ts +117 -0
  160. package/dist/runtime/render/particles.js +289 -0
  161. package/dist/runtime/render/post.d.ts +92 -0
  162. package/dist/runtime/render/post.js +191 -0
  163. package/dist/runtime/render/presets.d.ts +57 -0
  164. package/dist/runtime/render/presets.js +116 -0
  165. package/dist/runtime/render/quality.d.ts +113 -0
  166. package/dist/runtime/render/quality.js +180 -0
  167. package/dist/runtime/render/rig.d.ts +29 -0
  168. package/dist/runtime/render/rig.js +107 -0
  169. package/dist/runtime/render/sprite.d.ts +34 -0
  170. package/dist/runtime/render/sprite.js +58 -0
  171. package/dist/runtime/render/stack.d.ts +74 -0
  172. package/dist/runtime/render/stack.js +132 -0
  173. package/dist/runtime/render/vat.d.ts +78 -0
  174. package/dist/runtime/render/vat.js +219 -0
  175. package/dist/runtime/renderer.d.ts +19 -0
  176. package/dist/runtime/renderer.js +18 -0
  177. package/dist/runtime/stats.d.ts +11 -0
  178. package/dist/runtime/stats.js +29 -0
  179. package/dist/runtime/styles/handdrawn/ground.d.ts +11 -0
  180. package/dist/runtime/styles/handdrawn/ground.js +282 -0
  181. package/dist/runtime/styles/handdrawn/index.d.ts +4 -0
  182. package/dist/runtime/styles/handdrawn/index.js +94 -0
  183. package/dist/runtime/styles/handdrawn/ink.d.ts +31 -0
  184. package/dist/runtime/styles/handdrawn/ink.js +68 -0
  185. package/dist/runtime/styles/handdrawn/looks.d.ts +18 -0
  186. package/dist/runtime/styles/handdrawn/looks.js +42 -0
  187. package/dist/runtime/styles/handdrawn/paint.d.ts +59 -0
  188. package/dist/runtime/styles/handdrawn/paint.js +129 -0
  189. package/dist/runtime/styles/handdrawn/palette.d.ts +49 -0
  190. package/dist/runtime/styles/handdrawn/palette.js +70 -0
  191. package/dist/runtime/styles/handdrawn/textures.d.ts +27 -0
  192. package/dist/runtime/styles/handdrawn/textures.js +150 -0
  193. package/dist/runtime/styles/handdrawn/vfx.d.ts +14 -0
  194. package/dist/runtime/styles/handdrawn/vfx.js +73 -0
  195. package/dist/runtime/styles/index.d.ts +9 -0
  196. package/dist/runtime/styles/index.js +32 -0
  197. package/dist/runtime/styles/kit.d.ts +193 -0
  198. package/dist/runtime/styles/kit.js +1 -0
  199. package/dist/runtime/styles/pixel/index.d.ts +46 -0
  200. package/dist/runtime/styles/pixel/index.js +167 -0
  201. package/dist/runtime/styles/ps1/index.d.ts +29 -0
  202. package/dist/runtime/styles/ps1/index.js +41 -0
  203. package/dist/runtime/styles/ps1/lights.d.ts +47 -0
  204. package/dist/runtime/styles/ps1/lights.js +146 -0
  205. package/dist/runtime/styles/ps1/materials.d.ts +62 -0
  206. package/dist/runtime/styles/ps1/materials.js +285 -0
  207. package/dist/runtime/styles/ps1/pipeline.d.ts +52 -0
  208. package/dist/runtime/styles/ps1/pipeline.js +111 -0
  209. package/dist/runtime/styles/ps1/surfaces.d.ts +44 -0
  210. package/dist/runtime/styles/ps1/surfaces.js +228 -0
  211. package/dist/runtime/styles/toon/index.d.ts +5 -0
  212. package/dist/runtime/styles/toon/index.js +178 -0
  213. package/dist/runtime/styles/toon/ink.d.ts +39 -0
  214. package/dist/runtime/styles/toon/ink.js +73 -0
  215. package/dist/runtime/styles/toon/look.d.ts +10 -0
  216. package/dist/runtime/styles/toon/look.js +112 -0
  217. package/dist/runtime/styles/toon/material.d.ts +74 -0
  218. package/dist/runtime/styles/toon/material.js +208 -0
  219. package/dist/runtime/styles/toon/normals.d.ts +26 -0
  220. package/dist/runtime/styles/toon/normals.js +127 -0
  221. package/dist/runtime/styles/toon/shadows.d.ts +24 -0
  222. package/dist/runtime/styles/toon/shadows.js +42 -0
  223. package/dist/runtime/styles/toon/vfx.d.ts +15 -0
  224. package/dist/runtime/styles/toon/vfx.js +47 -0
  225. package/dist/runtime/styles/view.d.ts +35 -0
  226. package/dist/runtime/styles/view.js +34 -0
  227. package/dist/runtime/styles/voxel/core.d.ts +114 -0
  228. package/dist/runtime/styles/voxel/core.js +577 -0
  229. package/dist/runtime/styles/voxel/geometry.d.ts +27 -0
  230. package/dist/runtime/styles/voxel/geometry.js +40 -0
  231. package/dist/runtime/styles/voxel/index.d.ts +21 -0
  232. package/dist/runtime/styles/voxel/index.js +23 -0
  233. package/dist/runtime/styles/voxel/kit.d.ts +6 -0
  234. package/dist/runtime/styles/voxel/kit.js +11 -0
  235. package/dist/runtime/styles/voxel/look.d.ts +10 -0
  236. package/dist/runtime/styles/voxel/look.js +16 -0
  237. package/dist/runtime/styles/voxel/props.d.ts +9 -0
  238. package/dist/runtime/styles/voxel/props.js +52 -0
  239. package/dist/runtime/styles/voxel/shapes.d.ts +41 -0
  240. package/dist/runtime/styles/voxel/shapes.js +83 -0
  241. package/dist/runtime/styles/voxel/world.d.ts +49 -0
  242. package/dist/runtime/styles/voxel/world.js +422 -0
  243. package/llms.txt +183 -0
  244. package/package.json +82 -3
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Voxel meshes on the GPU: a greedy-meshed VoxelMesh as a three.js
3
+ * BufferGeometry (positions, flat normals, linear vertex colours with the
4
+ * occlusion baked in, and each vertex's rigid part), and the material every
5
+ * voxel thing in the style draws with.
6
+ */
7
+ import { BufferGeometry, MeshStandardNodeMaterial } from "three/webgpu";
8
+ import type { VoxelMesh } from "./core.js";
9
+ /** A BufferGeometry from a greedy-meshed grid. `voxelPart` holds each vertex's part when there is more than one. */
10
+ export declare function voxelGeometry(mesh: VoxelMesh, opts?: {
11
+ parts?: boolean;
12
+ }): BufferGeometry;
13
+ export interface VoxelMaterialOptions {
14
+ /** Glow colour (0 = none) and strength. */
15
+ readonly emissive?: number;
16
+ readonly emissiveIntensity?: number;
17
+ /** Default 0.85: voxel art reads matte. */
18
+ readonly roughness?: number;
19
+ readonly transparent?: boolean;
20
+ readonly opacity?: number;
21
+ }
22
+ /**
23
+ * The style's material: vertex colours (occlusion baked in), matte, no
24
+ * texture. A node material, so crowds and particles can drive its position
25
+ * and emissive nodes.
26
+ */
27
+ export declare function voxelMaterial(opts?: VoxelMaterialOptions): MeshStandardNodeMaterial;
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Voxel meshes on the GPU: a greedy-meshed VoxelMesh as a three.js
3
+ * BufferGeometry (positions, flat normals, linear vertex colours with the
4
+ * occlusion baked in, and each vertex's rigid part), and the material every
5
+ * voxel thing in the style draws with.
6
+ */
7
+ import { BufferAttribute, BufferGeometry, Color, MeshStandardNodeMaterial } from "three/webgpu";
8
+ /** A BufferGeometry from a greedy-meshed grid. `voxelPart` holds each vertex's part when there is more than one. */
9
+ export function voxelGeometry(mesh, opts = {}) {
10
+ const g = new BufferGeometry();
11
+ g.setAttribute("position", new BufferAttribute(mesh.positions, 3));
12
+ g.setAttribute("normal", new BufferAttribute(mesh.normals, 3));
13
+ g.setAttribute("color", new BufferAttribute(mesh.colors, 3));
14
+ if (opts.parts)
15
+ g.setAttribute("voxelPart", new BufferAttribute(new Float32Array(mesh.parts), 1));
16
+ const vertices = mesh.positions.length / 3;
17
+ g.setIndex(new BufferAttribute(vertices < 65536 ? new Uint16Array(mesh.indices) : mesh.indices, 1));
18
+ g.computeBoundingBox();
19
+ g.computeBoundingSphere();
20
+ return g;
21
+ }
22
+ /**
23
+ * The style's material: vertex colours (occlusion baked in), matte, no
24
+ * texture. A node material, so crowds and particles can drive its position
25
+ * and emissive nodes.
26
+ */
27
+ export function voxelMaterial(opts = {}) {
28
+ const m = new MeshStandardNodeMaterial();
29
+ m.vertexColors = true;
30
+ m.roughness = opts.roughness ?? 0.85;
31
+ m.metalness = 0;
32
+ m.color = new Color(1, 1, 1);
33
+ m.emissive = new Color(opts.emissive ?? 0);
34
+ m.emissiveIntensity = opts.emissiveIntensity ?? 1;
35
+ if (opts.transparent) {
36
+ m.transparent = true;
37
+ m.opacity = opts.opacity ?? 1;
38
+ }
39
+ return m;
40
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * The voxel art style: chunky cube-built worlds and
3
+ * characters. Library models are rebuilt as voxels at library build time
4
+ * (rigid parts on their bones, occlusion baked per face); this module is the
5
+ * runtime half: the voxel core, voxel geometry and material, procedural
6
+ * pickups and scenery, the voxel world builders, cube particles with
7
+ * voxel-shatter deaths, rigid-part crowds, and the style's look.
8
+ */
9
+ import type { BufferGeometry, MeshStandardNodeMaterial } from "three/webgpu";
10
+ export * from "./core.js";
11
+ export * from "./geometry.js";
12
+ export * from "./shapes.js";
13
+ export * from "./world.js";
14
+ export * from "./props.js";
15
+ export * from "./look.js";
16
+ export { voxelKit } from "./kit.js";
17
+ /** A procedural voxel pickup (library source `{ procedural: "voxel_<name>" }`): geometry centred on the origin and a glowing material. */
18
+ export declare function voxelPickup(name: string): {
19
+ geometry: BufferGeometry;
20
+ material: MeshStandardNodeMaterial;
21
+ } | null;
@@ -0,0 +1,23 @@
1
+ import { greedyMesh } from "./core.js";
2
+ import { voxelGeometry, voxelMaterial } from "./geometry.js";
3
+ import { pickupGrid } from "./shapes.js";
4
+ export * from "./core.js";
5
+ export * from "./geometry.js";
6
+ export * from "./shapes.js";
7
+ export * from "./world.js";
8
+ export * from "./props.js";
9
+ export * from "./look.js";
10
+ export { voxelKit } from "./kit.js";
11
+ /** A procedural voxel pickup (library source `{ procedural: "voxel_<name>" }`): geometry centred on the origin and a glowing material. */
12
+ export function voxelPickup(name) {
13
+ const p = pickupGrid(name);
14
+ if (!p)
15
+ return null;
16
+ const geometry = voxelGeometry(greedyMesh(p.grid, { splitParts: false }));
17
+ geometry.computeBoundingBox();
18
+ const box = geometry.boundingBox;
19
+ // Centre on the origin like the low-poly pickups (they bob around their middle).
20
+ if (box)
21
+ geometry.translate(0, -(box.min.y + box.max.y) / 2, 0);
22
+ return { geometry, material: voxelMaterial({ emissive: p.glow, emissiveIntensity: 0.9, roughness: 0.4 }) };
23
+ }
@@ -0,0 +1,6 @@
1
+ /**
2
+ * The voxel style's kit: what a template asks for when a game plays in
3
+ * `style: "voxel"`.
4
+ */
5
+ import type { StyleKit } from "../kit.js";
6
+ export declare const voxelKit: StyleKit;
@@ -0,0 +1,11 @@
1
+ import { voxelStack } from "./look.js";
2
+ import { voxelShape } from "./props.js";
3
+ import { voxelField, voxelPillar, terrainHeight } from "./world.js";
4
+ export const voxelKit = {
5
+ id: "voxel",
6
+ stack: (preset) => voxelStack(preset),
7
+ field: (spec) => voxelField(spec, spec.pillars ?? []),
8
+ groundHeight: (spec, x, z) => terrainHeight(spec, x, z),
9
+ pillar: (spec, theme, index) => voxelPillar(spec, theme, index),
10
+ shape: (name) => voxelShape(name),
11
+ };
@@ -0,0 +1,10 @@
1
+ /**
2
+ * The voxel style's light and grade. Cubes read by their faces: a strong,
3
+ * lower key light makes tops bright and sides a step darker, a weaker sky
4
+ * fill keeps the shadow side from going flat, and a gentler exposure and
5
+ * saturation keep the saturated voxel palettes from blowing out to white
6
+ * under the night grade's bloom.
7
+ */
8
+ import type { LookPreset } from "../../render/presets.js";
9
+ import type { StyleStack } from "../kit.js";
10
+ export declare function voxelStack(preset: LookPreset): StyleStack;
@@ -0,0 +1,16 @@
1
+ export function voxelStack(preset) {
2
+ // The key comes from the camera's left and a little behind, so the faces a top-down camera sees are lit unevenly.
3
+ const sunDir = [-0.6, 0.72, 0.42];
4
+ switch (preset) {
5
+ case "night":
6
+ return {
7
+ shadows: true,
8
+ lighting: { hemi: 1.45, sky: 0x8ea0e6, ground: 0x2a2416, sun: 0xd2dcff, sunIntensity: 3.9, sunDir, ambient: 0.22, shadowStrength: 0.62 },
9
+ grade: { exposure: 1.1, saturation: 1.02, contrast: 1.1, bloomThreshold: 0.92 },
10
+ };
11
+ case "dusk":
12
+ return { shadows: true, lighting: { sunDir, shadowStrength: 0.6 }, grade: { saturation: 1.0, bloomThreshold: 0.92 } };
13
+ default:
14
+ return { shadows: true, lighting: { sunDir, shadowStrength: 0.55 } };
15
+ }
16
+ }
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Template machinery shapes in voxels (StyleKit.shape): the debris chunk a
3
+ * kill throws (one cube, so a death reads as a model breaking into voxels),
4
+ * loose field rocks and cut stumps. Each is centred on the origin, like the
5
+ * primitives a template draws them with, and built once.
6
+ */
7
+ import type { StyleShape, StyleShapeName } from "../kit.js";
8
+ /** A machinery shape in voxels, or null to keep the template's own. */
9
+ export declare function voxelShape(name: StyleShapeName): StyleShape | null;
@@ -0,0 +1,52 @@
1
+ import { fillWhere, greedyMesh, hash3, jitter, VoxelGrid } from "./core.js";
2
+ import { voxelGeometry, voxelMaterial } from "./geometry.js";
3
+ /** Grid centred on the origin in all three axes. */
4
+ function centred(nx, ny, nz, size) {
5
+ return new VoxelGrid(nx, ny, nz, size, [(-nx * size) / 2, (-ny * size) / 2, (-nz * size) / 2]);
6
+ }
7
+ /** One cube about as big as the unit dodecahedron it replaces; white, so the instance colour is the chunk's colour. */
8
+ function chunk() {
9
+ const g = centred(1, 1, 1, 1.25);
10
+ g.set(0, 0, 0, 0xffffff);
11
+ return g;
12
+ }
13
+ /** A lumpy boulder (half size about 0.5 m) in warm field stone with a mossy cap. */
14
+ function rock() {
15
+ const n = 8;
16
+ const g = centred(n, 7, n, 0.125);
17
+ const c = n / 2;
18
+ fillWhere(g, (x, y, z) => {
19
+ const dx = (x - c) / 4;
20
+ const dy = (y - 3.5) / 3.5;
21
+ const dz = (z - c) / 4;
22
+ return dx * dx + dy * dy * 1.1 + dz * dz < 1 - (hash3(Math.floor(x), Math.floor(y), Math.floor(z), 61) - 0.5) * 0.35;
23
+ }, (x, y, z) => (y >= 5 && hash3(x, y, z, 63) < 0.55 ? jitter(0x4f6f3a, x, y, z, 0.08, 65) : jitter(0x7c7466, x, y, z, 0.1, 67)));
24
+ return g;
25
+ }
26
+ /** A cut stump (radius about 0.36 m, 0.9 m tall): bark rings and a pale cut top. */
27
+ function stump() {
28
+ const n = 6;
29
+ const g = centred(n, 7, n, 0.125);
30
+ const c = n / 2;
31
+ fillWhere(g, (x, _y, z) => Math.hypot(x - c, z - c) < 2.9, (x, y, z) => {
32
+ const r = Math.hypot(x + 0.5 - c, z + 0.5 - c);
33
+ if (y === 6)
34
+ return r < 1.6 ? jitter(0xc9a46c, x, y, z, 0.06, 71) : 0x8a6440;
35
+ return jitter((y & 1) === 0 ? 0x5c4430 : 0x4e3a28, x, y, z, 0.08, 73);
36
+ });
37
+ return g;
38
+ }
39
+ const BUILDERS = { chunk, rock, stump };
40
+ const cache = new Map();
41
+ /** A machinery shape in voxels, or null to keep the template's own. */
42
+ export function voxelShape(name) {
43
+ const hit = cache.get(name);
44
+ if (hit)
45
+ return hit;
46
+ const build = BUILDERS[name];
47
+ if (!build)
48
+ return null;
49
+ const shape = { geometry: voxelGeometry(greedyMesh(build(), { splitParts: false })), material: voxelMaterial({ roughness: 0.8 }) };
50
+ cache.set(name, shape);
51
+ return shape;
52
+ }
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Procedural voxel models the style builds at load (no file): pickups and
3
+ * scenery. Pure: each returns a VoxelGrid, the caller meshes it. Every
4
+ * colour varies a little per voxel (a seeded hash), so faces read as stacked
5
+ * cubes rather than flat plastic.
6
+ */
7
+ import { VoxelGrid } from "./core.js";
8
+ declare const GEMS: {
9
+ readonly small: {
10
+ readonly r: 2;
11
+ readonly light: 16765803;
12
+ readonly dark: 14714396;
13
+ readonly size: 0.075;
14
+ };
15
+ readonly mid: {
16
+ readonly r: 3;
17
+ readonly light: 10478847;
18
+ readonly dark: 3112920;
19
+ readonly size: 0.07;
20
+ };
21
+ readonly large: {
22
+ readonly r: 4;
23
+ readonly light: 16754406;
24
+ readonly dark: 13052047;
25
+ readonly size: 0.085;
26
+ };
27
+ };
28
+ /** A faceted voxel gem: a double pyramid, light on its upper faces, dark below, one bright glint. */
29
+ export declare function gemGrid(kind: keyof typeof GEMS): VoxelGrid;
30
+ /** A chunky plus sign: the universal heal. */
31
+ export declare function crossGrid(color?: number): VoxelGrid;
32
+ /** An energy cell: a squat battery with a bright core band. */
33
+ export declare function cellGrid(color?: number): VoxelGrid;
34
+ /** A little cluster of flames for braziers and campfires: hot core, orange tongues, red tips. */
35
+ export declare function flameGrid(seed?: number): VoxelGrid;
36
+ /** Pickups by procedural library name (style.voxel.gem_small is `voxel_gem_small`). */
37
+ export declare function pickupGrid(name: string): {
38
+ grid: VoxelGrid;
39
+ glow: number;
40
+ } | null;
41
+ export {};
@@ -0,0 +1,83 @@
1
+ /**
2
+ * Procedural voxel models the style builds at load (no file): pickups and
3
+ * scenery. Pure: each returns a VoxelGrid, the caller meshes it. Every
4
+ * colour varies a little per voxel (a seeded hash), so faces read as stacked
5
+ * cubes rather than flat plastic.
6
+ */
7
+ import { fillWhere, hash3, jitter, mixRgb, shadeRgb, VoxelGrid } from "./core.js";
8
+ /** Grid centred on x and z, standing on y = 0. */
9
+ function centred(nx, ny, nz, size) {
10
+ return new VoxelGrid(nx, ny, nz, size, [(-nx * size) / 2, 0, (-nz * size) / 2]);
11
+ }
12
+ const GEMS = {
13
+ small: { r: 2, light: 0xffd36b, dark: 0xe0861c, size: 0.075 },
14
+ mid: { r: 3, light: 0x9fe4ff, dark: 0x2f7fd8, size: 0.07 },
15
+ large: { r: 4, light: 0xffa6e6, dark: 0xc7288f, size: 0.085 },
16
+ };
17
+ /** A faceted voxel gem: a double pyramid, light on its upper faces, dark below, one bright glint. */
18
+ export function gemGrid(kind) {
19
+ const g = GEMS[kind];
20
+ const n = g.r * 2 + 1;
21
+ const h = g.r * 2 + 3;
22
+ const grid = centred(n, h, n, g.size);
23
+ const cx = n / 2;
24
+ const cy = h / 2;
25
+ fillWhere(grid, (x, y, z) => Math.abs(x - cx) + Math.abs(z - cx) + Math.abs(y - cy) * (g.r / (h / 2)) <= g.r + 0.5, (x, y, z) => {
26
+ const up = y + 0.5 > cy;
27
+ const base = up ? g.light : g.dark;
28
+ const glint = up && x === Math.floor(cx) - 1 && z === Math.floor(cx) && y === Math.floor(cy) + 1;
29
+ return glint ? 0xffffff : jitter(base, x, y, z, 0.07, 3);
30
+ });
31
+ return grid;
32
+ }
33
+ /** A chunky plus sign: the universal heal. */
34
+ export function crossGrid(color = 0x5dff7a) {
35
+ const grid = centred(7, 7, 3, 0.085);
36
+ fillWhere(grid, (x, y) => (x > 2 && x < 5) || (y > 2 && y < 5), (x, y, z) => {
37
+ if (x === 3 && y === 3)
38
+ return 0xeaffe8;
39
+ const end = x === 0 || x === 6 || y === 0 || y === 6;
40
+ return jitter(end ? shadeRgb(color, 0.82) : color, x, y, z, 0.06, 5);
41
+ });
42
+ return grid;
43
+ }
44
+ /** An energy cell: a squat battery with a bright core band. */
45
+ export function cellGrid(color = 0x6fd3ff) {
46
+ const grid = centred(5, 7, 5, 0.075);
47
+ fillWhere(grid, (x, y, z) => (y < 6 ? Math.abs(x - 2.5) < 2.2 && Math.abs(z - 2.5) < 2.2 : Math.abs(x - 2.5) < 1 && Math.abs(z - 2.5) < 1), (x, y, z) => (y === 6 ? 0xd8dde4 : y === 2 || y === 3 ? mixRgb(color, 0xffffff, 0.45) : jitter(shadeRgb(color, 0.75), x, y, z, 0.06, 7)));
48
+ return grid;
49
+ }
50
+ /** A little cluster of flames for braziers and campfires: hot core, orange tongues, red tips. */
51
+ export function flameGrid(seed = 1) {
52
+ const grid = centred(5, 7, 5, 0.12);
53
+ fillWhere(grid, (x, y, z) => {
54
+ const r = Math.hypot(x - 2.5, z - 2.5);
55
+ const reach = 2.4 - y * 0.34 + (hash3(Math.floor(x), 0, Math.floor(z), seed) - 0.5) * 1.2;
56
+ return r < reach;
57
+ }, (x, y, z) => {
58
+ const r = Math.hypot(x + 0.5 - 2.5, z + 0.5 - 2.5);
59
+ if (y < 2 && r < 1.2)
60
+ return 0xfff2b0;
61
+ if (y < 4)
62
+ return jitter(0xffa031, x, y, z, 0.08, seed);
63
+ return jitter(0xff5a1f, x, y, z, 0.08, seed);
64
+ });
65
+ return grid;
66
+ }
67
+ /** Pickups by procedural library name (style.voxel.gem_small is `voxel_gem_small`). */
68
+ export function pickupGrid(name) {
69
+ switch (name) {
70
+ case "gem_small":
71
+ return { grid: gemGrid("small"), glow: 0xff9a1f };
72
+ case "gem_mid":
73
+ return { grid: gemGrid("mid"), glow: 0x2f8fff };
74
+ case "gem_large":
75
+ return { grid: gemGrid("large"), glow: 0xff3fb8 };
76
+ case "cell_heal":
77
+ return { grid: crossGrid(), glow: 0x2bff6a };
78
+ case "cell_spark":
79
+ return { grid: cellGrid(), glow: 0x1e9bff };
80
+ default:
81
+ return null;
82
+ }
83
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Voxel worlds: the play field's floor, terraced ground past the wall, a
3
+ * stone (or steel) wall, pillars with a voxel flame, and ground clutter.
4
+ *
5
+ * Static voxel scenery is greedy-meshed with occlusion baked into vertex
6
+ * colours, and the material adds a per-voxel shade from the voxel's world
7
+ * cell (a hash), so large merged faces still read as stacked cubes without
8
+ * costing a quad per voxel. The floor is one plane painted per cell the same
9
+ * way, and every placement is seeded, so every client sees the same world.
10
+ */
11
+ import { MeshStandardNodeMaterial } from "three/webgpu";
12
+ import type { Object3D } from "three/webgpu";
13
+ import type { FieldSpec, PillarSpec, StyledPillar, WorldTheme } from "../kit.js";
14
+ /** Floor cell (and terrain voxel), m. */
15
+ export declare const WORLD_CELL = 0.5;
16
+ /** Palettes per theme (sRGB). */
17
+ export interface WorldPalette {
18
+ readonly grass: readonly number[];
19
+ readonly dirt: readonly number[];
20
+ readonly stone: readonly number[];
21
+ readonly moss: number;
22
+ readonly path: readonly number[];
23
+ readonly flowers: readonly number[];
24
+ }
25
+ export declare function paletteFor(theme: WorldTheme): WorldPalette;
26
+ /**
27
+ * The material for greedy-meshed static voxels: vertex colours (occlusion
28
+ * baked) times a per-voxel shade from the voxel's world cell, and a faint
29
+ * darkening along each voxel's edges so merged faces still show their cubes.
30
+ */
31
+ export declare function voxelWorldMaterial(opts?: {
32
+ cell: number;
33
+ jitter?: number;
34
+ edge?: number;
35
+ roughness?: number;
36
+ }): MeshStandardNodeMaterial;
37
+ /**
38
+ * Height of the voxel ground at (x, z), m: flat inside the field and for a
39
+ * strip past the wall, then terraces that climb away from it in whole
40
+ * voxels. Scenery standing outside the wall uses it to stand on the ground.
41
+ */
42
+ export declare function terrainHeight(spec: Pick<FieldSpec, "half" | "theme">, x: number, z: number): number;
43
+ /**
44
+ * The whole field: the painted floor, terraced ground past the wall, the
45
+ * wall, and ground clutter. Returns meshes to add to the scene.
46
+ */
47
+ export declare function voxelField(spec: FieldSpec, pillars?: readonly PillarSpec[]): Object3D[];
48
+ /** A stone column of rough courses with a capital, an iron brazier and a voxel flame (meadow); a steel post with a lamp (yard). */
49
+ export declare function voxelPillar(spec: PillarSpec, theme: WorldTheme, index: number): StyledPillar;