@netforge/engine 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/GAME-DESIGN.md +195 -0
- package/LICENSE +21 -0
- package/NOTICE +30 -0
- package/README.md +147 -2
- package/dist/api/appearance.d.ts +37 -0
- package/dist/api/appearance.js +41 -0
- package/dist/api/cards.d.ts +105 -0
- package/dist/api/cards.js +133 -0
- package/dist/api/collector.d.ts +114 -0
- package/dist/api/collector.js +204 -0
- package/dist/api/dungeon.d.ts +58 -0
- package/dist/api/dungeon.js +216 -0
- package/dist/api/harness.d.ts +149 -0
- package/dist/api/harness.js +549 -0
- package/dist/api/idle.d.ts +71 -0
- package/dist/api/idle.js +104 -0
- package/dist/api/race-harness.d.ts +3 -0
- package/dist/api/race-harness.js +148 -0
- package/dist/api/registry.d.ts +241 -0
- package/dist/api/registry.js +394 -0
- package/dist/api/scheduler.d.ts +56 -0
- package/dist/api/scheduler.js +160 -0
- package/dist/api/schemas.d.ts +958 -0
- package/dist/api/schemas.js +859 -0
- package/dist/api/tower.d.ts +127 -0
- package/dist/api/tower.js +183 -0
- package/dist/game/adapter.d.ts +69 -0
- package/dist/game/adapter.js +341 -0
- package/dist/game/arena-bot.d.ts +66 -0
- package/dist/game/arena-bot.js +188 -0
- package/dist/game/bot.d.ts +95 -0
- package/dist/game/bot.js +285 -0
- package/dist/game/compile.d.ts +97 -0
- package/dist/game/compile.js +476 -0
- package/dist/game/director.d.ts +42 -0
- package/dist/game/director.js +179 -0
- package/dist/game/earn-source.d.ts +122 -0
- package/dist/game/earn-source.js +386 -0
- package/dist/game/earn.d.ts +49 -0
- package/dist/game/earn.js +55 -0
- package/dist/game/index.d.ts +37 -0
- package/dist/game/index.js +25 -0
- package/dist/game/platformer.d.ts +156 -0
- package/dist/game/platformer.js +619 -0
- package/dist/game/profile.d.ts +97 -0
- package/dist/game/profile.js +140 -0
- package/dist/game/race.d.ts +177 -0
- package/dist/game/race.js +386 -0
- package/dist/game/racer.d.ts +98 -0
- package/dist/game/racer.js +379 -0
- package/dist/game/runner.d.ts +286 -0
- package/dist/game/runner.js +824 -0
- package/dist/game/threats.d.ts +23 -0
- package/dist/game/threats.js +49 -0
- package/dist/game/view.d.ts +47 -0
- package/dist/game/view.js +123 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.js +24 -0
- package/dist/net/bits.d.ts +33 -0
- package/dist/net/bits.js +135 -0
- package/dist/net/client.d.ts +75 -0
- package/dist/net/client.js +151 -0
- package/dist/net/index.d.ts +23 -0
- package/dist/net/index.js +23 -0
- package/dist/net/input.d.ts +49 -0
- package/dist/net/input.js +112 -0
- package/dist/net/interpolation.d.ts +37 -0
- package/dist/net/interpolation.js +97 -0
- package/dist/net/netsim.d.ts +22 -0
- package/dist/net/netsim.js +52 -0
- package/dist/net/prediction.d.ts +31 -0
- package/dist/net/prediction.js +101 -0
- package/dist/net/profile-client.d.ts +75 -0
- package/dist/net/profile-client.js +173 -0
- package/dist/net/protocol.d.ts +208 -0
- package/dist/net/protocol.js +8 -0
- package/dist/net/room-client.d.ts +57 -0
- package/dist/net/room-client.js +144 -0
- package/dist/net/schema.d.ts +78 -0
- package/dist/net/schema.js +121 -0
- package/dist/net/sim-adapter.d.ts +134 -0
- package/dist/net/sim-adapter.js +22 -0
- package/dist/net/snapshot.d.ts +61 -0
- package/dist/net/snapshot.js +301 -0
- package/dist/rules/adapter.d.ts +53 -0
- package/dist/rules/adapter.js +261 -0
- package/dist/rules/cards.d.ts +115 -0
- package/dist/rules/cards.js +547 -0
- package/dist/rules/collector.d.ts +161 -0
- package/dist/rules/collector.js +732 -0
- package/dist/rules/genres.d.ts +13 -0
- package/dist/rules/genres.js +38 -0
- package/dist/rules/harness.d.ts +16 -0
- package/dist/rules/harness.js +127 -0
- package/dist/rules/idle.d.ts +115 -0
- package/dist/rules/idle.js +370 -0
- package/dist/rules/index.d.ts +16 -0
- package/dist/rules/index.js +14 -0
- package/dist/rules/kit.d.ts +171 -0
- package/dist/rules/kit.js +88 -0
- package/dist/rules/tower.d.ts +214 -0
- package/dist/rules/tower.js +655 -0
- package/dist/runtime/arena.d.ts +86 -0
- package/dist/runtime/arena.js +269 -0
- package/dist/runtime/assets.d.ts +26 -0
- package/dist/runtime/assets.js +35 -0
- package/dist/runtime/camera.d.ts +113 -0
- package/dist/runtime/camera.js +247 -0
- package/dist/runtime/crowd.d.ts +18 -0
- package/dist/runtime/crowd.js +62 -0
- package/dist/runtime/feel/audio.d.ts +150 -0
- package/dist/runtime/feel/audio.js +327 -0
- package/dist/runtime/feel/clock.d.ts +52 -0
- package/dist/runtime/feel/clock.js +80 -0
- package/dist/runtime/feel/flash.d.ts +28 -0
- package/dist/runtime/feel/flash.js +60 -0
- package/dist/runtime/feel/index.d.ts +27 -0
- package/dist/runtime/feel/index.js +16 -0
- package/dist/runtime/feel/kit.d.ts +159 -0
- package/dist/runtime/feel/kit.js +226 -0
- package/dist/runtime/feel/knockback.d.ts +41 -0
- package/dist/runtime/feel/knockback.js +70 -0
- package/dist/runtime/feel/noise.d.ts +6 -0
- package/dist/runtime/feel/noise.js +30 -0
- package/dist/runtime/feel/numbers.d.ts +91 -0
- package/dist/runtime/feel/numbers.js +172 -0
- package/dist/runtime/feel/rumble.d.ts +40 -0
- package/dist/runtime/feel/rumble.js +58 -0
- package/dist/runtime/feel/sound.d.ts +96 -0
- package/dist/runtime/feel/sound.js +176 -0
- package/dist/runtime/feel/spring.d.ts +42 -0
- package/dist/runtime/feel/spring.js +95 -0
- package/dist/runtime/feel/trauma.d.ts +48 -0
- package/dist/runtime/feel/trauma.js +76 -0
- package/dist/runtime/feel/tween.d.ts +66 -0
- package/dist/runtime/feel/tween.js +180 -0
- package/dist/runtime/feel/types.d.ts +30 -0
- package/dist/runtime/feel/types.js +5 -0
- package/dist/runtime/index.d.ts +28 -0
- package/dist/runtime/index.js +26 -0
- package/dist/runtime/input.d.ts +38 -0
- package/dist/runtime/input.js +159 -0
- package/dist/runtime/interpolate.d.ts +6 -0
- package/dist/runtime/interpolate.js +13 -0
- package/dist/runtime/render/animation.d.ts +63 -0
- package/dist/runtime/render/animation.js +128 -0
- package/dist/runtime/render/atmosphere.d.ts +32 -0
- package/dist/runtime/render/atmosphere.js +59 -0
- package/dist/runtime/render/crowd-motion.d.ts +68 -0
- package/dist/runtime/render/crowd-motion.js +163 -0
- package/dist/runtime/render/decals.d.ts +64 -0
- package/dist/runtime/render/decals.js +222 -0
- package/dist/runtime/render/highlight.d.ts +29 -0
- package/dist/runtime/render/highlight.js +110 -0
- package/dist/runtime/render/index.d.ts +35 -0
- package/dist/runtime/render/index.js +22 -0
- package/dist/runtime/render/lighting.d.ts +50 -0
- package/dist/runtime/render/lighting.js +142 -0
- package/dist/runtime/render/particles.d.ts +117 -0
- package/dist/runtime/render/particles.js +289 -0
- package/dist/runtime/render/post.d.ts +92 -0
- package/dist/runtime/render/post.js +191 -0
- package/dist/runtime/render/presets.d.ts +57 -0
- package/dist/runtime/render/presets.js +116 -0
- package/dist/runtime/render/quality.d.ts +113 -0
- package/dist/runtime/render/quality.js +180 -0
- package/dist/runtime/render/rig.d.ts +29 -0
- package/dist/runtime/render/rig.js +107 -0
- package/dist/runtime/render/sprite.d.ts +34 -0
- package/dist/runtime/render/sprite.js +58 -0
- package/dist/runtime/render/stack.d.ts +74 -0
- package/dist/runtime/render/stack.js +132 -0
- package/dist/runtime/render/vat.d.ts +78 -0
- package/dist/runtime/render/vat.js +219 -0
- package/dist/runtime/renderer.d.ts +19 -0
- package/dist/runtime/renderer.js +18 -0
- package/dist/runtime/stats.d.ts +11 -0
- package/dist/runtime/stats.js +29 -0
- package/dist/runtime/styles/handdrawn/ground.d.ts +11 -0
- package/dist/runtime/styles/handdrawn/ground.js +282 -0
- package/dist/runtime/styles/handdrawn/index.d.ts +4 -0
- package/dist/runtime/styles/handdrawn/index.js +94 -0
- package/dist/runtime/styles/handdrawn/ink.d.ts +31 -0
- package/dist/runtime/styles/handdrawn/ink.js +68 -0
- package/dist/runtime/styles/handdrawn/looks.d.ts +18 -0
- package/dist/runtime/styles/handdrawn/looks.js +42 -0
- package/dist/runtime/styles/handdrawn/paint.d.ts +59 -0
- package/dist/runtime/styles/handdrawn/paint.js +129 -0
- package/dist/runtime/styles/handdrawn/palette.d.ts +49 -0
- package/dist/runtime/styles/handdrawn/palette.js +70 -0
- package/dist/runtime/styles/handdrawn/textures.d.ts +27 -0
- package/dist/runtime/styles/handdrawn/textures.js +150 -0
- package/dist/runtime/styles/handdrawn/vfx.d.ts +14 -0
- package/dist/runtime/styles/handdrawn/vfx.js +73 -0
- package/dist/runtime/styles/index.d.ts +9 -0
- package/dist/runtime/styles/index.js +32 -0
- package/dist/runtime/styles/kit.d.ts +193 -0
- package/dist/runtime/styles/kit.js +1 -0
- package/dist/runtime/styles/pixel/index.d.ts +46 -0
- package/dist/runtime/styles/pixel/index.js +167 -0
- package/dist/runtime/styles/ps1/index.d.ts +29 -0
- package/dist/runtime/styles/ps1/index.js +41 -0
- package/dist/runtime/styles/ps1/lights.d.ts +47 -0
- package/dist/runtime/styles/ps1/lights.js +146 -0
- package/dist/runtime/styles/ps1/materials.d.ts +62 -0
- package/dist/runtime/styles/ps1/materials.js +285 -0
- package/dist/runtime/styles/ps1/pipeline.d.ts +52 -0
- package/dist/runtime/styles/ps1/pipeline.js +111 -0
- package/dist/runtime/styles/ps1/surfaces.d.ts +44 -0
- package/dist/runtime/styles/ps1/surfaces.js +228 -0
- package/dist/runtime/styles/toon/index.d.ts +5 -0
- package/dist/runtime/styles/toon/index.js +178 -0
- package/dist/runtime/styles/toon/ink.d.ts +39 -0
- package/dist/runtime/styles/toon/ink.js +73 -0
- package/dist/runtime/styles/toon/look.d.ts +10 -0
- package/dist/runtime/styles/toon/look.js +112 -0
- package/dist/runtime/styles/toon/material.d.ts +74 -0
- package/dist/runtime/styles/toon/material.js +208 -0
- package/dist/runtime/styles/toon/normals.d.ts +26 -0
- package/dist/runtime/styles/toon/normals.js +127 -0
- package/dist/runtime/styles/toon/shadows.d.ts +24 -0
- package/dist/runtime/styles/toon/shadows.js +42 -0
- package/dist/runtime/styles/toon/vfx.d.ts +15 -0
- package/dist/runtime/styles/toon/vfx.js +47 -0
- package/dist/runtime/styles/view.d.ts +35 -0
- package/dist/runtime/styles/view.js +34 -0
- package/dist/runtime/styles/voxel/core.d.ts +114 -0
- package/dist/runtime/styles/voxel/core.js +577 -0
- package/dist/runtime/styles/voxel/geometry.d.ts +27 -0
- package/dist/runtime/styles/voxel/geometry.js +40 -0
- package/dist/runtime/styles/voxel/index.d.ts +21 -0
- package/dist/runtime/styles/voxel/index.js +23 -0
- package/dist/runtime/styles/voxel/kit.d.ts +6 -0
- package/dist/runtime/styles/voxel/kit.js +11 -0
- package/dist/runtime/styles/voxel/look.d.ts +10 -0
- package/dist/runtime/styles/voxel/look.js +16 -0
- package/dist/runtime/styles/voxel/props.d.ts +9 -0
- package/dist/runtime/styles/voxel/props.js +52 -0
- package/dist/runtime/styles/voxel/shapes.d.ts +41 -0
- package/dist/runtime/styles/voxel/shapes.js +83 -0
- package/dist/runtime/styles/voxel/world.d.ts +49 -0
- package/dist/runtime/styles/voxel/world.js +422 -0
- package/llms.txt +183 -0
- package/package.json +82 -3
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Procedural textures for the hand-drawn style, generated in JS (no DOM,
|
|
3
|
+
* no files, deterministic from a seed): a tileable noise field the line
|
|
4
|
+
* wobble, wet edges and hatching read, and a sheet of paper with grain and
|
|
5
|
+
* fibres the whole frame is printed on. Original work, so no licence
|
|
6
|
+
* question.
|
|
7
|
+
*/
|
|
8
|
+
import { DataTexture, LinearFilter, RepeatWrapping, RGBAFormat, UnsignedByteType } from "three/webgpu";
|
|
9
|
+
/** A small seeded generator (mulberry32). */
|
|
10
|
+
export function seeded(seed) {
|
|
11
|
+
let a = seed >>> 0;
|
|
12
|
+
return () => {
|
|
13
|
+
a = (a + 0x6d2b79f5) >>> 0;
|
|
14
|
+
let t = a;
|
|
15
|
+
t = Math.imul(t ^ (t >>> 15), t | 1);
|
|
16
|
+
t ^= t + Math.imul(t ^ (t >>> 7), t | 61);
|
|
17
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
/** Tileable value noise on a `size` grid with `cells` lattice cells per side, fractal over `octaves`. Values 0..1. */
|
|
21
|
+
export function tileNoise(size, cells, octaves, rnd) {
|
|
22
|
+
const out = new Float32Array(size * size);
|
|
23
|
+
let amp = 1;
|
|
24
|
+
let total = 0;
|
|
25
|
+
let c = cells;
|
|
26
|
+
for (let o = 0; o < octaves; o++) {
|
|
27
|
+
const lattice = new Float32Array(c * c);
|
|
28
|
+
for (let i = 0; i < lattice.length; i++)
|
|
29
|
+
lattice[i] = rnd();
|
|
30
|
+
const step = size / c;
|
|
31
|
+
for (let y = 0; y < size; y++) {
|
|
32
|
+
const gy = y / step;
|
|
33
|
+
const y0 = Math.floor(gy) % c;
|
|
34
|
+
const y1 = (y0 + 1) % c;
|
|
35
|
+
const fy = gy - Math.floor(gy);
|
|
36
|
+
const sy = fy * fy * (3 - 2 * fy);
|
|
37
|
+
for (let x = 0; x < size; x++) {
|
|
38
|
+
const gx = x / step;
|
|
39
|
+
const x0 = Math.floor(gx) % c;
|
|
40
|
+
const x1 = (x0 + 1) % c;
|
|
41
|
+
const fx = gx - Math.floor(gx);
|
|
42
|
+
const sx = fx * fx * (3 - 2 * fx);
|
|
43
|
+
const a = lattice[y0 * c + x0] ?? 0;
|
|
44
|
+
const b = lattice[y0 * c + x1] ?? 0;
|
|
45
|
+
const d = lattice[y1 * c + x0] ?? 0;
|
|
46
|
+
const e = lattice[y1 * c + x1] ?? 0;
|
|
47
|
+
const v = (a + (b - a) * sx) * (1 - sy) + (d + (e - d) * sx) * sy;
|
|
48
|
+
out[y * size + x] = (out[y * size + x] ?? 0) + v * amp;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
total += amp;
|
|
52
|
+
amp *= 0.5;
|
|
53
|
+
c *= 2;
|
|
54
|
+
}
|
|
55
|
+
for (let i = 0; i < out.length; i++)
|
|
56
|
+
out[i] = (out[i] ?? 0) / total;
|
|
57
|
+
return out;
|
|
58
|
+
}
|
|
59
|
+
function dataTexture(data, size) {
|
|
60
|
+
const t = new DataTexture(data, size, size, RGBAFormat, UnsignedByteType);
|
|
61
|
+
t.wrapS = RepeatWrapping;
|
|
62
|
+
t.wrapT = RepeatWrapping;
|
|
63
|
+
t.magFilter = LinearFilter;
|
|
64
|
+
t.minFilter = LinearFilter;
|
|
65
|
+
t.generateMipmaps = false;
|
|
66
|
+
t.needsUpdate = true;
|
|
67
|
+
return t;
|
|
68
|
+
}
|
|
69
|
+
/** Stretch a noise field so it spans 0..1 (value noise bunches around the middle). */
|
|
70
|
+
function contrast(f) {
|
|
71
|
+
let lo = Infinity;
|
|
72
|
+
let hi = -Infinity;
|
|
73
|
+
for (const v of f) {
|
|
74
|
+
if (v < lo)
|
|
75
|
+
lo = v;
|
|
76
|
+
if (v > hi)
|
|
77
|
+
hi = v;
|
|
78
|
+
}
|
|
79
|
+
const k = hi - lo > 1e-6 ? 1 / (hi - lo) : 1;
|
|
80
|
+
for (let i = 0; i < f.length; i++)
|
|
81
|
+
f[i] = ((f[i] ?? 0) - lo) * k;
|
|
82
|
+
return f;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Noise for the style's shaders, 256 px and tileable: R low (wobble, wet
|
|
86
|
+
* edges), G mid (line pressure and breaks), B fine (stroke jitter), A white.
|
|
87
|
+
*/
|
|
88
|
+
export function noiseData(seed = 11, size = 256) {
|
|
89
|
+
const rnd = seeded(seed);
|
|
90
|
+
const r = contrast(tileNoise(size, 4, 3, rnd));
|
|
91
|
+
const g = contrast(tileNoise(size, 8, 3, rnd));
|
|
92
|
+
const b = contrast(tileNoise(size, 32, 2, rnd));
|
|
93
|
+
const data = new Uint8Array(size * size * 4);
|
|
94
|
+
for (let i = 0; i < size * size; i++) {
|
|
95
|
+
data[i * 4] = Math.round((r[i] ?? 0) * 255);
|
|
96
|
+
data[i * 4 + 1] = Math.round((g[i] ?? 0) * 255);
|
|
97
|
+
data[i * 4 + 2] = Math.round((b[i] ?? 0) * 255);
|
|
98
|
+
data[i * 4 + 3] = Math.floor(rnd() * 256);
|
|
99
|
+
}
|
|
100
|
+
return data;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Cold-pressed paper, 512 px and tileable: R is the surface (1 = the top of
|
|
104
|
+
* the tooth, lower = valleys and fibres), G a slower mottle for the sheet's
|
|
105
|
+
* tone, B the tooth alone (where pigment granulates).
|
|
106
|
+
*/
|
|
107
|
+
export function paperData(seed = 5, size = 512) {
|
|
108
|
+
const rnd = seeded(seed);
|
|
109
|
+
const tooth = contrast(tileNoise(size, 64, 2, rnd));
|
|
110
|
+
const mottle = contrast(tileNoise(size, 4, 4, rnd));
|
|
111
|
+
const surface = new Float32Array(size * size);
|
|
112
|
+
for (let i = 0; i < surface.length; i++)
|
|
113
|
+
surface[i] = 0.9 + 0.1 * (tooth[i] ?? 0);
|
|
114
|
+
// Fibres: short soft curves, a little darker or lighter than the sheet.
|
|
115
|
+
const wrap = (v) => ((Math.round(v) % size) + size) % size;
|
|
116
|
+
for (let f = 0; f < 1400; f++) {
|
|
117
|
+
let x = rnd() * size;
|
|
118
|
+
let y = rnd() * size;
|
|
119
|
+
let a = rnd() * Math.PI * 2;
|
|
120
|
+
const len = 6 + rnd() * 26;
|
|
121
|
+
const dv = rnd() < 0.7 ? -(0.03 + rnd() * 0.05) : 0.03 + rnd() * 0.03;
|
|
122
|
+
for (let s = 0; s < len; s++) {
|
|
123
|
+
const i = wrap(y) * size + wrap(x);
|
|
124
|
+
surface[i] = Math.min(1, Math.max(0, (surface[i] ?? 0) + dv * (1 - Math.abs(s / len - 0.5))));
|
|
125
|
+
a += (rnd() - 0.5) * 0.35;
|
|
126
|
+
x += Math.cos(a);
|
|
127
|
+
y += Math.sin(a);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
const data = new Uint8Array(size * size * 4);
|
|
131
|
+
for (let i = 0; i < size * size; i++) {
|
|
132
|
+
data[i * 4] = Math.round((surface[i] ?? 0) * 255);
|
|
133
|
+
data[i * 4 + 1] = Math.round((mottle[i] ?? 0) * 255);
|
|
134
|
+
data[i * 4 + 2] = Math.round((tooth[i] ?? 0) * 255);
|
|
135
|
+
data[i * 4 + 3] = 255;
|
|
136
|
+
}
|
|
137
|
+
return data;
|
|
138
|
+
}
|
|
139
|
+
let noiseTex = null;
|
|
140
|
+
let paperTex = null;
|
|
141
|
+
/** The shared noise texture (built once per page). */
|
|
142
|
+
export function noiseTexture() {
|
|
143
|
+
noiseTex ??= dataTexture(noiseData(), 256);
|
|
144
|
+
return noiseTex;
|
|
145
|
+
}
|
|
146
|
+
/** The shared paper texture (built once per page). */
|
|
147
|
+
export function paperTexture() {
|
|
148
|
+
paperTex ??= dataTexture(paperData(), 512);
|
|
149
|
+
return paperTex;
|
|
150
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Effects drawn by hand: every particle is a painted fleck with an inked
|
|
3
|
+
* rim (no soft glow dots), smoke is a scribbled puff, scorches are ink
|
|
4
|
+
* blots, splats are watercolour blooms with a dark tide line, and rings
|
|
5
|
+
* are brush circles with dry-brush gaps. Same pools and draws as the
|
|
6
|
+
* engine's effects; only their fragment shading changes.
|
|
7
|
+
*/
|
|
8
|
+
import type { Texture } from "three/webgpu";
|
|
9
|
+
import type { ParticleShade } from "../../render/particles.js";
|
|
10
|
+
import type { DecalLook, RingLook } from "../kit.js";
|
|
11
|
+
/** Painted flecks and scribbled puffs, drawn with normal blending (the stack multiplies in each particle's alive flag). */
|
|
12
|
+
export declare function particleLook(noise: Texture): ParticleShade;
|
|
13
|
+
export declare function decalLook(noise: Texture): DecalLook;
|
|
14
|
+
export declare function ringLook(noise: Texture): RingLook;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { abs, atan, clamp, cos, float, length, max, min, mix, select, smoothstep, texture, vec2, vec3 } from "three/tsl";
|
|
2
|
+
import { linearRgb, PIGMENTS } from "./palette.js";
|
|
3
|
+
const inkLinear = () => vec3(...linearRgb(PIGMENTS.sepia));
|
|
4
|
+
/** Colours arrive linear and sometimes boosted for bloom: bring them back to paint (0..1, a touch muted). */
|
|
5
|
+
function paintColor(c) {
|
|
6
|
+
const k = max(max(c.x, c.y), max(c.z, float(1e-3)));
|
|
7
|
+
const unboosted = c.div(max(k, float(1)));
|
|
8
|
+
return mix(unboosted, vec3(0.5, 0.45, 0.4).mul(unboosted.x.add(unboosted.y).add(unboosted.z).div(3)), 0.12).mul(1.15);
|
|
9
|
+
}
|
|
10
|
+
/** Painted flecks and scribbled puffs, drawn with normal blending (the stack multiplies in each particle's alive flag). */
|
|
11
|
+
export function particleLook(noise) {
|
|
12
|
+
const shade = ({ uv, t, color, blend }) => {
|
|
13
|
+
const p = uv.sub(0.5).mul(2);
|
|
14
|
+
// A slightly lumpy outline so no two flecks are perfect circles.
|
|
15
|
+
const lump = texture(noise, uv.mul(0.35).add(t.mul(0.05))).b.sub(0.5).mul(0.22);
|
|
16
|
+
const d = length(p).add(lump);
|
|
17
|
+
if (blend === "add") {
|
|
18
|
+
// A painted fleck: solid paint, an inked rim, shrinking as it dies.
|
|
19
|
+
const edge = float(0.82).sub(t.mul(0.25));
|
|
20
|
+
const fill = float(1).sub(smoothstep(edge.sub(0.08), edge, d));
|
|
21
|
+
// The rim is a thin pen ring: on a big fleck it reads as ink, on a speck it stays a touch of shade (no dirt dots in a crowd).
|
|
22
|
+
const rim = smoothstep(edge.sub(0.2), edge.sub(0.06), d).mul(fill);
|
|
23
|
+
const paint = paintColor(color).mul(1.25);
|
|
24
|
+
const col = mix(paint, inkLinear(), rim.mul(0.45));
|
|
25
|
+
return { color: col, opacity: fill.mul(float(1).sub(smoothstep(0.75, 1, t))), blend: "alpha" };
|
|
26
|
+
}
|
|
27
|
+
// Smoke and dust: a pale scribbled puff with a broken pencil rim.
|
|
28
|
+
const fill = float(1).sub(smoothstep(0.7, 0.84, d));
|
|
29
|
+
const rim = smoothstep(0.52, 0.74, d).mul(fill).mul(smoothstep(0.35, 0.55, texture(noise, uv.mul(0.6)).g));
|
|
30
|
+
const wash = mix(paintColor(color), vec3(0.86, 0.82, 0.74), 0.55);
|
|
31
|
+
const col = mix(wash, inkLinear(), rim.mul(0.6));
|
|
32
|
+
return { color: col, opacity: fill.mul(0.55).mul(float(1).sub(t)), blend: "alpha" };
|
|
33
|
+
};
|
|
34
|
+
return { shade };
|
|
35
|
+
}
|
|
36
|
+
export function decalLook(noise) {
|
|
37
|
+
return ({ uv, r, angle, kind, t, color, shape, opacity }) => {
|
|
38
|
+
const n = texture(noise, uv.mul(0.5).add(vec2(cos(angle).mul(0.01), 0))).r;
|
|
39
|
+
const fade = float(1).sub(smoothstep(0.55, 1, t));
|
|
40
|
+
// Scorch: an ink blot with a crisp, ragged edge and a few spatters.
|
|
41
|
+
const blot = smoothstep(0.32, 0.4, shape.add(n.sub(0.5).mul(0.25)));
|
|
42
|
+
const spat = smoothstep(0.82, 0.86, texture(noise, uv.mul(1.7)).a).mul(smoothstep(1, 0.6, r)).mul(smoothstep(0.4, 0.7, r));
|
|
43
|
+
const scorchA = max(blot, spat).mul(0.85);
|
|
44
|
+
// Splat: a watercolour bloom, pale inside, dark tide line at its edge.
|
|
45
|
+
const bloom = smoothstep(0.3, 0.42, shape.add(n.sub(0.5).mul(0.3)));
|
|
46
|
+
const inner = smoothstep(0.45, 0.85, shape);
|
|
47
|
+
const splatA = bloom.mul(0.42).add(bloom.sub(inner).mul(0.45));
|
|
48
|
+
// Ring: a brush circle with dry-brush gaps.
|
|
49
|
+
const band = float(1).sub(smoothstep(0.03, 0.07, abs(r.sub(0.8).add(n.sub(0.5).mul(0.06)))));
|
|
50
|
+
const dry = smoothstep(0.25, 0.45, texture(noise, vec2(angle.mul(0.16), r.mul(0.2))).g);
|
|
51
|
+
const ringA = band.mul(dry);
|
|
52
|
+
const a = select(kind.lessThan(0.5), scorchA, select(kind.lessThan(1.5), splatA, ringA));
|
|
53
|
+
const tone = paintColor(color);
|
|
54
|
+
const col = select(kind.lessThan(0.5), mix(inkLinear(), tone, 0.25), select(kind.lessThan(1.5), mix(tone, tone.mul(0.6), bloom.sub(inner)), mix(tone, inkLinear(), 0.35)));
|
|
55
|
+
return { color: col, opacity: clamp(a.mul(opacity).mul(fade).mul(1.25), 0, 1), blending: "normal" };
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function ringLook(noise) {
|
|
59
|
+
return ({ uv, r, t, alive, color }) => {
|
|
60
|
+
const p = uv.sub(0.5);
|
|
61
|
+
const ang = atan(p.y, p.x);
|
|
62
|
+
const n = texture(noise, vec2(ang.mul(0.21), t.mul(0.1))).g;
|
|
63
|
+
// A brush stroke around the circle: thick at the start, thinning as it spreads, with gaps.
|
|
64
|
+
const width = mix(float(0.13), float(0.05), t);
|
|
65
|
+
const centre = float(0.9).add(n.sub(0.5).mul(0.05));
|
|
66
|
+
const band = float(1).sub(smoothstep(width.mul(0.5), width, abs(r.sub(centre))));
|
|
67
|
+
const dry = smoothstep(0.22, 0.4, n);
|
|
68
|
+
const inkRim = smoothstep(width.mul(0.15), width.mul(0.55), abs(r.sub(centre))).mul(band);
|
|
69
|
+
const paint = paintColor(color).mul(1.2);
|
|
70
|
+
const col = mix(paint, inkLinear(), min(inkRim.mul(0.8), float(0.8)));
|
|
71
|
+
return { color: col, opacity: band.mul(dry).mul(float(1).sub(t)).mul(alive), blending: "normal" };
|
|
72
|
+
};
|
|
73
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { StyleKit } from "./kit.js";
|
|
2
|
+
export type { FieldSpec, PillarSpec, DecalLook, DecalLookInput, LookOutput, RingLook, RingLookInput, StyleContext, StyledPillar, StyleKit, StylePost, StylePostInput, StyleSession, StyleShape, StyleShapeName, StyleStack, SurfaceKind, SurfaceOptions, WorldTheme, } from "./kit.js";
|
|
3
|
+
/** One entry per art style. Keep it a plain map. */
|
|
4
|
+
export declare const STYLE_KITS: Readonly<Record<string, StyleKit>>;
|
|
5
|
+
/** The art style a template draws in: a known `?style=` on the URL wins over the game's declared style. */
|
|
6
|
+
export declare function pickStyle(declared: string, requested: string | null | undefined): string;
|
|
7
|
+
/** The kit for a style, or null (low-poly, or a style with no kit yet). */
|
|
8
|
+
export declare function styleKit(style: string | null | undefined): StyleKit | null;
|
|
9
|
+
export * as voxel from "./voxel/index.js";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Art styles: what a game declared with
|
|
3
|
+
* `style: "<name>"` draws with, beyond its library models. Each style lives
|
|
4
|
+
* in its own folder and registers one entry in STYLE_KITS (the one
|
|
5
|
+
* registry). createRenderStack({ style }) applies a kit's render hooks
|
|
6
|
+
* (look, post, session); templates read `stack.kit` (or `styleKit(style)`)
|
|
7
|
+
* for its world builders, falling back to their own drawing for anything a
|
|
8
|
+
* kit leaves out. Low-poly is the templates' own drawing and has no kit.
|
|
9
|
+
*/
|
|
10
|
+
import { STYLES } from "../../api/schemas.js";
|
|
11
|
+
import { handdrawnKit } from "./handdrawn/index.js";
|
|
12
|
+
import { pixelKit } from "./pixel/index.js";
|
|
13
|
+
import { ps1Kit } from "./ps1/index.js";
|
|
14
|
+
import { toonKit } from "./toon/index.js";
|
|
15
|
+
import { voxelKit } from "./voxel/kit.js";
|
|
16
|
+
/** One entry per art style. Keep it a plain map. */
|
|
17
|
+
export const STYLE_KITS = {
|
|
18
|
+
handdrawn: handdrawnKit,
|
|
19
|
+
pixel: pixelKit,
|
|
20
|
+
ps1: ps1Kit,
|
|
21
|
+
toon: toonKit,
|
|
22
|
+
voxel: voxelKit,
|
|
23
|
+
};
|
|
24
|
+
/** The art style a template draws in: a known `?style=` on the URL wins over the game's declared style. */
|
|
25
|
+
export function pickStyle(declared, requested) {
|
|
26
|
+
return requested && STYLES.includes(requested) ? requested : declared;
|
|
27
|
+
}
|
|
28
|
+
/** The kit for a style, or null (low-poly, or a style with no kit yet). */
|
|
29
|
+
export function styleKit(style) {
|
|
30
|
+
return (style && STYLE_KITS[style]) || null;
|
|
31
|
+
}
|
|
32
|
+
export * as voxel from "./voxel/index.js";
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What an art style gives the runtime and a template.
|
|
3
|
+
* One interface for every style, two halves, every member optional:
|
|
4
|
+
*
|
|
5
|
+
* - render hooks, applied by createRenderStack({ style }) (render/stack.ts
|
|
6
|
+
* is the one place that looks a style up): `stack`/`look` presets, and
|
|
7
|
+
* `attach`, a per-renderer session that may wrap or replace the frame,
|
|
8
|
+
* add post stages, and reshade particles;
|
|
9
|
+
* - world builders a template asks for (`field`, `pillar`, `shape`...).
|
|
10
|
+
*
|
|
11
|
+
* A template draws anything a kit leaves out its own way, so a style can
|
|
12
|
+
* grow one piece at a time and a template never breaks on a missing piece.
|
|
13
|
+
*/
|
|
14
|
+
import type { BufferGeometry, Camera, Material, Node, Object3D, PassNode, Scene, Texture, UniformNode, Vector2, WebGPURenderer } from "three/webgpu";
|
|
15
|
+
import type { RendererHandle } from "../renderer.js";
|
|
16
|
+
import type { Atmosphere } from "../render/atmosphere.js";
|
|
17
|
+
import type { ParticleShade } from "../render/particles.js";
|
|
18
|
+
import type { PostFX } from "../render/post.js";
|
|
19
|
+
import type { Look, LookPreset } from "../render/presets.js";
|
|
20
|
+
import type { QualityTier } from "../render/quality.js";
|
|
21
|
+
import type { RenderStackOptions } from "../render/stack.js";
|
|
22
|
+
/** Words a template passes so one kit can dress different places: "meadow" (EMBERWATCH's night field), "yard" (VOLTYARD's lot). */
|
|
23
|
+
export type WorldTheme = string;
|
|
24
|
+
/** The play field: a square of half size `half` m with a wall `wallHeight` tall, and `outside` m of dressed ground past it. */
|
|
25
|
+
export interface FieldSpec {
|
|
26
|
+
readonly half: number;
|
|
27
|
+
readonly wallHeight: number;
|
|
28
|
+
readonly outside: number;
|
|
29
|
+
readonly theme: WorldTheme;
|
|
30
|
+
/** Draw the wall (default true). */
|
|
31
|
+
readonly wall?: boolean;
|
|
32
|
+
/** Pillars standing in the field, so ground clutter keeps clear of them. */
|
|
33
|
+
readonly pillars?: readonly PillarSpec[];
|
|
34
|
+
}
|
|
35
|
+
/** One pillar or post (sim metres). */
|
|
36
|
+
export interface PillarSpec {
|
|
37
|
+
readonly x: number;
|
|
38
|
+
readonly z: number;
|
|
39
|
+
readonly radius: number;
|
|
40
|
+
readonly height: number;
|
|
41
|
+
}
|
|
42
|
+
/** A pillar as drawn: its body (own material, so the template can fade it), the pieces on top, and where its flame burns (null: none). */
|
|
43
|
+
export interface StyledPillar {
|
|
44
|
+
readonly body: Object3D;
|
|
45
|
+
readonly fade: readonly Material[];
|
|
46
|
+
readonly top: readonly Object3D[];
|
|
47
|
+
readonly flame: readonly [number, number, number] | null;
|
|
48
|
+
}
|
|
49
|
+
/** A shape a template draws instanced (bolts, blades, chunks, props). */
|
|
50
|
+
export interface StyleShape {
|
|
51
|
+
readonly geometry: BufferGeometry;
|
|
52
|
+
readonly material: Material;
|
|
53
|
+
}
|
|
54
|
+
/** Template machinery shapes a style may redraw. */
|
|
55
|
+
export type StyleShapeName = "bolt" | "lance" | "blade" | "pellet" | "shard" | "chunk" | "rock" | "stump" | "barrel" | "crate" | "lantern" | "flame";
|
|
56
|
+
/** Overrides for the render stack under one look preset, plus the style's opinion on sun shadows. */
|
|
57
|
+
export interface StyleStack extends Partial<Pick<RenderStackOptions, "lighting" | "atmosphere" | "grade" | "makeParticles">> {
|
|
58
|
+
/** Sun shadows suit the style (a template may still turn them off for speed). */
|
|
59
|
+
readonly shadows?: boolean;
|
|
60
|
+
}
|
|
61
|
+
/** What a style's session is attached to (one renderer, one scene). */
|
|
62
|
+
export interface StyleContext {
|
|
63
|
+
readonly handle: RendererHandle;
|
|
64
|
+
readonly renderer: WebGPURenderer;
|
|
65
|
+
readonly scene: Scene;
|
|
66
|
+
readonly camera: Camera;
|
|
67
|
+
readonly tier: QualityTier;
|
|
68
|
+
/** The look preset in use. */
|
|
69
|
+
readonly preset: LookPreset;
|
|
70
|
+
/** The stack's post (grade, hurt pulse, vignette), when there is one. */
|
|
71
|
+
readonly post?: PostFX;
|
|
72
|
+
/** The stack's fog and sky, when there is one. */
|
|
73
|
+
readonly atmosphere?: Atmosphere;
|
|
74
|
+
/** Library id to URL (the template's LibraryClient), for the style's own textures. Absent or null: no library, use fallbacks. */
|
|
75
|
+
readonly resolve?: (id: string) => string | null;
|
|
76
|
+
}
|
|
77
|
+
/** What the post stages can read: the scene pass, sampleable at any uv. */
|
|
78
|
+
export interface StylePostInput {
|
|
79
|
+
/** Scene colour (linear HDR) as a texture node: `.sample(uv)` reads a neighbour. */
|
|
80
|
+
readonly color: Node<"vec4"> & {
|
|
81
|
+
sample(uv: Node<"vec2">): Node<"vec4">;
|
|
82
|
+
};
|
|
83
|
+
/** Scene depth (0..1 perspective depth) as a texture node. */
|
|
84
|
+
readonly depth: Node<"vec4"> & {
|
|
85
|
+
sample(uv: Node<"vec2">): Node<"vec4">;
|
|
86
|
+
};
|
|
87
|
+
/** One render pixel in uv units. */
|
|
88
|
+
readonly texel: UniformNode<"vec2", Vector2>;
|
|
89
|
+
readonly near: UniformNode<"float", number>;
|
|
90
|
+
readonly far: UniformNode<"float", number>;
|
|
91
|
+
}
|
|
92
|
+
/** Post-graph hooks, in graph order: called whenever the post stack rebuilds its node graph. */
|
|
93
|
+
export interface StylePost {
|
|
94
|
+
/** Configure the scene pass before anything samples it (extra MRT outputs, draw hooks). */
|
|
95
|
+
scenePass?(pass: PassNode): void;
|
|
96
|
+
/** HDR stage before bloom and grade: the colour to use instead of the scene pass. */
|
|
97
|
+
scene?(input: StylePostInput): Node<"vec4">;
|
|
98
|
+
/** Change the HDR colour (after bloom and outline, before the grade). */
|
|
99
|
+
color?(rgb: Node<"vec3">, pass: PassNode): Node<"vec3">;
|
|
100
|
+
/** Display stage, after tone mapping (sRGB 0..1): lines, paper, print. */
|
|
101
|
+
display?(color: Node<"vec4">, input: StylePostInput): Node<"vec4">;
|
|
102
|
+
}
|
|
103
|
+
/** What a ground decal's look can read (GroundDecals). */
|
|
104
|
+
export interface DecalLookInput {
|
|
105
|
+
readonly uv: Node<"vec2">;
|
|
106
|
+
/** Radius from the centre, 0..1 at the quad's edge. */
|
|
107
|
+
readonly r: Node<"float">;
|
|
108
|
+
/** Angle around the centre, radians, with the decal's random seed added. */
|
|
109
|
+
readonly angle: Node<"float">;
|
|
110
|
+
/** 0 scorch, 1 splat, 2 ring. */
|
|
111
|
+
readonly kind: Node<"float">;
|
|
112
|
+
/** 0 at birth, 1 at the end of its life. */
|
|
113
|
+
readonly t: Node<"float">;
|
|
114
|
+
readonly color: Node<"vec3">;
|
|
115
|
+
/** The engine's own shape mask, 0..1 (for styles that keep the shapes). */
|
|
116
|
+
readonly shape: Node<"float">;
|
|
117
|
+
/** Peak opacity times alive. */
|
|
118
|
+
readonly opacity: Node<"float">;
|
|
119
|
+
}
|
|
120
|
+
/** What a shockwave ring's look can read (GroundRings). */
|
|
121
|
+
export interface RingLookInput {
|
|
122
|
+
readonly uv: Node<"vec2">;
|
|
123
|
+
readonly r: Node<"float">;
|
|
124
|
+
readonly t: Node<"float">;
|
|
125
|
+
readonly alive: Node<"float">;
|
|
126
|
+
readonly color: Node<"vec3">;
|
|
127
|
+
}
|
|
128
|
+
/** A decal or ring look's answer: colour and opacity nodes, and the blend to draw with. */
|
|
129
|
+
export interface LookOutput {
|
|
130
|
+
readonly color: Node<"vec3">;
|
|
131
|
+
readonly opacity: Node<"float">;
|
|
132
|
+
readonly blending?: "add" | "normal";
|
|
133
|
+
}
|
|
134
|
+
export type DecalLook = (n: DecalLookInput) => LookOutput;
|
|
135
|
+
export type RingLook = (n: RingLookInput) => LookOutput;
|
|
136
|
+
/**
|
|
137
|
+
* Surfaces templates build themselves and may ask the style for: ground
|
|
138
|
+
* (a natural field), floor (paving), wall, stone, and glow (a pool of
|
|
139
|
+
* light on the ground, white with alpha, which the template tints).
|
|
140
|
+
*/
|
|
141
|
+
export type SurfaceKind = "ground" | "floor" | "wall" | "stone" | "glow";
|
|
142
|
+
export interface SurfaceOptions {
|
|
143
|
+
/** Metres one repeat of the texture covers (the template sets repeat). */
|
|
144
|
+
readonly tile?: number;
|
|
145
|
+
/** A hint at what the place is ("forest field", "power yard"). */
|
|
146
|
+
readonly mood?: string;
|
|
147
|
+
}
|
|
148
|
+
/** One style attached to one renderer and scene (StyleKit.attach). */
|
|
149
|
+
export interface StyleSession {
|
|
150
|
+
/** Draw a frame in the style: `draw` is the stack's own render (post or straight to the canvas). Omitted: the stack draws. */
|
|
151
|
+
render?(draw: () => void): void;
|
|
152
|
+
/** Post stages (the stack keeps post on at every tier when the kit says `needsPost`). */
|
|
153
|
+
readonly post?: StylePost;
|
|
154
|
+
/** Shapes and colours for the GPU particles (sparks, puffs, stars). */
|
|
155
|
+
readonly particles?: ParticleShade;
|
|
156
|
+
/** Shading for ground decals (scorches, splats) and shockwave rings. */
|
|
157
|
+
readonly decals?: DecalLook;
|
|
158
|
+
readonly rings?: RingLook;
|
|
159
|
+
/** Every frame, before drawing (real seconds since the page opened). */
|
|
160
|
+
frame?(seconds: number): void;
|
|
161
|
+
/** The game switched look preset. */
|
|
162
|
+
setPreset?(preset: LookPreset): void;
|
|
163
|
+
/** A texture for a template-built surface, or null to keep the template's own. */
|
|
164
|
+
surface?(kind: SurfaceKind, opts?: SurfaceOptions): Texture | null;
|
|
165
|
+
/** The render size in device pixels changed. */
|
|
166
|
+
setSize?(width: number, height: number): void;
|
|
167
|
+
/** The quality tier changed. */
|
|
168
|
+
setQuality?(tier: QualityTier): void;
|
|
169
|
+
dispose(): void;
|
|
170
|
+
}
|
|
171
|
+
export interface StyleKit {
|
|
172
|
+
readonly id: string;
|
|
173
|
+
/** Render stack overrides for a look preset (merged over `look`, under the template's own options). */
|
|
174
|
+
stack?(preset: LookPreset): StyleStack;
|
|
175
|
+
/** The style's whole version of a look preset: lighting, atmosphere and grade together. */
|
|
176
|
+
look?(preset: LookPreset): Look;
|
|
177
|
+
/** The style's picture lives in post: keep post on at the low tier (without bloom). */
|
|
178
|
+
readonly needsPost?: boolean;
|
|
179
|
+
/** Bloom by default in this style (a game's `look.bloom` still wins). Default true. */
|
|
180
|
+
readonly bloom?: boolean;
|
|
181
|
+
/** false: the style draws its own lines, so the stack's outline stays off. */
|
|
182
|
+
readonly outline?: boolean;
|
|
183
|
+
/** Attach the style to a renderer and scene: draw-time materials, post stages, particle look. */
|
|
184
|
+
attach?(ctx: StyleContext): StyleSession;
|
|
185
|
+
/** The field's floor, the dressed ground past it, and its wall. Add the result to the scene. */
|
|
186
|
+
field?(spec: FieldSpec): Object3D[];
|
|
187
|
+
/** Height of the style's ground at (x, z) for a field built by `field`, so scenery past the wall stands on it. */
|
|
188
|
+
groundHeight?(spec: FieldSpec, x: number, z: number): number;
|
|
189
|
+
/** One pillar. */
|
|
190
|
+
pillar?(spec: PillarSpec, theme: WorldTheme, index: number): StyledPillar;
|
|
191
|
+
/** A template machinery shape in the style, or null to keep the template's own. */
|
|
192
|
+
shape?(name: StyleShapeName): StyleShape | null;
|
|
193
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pixel art style. The scene renders into a
|
|
3
|
+
* low-resolution target, one pixel of it per sprite texel at the camera's
|
|
4
|
+
* focus, and every pixel goes to the screen as a hard square block: no
|
|
5
|
+
* filtering, no blur, one pixel scale for the whole picture. The colour is
|
|
6
|
+
* then snapped to the style's 16-colour palette (the library build snaps
|
|
7
|
+
* the sprites to the same one) with a 4x4 ordered dither, so lit 3D ground,
|
|
8
|
+
* walls and effects read as one piece of pixel art with the sprites.
|
|
9
|
+
*
|
|
10
|
+
* Sprites (render/sprite.ts) are resized by `spriteScale` here each frame,
|
|
11
|
+
* so a sprite texel is exactly one low-resolution pixel.
|
|
12
|
+
*/
|
|
13
|
+
import { PerspectiveCamera, Vector3 } from "three/webgpu";
|
|
14
|
+
import type { StyleKit } from "../kit.js";
|
|
15
|
+
/**
|
|
16
|
+
* The pixel style's palette (DawnBringer 16). The asset library's
|
|
17
|
+
* manifest/pixel.json carries the same list; its test keeps them equal.
|
|
18
|
+
*/
|
|
19
|
+
export declare const PIXEL_PALETTE: readonly string[];
|
|
20
|
+
export interface PixelStyleOptions {
|
|
21
|
+
/** Sprite texels (and so screen pixels of the low-res picture) per metre at the focus. Default 1 / SPRITE_TEXEL (16). */
|
|
22
|
+
readonly texelsPerMetre?: number;
|
|
23
|
+
/** Dither on the world's band edges, in light (0..1). Default 0.025. */
|
|
24
|
+
readonly dither?: number;
|
|
25
|
+
/** Sprite saturation before the palette snap. Default 1.25. */
|
|
26
|
+
readonly saturation?: number;
|
|
27
|
+
/** Light levels the world steps through: two dark field tones, then the light pools. Default [0.08, 0.14, 0.3, 0.52, 0.82]. */
|
|
28
|
+
readonly bands?: readonly number[];
|
|
29
|
+
/** Fewest low-res rows, so a tiny window stays legible. Default 120. */
|
|
30
|
+
readonly minRows?: number;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The integer block size (screen pixels per low-res pixel) that puts
|
|
34
|
+
* `texelsPerMetre` low-res rows on each metre of a view `viewMetres` tall.
|
|
35
|
+
*/
|
|
36
|
+
export declare function pixelBlock(bufferHeight: number, viewMetres: number, texelsPerMetre: number, minRows?: number): number;
|
|
37
|
+
/** Height in metres the camera sees at the ground point it looks at (perspective cameras; orthographic: its frustum). */
|
|
38
|
+
export declare function viewMetres(camera: PerspectiveCamera | {
|
|
39
|
+
isOrthographicCamera?: boolean;
|
|
40
|
+
top?: number;
|
|
41
|
+
bottom?: number;
|
|
42
|
+
zoom?: number;
|
|
43
|
+
}, forward: Vector3, position: Vector3): number;
|
|
44
|
+
/** The pixel style with its options. */
|
|
45
|
+
export declare function createPixelStyle(o?: PixelStyleOptions): StyleKit;
|
|
46
|
+
export declare const pixelKit: StyleKit;
|