@adatechnology/game-vfx-three 0.5.2 → 0.7.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/{chunk-ALDCQ5RH.js → chunk-CPRCWTSQ.js} +22 -5
- package/dist/chunk-CPRCWTSQ.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.global.js +26 -6
- package/dist/index.global.js.map +1 -1
- package/dist/index.js +1 -1
- package/dist/testing.js +1 -1
- package/package.json +4 -4
- package/dist/chunk-ALDCQ5RH.js.map +0 -1
|
@@ -467,7 +467,11 @@ function createMarkTextures(THREE, createCanvas) {
|
|
|
467
467
|
}
|
|
468
468
|
|
|
469
469
|
// src/marks.ts
|
|
470
|
-
var
|
|
470
|
+
var FLAT_STEPS_PER_METRE = 8;
|
|
471
|
+
var MAX_FLAT_STEPS = 48;
|
|
472
|
+
var DUG_STEPS_PER_METRE = 20;
|
|
473
|
+
var MAX_DUG_STEPS = 64;
|
|
474
|
+
var FLAT_TOLERANCE = 2e-3;
|
|
471
475
|
var MIN_CONFORM_STEPS = 16;
|
|
472
476
|
var BLOOD_GROW_RATE = 1.2;
|
|
473
477
|
var BLOOD_START_GROWTH = 0.05;
|
|
@@ -550,9 +554,21 @@ function createMarkLayer(THREE, options) {
|
|
|
550
554
|
spareGeometries.push(oldest.mesh.geometry);
|
|
551
555
|
if (spareGeometries.length > MAX_SPARE_GROUND_GEOMETRIES) spareGeometries.shift().dispose();
|
|
552
556
|
}
|
|
557
|
+
const heightAt = options.heightAt ?? ((x, z) => options.ground?.heightAt(x, z) ?? 0);
|
|
558
|
+
function groundDipsUnder(x, z, radius) {
|
|
559
|
+
const centre = heightAt(x, z);
|
|
560
|
+
for (const share of [0.25, 0.5, 0.75]) {
|
|
561
|
+
for (let ray = 0; ray < 8; ray++) {
|
|
562
|
+
const angle = ray / 8 * Math.PI * 2;
|
|
563
|
+
if (Math.abs(heightAt(x + Math.cos(angle) * radius * share, z + Math.sin(angle) * radius * share) - centre) > FLAT_TOLERANCE) return true;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
553
568
|
function conform(mark, material) {
|
|
554
569
|
const radius = mark.radius;
|
|
555
|
-
const
|
|
570
|
+
const dug = options.heightAt !== void 0 && groundDipsUnder(mark.x, mark.z, radius);
|
|
571
|
+
const steps = Math.max(MIN_CONFORM_STEPS, Math.min(dug ? MAX_DUG_STEPS : MAX_FLAT_STEPS, Math.round(radius * (dug ? DUG_STEPS_PER_METRE : FLAT_STEPS_PER_METRE))));
|
|
556
572
|
if (groundMarks.length >= maxGroundMarks) evictOldestGroundMark();
|
|
557
573
|
const geometry = takeSpare((steps + 1) * (steps + 1)) ?? new THREE.PlaneGeometry(2, 2, steps, steps).rotateX(-Math.PI / 2);
|
|
558
574
|
const grid = geometry.attributes.position;
|
|
@@ -564,7 +580,7 @@ function createMarkLayer(THREE, options) {
|
|
|
564
580
|
const localZ = Math.fround(Math.floor(index / (steps + 1)) * cell - 1) * radius;
|
|
565
581
|
const worldX = mark.x + localX * cos - localZ * sin;
|
|
566
582
|
const worldZ = mark.z + localX * sin + localZ * cos;
|
|
567
|
-
grid.setXYZ(index, worldX,
|
|
583
|
+
grid.setXYZ(index, worldX, heightAt(worldX, worldZ) + mark.lift, worldZ);
|
|
568
584
|
}
|
|
569
585
|
grid.needsUpdate = true;
|
|
570
586
|
geometry.computeVertexNormals();
|
|
@@ -1376,7 +1392,7 @@ function createVfxRenderer(THREE, options) {
|
|
|
1376
1392
|
const shocks = createShockLayer(THREE, pools.shocks);
|
|
1377
1393
|
const sprites = createSpriteLayer(THREE, world.sprites(), options.pointScale ?? 700);
|
|
1378
1394
|
const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI, options.lights);
|
|
1379
|
-
const marks = createMarkLayer(THREE, { ground: pools.ground, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
1395
|
+
const marks = createMarkLayer(THREE, { ground: pools.ground, ...world.hostGroundAt ? { heightAt: world.hostGroundAt } : {}, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
1380
1396
|
root.add(puffs.mesh, sparks.mesh, glows.mesh, chunks.rocks, chunks.plates, shocks.group, lights.group, sprites.additive, sprites.normal, marks.group);
|
|
1381
1397
|
const stopMarks = world.onMarks((event) => marks.handle(event));
|
|
1382
1398
|
const overlay = options.overlay ? createScreenOverlay(options.overlay) : void 0;
|
|
@@ -1429,6 +1445,7 @@ function createVfxRenderer(THREE, options) {
|
|
|
1429
1445
|
drawCalls = Number(lastDrawn.puffs > 0) + Number(lastDrawn.sparks > 0) + Number(lastDrawn.glows > 0) + Number(chunks.rocks.count > 0) + Number(chunks.plates.count > 0) + Number(sprites.additive.geometry.drawRange.count > 0) + Number(sprites.normal.geometry.drawRange.count > 0) + lastDrawn.shocks * 2 + marks.count() + workshopCalls;
|
|
1430
1446
|
}
|
|
1431
1447
|
return {
|
|
1448
|
+
root,
|
|
1432
1449
|
world,
|
|
1433
1450
|
play(request) {
|
|
1434
1451
|
followCamera();
|
|
@@ -1901,4 +1918,4 @@ export {
|
|
|
1901
1918
|
benchText,
|
|
1902
1919
|
createVfxTestModule
|
|
1903
1920
|
};
|
|
1904
|
-
//# sourceMappingURL=chunk-
|
|
1921
|
+
//# sourceMappingURL=chunk-CPRCWTSQ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/bench/module.ts","../src/renderer.ts","../src/shaders/glow.ts","../src/shaders/noise.ts","../src/shaders/puff.ts","../src/shaders/spark.ts","../src/instanced.ts","../src/lights.ts","../src/canvas.ts","../src/marks.ts","../src/mesh-layer.ts","../src/screen-overlay.ts","../src/shaders/shock.ts","../src/shocks.ts","../src/shaders/sprite.ts","../src/sprites.ts","../src/workshop-layers.ts","../src/shaders/workshop-sprite.ts","../src/bench/text.ts"],"sourcesContent":["import type * as THREE_NS from \"three\";\nimport type {\n BenchChange,\n BenchSheet,\n ChoiceOption,\n EffectHandle,\n EffectSink,\n ModuleControl,\n ModuleHost,\n ModuleLayer,\n ModuleMetric,\n TestableModule,\n} from \"@adatechnology/game-contracts\";\nimport {\n EVENT_BUDGET,\n EXPLOSIONS,\n GAME_EFFECTS,\n estimateCost,\n resolveStrings,\n} from \"@adatechnology/game-vfx\";\nimport type { EffectDef, ExplosionDef } from \"@adatechnology/game-vfx\";\nimport { createVfxRenderer, VFX_LAYERS } from \"../renderer\";\nimport type { ThreeLib, VfxRenderer } from \"../types\";\nimport { benchText } from \"./text\";\n\nexport interface VfxTestModuleOptions {\n readonly locale?: string;\n /** The recipes the bench lists (default `GAME_EFFECTS`) and the explosions (default `EXPLOSIONS`). */\n readonly effects?: Readonly<Record<string, EffectDef>>;\n readonly explosions?: Readonly<Record<string, ExplosionDef>>;\n /** Seconds between two replays while `auto_repeat` is on. */\n readonly repeatSeconds?: number;\n}\n\nconst DEFAULT_EFFECT = \"m67\";\n/** The profile the Lab falls back to for an unknown explosive: not something to pick. */\nconst FALLBACK_EXPLOSION = \"generic\";\nconst NO_VARIANT = \"none\";\nconst BLAST_POINT: readonly [number, number, number] = [0, 0.1, 0];\nconst DEFAULT_DISTANCE = 14;\nconst DEFAULT_REPEAT_SECONDS = 4;\nconst LIGHT_BUDGET = EVENT_BUDGET.blastLights + EVENT_BUDGET.fireLights;\nconst SEGMENT_COLORS = [\"#ffb347\", \"#ff7a2a\", \"#8a8f98\", \"#5c6370\"] as const;\n\nconst TEAMS = [\n \"creatures\",\n \"weapons\",\n \"destruction\",\n \"world\",\n \"vehicles\",\n \"screen\",\n] as const;\nconst LAYER_ID = \"show_\";\n\nconst humanize = (id: string): string => id.replace(/_/g, \" \");\n\n/** Where the bench stands for a distance (m): a three-quarter view that keeps the blast in frame. */\nconst eyeFor = (distance: number): [number, number, number] => [\n distance * 0.6,\n distance * 0.35 + 1.4,\n distance * 0.8,\n];\n\n/** The tick marks and segments of a sheet's timeline: an explosion's flash, fireball and smoke, or a recipe's time. */\nfunction timelineOf(\n explosion: ExplosionDef | undefined,\n recipe: EffectDef | undefined,\n metric: string,\n): NonNullable<BenchSheet[\"timeline\"]> {\n if (explosion) {\n const flash = explosion.flash.life ?? 0.2;\n const smoke = Math.max(explosion.smoke.life, 1);\n return {\n segments: [\n { name: \"flash\", start: 0, end: flash, color: SEGMENT_COLORS[0] },\n {\n name: \"fireball\",\n start: 0,\n end: Math.min(smoke, 2.4),\n color: SEGMENT_COLORS[1],\n },\n { name: \"smoke\", start: 0.4, end: smoke, color: SEGMENT_COLORS[2] },\n ],\n ticks: Array.from({ length: Math.ceil(smoke) }, (_, index) => index + 1),\n metric,\n };\n }\n const span = recipe?.loop && recipe.loop > 0 ? recipe.loop : 4;\n return {\n segments: [\n { name: recipe?.id ?? \"\", start: 0, end: span, color: SEGMENT_COLORS[1] },\n ],\n ticks: Array.from({ length: Math.floor(span) }, (_, index) => index + 1),\n metric,\n };\n}\n\n/**\n * The effects bench: pick an explosion or a recipe (listed by team), its variant, the distance, the quality and the layers, replay it or let it repeat,\n * and watch the particle and light counters against the budget. It plays through `host.effects` (the room's world) and, in a host without one, draws\n * into a renderer of its own.\n */\nexport function createVfxTestModule(\n options: VfxTestModuleOptions = {},\n): TestableModule {\n const locale = options.locale ?? \"en\";\n const recipes = options.effects ?? GAME_EFFECTS;\n const explosions = options.explosions ?? EXPLOSIONS;\n const text = benchText(locale);\n const strings = resolveStrings(locale);\n\n const effectOptions = (): ChoiceOption[] => [\n ...Object.keys(explosions)\n .filter((id) => id !== FALLBACK_EXPLOSION)\n .map((id) => ({\n id,\n name: humanize(id),\n group: strings.groups.explosions ?? text.sheet.explosion,\n })),\n // an id the explosions already use is the explosion's: the sink tries the explosions first, so the recipe of the same name could not be reached\n ...TEAMS.flatMap((team) =>\n Object.values(recipes)\n .filter((def) => def.team === team && !(def.id in explosions))\n .map((def) => ({\n id: def.id,\n name: strings.effects[def.id]?.name ?? humanize(def.id),\n group: strings.groups[def.team] ?? def.team,\n })),\n ),\n ];\n\n const sheetFor = (id: string): BenchSheet => {\n const explosion = explosions[id];\n if (explosion) {\n return {\n kicker: strings.groups.explosions ?? text.sheet.explosion,\n title: humanize(id),\n facts: [\n { label: text.sheet.lethal, value: `${explosion.lethal} m` },\n { label: text.sheet.injury, value: `${explosion.injury} m` },\n { label: text.sheet.radius, value: `${explosion.visualRadius} m` },\n { label: text.sheet.fireballs, value: String(explosion.fireballs) },\n {\n label: text.sheet.particles,\n value: `${estimateCost(explosion)} / ${EVENT_BUDGET.particles}`,\n },\n ],\n timeline: timelineOf(explosion, undefined, \"blast_time\"),\n };\n }\n const recipe = recipes[id];\n const words = strings.effects[id];\n const labels = strings.sheet;\n return {\n kicker: recipe ? (strings.groups[recipe.team] ?? recipe.team) : undefined,\n title: words?.name ?? humanize(id),\n ...(words ? { body: words.short } : {}),\n facts: words\n ? [{ label: labels.budget, value: `${words.cost} · ${words.costNote}` }]\n : [],\n steps: words\n ? [\n { at: labels.when, text: words.when },\n { at: labels.look, text: words.look },\n { at: labels.budget, text: words.budget },\n { at: labels.network, text: words.network },\n ]\n : [],\n timeline: timelineOf(undefined, recipe, \"phase\"),\n };\n };\n\n const controls = (): ModuleControl[] => [\n {\n kind: \"choice\",\n id: \"effect\",\n name: text.controls.effect,\n options: effectOptions(),\n default:\n DEFAULT_EFFECT in explosions ? DEFAULT_EFFECT : effectOptions()[0]!.id,\n },\n {\n kind: \"choice\",\n id: \"variant\",\n name: text.controls.variant,\n options: [{ id: NO_VARIANT, name: text.none }],\n default: NO_VARIANT,\n hidden: true,\n },\n { kind: \"action\", id: \"replay\", name: text.controls.replay },\n {\n kind: \"boolean\",\n id: \"auto_repeat\",\n name: text.controls.auto_repeat,\n default: false,\n },\n {\n kind: \"number\",\n id: \"distance\",\n name: text.controls.distance,\n min: 4,\n max: 120,\n step: 1,\n unit: \"m\",\n default: DEFAULT_DISTANCE,\n },\n {\n kind: \"choice\",\n id: \"lod_band\",\n name: text.controls.lod_band,\n options: ([\"auto\", \"near\", \"middle\", \"far\"] as const).map((id) => ({\n id,\n name: text.lod[id],\n })),\n default: \"auto\",\n },\n {\n kind: \"choice\",\n id: \"quality\",\n name: text.controls.quality,\n options: ([\"high\", \"medium\", \"low\"] as const).map((id) => ({\n id,\n name: text.quality[id],\n })),\n default: \"high\",\n },\n ];\n\n const layers = (): ModuleLayer[] =>\n VFX_LAYERS.map((id) => ({ id: `${LAYER_ID}${id}`, name: text.layers[id] }));\n\n /** The live counters: shared by `metrics` and filled by `attach` (a module without a host reads zeros). */\n let read: () => {\n stats: Readonly<Record<string, number>>;\n phase: number;\n budget: number;\n } = () => ({ stats: {}, phase: 0, budget: 0 });\n\n const metrics = (): ModuleMetric[] => [\n {\n id: \"puffs\",\n name: text.metrics.puffs,\n digits: 0,\n read: () => read().stats.puffs ?? 0,\n },\n {\n id: \"sparks\",\n name: text.metrics.sparks,\n digits: 0,\n read: () => read().stats.sparks ?? 0,\n },\n {\n id: \"debris\",\n name: text.metrics.debris,\n digits: 0,\n max: EVENT_BUDGET.debris,\n read: () => read().stats.chunks ?? 0,\n },\n {\n id: \"lights\",\n name: text.metrics.lights,\n digits: 0,\n max: LIGHT_BUDGET,\n read: () =>\n (read().stats.blastLights ?? 0) + (read().stats.fireLights ?? 0),\n },\n {\n id: \"budget_particles\",\n name: text.metrics.budget_particles,\n digits: 0,\n max: EVENT_BUDGET.particles,\n read: () => read().budget,\n },\n {\n id: \"lod\",\n name: text.metrics.lod,\n digits: 2,\n read: () => read().stats.lod ?? 1,\n },\n {\n id: \"phase\",\n name: text.metrics.phase,\n unit: \"s\",\n digits: 2,\n read: () => read().phase,\n },\n {\n id: \"blast_time\",\n name: text.metrics.blast_time,\n unit: \"s\",\n digits: 2,\n read: () => Math.max(0, read().stats.blastTime ?? 0),\n },\n ];\n\n return {\n id: \"vfx\",\n name: text.module,\n ground: { surface: 'dirt' },\n group: \"effects\",\n items: () => [],\n controls,\n layers,\n metrics,\n // opening the effects area puts the camera at the bench view (the initial distance does not move it: that would take the player's view on load)\n area: () => ({\n placements: [],\n view: { eye: eyeFor(DEFAULT_DISTANCE), target: [0, 1.2, 0] },\n }),\n attach(host: ModuleHost) {\n const bench = host.bench;\n let own: VfxRenderer | undefined;\n let sink: EffectSink | undefined = host.effects;\n if (!sink) {\n own = createVfxRenderer(host.THREE as ThreeLib, {\n scene: host.scene as THREE_NS.Scene,\n camera: host.camera as THREE_NS.PerspectiveCamera,\n });\n sink = own;\n }\n const effects = sink;\n let effect = \"m67\";\n let variant = NO_VARIANT;\n let distance = DEFAULT_DISTANCE;\n let auto = false;\n let phase = 0;\n let handle: EffectHandle | null = null;\n let sinceRepeat = 0;\n // The room hands a module its initial and restored values right after attach (`sendInitial`), in the same tick: those set the state\n // (effect, variant, sheet) but must not play. Playing starts with the first frame, i.e. with what the user does afterwards.\n let live = false;\n\n read = () => {\n const def = explosions[effect];\n const recipe = recipes[effect];\n const budget = def\n ? estimateCost(def)\n : (recipe?.budget.particles ?? 0);\n return { stats: effects.stats?.() ?? {}, phase, budget };\n };\n\n function replay(): void {\n if (handle !== null) effects.stop(handle);\n phase = 0;\n sinceRepeat = 0;\n handle = effects.play({\n effect,\n point: [BLAST_POINT[0], BLAST_POINT[1], BLAST_POINT[2]],\n direction: [1, 0.2, 0.4],\n normal: [0, 1, 0],\n ...(variant !== NO_VARIANT &&\n recipes[effect]?.params?.options.includes(variant)\n ? { param: variant }\n : {}),\n });\n }\n\n function choose(id: string): void {\n effect = id;\n const params = recipes[id]?.params;\n variant = params\n ? (params.options[params.default] ?? params.options[0] ?? NO_VARIANT)\n : NO_VARIANT;\n bench?.patch(\n \"variant\",\n params\n ? {\n hidden: false,\n options: params.options.map((option) => ({\n id: option,\n name: option,\n })),\n value: variant,\n }\n : {\n hidden: true,\n options: [{ id: NO_VARIANT, name: text.none }],\n value: NO_VARIANT,\n },\n );\n bench?.sheet?.(sheetFor(id));\n if (live) replay();\n }\n\n function look(): void {\n const eye = eyeFor(distance);\n bench?.look(eye, [0, 1.2, 0]);\n }\n\n const apply = (change: BenchChange): void => {\n if (change.kind === \"layer\")\n effects.configure?.({\n [`layer_${change.id.slice(LAYER_ID.length)}`]: change.on,\n });\n else if (change.kind === \"action\") {\n if (change.id === \"replay\") replay();\n } else if (change.id === \"effect\" && typeof change.value === \"string\")\n choose(change.value);\n else if (change.id === \"variant\" && typeof change.value === \"string\") {\n variant = change.value;\n if (live && recipes[effect]?.params) replay();\n } else if (change.id === \"auto_repeat\") auto = change.value === true;\n else if (change.id === \"distance\" && typeof change.value === \"number\") {\n distance = change.value;\n look();\n } else if (change.id === \"lod_band\" || change.id === \"quality\")\n effects.configure?.({ [change.id]: change.value });\n };\n const offChange = bench?.onChange(apply);\n const offFrame = host.onFrame((dt) => {\n live = true;\n phase += dt;\n sinceRepeat += dt;\n own?.update(dt);\n if (\n auto &&\n sinceRepeat >= (options.repeatSeconds ?? DEFAULT_REPEAT_SECONDS)\n )\n replay();\n });\n return () => {\n offChange?.();\n offFrame();\n if (handle !== null) effects.stop(handle);\n bench?.sheet?.(null);\n own?.dispose();\n read = () => ({ stats: {}, phase: 0, budget: 0 });\n };\n },\n };\n}\n","import type * as THREE_NS from 'three'\nimport type { ControlValue } from '@adatechnology/game-contracts'\nimport { markKitOrigin } from '@adatechnology/game-contracts'\nimport { colorOfChunk, createVfx, hexToLinearRgb } from '@adatechnology/game-vfx'\nimport type { ScreenState, VfxWorld, WorkshopEngine } from '@adatechnology/game-vfx'\nimport { createChunkLayer, createGlowLayer, createPuffLayer, createSparkLayer } from './instanced'\nimport type { PuffUniforms } from './instanced'\nimport { createLightLayer } from './lights'\nimport { createMarkLayer } from './marks'\nimport { createMeshLayerProbes } from './mesh-layer'\nimport { createScreenOverlay } from './screen-overlay'\nimport { createShockLayer } from './shocks'\nimport { createSpriteLayer } from './sprites'\nimport type { ThreeLib, VfxRenderer, VfxRendererOptions } from './types'\nimport { createWorkshopLayers } from './workshop-layers'\nimport type { WorkshopLayers } from './workshop-layers'\n\nconst LAB_LIGHT_DIRECTION = [-14, 26, 12] as const\nconst SKY_COLOR = 0x6f7c92\nconst GROUND_COLOR = 0x2a241f\nconst LOD_BANDS: Readonly<Record<string, number | null>> = { auto: null, near: 1, middle: 0.5, far: 0.2 }\n/** The quality names the bench offers, as the Workshop's levels (0 keeps every particle). */\nconst QUALITY_LEVELS: Readonly<Record<string, number>> = { high: 0, medium: 1, low: 2 }\n/** `configure({ layer_<id>: false })` hides a layer of the renderer: `puffs`, `sparks`, `glows`, `debris`, `shock`, `sprites`. */\nexport const VFX_LAYERS = ['puffs', 'sparks', 'glows', 'debris', 'shock', 'sprites'] as const\nconst LAYER_PREFIX = 'layer_'\nconst SHAKE_REACH = 0.18\nconst SHAKE_FLOOR = 0.001\n\nfunction isWorld(value: unknown): value is VfxWorld {\n return typeof value === 'object' && value !== null && 'explosion' in value && typeof (value as VfxWorld).explosion === 'function'\n}\n\n/** The overlay shows the Lab's screen and the Workshop's together: the stronger of each field. */\nfunction mergeScreens(lab: ScreenState, workshop: ScreenState | undefined): ScreenState {\n if (!workshop) return lab\n const merged = { ...lab }\n for (const key of Object.keys(lab) as (keyof ScreenState)[]) merged[key] = Math.max(lab[key], workshop[key])\n return merged\n}\n\nfunction prefersReducedMotion(): boolean {\n return typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion: reduce)').matches\n}\n\n/** Draws a `VfxWorld`: the Lab's shaders, debris, shock, lights, marks and the screen overlay, and plays effects asked of it by id (`EffectSink`). */\nexport function createVfxRenderer(THREE: ThreeLib, options: VfxRendererOptions): VfxRenderer {\n const reducedMotion = options.reducedMotion ?? prefersReducedMotion()\n const requested = options.vfx\n const world = isWorld(requested) ? requested : createVfx({ profile: options.quality ?? 'medium', reducedMotion, ...requested })\n const pools = world.pools()\n // The probes of the last warm-up keep their materials until the next one: a program is destroyed when the last material that uses it is disposed (every solid particle disposes its own),\n // and a material that does not use lights keeps the program of the lights it was first drawn with, so each warm-up needs materials of its own.\n let anchors: { readonly meshes: THREE_NS.Mesh[]; readonly group: THREE_NS.Group } | undefined\n const releaseAnchors = (): void => {\n if (!anchors) return\n anchors.meshes[0]?.geometry.dispose()\n for (const mesh of anchors.meshes) (mesh.material as THREE_NS.Material).dispose()\n anchors = undefined\n }\n const root = markKitOrigin(new THREE.Group(), { owner: 'game-vfx-three', kind: 'effect' })\n options.scene.add(root)\n\n const direction = new THREE.Vector3(...(options.lightDirection ?? LAB_LIGHT_DIRECTION)).normalize()\n const sky = hexToLinearRgb(SKY_COLOR)\n const ground = hexToLinearRgb(GROUND_COLOR)\n const uniforms: PuffUniforms = {\n uLight: { value: direction },\n uSky: { value: new THREE.Vector3(sky[0] * 0.55, sky[1] * 0.55, sky[2] * 0.55) },\n uGround: { value: new THREE.Vector3(ground[0] * 0.6, ground[1] * 0.6, ground[2] * 0.6) },\n uGlowPos: { value: new THREE.Vector3() },\n uGlowCol: { value: new THREE.Vector3(1, 0.5, 0.2) },\n uGlowI: { value: 0 },\n uTime: { value: 0 },\n }\n const puffs = createPuffLayer(THREE, pools.puffs, uniforms)\n const sparks = createSparkLayer(THREE, pools.sparks)\n const glows = createGlowLayer(THREE, pools.glows)\n const rockGeometry = new THREE.DodecahedronGeometry(0.5, 0)\n const plateGeometry = new THREE.BoxGeometry(1, 1, 1)\n const chunks = createChunkLayer(THREE, pools.chunks, { rock: rockGeometry, plate: plateGeometry }, colorOfChunk)\n const shocks = createShockLayer(THREE, pools.shocks)\n const sprites = createSpriteLayer(THREE, world.sprites(), options.pointScale ?? 700)\n const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI, options.lights)\n const marks = createMarkLayer(THREE, { ground: pools.ground, ...(world.hostGroundAt ? { heightAt: world.hostGroundAt } : {}), createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits })\n root.add(puffs.mesh, sparks.mesh, glows.mesh, chunks.rocks, chunks.plates, shocks.group, lights.group, sprites.additive, sprites.normal, marks.group)\n const stopMarks = world.onMarks((event) => marks.handle(event))\n const overlay = options.overlay ? createScreenOverlay(options.overlay) : undefined\n let drawCalls = 0\n let workshopLayers: WorkshopLayers | undefined\n let workshopEngine: WorkshopEngine | undefined\n const layerOn = new Map<string, boolean>()\n const layerObjects = (): Record<string, THREE_NS.Object3D[]> => ({\n puffs: [puffs.mesh],\n sparks: [sparks.mesh],\n glows: [glows.mesh],\n debris: [chunks.rocks, chunks.plates],\n shock: [shocks.group],\n sprites: [sprites.additive, sprites.normal, ...(workshopLayers ? [workshopLayers.group] : [])],\n })\n const applyLayers = (): void => {\n for (const [id, objects] of Object.entries(layerObjects())) for (const object of objects) object.visible = layerOn.get(id) !== false\n }\n const screenNow = (): ScreenState => mergeScreens(world.screen(), world.peekWorkshop()?.screen)\n let clock = 0\n const lastDrawn = { puffs: 0, sparks: 0, glows: 0, chunks: 0, shocks: 0, sprites: 0 }\n\n function followCamera(): void {\n const position = options.camera.position\n world.setCamera([position.x, position.y, position.z])\n }\n\n /** Draws the workshop's pools the first time it exists; its point lights are part of every lit material's program key, so they must not appear mid-game. */\n function attachWorkshopLayers(): void {\n const engine = world.peekWorkshop()\n if (!engine || engine === workshopEngine) return\n workshopLayers?.dispose()\n if (workshopLayers) root.remove(workshopLayers.group)\n workshopEngine = engine\n workshopLayers = createWorkshopLayers(THREE, engine, options.pointScale ?? 700, 1, options.lights)\n root.add(workshopLayers.group)\n applyLayers()\n }\n\n function syncAll(): void {\n lastDrawn.puffs = puffs.sync()\n lastDrawn.sparks = sparks.sync()\n lastDrawn.glows = glows.sync()\n lastDrawn.chunks = chunks.sync()\n lastDrawn.shocks = shocks.sync()\n lastDrawn.sprites = sprites.sync()\n lights.sync()\n attachWorkshopLayers()\n const workshopCalls = workshopLayers?.sync() ?? 0\n const glow = pools.lights.glow\n uniforms.uGlowPos.value.set(glow.x, glow.y, glow.z)\n uniforms.uGlowCol.value.set(glow.color[0], glow.color[1], glow.color[2])\n uniforms.uGlowI.value = glow.intensity\n drawCalls = Number(lastDrawn.puffs > 0) + Number(lastDrawn.sparks > 0) + Number(lastDrawn.glows > 0) + Number(chunks.rocks.count > 0) + Number(chunks.plates.count > 0) + Number(sprites.additive.geometry.drawRange.count > 0) + Number(sprites.normal.geometry.drawRange.count > 0) + lastDrawn.shocks * 2 + marks.count() + workshopCalls\n }\n\n return {\n root,\n world,\n play(request) {\n followCamera()\n const explosion = world.explosion(request.effect, request.point, {\n ...(request.direction ? { direction: request.direction } : {}),\n ...(request.seed !== undefined ? { seed: request.seed } : {}),\n ...(request.scale !== undefined ? { scale: request.scale } : {}),\n })\n if (explosion !== null) return explosion\n return world.play(request.effect, request.point, {\n ...(request.direction ? { direction: request.direction } : {}),\n ...(request.normal ? { normal: request.normal } : {}),\n ...(request.orientation ? { orientation: request.orientation } : {}),\n ...(request.seed !== undefined ? { seed: request.seed } : {}),\n ...(request.param !== undefined ? { param: request.param } : {}),\n ...(request.values ? { values: request.values } : {}),\n })\n },\n stop: (handle) => world.stop(handle),\n // a module's closed space (a shut car's cabin): the world's smoke, dust and steam go round it\n enclose: (id, enclosure) => world.enclose(id, enclosure),\n configure(settings: Readonly<Record<string, ControlValue>>) {\n const band = settings.lod_band\n if (typeof band === 'string' && band in LOD_BANDS) world.forceLod(LOD_BANDS[band] ?? null)\n const quality = settings.quality\n if (typeof quality === 'string' && quality in QUALITY_LEVELS) world.workshop().setQuality(QUALITY_LEVELS[quality] ?? 0)\n let layersChanged = false\n for (const [key, value] of Object.entries(settings)) {\n if (!key.startsWith(LAYER_PREFIX) || typeof value !== 'boolean') continue\n layerOn.set(key.slice(LAYER_PREFIX.length), value)\n layersChanged = true\n }\n if (layersChanged) applyLayers()\n },\n catalog: () => [...world.catalog(), ...world.effectIds()],\n update(dt) {\n clock += dt\n uniforms.uTime.value = clock\n followCamera()\n world.update(dt)\n marks.update(dt)\n syncAll()\n overlay?.update(screenNow())\n },\n warmUpProbes() {\n releaseAnchors()\n marks.prepare()\n world.workshop()\n attachWorkshopLayers()\n const meshes = createMeshLayerProbes(THREE)\n for (const mesh of meshes) mesh.frustumCulled = false\n const group = new THREE.Group()\n group.add(...meshes, ...marks.probes())\n anchors = { meshes, group }\n return { group, dispose: () => {} }\n },\n applyCamera() {\n const shake = screenNow().shake\n if (reducedMotion || !(shake > SHAKE_FLOOR)) return () => {}\n const camera = options.camera as THREE_NS.Camera\n const base = camera.position.clone()\n const reach = shake * SHAKE_REACH\n camera.position.x += Math.sin(clock * 71) * reach\n camera.position.y += Math.sin(clock * 53 + 1) * reach * 0.7\n camera.position.z += Math.sin(clock * 67 + 2) * reach\n return () => camera.position.copy(base)\n },\n stats() {\n const { lastBlast, ...counters } = world.stats()\n return { ...counters, last_puffs: lastBlast.puffs, last_sparks: lastBlast.sparks, last_chunks: lastBlast.chunks, last_lights: lastBlast.lights, drawCalls }\n },\n screen: screenNow,\n dispose() {\n releaseAnchors()\n stopMarks()\n overlay?.dispose()\n workshopLayers?.dispose()\n for (const layer of [puffs, sparks, glows, chunks, shocks, lights, marks, sprites]) layer.dispose()\n rockGeometry.dispose()\n plateGeometry.dispose()\n options.scene.remove(root)\n },\n }\n}\n","/** The additive halo (Lab L297-304), verbatim except for the r160 colour-space chunk. */\nexport const GLOW_VERTEX = `attribute vec4 aP;attribute vec4 aC;varying vec2 vU;varying vec4 vC;\nvoid main(){vec3 R=vec3(viewMatrix[0][0],viewMatrix[1][0],viewMatrix[2][0]);vec3 Up=vec3(viewMatrix[0][1],viewMatrix[1][1],viewMatrix[2][1]);\nvec3 wp=aP.xyz+(R*position.x+Up*position.y)*aP.w;vU=position.xy;vC=aC;gl_Position=projectionMatrix*viewMatrix*vec4(wp,1.);}`\n\nexport const GLOW_FRAGMENT = `varying vec2 vU;varying vec4 vC;void main(){float r=dot(vU,vU);if(r>1.)discard;float f=exp(-r*4.2)-.015;gl_FragColor=vec4(vC.rgb*vC.a*max(f,0.),1.);\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n}`\n","/** The value noise the puff shader builds its dissolve from (Lab L116-122), verbatim. */\nexport const GL_NOISE = `\nfloat h3(vec3 p){p=fract(p*.3183099+.1);p*=17.0;return fract(p.x*p.y*p.z*(p.x+p.y+p.z));}\nfloat vn(vec3 x){vec3 i=floor(x),f=fract(x);f=f*f*(3.-2.*f);\n return mix(mix(mix(h3(i),h3(i+vec3(1,0,0)),f.x),mix(h3(i+vec3(0,1,0)),h3(i+vec3(1,1,0)),f.x),f.y),\n mix(mix(h3(i+vec3(0,0,1)),h3(i+vec3(1,0,1)),f.x),mix(h3(i+vec3(0,1,1)),h3(i+vec3(1,1,1)),f.x),f.y),f.z);}\n`\n","import { GL_NOISE } from './noise'\n\n/**\n * The puff shader of the Lab (L130-192), verbatim: a faceted icosahedron per puff, a five-band posterised heat ramp, a noise dissolve and banded light.\n * The only change is the r160 colour-space chunk: `encodings_fragment` (r128) is `colorspace_fragment` now.\n */\nexport const PUFF_VERTEX = `${GL_NOISE}\nattribute vec4 aP;attribute vec4 aD;attribute vec3 aC;\nvarying vec3 vWP;varying vec3 vL;varying vec4 vD;varying vec3 vC;\nvoid main(){\n vec3 p=position;\n float s=aD.z;\n float n=vn(p*1.6+vec3(s*11.0,s*7.0,s*3.0));\n p*=0.78+0.5*n;\n float a=s*6.2831;float c=cos(a),si=sin(a);p.xz=mat2(c,-si,si,c)*p.xz;\n vL=p;\n vec3 wp=aP.xyz+p*aP.w;\n vWP=wp;vD=aD;vC=aC;\n gl_Position=projectionMatrix*viewMatrix*vec4(wp,1.0);\n}`\n\nexport const PUFF_FRAGMENT = `${GL_NOISE}\nuniform vec3 uLight;uniform vec3 uSky;uniform vec3 uGround;uniform vec3 uGlowPos;uniform vec3 uGlowCol;uniform float uGlowI;\nvarying vec3 vWP;varying vec3 vL;varying vec4 vD;varying vec3 vC;\nvec3 L(vec3 c){return pow(c,vec3(2.2));}\nvec3 ramp(float h){\n vec3 c0=L(vec3(.36,.07,.03)),c1=L(vec3(.76,.21,.1)),c2=L(vec3(1.,.54,.16)),c3=L(vec3(1.,.83,.42)),c4=L(vec3(1.,.96,.84));\n if(h<.25)return mix(c0,c1,h/.25);\n if(h<.5)return mix(c1,c2,(h-.25)/.25);\n if(h<.8)return mix(c2,c3,(h-.5)/.3);\n return mix(c3,c4,clamp((h-.8)/.4,0.,1.));\n}\nvoid main(){\n vec3 N=normalize(cross(dFdx(vWP),dFdy(vWP)));\n float age=vD.x,heat=vD.y,kind=vD.w;\n float n=vn(vL*2.4+vD.z*13.0);\n float diss=smoothstep(.5,1.,age);\n if(n<diss*1.08-.04)discard;\n float lam=max(dot(N,uLight),0.);\n float band=lam>.55?1.:lam>.15?.68:.42;\n vec3 col=vC*(vec3(.5,.56,.7)*band*1.05+vec3(.2,.19,.18)+uGround*(.4-.4*N.y));\n vec3 tg=uGlowPos-vWP;float dg=length(tg)+.001;\n float gi=uGlowI/(1.+dg*dg*.05)*(.3+.7*max(dot(N,tg/dg),0.));\n col+=uGlowCol*gi*vC*1.6;\n float h=heat*(.72+.56*n)+heat*(-N.y)*.18;\n if(h>.05){\n float hq=floor(h*5.+.5)/5.;\n vec3 fc=ramp(clamp(hq,0.,1.2))*(1.1+3.1*hq);\n col=mix(col,fc,smoothstep(.04,.2,h));\n }\n if(kind>2.5&&kind<3.5){col+=vec3(.02,.025,.03);}\n gl_FragColor=vec4(col,1.);\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n}`\n","/** The streak shader of shrapnel, sparks and embers (Lab L255-275), verbatim except for the r160 colour-space chunk. */\nexport const SPARK_VERTEX = `\nattribute vec3 aPos;attribute vec3 aVel;attribute vec4 aE;varying vec2 vU;varying vec4 vE;\nvoid main(){\n float sp=length(aVel)+1e-4;vec3 d=aVel/sp;\n vec3 tc=normalize(cameraPosition-aPos);\n vec3 sd=normalize(cross(d,tc)+vec3(1e-5));\n float len=max(aE.y*2.5,min(sp*aE.z,2.2));\n vec3 wp=aPos+sd*position.x*aE.y-d*position.y*len;\n vU=position.xy;vE=aE;\n gl_Position=projectionMatrix*viewMatrix*vec4(wp,1.);\n}`\n\nexport const SPARK_FRAGMENT = `\nvarying vec2 vU;varying vec4 vE;\nvoid main(){\n float age=vE.x,k=vE.w;\n float w=1.-abs(vU.x)*2.;w=w*w;\n float tail=1.-vU.y;\n vec3 c;\n if(k<.5){c=mix(vec3(4.,3.3,2.2),vec3(2.4,.7,.12),smoothstep(0.,.55,age));c=mix(c,vec3(.5,.06,.02),smoothstep(.55,1.,age));}\n else if(k<1.5){c=mix(vec3(1.6,1.6,1.6),vec3(.35,.35,.36),smoothstep(0.,.4,age));}\n else if(k<2.5){c=mix(vec3(5.,5.,6.),vec3(1.,1.3,2.),smoothstep(0.,.5,age));}\n else if(k<3.5){c=vec3(.9,1.2,1.4)*(1.-age);}\n else {c=mix(vec3(3.2,1.4,.3),vec3(1.2,.25,.05),age);}\n float a=w*(.35+.65*tail)*(1.-smoothstep(.75,1.,age));\n gl_FragColor=vec4(c*a,1.);\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n}`\n","import type * as THREE_NS from 'three'\nimport type { Chunk, Glow, OrderedPool, Puff, Spark } from '@adatechnology/game-vfx'\nimport { GLOW_FRAGMENT, GLOW_VERTEX } from './shaders/glow'\nimport { PUFF_FRAGMENT, PUFF_VERTEX } from './shaders/puff'\nimport { SPARK_FRAGMENT, SPARK_VERTEX } from './shaders/spark'\nimport type { ThreeLib } from './types'\n\nexport interface DrawnLayer {\n readonly mesh: THREE_NS.Mesh\n /** Copies the pool into the instance buffers and answers how many are drawn. */\n sync(): number\n dispose(): void\n}\n\ntype Attribute = THREE_NS.InstancedBufferAttribute\n\nfunction dynamic(THREE: ThreeLib, array: Float32Array, size: number): Attribute {\n return new THREE.InstancedBufferAttribute(array, size).setUsage(THREE.DynamicDrawUsage)\n}\n\nexport interface PuffUniforms {\n uLight: { value: THREE_NS.Vector3 }\n uSky: { value: THREE_NS.Vector3 }\n uGround: { value: THREE_NS.Vector3 }\n uGlowPos: { value: THREE_NS.Vector3 }\n uGlowCol: { value: THREE_NS.Vector3 }\n uGlowI: { value: number }\n uTime: { value: number }\n}\n\nexport function createPuffLayer(THREE: ThreeLib, pool: OrderedPool<Puff>, uniforms: PuffUniforms): DrawnLayer {\n const capacity = pool.capacity\n const geometry = new THREE.InstancedBufferGeometry()\n geometry.setAttribute('position', new THREE.IcosahedronGeometry(1, 1).getAttribute('position'))\n const a = new Float32Array(capacity * 4)\n const d = new Float32Array(capacity * 4)\n const c = new Float32Array(capacity * 3)\n const attributes = [dynamic(THREE, a, 4), dynamic(THREE, d, 4), dynamic(THREE, c, 3)] as const\n geometry.setAttribute('aP', attributes[0])\n geometry.setAttribute('aD', attributes[1])\n geometry.setAttribute('aC', attributes[2])\n geometry.instanceCount = 0\n const material = new THREE.ShaderMaterial({ uniforms: uniforms as never, vertexShader: PUFF_VERTEX, fragmentShader: PUFF_FRAGMENT })\n const mesh = new THREE.Mesh(geometry, material)\n mesh.name = 'vfx-puffs'\n mesh.frustumCulled = false\n return {\n mesh,\n sync() {\n let n = 0\n for (const p of pool.items) {\n a[n * 4] = p.x\n a[n * 4 + 1] = p.y\n a[n * 4 + 2] = p.z\n a[n * 4 + 3] = p.size\n d[n * 4] = p.age\n d[n * 4 + 1] = p.heat\n d[n * 4 + 2] = p.seed\n d[n * 4 + 3] = p.kind\n c[n * 3] = p.color[0]\n c[n * 3 + 1] = p.color[1]\n c[n * 3 + 2] = p.color[2]\n n++\n }\n geometry.instanceCount = n\n for (const attribute of attributes) attribute.needsUpdate = true\n return n\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\nexport function createSparkLayer(THREE: ThreeLib, pool: OrderedPool<Spark>): DrawnLayer {\n const capacity = pool.capacity\n const geometry = new THREE.InstancedBufferGeometry()\n geometry.setAttribute('position', new THREE.Float32BufferAttribute([-0.5, 0, 0, 0.5, 0, 0, 0.5, 1, 0, -0.5, 1, 0], 3))\n geometry.setIndex([0, 1, 2, 0, 2, 3])\n const position = new Float32Array(capacity * 3)\n const velocity = new Float32Array(capacity * 3)\n const extra = new Float32Array(capacity * 4)\n const attributes = [dynamic(THREE, position, 3), dynamic(THREE, velocity, 3), dynamic(THREE, extra, 4)] as const\n geometry.setAttribute('aPos', attributes[0])\n geometry.setAttribute('aVel', attributes[1])\n geometry.setAttribute('aE', attributes[2])\n geometry.instanceCount = 0\n const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: SPARK_VERTEX, fragmentShader: SPARK_FRAGMENT })\n const mesh = new THREE.Mesh(geometry, material)\n mesh.name = 'vfx-sparks'\n mesh.frustumCulled = false\n mesh.renderOrder = 5\n return {\n mesh,\n sync() {\n let n = 0\n for (const s of pool.items) {\n position[n * 3] = s.x\n position[n * 3 + 1] = s.y\n position[n * 3 + 2] = s.z\n velocity[n * 3] = s.vx\n velocity[n * 3 + 1] = s.vy\n velocity[n * 3 + 2] = s.vz\n extra[n * 4] = s.age\n extra[n * 4 + 1] = s.w\n extra[n * 4 + 2] = s.st\n extra[n * 4 + 3] = s.kind\n n++\n }\n geometry.instanceCount = n\n for (const attribute of attributes) attribute.needsUpdate = true\n return n\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\nexport function createGlowLayer(THREE: ThreeLib, pool: OrderedPool<Glow>): DrawnLayer {\n const capacity = pool.capacity\n const geometry = new THREE.InstancedBufferGeometry()\n geometry.setAttribute('position', new THREE.Float32BufferAttribute([-1, -1, 0, 1, -1, 0, 1, 1, 0, -1, 1, 0], 3))\n geometry.setIndex([0, 1, 2, 0, 2, 3])\n const where = new Float32Array(capacity * 4)\n const color = new Float32Array(capacity * 4)\n const attributes = [dynamic(THREE, where, 4), dynamic(THREE, color, 4)] as const\n geometry.setAttribute('aP', attributes[0])\n geometry.setAttribute('aC', attributes[1])\n geometry.instanceCount = 0\n const material = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, vertexShader: GLOW_VERTEX, fragmentShader: GLOW_FRAGMENT })\n const mesh = new THREE.Mesh(geometry, material)\n mesh.name = 'vfx-glows'\n mesh.frustumCulled = false\n mesh.renderOrder = 6\n return {\n mesh,\n sync() {\n let n = 0\n for (const g of pool.items) {\n where[n * 4] = g.outX\n where[n * 4 + 1] = g.outY\n where[n * 4 + 2] = g.outZ\n where[n * 4 + 3] = g.outSize\n color[n * 4] = g.color[0]\n color[n * 4 + 1] = g.color[1]\n color[n * 4 + 2] = g.color[2]\n color[n * 4 + 3] = g.outIntensity\n n++\n }\n geometry.instanceCount = n\n for (const attribute of attributes) attribute.needsUpdate = true\n return n\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\nexport interface ChunkLayer {\n readonly rocks: THREE_NS.InstancedMesh\n readonly plates: THREE_NS.InstancedMesh\n sync(): number\n dispose(): void\n}\n\nexport function createChunkLayer(THREE: ThreeLib, pool: OrderedPool<Chunk>, shapes: { rock: THREE_NS.BufferGeometry; plate: THREE_NS.BufferGeometry }, colorOf: (chunk: Chunk) => readonly [number, number, number]): ChunkLayer {\n const capacity = pool.capacity\n const rockMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.85, flatShading: true })\n const plateMaterial = rockMaterial.clone()\n const make = (geometry: THREE_NS.BufferGeometry, material: THREE_NS.Material): THREE_NS.InstancedMesh => {\n const mesh = new THREE.InstancedMesh(geometry, material, capacity)\n mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)\n mesh.castShadow = true\n mesh.receiveShadow = true\n mesh.frustumCulled = false\n mesh.count = 0\n mesh.setColorAt(0, new THREE.Color(1, 1, 1))\n return mesh\n }\n const rocks = make(shapes.rock, rockMaterial)\n const plates = make(shapes.plate, plateMaterial)\n const matrix = new THREE.Matrix4()\n const quaternion = new THREE.Quaternion()\n const euler = new THREE.Euler()\n const position = new THREE.Vector3()\n const scale = new THREE.Vector3()\n return {\n rocks,\n plates,\n sync() {\n let rockCount = 0\n let plateCount = 0\n for (const chunk of pool.items) {\n euler.set(chunk.rx, chunk.ry, chunk.rz)\n quaternion.setFromEuler(euler)\n matrix.compose(position.set(chunk.x, chunk.y, chunk.z), quaternion, scale.set(chunk.sx, chunk.sy, chunk.sz))\n const mesh = chunk.plate ? plates : rocks\n const index = chunk.plate ? plateCount++ : rockCount++\n mesh.setMatrixAt(index, matrix)\n const color = colorOf(chunk)\n const colors = mesh.instanceColor!.array as Float32Array\n colors[index * 3] = color[0]\n colors[index * 3 + 1] = color[1]\n colors[index * 3 + 2] = color[2]\n }\n rocks.count = rockCount\n plates.count = plateCount\n for (const mesh of [rocks, plates]) {\n mesh.instanceMatrix.needsUpdate = true\n mesh.instanceColor!.needsUpdate = true\n }\n return rockCount + plateCount\n },\n dispose() {\n rockMaterial.dispose()\n plateMaterial.dispose()\n rocks.dispose()\n plates.dispose()\n },\n }\n}\n","import type * as THREE_NS from 'three'\nimport type { LightPool } from '@adatechnology/game-vfx'\nimport { LIGHT_PRIORITY } from '@adatechnology/game-render-three'\nimport type { LightBudget, LightHandle } from '@adatechnology/game-render-three'\nimport type { ThreeLib } from './types'\n\n/** Below this the pool entry counts as off, so its slot goes back to the budget in the same frame. */\nexport const LIGHT_ON_THRESHOLD = 0.05\nconst FIRE_COLOR = 0xff7a2a\nconst FIRE_DECAY = 2\nconst BLAST_DECAY = 2\n\n/** Keeps one budget handle per pool entry: takes a slot while the entry burns, gives it back the frame it goes out. */\nexport function followEntry(\n budget: LightBudget,\n handles: (LightHandle | null)[],\n index: number,\n entry: { readonly intensity: number },\n request: Parameters<LightBudget['acquire']>[0],\n): void {\n const handle = handles[index] ?? null\n if (entry.intensity <= LIGHT_ON_THRESHOLD) {\n handle?.release({ fadeMs: 0 })\n handles[index] = null\n return\n }\n if (handle?.alive) {\n handle.update({ color: request.color, intensity: request.intensity, distance: request.distance, position: request.position })\n return\n }\n handles[index] = budget.acquire(request)\n}\n\nexport interface LightLayer {\n readonly group: THREE_NS.Group\n /** Moves and lights the 4 blast lights and 2 fire lights from the pool; answers how many are lit. */\n sync(): number\n dispose(): void\n}\n\n/** The Lab's light pool as real point lights (L349-365). Colours are the raw numbers the Lab used, not converted from sRGB. */\nexport function createLightLayer(THREE: ThreeLib, pool: LightPool, scale: number, budget?: LightBudget): LightLayer {\n const group = new THREE.Group()\n if (budget) return createBudgetedLightLayer(group, pool, scale, budget)\n const blast = pool.blast.map(() => {\n // eslint-disable-next-line no-restricted-syntax -- D2: legacy path without LightBudget, removed in the next major\n const light = new THREE.PointLight(0xffa050, 0, 30, 2)\n light.position.set(0, -50, 0)\n group.add(light)\n return light\n })\n const fire = pool.fire.map(() => {\n // eslint-disable-next-line no-restricted-syntax -- D2: legacy path without LightBudget, removed in the next major\n const light = new THREE.PointLight(0xff7a2a, 0, 16, 2)\n light.position.set(0, -50, 0)\n group.add(light)\n return light\n })\n return {\n group,\n sync() {\n let lit = 0\n pool.blast.forEach((entry, index) => {\n const light = blast[index]!\n light.position.set(entry.x, entry.y, entry.z)\n light.distance = entry.distance\n light.color.setRGB(entry.color[0], entry.color[1], entry.color[2], THREE.LinearSRGBColorSpace)\n light.intensity = entry.intensity * scale\n if (entry.intensity > 0.05) lit++\n })\n pool.fire.forEach((entry, index) => {\n const light = fire[index]!\n light.position.set(entry.x, entry.y, entry.z)\n light.distance = entry.distance\n light.intensity = entry.intensity * scale\n if (entry.intensity > 0.05) lit++\n })\n return lit\n },\n dispose() {\n for (const light of [...blast, ...fire]) light.dispose()\n },\n }\n}\n\n/** The same lights as requests to the budget; the group stays in the root, empty, so the indices of the root's children do not move. */\nfunction createBudgetedLightLayer(group: THREE_NS.Group, pool: LightPool, scale: number, budget: LightBudget): LightLayer {\n const blast: (LightHandle | null)[] = pool.blast.map(() => null)\n const fire: (LightHandle | null)[] = pool.fire.map(() => null)\n return {\n group,\n sync() {\n let lit = 0\n pool.blast.forEach((entry, index) => {\n const request = { owner: 'vfx.blast', priority: LIGHT_PRIORITY.blast, urgent: true, color: entry.color, intensity: entry.intensity * scale, distance: entry.distance, decay: BLAST_DECAY, position: [entry.x, entry.y, entry.z] as const }\n followEntry(budget, blast, index, entry, request)\n if (entry.intensity > LIGHT_ON_THRESHOLD) lit++\n })\n pool.fire.forEach((entry, index) => {\n const request = { owner: 'vfx.fire', priority: LIGHT_PRIORITY.fire, color: FIRE_COLOR, intensity: entry.intensity * scale, distance: entry.distance, decay: FIRE_DECAY, position: [entry.x, entry.y, entry.z] as const }\n followEntry(budget, fire, index, entry, request)\n if (entry.intensity > LIGHT_ON_THRESHOLD) lit++\n })\n return lit\n },\n dispose() {\n for (const handle of [...blast, ...fire]) handle?.release({ fadeMs: 0 })\n },\n }\n}\n","import { lehmer } from '@adatechnology/game-vfx'\nimport type { RandomStream } from '@adatechnology/game-vfx'\nimport type { CanvasContextLike, CanvasLike, ThreeLib } from './types'\nimport type * as THREE_NS from 'three'\n\nconst SCORCH_SEED = 5\nconst TEXTURE_SIZE = 256\nconst FULL_TURN = Math.PI * 2\n\n/** Where a texture draws its randomness: the Lab seeded the page with 5 before it made the marks, so the textures do not touch the effect's own stream. */\nexport function createTextureStream(): RandomStream {\n return lehmer(SCORCH_SEED)\n}\n\n/** Without a DOM (a server, a test in Node) there is nothing to draw on: the textures stay blank and the marks still lay down their geometry. */\nfunction blankCanvas(): CanvasLike {\n return { width: 0, height: 0, getContext: () => null }\n}\n\nfunction defaultCanvas(): CanvasLike {\n if (typeof document === 'undefined') return blankCanvas()\n return document.createElement('canvas') as unknown as CanvasLike\n}\n\nfunction paint(createCanvas: () => CanvasLike, draw: (context: CanvasContextLike, size: number) => void): CanvasLike {\n const canvas = createCanvas()\n canvas.width = TEXTURE_SIZE\n canvas.height = TEXTURE_SIZE\n const context = canvas.getContext('2d')\n if (context) draw(context, TEXTURE_SIZE)\n return canvas\n}\n\nfunction drawScorch(context: CanvasContextLike, size: number, random: RandomStream): void {\n context.clearRect(0, 0, size, size)\n const center = size / 2\n for (let ray = 0; ray < 60; ray++) {\n const angle = random.next() * FULL_TURN\n const length = center * (0.55 + random.next() * 0.42)\n context.strokeStyle = `rgba(8,6,5,${0.25 + random.next() * 0.35})`\n context.lineWidth = 2 + random.next() * 6\n context.beginPath()\n context.moveTo(center, center)\n context.lineTo(center + Math.cos(angle) * length, center + Math.sin(angle) * length)\n context.stroke()\n }\n const gradient = context.createRadialGradient(center, center, 0, center, center, center * 0.72)\n gradient.addColorStop(0, 'rgba(4,3,3,.96)')\n gradient.addColorStop(0.55, 'rgba(10,8,7,.85)')\n gradient.addColorStop(1, 'rgba(14,11,9,0)')\n context.fillStyle = gradient\n context.fillRect(0, 0, size, size)\n for (let spot = 0; spot < 26; spot++) {\n context.fillStyle = `rgba(60,40,28,${0.15 + random.next() * 0.2})`\n context.beginPath()\n context.arc(center + random.between(-0.4, 0.4) * center, center + random.between(-0.4, 0.4) * center, 2 + random.next() * 7, 0, 7)\n context.fill()\n }\n}\n\nfunction drawDirt(context: CanvasContextLike, size: number, random: RandomStream): void {\n const center = size / 2\n context.clearRect(0, 0, size, size)\n const gradient = context.createRadialGradient(center, center, 0, center, center, center)\n gradient.addColorStop(0, 'rgba(92,72,52,1)')\n gradient.addColorStop(0.6, 'rgba(118,92,64,1)')\n gradient.addColorStop(0.82, 'rgba(80,64,50,.8)')\n gradient.addColorStop(1, 'rgba(40,36,34,0)')\n context.fillStyle = gradient\n context.fillRect(0, 0, size, size)\n for (let speck = 0; speck < 420; speck++) {\n const angle = random.next() * FULL_TURN\n const distance = Math.sqrt(random.next()) * center * 0.8\n context.fillStyle = random.next() < 0.5 ? 'rgba(40,30,22,.5)' : 'rgba(160,132,96,.5)'\n context.beginPath()\n context.arc(center + Math.cos(angle) * distance, center + Math.sin(angle) * distance, 1 + random.next() * 3.5, 0, 7)\n context.fill()\n }\n}\n\nexport interface MarkTextures {\n readonly scorch: readonly THREE_NS.CanvasTexture[]\n readonly dirt: THREE_NS.CanvasTexture\n}\n\n/** The three scorch textures and the dirt one (L443-457), drawn once from a stream seeded like the page's. */\nexport function createMarkTextures(THREE: ThreeLib, createCanvas: (() => CanvasLike) | undefined): MarkTextures {\n const make = createCanvas ?? defaultCanvas\n const random = createTextureStream()\n const texture = (canvas: CanvasLike): THREE_NS.CanvasTexture => {\n const result = new THREE.CanvasTexture(canvas as unknown as HTMLCanvasElement)\n result.colorSpace = THREE.SRGBColorSpace\n result.anisotropy = 4\n return result\n }\n const scorch = [0, 1, 2].map(() => texture(paint(make, (context, size) => drawScorch(context, size, random))))\n const dirt = texture(paint(make, (context, size) => drawDirt(context, size, random)))\n return { scorch, dirt }\n}\n","import type * as THREE_NS from 'three'\nimport type { BloodMark, DirtMark, GroundField, Mark, MarkEvent, RockMark, ScorchMark } from '@adatechnology/game-vfx'\nimport { createMarkTextures } from './canvas'\nimport type { MarkTextures } from './canvas'\nimport type { CanvasLike, ThreeLib } from './types'\n\n/** Grid lines per metre of mark radius on flat ground (the team's Explosion Lab density). */\nconst FLAT_STEPS_PER_METRE = 8\nconst MAX_FLAT_STEPS = 48\n/** On ground that dips under the mark (a crater the host's terrain dug): a grenade's bowl (about 0.4 m) needs cells of ten centimetres or the mark cuts across it. */\nconst DUG_STEPS_PER_METRE = 20\nconst MAX_DUG_STEPS = 64\n/** Height spread under a mark, in metres, past which the ground counts as dug. */\nconst FLAT_TOLERANCE = 0.002\nconst MIN_CONFORM_STEPS = 16\nconst BLOOD_GROW_RATE = 1.2\nconst BLOOD_START_GROWTH = 0.05\n\nconst DEFAULT_MAX_GROUND_MARKS = 64\nconst DEFAULT_MAX_ROCKS = 512\nconst DEFAULT_MAX_BLOOD = 256\n/** Geometries of evicted ground marks kept to be refilled; past this the extra ones are freed. */\nconst MAX_SPARE_GROUND_GEOMETRIES = 16\n\ninterface GroundDrawn {\n readonly mesh: THREE_NS.Mesh\n steps: number\n}\n\ninterface BloodDrawn {\n readonly position: readonly [number, number, number]\n readonly rotation: number\n readonly scaleX: number\n readonly scaleZ: number\n age: number\n}\n\nexport interface MarkLayer {\n readonly group: THREE_NS.Group\n /** The shared rock and plate shapes, so the debris and the rim rocks use the same geometry. */\n handle(event: MarkEvent): void\n update(dt: number): void\n /** Puts the instanced meshes in the scene now, so their shader programs link while loading instead of at the first mark. */\n prepare(): void\n /** One throwaway mesh per ground-mark material (scorch variants, dirt), so a host's warm-up draws them in every fog state: they are made on demand, a program of theirs is not linked by the instanced meshes. */\n probes(): THREE_NS.Mesh[]\n /** The draw calls the marks cost right now. */\n count(): number\n dispose(): void\n}\n\nexport interface MarkLayerOptions {\n readonly ground: GroundField | undefined\n /** Height of the host's own ground a scorch or dirt mark is laid on; default the `ground` field, else flat at 0. A host with its own terrain passes it here so a mark lines the crater instead of lying flat over it (with a finer grid where the ground dips under the mark). */\n readonly heightAt?: (x: number, z: number) => number\n readonly createCanvas: (() => CanvasLike) | undefined\n readonly rockGeometry: THREE_NS.BufferGeometry\n readonly plateGeometry: THREE_NS.BufferGeometry\n /** Scorch and dirt meshes alive at once; the oldest is reused for the next. Default 64. */\n readonly maxGroundMarks?: number\n /** Rim rocks and plates alive at once (each shape has its own instanced mesh of this size); the oldest is overwritten. Default 512. */\n readonly maxRocks?: number\n /** Blood pools alive at once; the oldest is overwritten. Default 256. */\n readonly maxBlood?: number\n}\n\n/**\n * The scorch, dirt, rim rocks and blood of the Lab as meshes (L443-476). A scorch or dirt mesh follows the ground as it was the moment the mark was\n * made (`conform`), so the renderer builds it from the mark event, not later.\n */\nexport function createMarkLayer(THREE: ThreeLib, options: MarkLayerOptions): MarkLayer {\n const group = new THREE.Group()\n const textures: MarkTextures = createMarkTextures(THREE, options.createCanvas)\n const owned: { dispose(): void }[] = [...textures.scorch, textures.dirt]\n const scorchMaterials = textures.scorch.map((map) => {\n const material = new THREE.MeshStandardMaterial({ map, transparent: true, depthWrite: false, roughness: 1, polygonOffset: true, polygonOffsetFactor: -2, polygonOffsetUnits: -2 })\n owned.push(material)\n return material\n })\n const dirtMaterial = new THREE.MeshStandardMaterial({\n map: textures.dirt, transparent: true, depthWrite: false, roughness: 1, flatShading: true, polygonOffset: true, polygonOffsetFactor: -1, polygonOffsetUnits: -1,\n })\n owned.push(dirtMaterial)\n const bloodMaterial = new THREE.MeshStandardMaterial({ color: 0x5c0a0a, roughness: 0.15, metalness: 0.1, polygonOffset: true, polygonOffsetFactor: -3, polygonOffsetUnits: -3 })\n const bloodGeometry = new THREE.CircleGeometry(0.5, 9).rotateX(-Math.PI / 2)\n owned.push(bloodMaterial, bloodGeometry)\n const maxGroundMarks = options.maxGroundMarks ?? DEFAULT_MAX_GROUND_MARKS\n /* the instanced meshes join the scene with the first mark of their kind, so a world that drew no marks has the same scene it always had */\n const instanced: { blood?: THREE_NS.InstancedMesh; rock?: THREE_NS.InstancedMesh; plate?: THREE_NS.InstancedMesh; rockMaterial?: THREE_NS.MeshStandardMaterial } = {}\n function rockMaterial(): THREE_NS.MeshStandardMaterial {\n if (!instanced.rockMaterial) {\n instanced.rockMaterial = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.9, metalness: 0, flatShading: true })\n owned.push(instanced.rockMaterial)\n }\n return instanced.rockMaterial\n }\n function bloodMesh(): THREE_NS.InstancedMesh {\n return (instanced.blood ??= attach(createInstanced(bloodGeometry, bloodMaterial, options.maxBlood ?? DEFAULT_MAX_BLOOD)))\n }\n function rockMesh(): THREE_NS.InstancedMesh {\n return (instanced.rock ??= attach(createInstanced(options.rockGeometry, rockMaterial(), options.maxRocks ?? DEFAULT_MAX_ROCKS), true))\n }\n function plateMesh(): THREE_NS.InstancedMesh {\n return (instanced.plate ??= attach(createInstanced(options.plateGeometry, rockMaterial(), options.maxRocks ?? DEFAULT_MAX_ROCKS), true))\n }\n function attach(mesh: THREE_NS.InstancedMesh, castShadow = false): THREE_NS.InstancedMesh {\n mesh.castShadow = castShadow\n group.add(mesh)\n return mesh\n }\n let probeGeometry: THREE_NS.BufferGeometry | undefined\n const groundMarks: GroundDrawn[] = []\n const spareGeometries: THREE_NS.BufferGeometry[] = []\n const blood: BloodDrawn[] = []\n const placed = { blood: 0, rock: 0, plate: 0 }\n const matrix = new THREE.Matrix4()\n const position = new THREE.Vector3()\n const quaternion = new THREE.Quaternion()\n const euler = new THREE.Euler()\n const scale = new THREE.Vector3()\n const color = new THREE.Color()\n const up = new THREE.Vector3(0, 1, 0)\n\n function createInstanced(geometry: THREE_NS.BufferGeometry, material: THREE_NS.Material, capacity: number): THREE_NS.InstancedMesh {\n const mesh = new THREE.InstancedMesh(geometry, material, capacity)\n mesh.count = 0\n mesh.frustumCulled = false\n mesh.receiveShadow = true\n return mesh\n }\n\n function takeSpare(vertexCount: number): THREE_NS.BufferGeometry | undefined {\n const found = spareGeometries.findIndex((geometry) => geometry.getAttribute('position').count === vertexCount)\n return found < 0 ? undefined : spareGeometries.splice(found, 1)[0]\n }\n\n function evictOldestGroundMark(): void {\n const oldest = groundMarks.shift()!\n group.remove(oldest.mesh)\n spareGeometries.push(oldest.mesh.geometry)\n if (spareGeometries.length > MAX_SPARE_GROUND_GEOMETRIES) spareGeometries.shift()!.dispose()\n }\n\n const heightAt = options.heightAt ?? ((x: number, z: number): number => options.ground?.heightAt(x, z) ?? 0)\n /** Samples the ground across the mark: flat ground keeps the light grid, a bowl gets the fine one. */\n function groundDipsUnder(x: number, z: number, radius: number): boolean {\n const centre = heightAt(x, z)\n for (const share of [0.25, 0.5, 0.75]) {\n for (let ray = 0; ray < 8; ray++) {\n const angle = (ray / 8) * Math.PI * 2\n if (Math.abs(heightAt(x + Math.cos(angle) * radius * share, z + Math.sin(angle) * radius * share) - centre) > FLAT_TOLERANCE) return true\n }\n }\n return false\n }\n function conform(mark: ScorchMark | DirtMark, material: THREE_NS.Material): void {\n const radius = mark.radius\n const dug = options.heightAt !== undefined && groundDipsUnder(mark.x, mark.z, radius)\n const steps = Math.max(MIN_CONFORM_STEPS, Math.min(dug ? MAX_DUG_STEPS : MAX_FLAT_STEPS, Math.round(radius * (dug ? DUG_STEPS_PER_METRE : FLAT_STEPS_PER_METRE))))\n if (groundMarks.length >= maxGroundMarks) evictOldestGroundMark()\n const geometry = takeSpare((steps + 1) * (steps + 1)) ?? new THREE.PlaneGeometry(2, 2, steps, steps).rotateX(-Math.PI / 2)\n const grid = geometry.attributes.position!\n const cell = 2 / steps\n const cos = Math.cos(mark.rotation)\n const sin = Math.sin(mark.rotation)\n for (let index = 0; index < grid.count; index++) {\n // the unit grid of `PlaneGeometry(2, 2)` turned flat, in float32 like the buffer it would be read back from, so a reused geometry lands where a fresh one does\n const localX = Math.fround((index % (steps + 1)) * cell - 1) * radius\n const localZ = Math.fround(Math.floor(index / (steps + 1)) * cell - 1) * radius\n const worldX = mark.x + localX * cos - localZ * sin\n const worldZ = mark.z + localX * sin + localZ * cos\n grid.setXYZ(index, worldX, heightAt(worldX, worldZ) + mark.lift, worldZ)\n }\n grid.needsUpdate = true\n geometry.computeVertexNormals()\n geometry.attributes.normal!.needsUpdate = true\n geometry.boundingSphere = null\n geometry.boundingBox = null\n const mesh = new THREE.Mesh(geometry, material as THREE_NS.MeshStandardMaterial)\n mesh.receiveShadow = true\n group.add(mesh)\n groundMarks.push({ mesh, steps })\n }\n\n function addRock(mark: RockMark): void {\n const mesh = mark.plate ? plateMesh() : rockMesh()\n const slot = mark.plate ? 'plate' : 'rock'\n const index = placed[slot]++ % mesh.instanceMatrix.count\n quaternion.setFromEuler(euler.set(mark.rotation[0], mark.rotation[1], mark.rotation[2]))\n mesh.setMatrixAt(index, matrix.compose(position.set(mark.x, mark.y, mark.z), quaternion, scale.set(mark.scale[0], mark.scale[1], mark.scale[2])))\n mesh.setColorAt(index, color.set(mark.color))\n mesh.count = Math.min(placed[slot], mesh.instanceMatrix.count)\n mesh.instanceMatrix.needsUpdate = true\n mesh.instanceColor!.needsUpdate = true\n }\n\n function writeBlood(index: number, drawn: BloodDrawn, growth: number): void {\n quaternion.setFromAxisAngle(up, drawn.rotation)\n const mesh = bloodMesh()\n mesh.setMatrixAt(index, matrix.compose(position.set(drawn.position[0], drawn.position[1], drawn.position[2]), quaternion, scale.set(drawn.scaleX * growth, 1, drawn.scaleZ * growth)))\n mesh.instanceMatrix.needsUpdate = true\n }\n\n function addBlood(mark: BloodMark): void {\n const index = placed.blood++ % bloodMesh().instanceMatrix.count\n const drawn: BloodDrawn = { position: [mark.x, mark.y, mark.z], rotation: mark.rotation, scaleX: mark.scaleX, scaleZ: mark.scaleZ, age: 0 }\n blood[index] = drawn\n writeBlood(index, drawn, BLOOD_START_GROWTH)\n bloodMesh().count = Math.min(placed.blood, bloodMesh().instanceMatrix.count)\n }\n\n function build(mark: Mark): void {\n if (mark.kind === 'scorch') conform(mark, scorchMaterials[mark.variant]!)\n else if (mark.kind === 'dirt') conform(mark, dirtMaterial)\n else if (mark.kind === 'rock') addRock(mark)\n else addBlood(mark)\n }\n\n function clearMarks(): void {\n for (const drawn of groundMarks) group.remove(drawn.mesh)\n for (const drawn of groundMarks) drawn.mesh.geometry.dispose()\n groundMarks.length = 0\n for (const geometry of spareGeometries) geometry.dispose()\n spareGeometries.length = 0\n blood.length = 0\n placed.blood = placed.rock = placed.plate = 0\n for (const mesh of [instanced.blood, instanced.rock, instanced.plate]) if (mesh) mesh.count = 0\n }\n\n return {\n group,\n handle(event) {\n if (event.type === 'clear') clearMarks()\n else build(event.mark)\n },\n prepare() {\n bloodMesh()\n rockMesh()\n plateMesh()\n },\n probes() {\n probeGeometry ??= new THREE.PlaneGeometry(0.001, 0.001).rotateX(-Math.PI / 2)\n return [...scorchMaterials, dirtMaterial].map((material) => {\n const mesh = new THREE.Mesh(probeGeometry, material)\n mesh.receiveShadow = true\n mesh.frustumCulled = false\n return mesh\n })\n },\n update(dt) {\n for (let index = 0; index < blood.length; index++) {\n const drawn = blood[index]\n if (!drawn || drawn.age > 1) continue\n drawn.age += dt * BLOOD_GROW_RATE\n writeBlood(index, drawn, Math.max(BLOOD_START_GROWTH, 1 - Math.pow(1 - Math.min(1, drawn.age), 2.5)))\n }\n },\n count: () => groundMarks.length + [instanced.blood, instanced.rock, instanced.plate].filter((mesh) => mesh && mesh.count > 0).length,\n dispose() {\n clearMarks()\n for (const mesh of [instanced.blood, instanced.rock, instanced.plate]) mesh?.dispose()\n probeGeometry?.dispose()\n for (const item of owned) item.dispose()\n },\n }\n}\n","import type * as THREE_NS from 'three'\nimport type { MeshParticle, MeshPool } from '@adatechnology/game-vfx'\nimport type { ThreeLib } from './types'\n\nconst SPHERE_DEFAULT_WIDTH = 8\nconst SPHERE_DEFAULT_HEIGHT = 6\n/** Idle meshes kept per kind of material, for the next particles to reuse. */\nconst MAX_PARKED_MESHES_PER_KIND = 256\n\nexport interface MeshLayer {\n readonly group: THREE_NS.Group\n /** Puts a mesh on every live solid particle and takes it off the ones that ended; answers how many are drawn. */\n sync(): number\n dispose(): void\n}\n\n/** A unit shape (radius 1, height 1): the size of each particle is the mesh's scale, so one geometry serves every size. */\nfunction geometryOf(THREE: ThreeLib, particle: MeshParticle): THREE_NS.BufferGeometry {\n switch (particle.shape) {\n case 'cone': return new THREE.ConeGeometry(1, 1, particle.segments || undefined, particle.segments2 || 1, false)\n case 'cone_open': return new THREE.ConeGeometry(1, 1, particle.segments || undefined, particle.segments2 || 1, true)\n case 'sphere': return new THREE.SphereGeometry(1, particle.segments || SPHERE_DEFAULT_WIDTH, particle.segments2 || SPHERE_DEFAULT_HEIGHT)\n case 'icosahedron': return new THREE.IcosahedronGeometry(1, particle.segments)\n }\n}\n\nfunction isCone(particle: MeshParticle): boolean {\n return particle.shape === 'cone' || particle.shape === 'cone_open'\n}\n\n/** The materials the gallery gives these: a flat, translucent colour (added to what is behind it for a flash), or a rough grey that the scene's lights shade (smoke). */\nfunction materialOf(THREE: ThreeLib, particle: Pick<MeshParticle, 'lit' | 'color' | 'opacity' | 'additive'>): THREE_NS.Material {\n if (particle.lit) return new THREE.MeshStandardMaterial({ color: particle.color, roughness: 1, metalness: 0, transparent: true, opacity: particle.opacity, depthWrite: false })\n return new THREE.MeshBasicMaterial({ color: particle.color, transparent: true, opacity: particle.opacity, depthWrite: false, ...(particle.additive ? { blending: THREE.AdditiveBlending } : {}) })\n}\n\n/** One throwaway mesh per material the layer draws with (lit smoke, flat, additive flash), for a host to compile their shader programs before the first effect needs them. */\nexport function createMeshLayerProbes(THREE: ThreeLib): THREE_NS.Mesh[] {\n const geometry = new THREE.BoxGeometry(0.001, 0.001, 0.001)\n return [{ lit: true, additive: false }, { lit: false, additive: false }, { lit: false, additive: true }].map(\n (kind) => new THREE.Mesh(geometry, materialOf(THREE, { ...kind, color: 0x808080, opacity: 0.5 })),\n )\n}\n\ninterface DrawnMesh {\n readonly mesh: THREE_NS.Mesh\n readonly parkingKey: string\n stamp: number\n}\n\nfunction geometryKeyOf(particle: MeshParticle): string {\n return `${particle.shape}:${particle.segments}:${particle.segments2}`\n}\n\n/**\n * The Workshop's solid particles (`MeshPool`) as three.js meshes, one each, like the gallery. The look is the gallery's; what changed is where the parts come from: a geometry is\n * shared by every particle of the same shape and size, and a mesh whose particle ended is parked, with its material, for the next particle of the same kind instead of being\n * disposed, so an explosion allocates nothing on the GPU once one of its kind has gone off. A mesh sits at the group's point plus the group's turn applied to the piece's\n * place times the scale, turned by the group's turn and then by the piece's own Euler angles.\n */\nexport function createMeshLayer(THREE: ThreeLib, pool: MeshPool): MeshLayer {\n const group = new THREE.Group()\n group.name = 'workshop-meshes'\n const drawn = new Map<number, DrawnMesh>()\n const geometries = new Map<string, THREE_NS.BufferGeometry>()\n const parked = new Map<string, THREE_NS.Mesh[]>()\n const frame = new THREE.Quaternion()\n const euler = new THREE.Euler()\n const turn = new THREE.Quaternion()\n const offset = new THREE.Vector3()\n let stamp = 0\n\n function geometryFor(particle: MeshParticle): THREE_NS.BufferGeometry {\n const key = geometryKeyOf(particle)\n let geometry = geometries.get(key)\n if (!geometry) {\n geometry = geometryOf(THREE, particle)\n geometries.set(key, geometry)\n }\n return geometry\n }\n\n function acquire(particle: MeshParticle): DrawnMesh {\n const parkingKey = `${geometryKeyOf(particle)}|${particle.lit}|${particle.additive}`\n const mesh = parked.get(parkingKey)?.pop() ?? new THREE.Mesh(geometryFor(particle), materialOf(THREE, particle))\n ;(mesh.material as THREE_NS.MeshBasicMaterial).color.set(particle.color)\n mesh.frustumCulled = false\n mesh.renderOrder = particle.additive ? 5 : 3\n group.add(mesh)\n return { mesh, parkingKey, stamp }\n }\n\n function park(entry: DrawnMesh): void {\n entry.mesh.removeFromParent()\n let free = parked.get(entry.parkingKey)\n if (!free) {\n free = []\n parked.set(entry.parkingKey, free)\n }\n if (free.length < MAX_PARKED_MESHES_PER_KIND) free.push(entry.mesh)\n else (entry.mesh.material as THREE_NS.Material).dispose()\n }\n\n return {\n group,\n sync() {\n stamp++\n for (const particle of pool.particles) {\n let entry = drawn.get(particle.id)\n if (!entry) {\n entry = acquire(particle)\n drawn.set(particle.id, entry)\n }\n entry.stamp = stamp\n const mesh = entry.mesh\n frame.set(particle.frame[0], particle.frame[1], particle.frame[2], particle.frame[3])\n offset.set(particle.at[0], particle.at[1], particle.at[2]).multiplyScalar(particle.scale).applyQuaternion(frame)\n mesh.position.set(particle.x + offset.x, particle.y + offset.y, particle.z + offset.z)\n turn.setFromEuler(euler.set(particle.rx, particle.ry, particle.rz))\n mesh.quaternion.copy(frame).multiply(turn)\n mesh.scale.set(particle.radius * particle.scale, (isCone(particle) ? particle.height : particle.radius) * particle.scale, particle.radius * particle.scale)\n ;(mesh.material as THREE_NS.Material).opacity = particle.opacity\n }\n for (const [id, entry] of drawn) {\n if (entry.stamp === stamp) continue\n park(entry)\n drawn.delete(id)\n }\n return pool.count\n },\n dispose() {\n for (const entry of drawn.values()) park(entry)\n drawn.clear()\n for (const free of parked.values()) for (const mesh of free) (mesh.material as THREE_NS.Material).dispose()\n parked.clear()\n for (const geometry of geometries.values()) geometry.dispose()\n geometries.clear()\n group.removeFromParent()\n },\n }\n}\n","import type { ScreenState } from '@adatechnology/game-vfx'\n\nexport interface ScreenOverlay {\n update(state: Readonly<ScreenState>): void\n dispose(): void\n}\n\nconst clamp = (value: number, min: number, max: number): number => (value < min ? min : value > max ? max : value)\n\nfunction layer(container: HTMLElement, name: string, blend?: string): HTMLDivElement {\n const element = container.ownerDocument.createElement('div')\n element.dataset.vfxOverlay = name\n Object.assign(element.style, { position: 'absolute', inset: '0', pointerEvents: 'none', opacity: '0' })\n if (blend) element.style.mixBlendMode = blend\n container.appendChild(element)\n return element\n}\n\n/**\n * The screen effects as overlays inside the host's container: the Lab's white flash (L1087, `mix-blend-mode: screen`) and the Workshop's white,\n * red edge, the two sides and the gas tint (W356-366), with the same colours. Nothing is drawn while the state is at rest.\n */\nexport function createScreenOverlay(container: HTMLElement): ScreenOverlay {\n const flash = layer(container, 'flash', 'screen')\n flash.style.background = '#fff'\n const white = layer(container, 'white')\n const red = layer(container, 'red')\n const sides = layer(container, 'sides')\n const gas = layer(container, 'gas')\n const elements = [flash, white, red, sides, gas]\n return {\n update(state) {\n flash.style.opacity = clamp(state.flash, 0, 1).toFixed(3)\n white.style.opacity = '1'\n white.style.background = `rgba(235,240,255,${clamp(state.white, 0, 1).toFixed(2)})`\n red.style.opacity = '1'\n red.style.background = `radial-gradient(ellipse at center, transparent 40%, rgba(170,16,12,${(clamp(state.red, 0, 1) * 0.85).toFixed(2)}) 100%)`\n sides.style.opacity = '1'\n sides.style.background = `linear-gradient(90deg, rgba(190,20,14,${(state.directionLeft * 0.8).toFixed(2)}) 0%, transparent 35%, transparent 65%, rgba(190,20,14,${(state.directionRight * 0.8).toFixed(2)}) 100%)`\n gas.style.opacity = '1'\n gas.style.background = state.gas > 0.01 ? `rgba(90,130,40,${(state.gas * 0.55).toFixed(2)})` : 'transparent'\n },\n dispose() {\n for (const element of elements) element.remove()\n },\n }\n}\n","/** The shock shell (fresnel edge, Lab L322-325) and the dust ring on the ground (L326-333), verbatim except for the r160 colour-space chunk. */\nexport const SHELL_VERTEX = `varying vec3 vN;varying vec3 vV;void main(){vec4 wp=modelMatrix*vec4(position,1.);vN=normalize(mat3(modelMatrix)*normal);vV=normalize(cameraPosition-wp.xyz);gl_Position=projectionMatrix*viewMatrix*wp;}`\n\nexport const SHELL_FRAGMENT = `uniform float uA;varying vec3 vN;varying vec3 vV;void main(){float f=1.-abs(dot(vN,vV));f=pow(f,5.);gl_FragColor=vec4(vec3(1.,.93,.82)*f*uA*.45,1.);\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n}`\n\nexport const RING_VERTEX = `varying vec2 vU;void main(){vU=position.xz;gl_Position=projectionMatrix*viewMatrix*modelMatrix*vec4(position,1.);}`\n\nexport const RING_FRAGMENT = `uniform float uA;uniform float uW;uniform vec3 uC;varying vec2 vU;\n float h(vec2 p){return fract(sin(dot(p,vec2(12.9898,78.233)))*43758.5453);}\n void main(){float r=length(vU);float b=smoothstep(1.,1.-uW,r)*smoothstep(1.-uW*3.5,1.-uW,r);float a=atan(vU.y,vU.x);float n=.7+.3*h(vec2(floor(a*14.),1.));gl_FragColor=vec4(uC,b*uA*n);\n #include <tonemapping_fragment>\n #include <colorspace_fragment>\n}`\n","import type * as THREE_NS from 'three'\nimport type { OrderedPool, Shock } from '@adatechnology/game-vfx'\nimport { RING_FRAGMENT, RING_VERTEX, SHELL_FRAGMENT, SHELL_VERTEX } from './shaders/shock'\nimport type { ThreeLib } from './types'\n\ninterface Pair {\n readonly shell: THREE_NS.Mesh\n readonly ring: THREE_NS.Mesh\n readonly shellAlpha: { value: number }\n readonly ringAlpha: { value: number }\n}\n\nconst RING_HEIGHT = 0.05\n\nexport interface ShockLayer {\n readonly group: THREE_NS.Group\n sync(): number\n dispose(): void\n}\n\n/** The shock shell and ground ring of each live shock (L319-348): one pair of meshes per slot, shown while the slot has a shock. */\nexport function createShockLayer(THREE: ThreeLib, pool: OrderedPool<Shock>): ShockLayer {\n const group = new THREE.Group()\n const shellGeometry = new THREE.SphereGeometry(1, 28, 18)\n const ringGeometry = new THREE.PlaneGeometry(2, 2).rotateX(-Math.PI / 2)\n const pairs: Pair[] = []\n\n function makePair(): Pair {\n const shellAlpha = { value: 0 }\n const ringAlpha = { value: 0 }\n const shellMaterial = new THREE.ShaderMaterial({ transparent: true, depthWrite: false, blending: THREE.AdditiveBlending, uniforms: { uA: shellAlpha }, vertexShader: SHELL_VERTEX, fragmentShader: SHELL_FRAGMENT })\n const ringMaterial = new THREE.ShaderMaterial({\n transparent: true, depthWrite: false, uniforms: { uA: ringAlpha, uW: { value: 0.12 }, uC: { value: new THREE.Color(0.55, 0.5, 0.44) } }, vertexShader: RING_VERTEX, fragmentShader: RING_FRAGMENT,\n })\n const shell = new THREE.Mesh(shellGeometry, shellMaterial)\n shell.renderOrder = 4\n const ring = new THREE.Mesh(ringGeometry, ringMaterial)\n ring.renderOrder = 3\n group.add(shell, ring)\n return { shell, ring, shellAlpha, ringAlpha }\n }\n\n return {\n group,\n sync() {\n const shocks = pool.items\n for (let index = 0; index < shocks.length; index++) {\n const pair = (pairs[index] ??= makePair())\n const shock = shocks[index]!\n pair.shell.visible = pair.ring.visible = true\n pair.shell.position.set(shock.x, shock.y, shock.z)\n pair.shell.scale.setScalar(shock.shellScale)\n pair.shellAlpha.value = shock.shellAlpha\n pair.ring.position.set(shock.x, RING_HEIGHT, shock.z)\n pair.ring.scale.setScalar(shock.ringScale)\n pair.ringAlpha.value = shock.ringAlpha\n }\n for (let index = shocks.length; index < pairs.length; index++) pairs[index]!.shell.visible = pairs[index]!.ring.visible = false\n return shocks.length\n },\n dispose() {\n for (const pair of pairs) {\n ;(pair.shell.material as THREE_NS.Material).dispose()\n ;(pair.ring.material as THREE_NS.Material).dispose()\n }\n shellGeometry.dispose()\n ringGeometry.dispose()\n },\n }\n}\n","/** The soft round point sprite of the game's sprite kinds (moved verbatim from the destruction renderer's particles). */\nexport const SPRITE_VERTEX = `\nuniform float uScale;\nattribute float size;\nattribute float alpha;\nattribute vec3 pcolor;\nvarying float vAlpha;\nvarying vec3 vColor;\nvoid main() {\n vAlpha = alpha;\n vColor = pcolor;\n vec4 mv = modelViewMatrix * vec4(position, 1.0);\n gl_PointSize = min(size * uScale / max(0.1, -mv.z), 256.0);\n gl_Position = projectionMatrix * mv;\n}`\n\nexport const SPRITE_FRAGMENT = `\nvarying float vAlpha;\nvarying vec3 vColor;\nvoid main() {\n float d = length(gl_PointCoord - vec2(0.5)) * 2.0;\n float a = (1.0 - smoothstep(0.35, 1.0, d)) * vAlpha;\n if (a < 0.004) discard;\n gl_FragColor = vec4(vColor, a);\n}`\n","import type * as THREE_NS from 'three'\nimport type { SpriteKindPool, SpriteKindSystem } from '@adatechnology/game-vfx'\nimport { SPRITE_FRAGMENT, SPRITE_VERTEX } from './shaders/sprite'\nimport type { ThreeLib } from './types'\n\nexport interface SpriteLayer {\n readonly additive: THREE_NS.Points\n readonly normal: THREE_NS.Points\n /** Tells the GPU what changed and answers how many sprites are drawn. */\n sync(): number\n dispose(): void\n}\n\ninterface Drawn {\n readonly points: THREE_NS.Points\n sync(): number\n dispose(): void\n}\n\nfunction drawPool(THREE: ThreeLib, pool: SpriteKindPool, additive: boolean, pointScale: number): Drawn {\n const geometry = new THREE.BufferGeometry()\n const attributes: [string, Float32Array, number][] = [['position', pool.position, 3], ['pcolor', pool.color, 3], ['alpha', pool.alpha, 1], ['size', pool.size, 1]]\n const buffers = attributes.map(([name, array, size]) => {\n const attribute = new THREE.BufferAttribute(array, size).setUsage(THREE.DynamicDrawUsage)\n geometry.setAttribute(name, attribute)\n return attribute\n })\n geometry.setDrawRange(0, 0)\n const material = new THREE.ShaderMaterial({\n uniforms: { uScale: { value: pointScale } },\n vertexShader: SPRITE_VERTEX,\n fragmentShader: SPRITE_FRAGMENT,\n transparent: true,\n depthWrite: false,\n blending: additive ? THREE.AdditiveBlending : THREE.NormalBlending,\n })\n const points = new THREE.Points(geometry, material)\n points.frustumCulled = false\n points.name = additive ? 'vfx-sprites-additive' : 'vfx-sprites'\n points.renderOrder = additive ? 11 : 10\n return {\n points,\n sync() {\n geometry.setDrawRange(0, pool.drawCount)\n for (const buffer of buffers) buffer.needsUpdate = true\n return pool.drawCount\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\n/** Draws the game's sprite kinds (debris, sparks, smoke, steam, drips...) as two soft point layers, additive and normal. */\nexport function createSpriteLayer(THREE: ThreeLib, system: SpriteKindSystem, pointScale: number): SpriteLayer {\n const additive = drawPool(THREE, system.additive, true, pointScale)\n const normal = drawPool(THREE, system.normal, false, pointScale)\n return {\n additive: additive.points,\n normal: normal.points,\n sync: () => additive.sync() + normal.sync(),\n dispose() {\n additive.dispose()\n normal.dispose()\n },\n }\n}\n","import type * as THREE_NS from 'three'\nimport { LIGHT_PRIORITY } from '@adatechnology/game-render-three'\nimport type { LightBudget, LightHandle } from '@adatechnology/game-render-three'\nimport type { Decal, WorkshopEngine } from '@adatechnology/game-vfx'\nimport { followEntry } from './lights'\nimport { createMeshLayer } from './mesh-layer'\nimport { WORKSHOP_SPRITE_FRAGMENT, WORKSHOP_SPRITE_VERTEX } from './shaders/workshop-sprite'\nimport type { ThreeLib } from './types'\n\nconst DEBRIS_CAPACITY = 500\nconst DECAL_CAPACITY = 400\nconst RING_CAPACITY = 120\nconst RIPPLE_SEGMENTS = 12\nconst FADE_SECONDS = 0.5\nconst FIRE_LIGHT_COLOR = 0xff7a2a\nconst FIRE_LIGHT_DISTANCE = 14\nconst GLOSS_DRIED_AT = 0.85\nconst BROWN = 0x2a1610\nconst GROUND_COLOR = 0x888888\nconst FUEL_DRIED = 0x888888\n\nexport interface WorkshopLayers {\n readonly group: THREE_NS.Group\n /** Copies the pools into the draw buffers; answers how many draw calls have something to draw. */\n sync(): number\n dispose(): void\n}\n\ninterface Drawn {\n readonly object: THREE_NS.Object3D\n sync(): boolean\n dispose(): void\n}\n\nconst clamp = (v: number, lo: number, hi: number): number => (v < lo ? lo : v > hi ? hi : v)\n\nfunction spriteLayer(THREE: ThreeLib, pool: WorkshopEngine['add'], additive: boolean, soft: number, scale: number): Drawn {\n const geometry = new THREE.BufferGeometry()\n const arrays: [string, Float32Array, number][] = [['position', pool.position, 3], ['pcol', pool.color, 3], ['size', pool.size, 1], ['alpha', pool.alpha, 1]]\n const buffers = arrays.map(([name, array, size]) => {\n const attribute = new THREE.BufferAttribute(array, size).setUsage(THREE.DynamicDrawUsage)\n geometry.setAttribute(name, attribute)\n return attribute\n })\n geometry.setDrawRange(0, 0)\n const material = new THREE.ShaderMaterial({\n uniforms: { uScale: { value: scale }, uSoft: { value: soft } },\n vertexShader: WORKSHOP_SPRITE_VERTEX,\n fragmentShader: WORKSHOP_SPRITE_FRAGMENT,\n transparent: true,\n depthWrite: false,\n blending: additive ? THREE.AdditiveBlending : THREE.NormalBlending,\n })\n const points = new THREE.Points(geometry, material)\n points.frustumCulled = false\n points.renderOrder = additive ? 3 : 2\n points.name = additive ? 'workshop-add' : 'workshop-normal'\n return {\n object: points,\n sync() {\n geometry.setDrawRange(0, pool.count)\n for (const buffer of buffers) buffer.needsUpdate = true\n return pool.count > 0\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\nfunction streakLayer(THREE: ThreeLib, pool: WorkshopEngine['streaks']): Drawn {\n const geometry = new THREE.BufferGeometry()\n const position = new THREE.BufferAttribute(pool.segment, 3).setUsage(THREE.DynamicDrawUsage)\n const color = new THREE.BufferAttribute(pool.segmentColor, 3).setUsage(THREE.DynamicDrawUsage)\n geometry.setAttribute('position', position)\n geometry.setAttribute('color', color)\n geometry.setDrawRange(0, 0)\n const material = new THREE.LineBasicMaterial({ vertexColors: true, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false })\n const lines = new THREE.LineSegments(geometry, material)\n lines.frustumCulled = false\n lines.renderOrder = 4\n lines.name = 'workshop-streaks'\n return {\n object: lines,\n sync() {\n geometry.setDrawRange(0, pool.count * 2)\n position.needsUpdate = color.needsUpdate = true\n return pool.count > 0\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\n/** The Workshop's rain (W317-320): one line segment per streak, pale blue, 35% opaque. */\nfunction rainLayer(THREE: ThreeLib, rain: WorkshopEngine['rain']): Drawn {\n const geometry = new THREE.BufferGeometry()\n const position = new THREE.BufferAttribute(rain.positions, 3).setUsage(THREE.DynamicDrawUsage)\n geometry.setAttribute('position', position)\n geometry.setDrawRange(0, 0)\n const material = new THREE.LineBasicMaterial({ color: 0x9fb3cf, transparent: true, opacity: 0.35, depthWrite: false })\n const lines = new THREE.LineSegments(geometry, material)\n lines.frustumCulled = false\n lines.name = 'workshop-rain'\n return {\n object: lines,\n sync() {\n const drawn = rain.on && rain.count > 0\n lines.visible = drawn\n geometry.setDrawRange(0, drawn ? rain.count * 2 : 0)\n position.needsUpdate = true\n return drawn\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\nfunction debrisLayer(THREE: ThreeLib, pool: WorkshopEngine['debris']): Drawn {\n const geometry = new THREE.BoxGeometry(1, 1, 1)\n const material = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.45, metalness: 0.25, flatShading: true })\n const mesh = new THREE.InstancedMesh(geometry, material, DEBRIS_CAPACITY)\n mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)\n mesh.frustumCulled = false\n mesh.name = 'workshop-debris'\n const euler = new THREE.Euler()\n const quaternion = new THREE.Quaternion()\n const position = new THREE.Vector3()\n const scale = new THREE.Vector3()\n const matrix = new THREE.Matrix4()\n const colour = new THREE.Color()\n const hidden = new THREE.Matrix4().makeScale(0, 0, 0)\n for (let index = 0; index < DEBRIS_CAPACITY; index++) mesh.setMatrixAt(index, hidden)\n mesh.setColorAt(0, colour.setHex(0xffffff))\n return {\n object: mesh,\n sync() {\n let drawn = false\n for (let index = 0; index < DEBRIS_CAPACITY; index++) {\n const piece = pool.pieces[index]!\n if (!piece.on) {\n mesh.setMatrixAt(index, hidden)\n continue\n }\n drawn = true\n const shrink = Math.min(1, piece.life / FADE_SECONDS)\n euler.set(piece.rx, piece.ry, piece.rz)\n quaternion.setFromEuler(euler)\n matrix.compose(position.set(piece.x, piece.y, piece.z), quaternion, scale.set(piece.sx * shrink, piece.sy * shrink, piece.sz * shrink))\n mesh.setMatrixAt(index, matrix)\n mesh.setColorAt(index, colour.setHex(piece.color))\n }\n mesh.instanceMatrix.needsUpdate = true\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true\n return drawn\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\n/** A decal's current look from its fields (W276-306): it grows, a wet one creeps, dries towards its dry colour or evaporates. */\nfunction decalLook(decal: Decal, colour: THREE_NS.Color, dryColour: THREE_NS.Color, brown: THREE_NS.Color, ground: THREE_NS.Color, index: number): { sx: number; sy: number; dried: boolean } | null {\n const grown = decal.grow > 0 ? 1 - Math.pow(1 - Math.min(1, decal.t / decal.grow), 2.4) : 1\n let sx = decal.sx * grown\n let sy = decal.sy * grown\n colour.setHex(decal.color)\n let dried = false\n const fluid = decal.fluid\n if (fluid) {\n const creep = fluid === 'oil' ? 0.5 : fluid === 'fuel' ? 0.7 : fluid === 'bile' ? 0.25 : fluid === 'water' ? 0.2 : 0.3\n const age = decal.t\n if (decal.dryTime > 0) {\n const k = clamp((age - decal.dryAt) / decal.dryTime, 0, 1)\n if (decal.dryColor >= 0) dryColour.setHex(decal.dryColor)\n else dryColour.copy(colour).multiplyScalar(0.45).lerp(brown, 0.45)\n dried = k > GLOSS_DRIED_AT\n const spread = dried ? 1 + creep : 1 + creep * (1 - Math.exp(-age / 6))\n sx *= dried ? spread : spread * (1 + 0.04 * Math.sin(age * 1.9 + index))\n sy *= dried ? spread : spread * (1 + 0.04 * Math.cos(age * 1.5 + index * 0.7))\n colour.lerp(dryColour, k)\n } else {\n const spread = 1 + creep * (1 - Math.exp(-age / 6))\n sx *= spread * (1 + 0.04 * Math.sin(age * 1.9 + index))\n sy *= spread * (1 + 0.04 * Math.cos(age * 1.5 + index * 0.7))\n if (fluid === 'fuel' || fluid === 'water') {\n const [wait, span] = fluid === 'fuel' ? [6, 5] : [40, 20]\n const gone = clamp((age - wait) / span, 0, 1)\n sx *= 1 - gone * 0.85\n sy *= 1 - gone * 0.85\n colour.lerp(ground.setHex(fluid === 'fuel' ? FUEL_DRIED : GROUND_COLOR), gone * 0.8)\n if (gone >= 1) return null\n }\n }\n }\n return { sx, sy, dried }\n}\n\nfunction decalLayer(THREE: ThreeLib, pool: WorkshopEngine['decals']): Drawn {\n const geometry = new THREE.CircleGeometry(0.5, RIPPLE_SEGMENTS)\n const positions = geometry.getAttribute('position')\n // a blob, not a disc: each rim vertex is pulled in by a fixed amount between .72 and 1.12\n for (let index = 1; index < positions.count; index++) {\n const k = 0.72 + (((index * 2654435761) >>> 0) / 4294967296) * 0.4\n positions.setXY(index, positions.getX(index) * k, positions.getY(index) * k)\n }\n const wet = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.1, metalness: 0.3, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 })\n const dry = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 1, metalness: 0, flatShading: true, polygonOffset: true, polygonOffsetFactor: -4, polygonOffsetUnits: -4 })\n const wetMesh = new THREE.InstancedMesh(geometry, wet, DECAL_CAPACITY)\n const dryMesh = new THREE.InstancedMesh(geometry, dry, DECAL_CAPACITY)\n const group = new THREE.Group()\n group.name = 'workshop-decals'\n for (const mesh of [wetMesh, dryMesh]) {\n mesh.frustumCulled = false\n mesh.renderOrder = 1\n mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)\n group.add(mesh)\n }\n const hidden = new THREE.Matrix4().makeScale(0, 0, 0)\n const colour = new THREE.Color()\n const dryColour = new THREE.Color()\n const brown = new THREE.Color(BROWN)\n const ground = new THREE.Color()\n const normal = new THREE.Vector3()\n const forward = new THREE.Vector3(0, 0, 1)\n const turn = new THREE.Quaternion()\n const quaternion = new THREE.Quaternion()\n const position = new THREE.Vector3()\n const scale = new THREE.Vector3()\n const matrix = new THREE.Matrix4()\n wetMesh.setColorAt(0, colour.setHex(0))\n dryMesh.setColorAt(0, colour.setHex(0))\n for (let index = 0; index < DECAL_CAPACITY; index++) {\n wetMesh.setMatrixAt(index, hidden)\n dryMesh.setMatrixAt(index, hidden)\n }\n return {\n object: group,\n sync() {\n let drawn = false\n for (let index = 0; index < DECAL_CAPACITY; index++) {\n const decal = pool.decals[index]!\n wetMesh.setMatrixAt(index, hidden)\n dryMesh.setMatrixAt(index, hidden)\n if (!decal.on || decal.t < 0) continue\n const look = decalLook(decal, colour, dryColour, brown, ground, index)\n if (!look) continue\n drawn = true\n normal.set(decal.normal[0], decal.normal[1], decal.normal[2])\n quaternion.setFromUnitVectors(forward, normal)\n quaternion.multiply(turn.setFromAxisAngle(forward, index * 2.399963))\n const offset = 0.004 + (index % 40) * 0.0004\n matrix.compose(position.set(decal.x + normal.x * offset, decal.y + normal.y * offset, decal.z + normal.z * offset), quaternion, scale.set(look.sx, look.sy, 1))\n const mesh = look.dried ? dryMesh : wetMesh\n mesh.setMatrixAt(index, matrix)\n mesh.setColorAt(index, colour)\n }\n for (const mesh of [wetMesh, dryMesh]) {\n mesh.instanceMatrix.needsUpdate = true\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true\n }\n return drawn\n },\n dispose() {\n geometry.dispose()\n wet.dispose()\n dry.dispose()\n },\n }\n}\n\nfunction ringLayer(THREE: ThreeLib, pool: WorkshopEngine['rings']): Drawn {\n const geometry = new THREE.RingGeometry(0.86, 1, 40)\n const material = new THREE.MeshBasicMaterial({ color: 0xffffff, transparent: true, blending: THREE.AdditiveBlending, depthWrite: false, side: THREE.DoubleSide })\n const mesh = new THREE.InstancedMesh(geometry, material, RING_CAPACITY)\n mesh.frustumCulled = false\n mesh.instanceMatrix.setUsage(THREE.DynamicDrawUsage)\n mesh.name = 'workshop-rings'\n const hidden = new THREE.Matrix4().makeScale(0, 0, 0)\n const colour = new THREE.Color()\n const normal = new THREE.Vector3()\n const forward = new THREE.Vector3(0, 0, 1)\n const quaternion = new THREE.Quaternion()\n const position = new THREE.Vector3()\n const scale = new THREE.Vector3()\n const matrix = new THREE.Matrix4()\n mesh.setColorAt(0, colour.setHex(0))\n for (let index = 0; index < RING_CAPACITY; index++) mesh.setMatrixAt(index, hidden)\n return {\n object: mesh,\n sync() {\n let drawn = false\n for (let index = 0; index < RING_CAPACITY; index++) {\n const ring = pool.rings[index]!\n if (!ring.on) {\n mesh.setMatrixAt(index, hidden)\n continue\n }\n drawn = true\n const k = Math.min(1, ring.t / ring.duration)\n const radius = ring.from + (ring.to - ring.from) * (1 - Math.pow(1 - k, 2))\n quaternion.setFromUnitVectors(forward, normal.set(ring.normal[0], ring.normal[1], ring.normal[2]))\n matrix.compose(position.set(ring.point[0], ring.point[1], ring.point[2]), quaternion, scale.set(radius, radius, 1))\n mesh.setMatrixAt(index, matrix)\n mesh.setColorAt(index, colour.setHex(ring.color).multiplyScalar(ring.hold ? ring.hold : 1 - k))\n }\n mesh.instanceMatrix.needsUpdate = true\n if (mesh.instanceColor) mesh.instanceColor.needsUpdate = true\n return drawn\n },\n dispose() {\n geometry.dispose()\n material.dispose()\n },\n }\n}\n\n/**\n * Draws the pools of the world's Workshop engine (what `world.play` fills): the two sprite systems, the streaks, the physics debris, the decals, the\n * expanding rings and the flash and fire lights, with the page's shaders and materials.\n */\nexport function createWorkshopLayers(THREE: ThreeLib, engine: WorkshopEngine, pointScale: number, lightScale: number, budget?: LightBudget): WorkshopLayers {\n const group = new THREE.Group()\n group.name = 'workshop'\n const layers: Drawn[] = [\n spriteLayer(THREE, engine.add, true, 1, pointScale),\n spriteLayer(THREE, engine.normal, false, 0.55, pointScale),\n streakLayer(THREE, engine.streaks),\n rainLayer(THREE, engine.rain),\n debrisLayer(THREE, engine.debris),\n decalLayer(THREE, engine.decals),\n ringLayer(THREE, engine.rings),\n ]\n for (const layer of layers) group.add(layer.object)\n const meshes = createMeshLayer(THREE, engine.meshes)\n group.add(meshes.group)\n const lights = budget ? budgetedLights(engine, lightScale, budget) : legacyLights(THREE, engine, lightScale, group)\n return {\n group,\n sync() {\n let drawCalls = 0\n for (const layer of layers) if (layer.sync()) drawCalls++\n drawCalls += meshes.sync()\n lights.sync()\n return drawCalls\n },\n dispose() {\n for (const layer of layers) layer.dispose()\n meshes.dispose()\n lights.dispose()\n group.clear()\n },\n }\n}\n\ntype WorkshopLights = { sync(): void; dispose(): void }\n\n/** @deprecated Lights created here change every lit material's program key; pass a LightBudget. Removed in the next major. */\nfunction legacyLights(THREE: ThreeLib, engine: WorkshopEngine, lightScale: number, group: THREE_NS.Group): WorkshopLights {\n // eslint-disable-next-line no-restricted-syntax -- D2: legacy path without LightBudget, removed in the next major\n const flashLights = engine.lights.lights.map(() => new THREE.PointLight(0xffc070, 0, 14))\n // eslint-disable-next-line no-restricted-syntax -- D2: legacy path without LightBudget, removed in the next major\n const fireLights = engine.lights.fire.map(() => new THREE.PointLight(FIRE_LIGHT_COLOR, 0, FIRE_LIGHT_DISTANCE))\n for (const light of [...flashLights, ...fireLights]) group.add(light)\n return {\n sync() {\n engine.lights.lights.forEach((source, index) => {\n const light = flashLights[index]!\n light.position.set(source.x, source.y, source.z)\n light.color.setHex(source.color)\n light.distance = source.distance\n light.intensity = source.intensity * lightScale\n })\n engine.lights.fire.forEach((source, index) => {\n const light = fireLights[index]!\n light.position.set(source.x, source.y, source.z)\n light.intensity = source.intensity * lightScale\n })\n },\n dispose() {},\n }\n}\n\nfunction budgetedLights(engine: WorkshopEngine, lightScale: number, budget: LightBudget): WorkshopLights {\n const flash: (LightHandle | null)[] = engine.lights.lights.map(() => null)\n const fire: (LightHandle | null)[] = engine.lights.fire.map(() => null)\n return {\n sync() {\n engine.lights.lights.forEach((source, index) => {\n const request = { owner: 'vfx.workshop', priority: LIGHT_PRIORITY.blast, urgent: true, color: source.color, intensity: source.intensity * lightScale, distance: source.distance, position: [source.x, source.y, source.z] as const }\n followEntry(budget, flash, index, source, request)\n })\n engine.lights.fire.forEach((source, index) => {\n const request = { owner: 'vfx.workshop', priority: LIGHT_PRIORITY.fire, color: FIRE_LIGHT_COLOR, intensity: source.intensity * lightScale, distance: FIRE_LIGHT_DISTANCE, position: [source.x, source.y, source.z] as const }\n followEntry(budget, fire, index, source, request)\n })\n },\n dispose() {\n for (const handle of [...flash, ...fire]) handle?.release({ fadeMs: 0 })\n },\n }\n}\n","/** The Workshop's soft point sprite (W168-171): the size is in metres, clamped to 1..512 px; `uSoft` is 1 for the soft (normal blend) pool. */\nexport const WORKSHOP_SPRITE_VERTEX = `attribute float size;attribute float alpha;attribute vec3 pcol;varying vec3 vC;varying float vA;uniform float uScale;\nvoid main(){vC=pcol;vA=alpha;vec4 mv=modelViewMatrix*vec4(position,1.);gl_PointSize=clamp(size*uScale/-mv.z,1.,512.);gl_Position=projectionMatrix*mv;}`\n\nexport const WORKSHOP_SPRITE_FRAGMENT = `uniform float uSoft;varying vec3 vC;varying float vA;\nvoid main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a=mix(smoothstep(1.,.78,r),pow(1.-r,1.5),uSoft);gl_FragColor=vec4(vC,vA*a);}`\n","/** The words of the effects bench, per locale (the effects' own texts live in `@adatechnology/game-vfx`). */\nexport interface BenchText {\n readonly module: string\n readonly controls: Readonly<Record<'effect' | 'variant' | 'replay' | 'auto_repeat' | 'distance' | 'lod_band' | 'quality', string>>\n readonly lod: Readonly<Record<'auto' | 'near' | 'middle' | 'far', string>>\n readonly quality: Readonly<Record<'high' | 'medium' | 'low', string>>\n readonly layers: Readonly<Record<'puffs' | 'sparks' | 'glows' | 'debris' | 'shock' | 'sprites', string>>\n readonly metrics: Readonly<Record<'puffs' | 'sparks' | 'debris' | 'lights' | 'budget_particles' | 'lod' | 'phase' | 'blast_time', string>>\n readonly sheet: Readonly<Record<'explosion' | 'lethal' | 'injury' | 'radius' | 'fireballs' | 'particles' | 'scale', string>>\n readonly none: string\n}\n\nexport const benchTexts: Readonly<Record<string, BenchText>> = {\n en: {\n module: 'Effects',\n controls: { effect: 'Effect', variant: 'Variant', replay: 'Replay', auto_repeat: 'Auto replay', distance: 'Distance', lod_band: 'LOD band', quality: 'Quality' },\n lod: { auto: 'Auto', near: 'Near', middle: 'Middle', far: 'Far' },\n quality: { high: 'High', medium: 'Medium', low: 'Low' },\n layers: { puffs: 'Smoke and fire', sparks: 'Sparks', glows: 'Glows', debris: 'Debris', shock: 'Shock wave', sprites: 'Droplets and recipes' },\n metrics: { puffs: 'Puffs', sparks: 'Sparks', debris: 'Debris', lights: 'Lights', budget_particles: 'Particles of the effect', lod: 'LOD scale', phase: 'Time since replay', blast_time: 'Time since the blast' },\n sheet: { explosion: 'Explosion', lethal: 'Lethal radius', injury: 'Injury radius', radius: 'Fireball', fireballs: 'Fireballs', particles: 'Particles', scale: 'Scale' },\n none: 'None',\n },\n 'pt-BR': {\n module: 'Efeitos',\n controls: { effect: 'Efeito', variant: 'Variante', replay: 'Repetir', auto_repeat: 'Repetição automática', distance: 'Distância', lod_band: 'Faixa de LOD', quality: 'Qualidade' },\n lod: { auto: 'Automático', near: 'Perto', middle: 'Meio', far: 'Longe' },\n quality: { high: 'Alta', medium: 'Média', low: 'Baixa' },\n layers: { puffs: 'Fumaça e fogo', sparks: 'Faíscas', glows: 'Brilhos', debris: 'Destroços', shock: 'Onda de choque', sprites: 'Gotas e receitas' },\n metrics: { puffs: 'Nuvens', sparks: 'Faíscas', debris: 'Destroços', lights: 'Luzes', budget_particles: 'Partículas do efeito', lod: 'Escala de LOD', phase: 'Tempo desde a repetição', blast_time: 'Tempo desde a explosão' },\n sheet: { explosion: 'Explosão', lethal: 'Raio letal', injury: 'Raio de ferimento', radius: 'Bola de fogo', fireballs: 'Bolas de fogo', particles: 'Partículas', scale: 'Escala' },\n none: 'Nenhuma',\n },\n}\n\nexport const benchText = (locale: string): BenchText => benchTexts[locale] ?? benchTexts.en!\n"],"mappings":"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","names":["LIGHT_PRIORITY","clamp","layer","LIGHT_PRIORITY","GROUND_COLOR","layer"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -64,6 +64,8 @@ interface VfxRendererOptions {
|
|
|
64
64
|
type VfxRendererStats = Readonly<Record<string, number>>;
|
|
65
65
|
interface VfxRenderer extends EffectSink {
|
|
66
66
|
readonly world: VfxWorld;
|
|
67
|
+
/** The one group every effect draws under (added to `scene`): what a warmup of the effects draws alone. */
|
|
68
|
+
readonly root: THREE_NS.Group;
|
|
67
69
|
/** Steps the world, then redraws everything from it. Call once per frame (a shared world is stepped here, nowhere else). */
|
|
68
70
|
update(dt: number): void;
|
|
69
71
|
/** Meshes that use the materials of the solid particles, to render once so that the first effect does not build their shader programs in the middle of a frame. */
|
|
@@ -137,6 +139,8 @@ interface MarkLayer {
|
|
|
137
139
|
}
|
|
138
140
|
interface MarkLayerOptions {
|
|
139
141
|
readonly ground: GroundField | undefined;
|
|
142
|
+
/** Height of the host's own ground a scorch or dirt mark is laid on; default the `ground` field, else flat at 0. A host with its own terrain passes it here so a mark lines the crater instead of lying flat over it (with a finer grid where the ground dips under the mark). */
|
|
143
|
+
readonly heightAt?: (x: number, z: number) => number;
|
|
140
144
|
readonly createCanvas: (() => CanvasLike) | undefined;
|
|
141
145
|
readonly rockGeometry: THREE_NS.BufferGeometry;
|
|
142
146
|
readonly plateGeometry: THREE_NS.BufferGeometry;
|
package/dist/index.global.js
CHANGED
|
@@ -5670,13 +5670,14 @@ var GameVfxThree = (() => {
|
|
|
5670
5670
|
function composeAfterEffects(context) {
|
|
5671
5671
|
const { core, def, random, x, y, z } = context;
|
|
5672
5672
|
const mark = def.mark;
|
|
5673
|
-
|
|
5673
|
+
const keepsMarks = !core.marklessAt?.(x, z);
|
|
5674
|
+
if (keepsMarks && mark.crater && mark.dent && y < 1.2) {
|
|
5674
5675
|
core.emit({ type: "crater", x, z, radius: mark.crater, depth: mark.dent });
|
|
5675
5676
|
core.trace?.crater?.(x, z, mark.crater, mark.dent);
|
|
5676
5677
|
addCrater(core.marks, core.ground, random, { x, z, radius: mark.crater, depth: mark.dent, marks: core.layers.mark });
|
|
5677
5678
|
if (core.layers.shrapnel) composeRimDebris(context);
|
|
5678
5679
|
}
|
|
5679
|
-
if (mark.scorch && y < 1.2 && core.layers.mark) {
|
|
5680
|
+
if (keepsMarks && mark.scorch && y < 1.2 && core.layers.mark) {
|
|
5680
5681
|
core.trace?.scorch?.(x, z, mark.scorch);
|
|
5681
5682
|
addScorch(core.marks, random, x, z, mark.scorch);
|
|
5682
5683
|
}
|
|
@@ -7427,6 +7428,7 @@ var GameVfxThree = (() => {
|
|
|
7427
7428
|
spawned: { puffs: 0, sparks: 0, chunks: 0, lights: 0 },
|
|
7428
7429
|
clock: { time: 0, lastBlast: -1, lod: 1, forcedLod: null },
|
|
7429
7430
|
groundAt,
|
|
7431
|
+
...options.marklessAt ? { marklessAt: options.marklessAt } : {},
|
|
7430
7432
|
emit: (request) => options.onRequest?.(request)
|
|
7431
7433
|
};
|
|
7432
7434
|
function definitionOf(id) {
|
|
@@ -7453,6 +7455,7 @@ var GameVfxThree = (() => {
|
|
|
7453
7455
|
return player ?? (player = createEffectPlayer({ engine: workshop(), effects, view }));
|
|
7454
7456
|
}
|
|
7455
7457
|
return {
|
|
7458
|
+
hostGroundAt: options.groundAt,
|
|
7456
7459
|
play(id, point, playOptions = {}) {
|
|
7457
7460
|
if (!(id in effects)) return null;
|
|
7458
7461
|
const seed = playOptions.seed ?? (randomMode === "shared" ? void 0 : Math.imul(++handles.events, AUTO_SEED) + (options.seed ?? 0));
|
|
@@ -8885,7 +8888,11 @@ void main(){
|
|
|
8885
8888
|
}
|
|
8886
8889
|
|
|
8887
8890
|
// src/marks.ts
|
|
8888
|
-
var
|
|
8891
|
+
var FLAT_STEPS_PER_METRE = 8;
|
|
8892
|
+
var MAX_FLAT_STEPS = 48;
|
|
8893
|
+
var DUG_STEPS_PER_METRE = 20;
|
|
8894
|
+
var MAX_DUG_STEPS = 64;
|
|
8895
|
+
var FLAT_TOLERANCE = 2e-3;
|
|
8889
8896
|
var MIN_CONFORM_STEPS = 16;
|
|
8890
8897
|
var BLOOD_GROW_RATE = 1.2;
|
|
8891
8898
|
var BLOOD_START_GROWTH = 0.05;
|
|
@@ -8968,9 +8975,21 @@ void main(){
|
|
|
8968
8975
|
spareGeometries.push(oldest.mesh.geometry);
|
|
8969
8976
|
if (spareGeometries.length > MAX_SPARE_GROUND_GEOMETRIES) spareGeometries.shift().dispose();
|
|
8970
8977
|
}
|
|
8978
|
+
const heightAt = options.heightAt ?? ((x, z) => options.ground?.heightAt(x, z) ?? 0);
|
|
8979
|
+
function groundDipsUnder(x, z, radius) {
|
|
8980
|
+
const centre = heightAt(x, z);
|
|
8981
|
+
for (const share of [0.25, 0.5, 0.75]) {
|
|
8982
|
+
for (let ray = 0; ray < 8; ray++) {
|
|
8983
|
+
const angle = ray / 8 * Math.PI * 2;
|
|
8984
|
+
if (Math.abs(heightAt(x + Math.cos(angle) * radius * share, z + Math.sin(angle) * radius * share) - centre) > FLAT_TOLERANCE) return true;
|
|
8985
|
+
}
|
|
8986
|
+
}
|
|
8987
|
+
return false;
|
|
8988
|
+
}
|
|
8971
8989
|
function conform(mark, material) {
|
|
8972
8990
|
const radius = mark.radius;
|
|
8973
|
-
const
|
|
8991
|
+
const dug = options.heightAt !== void 0 && groundDipsUnder(mark.x, mark.z, radius);
|
|
8992
|
+
const steps = Math.max(MIN_CONFORM_STEPS, Math.min(dug ? MAX_DUG_STEPS : MAX_FLAT_STEPS, Math.round(radius * (dug ? DUG_STEPS_PER_METRE : FLAT_STEPS_PER_METRE))));
|
|
8974
8993
|
if (groundMarks.length >= maxGroundMarks) evictOldestGroundMark();
|
|
8975
8994
|
const geometry = takeSpare((steps + 1) * (steps + 1)) ?? new THREE.PlaneGeometry(2, 2, steps, steps).rotateX(-Math.PI / 2);
|
|
8976
8995
|
const grid = geometry.attributes.position;
|
|
@@ -8982,7 +9001,7 @@ void main(){
|
|
|
8982
9001
|
const localZ = Math.fround(Math.floor(index / (steps + 1)) * cell - 1) * radius;
|
|
8983
9002
|
const worldX = mark.x + localX * cos2 - localZ * sin2;
|
|
8984
9003
|
const worldZ = mark.z + localX * sin2 + localZ * cos2;
|
|
8985
|
-
grid.setXYZ(index, worldX,
|
|
9004
|
+
grid.setXYZ(index, worldX, heightAt(worldX, worldZ) + mark.lift, worldZ);
|
|
8986
9005
|
}
|
|
8987
9006
|
grid.needsUpdate = true;
|
|
8988
9007
|
geometry.computeVertexNormals();
|
|
@@ -9791,7 +9810,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9791
9810
|
const shocks = createShockLayer(THREE, pools.shocks);
|
|
9792
9811
|
const sprites = createSpriteLayer(THREE, world.sprites(), options.pointScale ?? 700);
|
|
9793
9812
|
const lights = createLightLayer(THREE, pools.lights, options.lightScale ?? Math.PI, options.lights);
|
|
9794
|
-
const marks = createMarkLayer(THREE, { ground: pools.ground, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
9813
|
+
const marks = createMarkLayer(THREE, { ground: pools.ground, ...world.hostGroundAt ? { heightAt: world.hostGroundAt } : {}, createCanvas: options.createCanvas, rockGeometry, plateGeometry, ...options.markLimits });
|
|
9795
9814
|
root.add(puffs.mesh, sparks.mesh, glows.mesh, chunks.rocks, chunks.plates, shocks.group, lights.group, sprites.additive, sprites.normal, marks.group);
|
|
9796
9815
|
const stopMarks = world.onMarks((event) => marks.handle(event));
|
|
9797
9816
|
const overlay = options.overlay ? createScreenOverlay(options.overlay) : void 0;
|
|
@@ -9844,6 +9863,7 @@ void main(){vec2 d=gl_PointCoord-.5;float r=length(d)*2.;if(r>1.)discard;float a
|
|
|
9844
9863
|
drawCalls = Number(lastDrawn.puffs > 0) + Number(lastDrawn.sparks > 0) + Number(lastDrawn.glows > 0) + Number(chunks.rocks.count > 0) + Number(chunks.plates.count > 0) + Number(sprites.additive.geometry.drawRange.count > 0) + Number(sprites.normal.geometry.drawRange.count > 0) + lastDrawn.shocks * 2 + marks.count() + workshopCalls;
|
|
9845
9864
|
}
|
|
9846
9865
|
return {
|
|
9866
|
+
root,
|
|
9847
9867
|
world,
|
|
9848
9868
|
play(request) {
|
|
9849
9869
|
followCamera();
|