@multiplekex/shallot 0.1.12 → 0.2.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/package.json +3 -4
- package/src/core/builder.ts +71 -32
- package/src/core/component.ts +25 -11
- package/src/core/index.ts +14 -13
- package/src/core/math.ts +135 -0
- package/src/core/runtime.ts +0 -1
- package/src/core/state.ts +9 -68
- package/src/core/xml.ts +381 -265
- package/src/editor/format.ts +5 -0
- package/src/editor/index.ts +101 -0
- package/src/extras/arrows/index.ts +28 -69
- package/src/extras/gradient/index.ts +36 -52
- package/src/extras/lines/index.ts +51 -122
- package/src/extras/orbit/index.ts +40 -15
- package/src/extras/text/font.ts +546 -0
- package/src/extras/text/index.ts +158 -204
- package/src/extras/text/sdf.ts +429 -0
- package/src/standard/activity/index.ts +172 -0
- package/src/standard/compute/graph.ts +23 -23
- package/src/standard/compute/index.ts +76 -61
- package/src/standard/defaults.ts +8 -5
- package/src/standard/index.ts +1 -0
- package/src/standard/input/index.ts +30 -19
- package/src/standard/loading/index.ts +18 -13
- package/src/standard/render/bvh/blas.ts +752 -0
- package/src/standard/render/bvh/radix.ts +476 -0
- package/src/standard/render/bvh/structs.ts +167 -0
- package/src/standard/render/bvh/tlas.ts +886 -0
- package/src/standard/render/bvh/traverse.ts +467 -0
- package/src/standard/render/camera.ts +302 -27
- package/src/standard/render/data.ts +93 -0
- package/src/standard/render/depth.ts +117 -0
- package/src/standard/render/forward/index.ts +259 -0
- package/src/standard/render/forward/raster.ts +228 -0
- package/src/standard/render/index.ts +443 -70
- package/src/standard/render/indirect.ts +40 -0
- package/src/standard/render/instance.ts +214 -0
- package/src/standard/render/intersection.ts +72 -0
- package/src/standard/render/light.ts +16 -16
- package/src/standard/render/mesh/index.ts +67 -75
- package/src/standard/render/mesh/unified.ts +96 -0
- package/src/standard/render/{transparent.ts → overlay.ts} +14 -15
- package/src/standard/render/pass.ts +10 -4
- package/src/standard/render/postprocess.ts +142 -64
- package/src/standard/render/ray.ts +61 -0
- package/src/standard/render/scene.ts +38 -164
- package/src/standard/render/shaders.ts +484 -0
- package/src/standard/render/surface/compile.ts +3 -10
- package/src/standard/render/surface/index.ts +60 -30
- package/src/standard/render/surface/noise.ts +45 -0
- package/src/standard/render/surface/structs.ts +60 -19
- package/src/standard/render/surface/wgsl.ts +573 -0
- package/src/standard/render/triangle.ts +84 -0
- package/src/standard/transforms/index.ts +4 -6
- package/src/standard/tween/index.ts +10 -1
- package/src/standard/tween/sequence.ts +24 -16
- package/src/standard/tween/tween.ts +67 -16
- package/src/core/types.ts +0 -37
- package/src/standard/compute/inspect.ts +0 -201
- package/src/standard/compute/pass.ts +0 -23
- package/src/standard/compute/timing.ts +0 -139
- package/src/standard/render/forward.ts +0 -273
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { Node } from "../core";
|
|
2
|
+
|
|
3
|
+
export { format } from "./format";
|
|
4
|
+
|
|
5
|
+
type Add = { type: "add"; parent: Node | null; node: Node; index: number };
|
|
6
|
+
type Remove = { type: "remove"; parent: Node | null; node: Node; index: number };
|
|
7
|
+
type SetAttr = { type: "setAttr"; node: Node; name: string; prev: string | null; next: string };
|
|
8
|
+
|
|
9
|
+
export type Command = Add | Remove | SetAttr;
|
|
10
|
+
|
|
11
|
+
export type History = { undo: Command[]; redo: Command[] };
|
|
12
|
+
|
|
13
|
+
export type Selection = Set<Node>;
|
|
14
|
+
|
|
15
|
+
function getChildren(parent: Node | null, nodes: Node[]): Node[] {
|
|
16
|
+
return parent ? parent.children : nodes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function apply(nodes: Node[], cmd: Command): void {
|
|
20
|
+
switch (cmd.type) {
|
|
21
|
+
case "add": {
|
|
22
|
+
const children = getChildren(cmd.parent, nodes);
|
|
23
|
+
children.splice(cmd.index, 0, cmd.node);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case "remove": {
|
|
27
|
+
const children = getChildren(cmd.parent, nodes);
|
|
28
|
+
children.splice(cmd.index, 1);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case "setAttr": {
|
|
32
|
+
const idx = cmd.node.attrs.findIndex((a) => a.name === cmd.name);
|
|
33
|
+
if (idx >= 0) {
|
|
34
|
+
cmd.node.attrs[idx].value = cmd.next;
|
|
35
|
+
} else {
|
|
36
|
+
cmd.node.attrs.push({ name: cmd.name, value: cmd.next });
|
|
37
|
+
}
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function reverse(nodes: Node[], cmd: Command): void {
|
|
44
|
+
switch (cmd.type) {
|
|
45
|
+
case "add": {
|
|
46
|
+
const children = getChildren(cmd.parent, nodes);
|
|
47
|
+
children.splice(cmd.index, 1);
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
case "remove": {
|
|
51
|
+
const children = getChildren(cmd.parent, nodes);
|
|
52
|
+
children.splice(cmd.index, 0, cmd.node);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
case "setAttr": {
|
|
56
|
+
const idx = cmd.node.attrs.findIndex((a) => a.name === cmd.name);
|
|
57
|
+
if (cmd.prev === null) {
|
|
58
|
+
if (idx >= 0) cmd.node.attrs.splice(idx, 1);
|
|
59
|
+
} else if (idx >= 0) {
|
|
60
|
+
cmd.node.attrs[idx].value = cmd.prev;
|
|
61
|
+
}
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export function execute(history: History, nodes: Node[], cmd: Command): void {
|
|
68
|
+
apply(nodes, cmd);
|
|
69
|
+
history.undo.push(cmd);
|
|
70
|
+
history.redo.length = 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export function undo(history: History, nodes: Node[]): void {
|
|
74
|
+
const cmd = history.undo.pop();
|
|
75
|
+
if (!cmd) return;
|
|
76
|
+
reverse(nodes, cmd);
|
|
77
|
+
history.redo.push(cmd);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function redo(history: History, nodes: Node[]): void {
|
|
81
|
+
const cmd = history.redo.pop();
|
|
82
|
+
if (!cmd) return;
|
|
83
|
+
apply(nodes, cmd);
|
|
84
|
+
history.undo.push(cmd);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function select(selection: Selection, ...nodesToSelect: Node[]): void {
|
|
88
|
+
for (const node of nodesToSelect) {
|
|
89
|
+
selection.add(node);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function deselect(selection: Selection, ...nodesToDeselect: Node[]): void {
|
|
94
|
+
for (const node of nodesToDeselect) {
|
|
95
|
+
selection.delete(node);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function clear(selection: Selection): void {
|
|
100
|
+
selection.clear();
|
|
101
|
+
}
|
|
@@ -1,15 +1,24 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import {
|
|
2
|
+
MAX_ENTITIES,
|
|
3
|
+
resource,
|
|
4
|
+
createFieldProxy,
|
|
5
|
+
type Plugin,
|
|
6
|
+
type State,
|
|
7
|
+
type System,
|
|
8
|
+
type FieldProxy,
|
|
9
|
+
} from "../../core";
|
|
10
|
+
import { setTraits } from "../../core/component";
|
|
3
11
|
import { Compute, ComputePlugin, createEntityIdBuffer } from "../../standard/compute";
|
|
4
12
|
import {
|
|
5
13
|
Render,
|
|
6
14
|
RenderPlugin,
|
|
7
|
-
DEPTH_FORMAT,
|
|
8
15
|
Pass,
|
|
9
16
|
registerDraw,
|
|
10
17
|
type Draw,
|
|
11
18
|
type SharedPassContext,
|
|
12
19
|
} from "../../standard/render";
|
|
20
|
+
import { DEPTH_FORMAT } from "../../standard/render/scene";
|
|
21
|
+
import { SCENE_STRUCT_WGSL } from "../../standard/render/shaders";
|
|
13
22
|
import { Transform } from "../../standard/transforms";
|
|
14
23
|
import { Line, Lines, LinesPlugin } from "../lines";
|
|
15
24
|
|
|
@@ -17,44 +26,16 @@ export const ArrowData = {
|
|
|
17
26
|
data: new Float32Array(MAX_ENTITIES * 4),
|
|
18
27
|
};
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
function arrowProxy(offset: number): ArrowProxy {
|
|
23
|
-
const data = ArrowData.data;
|
|
24
|
-
|
|
25
|
-
function getValue(eid: number): number {
|
|
26
|
-
return data[eid * 4 + offset];
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function setValue(eid: number, value: number): void {
|
|
30
|
-
data[eid * 4 + offset] = value;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return new Proxy([] as unknown as ArrowProxy, {
|
|
34
|
-
get(_, prop) {
|
|
35
|
-
if (prop === "get") return getValue;
|
|
36
|
-
if (prop === "set") return setValue;
|
|
37
|
-
const eid = Number(prop);
|
|
38
|
-
if (Number.isNaN(eid)) return undefined;
|
|
39
|
-
return getValue(eid);
|
|
40
|
-
},
|
|
41
|
-
set(_, prop, value) {
|
|
42
|
-
const eid = Number(prop);
|
|
43
|
-
if (Number.isNaN(eid)) return false;
|
|
44
|
-
setValue(eid, value);
|
|
45
|
-
return true;
|
|
46
|
-
},
|
|
47
|
-
});
|
|
48
|
-
}
|
|
29
|
+
const data = ArrowData.data;
|
|
49
30
|
|
|
50
31
|
export const Arrow: {
|
|
51
|
-
start:
|
|
52
|
-
end:
|
|
53
|
-
size:
|
|
32
|
+
start: FieldProxy;
|
|
33
|
+
end: FieldProxy;
|
|
34
|
+
size: FieldProxy;
|
|
54
35
|
} = {
|
|
55
|
-
start:
|
|
56
|
-
end:
|
|
57
|
-
size:
|
|
36
|
+
start: createFieldProxy(data, 4, 0),
|
|
37
|
+
end: createFieldProxy(data, 4, 1),
|
|
38
|
+
size: createFieldProxy(data, 4, 2),
|
|
58
39
|
};
|
|
59
40
|
|
|
60
41
|
setTraits(Arrow, {
|
|
@@ -63,11 +44,6 @@ setTraits(Arrow, {
|
|
|
63
44
|
end: 1,
|
|
64
45
|
size: 1,
|
|
65
46
|
}),
|
|
66
|
-
accessors: {
|
|
67
|
-
start: Arrow.start,
|
|
68
|
-
end: Arrow.end,
|
|
69
|
-
size: Arrow.size,
|
|
70
|
-
},
|
|
71
47
|
});
|
|
72
48
|
|
|
73
49
|
export interface ArrowsConfig {
|
|
@@ -87,16 +63,7 @@ struct VertexOutput {
|
|
|
87
63
|
@location(0) color: vec4<f32>,
|
|
88
64
|
}
|
|
89
65
|
|
|
90
|
-
|
|
91
|
-
viewProj: mat4x4<f32>,
|
|
92
|
-
cameraWorld: mat4x4<f32>,
|
|
93
|
-
ambientColor: vec4<f32>,
|
|
94
|
-
sunDirection: vec4<f32>,
|
|
95
|
-
sunColor: vec4<f32>,
|
|
96
|
-
cameraMode: f32,
|
|
97
|
-
cameraSize: f32,
|
|
98
|
-
viewport: vec2<f32>,
|
|
99
|
-
}
|
|
66
|
+
${SCENE_STRUCT_WGSL}
|
|
100
67
|
|
|
101
68
|
struct ArrowData {
|
|
102
69
|
start: f32,
|
|
@@ -133,48 +100,40 @@ fn vs(@builtin(vertex_index) vid: u32, @builtin(instance_index) iid: u32) -> Ver
|
|
|
133
100
|
let line = lines[eid];
|
|
134
101
|
let transform = matrices[eid];
|
|
135
102
|
|
|
136
|
-
// Extract scale from transform matrix (use X axis scale)
|
|
137
103
|
let scale = length(transform[0].xyz);
|
|
138
104
|
|
|
139
105
|
let start = transform[3].xyz;
|
|
140
106
|
let rotation = mat3x3<f32>(transform[0].xyz, transform[1].xyz, transform[2].xyz);
|
|
141
107
|
let end = start + rotation * line.offset;
|
|
142
108
|
|
|
143
|
-
// Project start and end to clip space
|
|
144
109
|
let startClip = scene.viewProj * vec4(start, 1.0);
|
|
145
110
|
let endClip = scene.viewProj * vec4(end, 1.0);
|
|
146
111
|
|
|
147
|
-
// Convert to screen space (pixels from center)
|
|
148
112
|
let startScreen = (startClip.xy / startClip.w) * scene.viewport * 0.5;
|
|
149
113
|
let endScreen = (endClip.xy / endClip.w) * scene.viewport * 0.5;
|
|
150
114
|
|
|
151
|
-
// Anchor point in screen space
|
|
152
115
|
let anchorScreen = select(startScreen, endScreen, isEnd);
|
|
153
116
|
let anchorDepth = select(startClip.z / startClip.w, endClip.z / endClip.w, isEnd);
|
|
154
117
|
|
|
155
|
-
// Line direction in screen space (correct for aspect ratio)
|
|
156
118
|
let dir = endScreen - startScreen;
|
|
157
119
|
let len = length(dir);
|
|
158
120
|
let normDir = select(vec2(1.0, 0.0), dir / len, len > 0.0001);
|
|
159
121
|
let perp = vec2(-normDir.y, normDir.x);
|
|
160
122
|
|
|
161
|
-
// Arrow direction (pointing away from line)
|
|
162
123
|
let arrowDir = select(-normDir, normDir, isEnd);
|
|
163
124
|
|
|
164
|
-
|
|
165
|
-
let arrowLengthPx = arrow.size * line.thickness * 4.0 * scale;
|
|
166
|
-
let arrowWidthPx = arrow.size * line.thickness * 2.0 * scale;
|
|
125
|
+
let viewportScale = scene.viewport.y / 1080.0;
|
|
126
|
+
let arrowLengthPx = arrow.size * line.thickness * 4.0 * scale * viewportScale;
|
|
127
|
+
let arrowWidthPx = arrow.size * line.thickness * 2.0 * scale * viewportScale;
|
|
167
128
|
|
|
168
|
-
// Build triangle in screen space
|
|
169
129
|
var posScreen: vec2<f32>;
|
|
170
130
|
switch vid {
|
|
171
|
-
case 0u: { posScreen = anchorScreen; }
|
|
131
|
+
case 0u: { posScreen = anchorScreen; }
|
|
172
132
|
case 1u: { posScreen = anchorScreen - arrowDir * arrowLengthPx + perp * arrowWidthPx; }
|
|
173
133
|
case 2u: { posScreen = anchorScreen - arrowDir * arrowLengthPx - perp * arrowWidthPx; }
|
|
174
134
|
default: { posScreen = anchorScreen; }
|
|
175
135
|
}
|
|
176
136
|
|
|
177
|
-
// Convert back to NDC
|
|
178
137
|
let pos = posScreen / (scene.viewport * 0.5);
|
|
179
138
|
|
|
180
139
|
var out: VertexOutput;
|
|
@@ -252,7 +211,7 @@ function createArrowsDraw(config: ArrowsConfig): Draw {
|
|
|
252
211
|
|
|
253
212
|
return {
|
|
254
213
|
id: "arrows",
|
|
255
|
-
pass: Pass.
|
|
214
|
+
pass: Pass.Overlay,
|
|
256
215
|
order: 1,
|
|
257
216
|
|
|
258
217
|
execute() {},
|
|
@@ -285,13 +244,13 @@ function createArrowsDraw(config: ArrowsConfig): Draw {
|
|
|
285
244
|
};
|
|
286
245
|
}
|
|
287
246
|
|
|
288
|
-
export interface
|
|
247
|
+
export interface Arrows {
|
|
289
248
|
buffer: GPUBuffer;
|
|
290
249
|
entityIds: GPUBuffer;
|
|
291
250
|
count: number;
|
|
292
251
|
}
|
|
293
252
|
|
|
294
|
-
export const Arrows = resource<
|
|
253
|
+
export const Arrows = resource<Arrows>("arrows");
|
|
295
254
|
|
|
296
255
|
const arrowEntityIdArray = new Uint32Array(MAX_ENTITIES * 2);
|
|
297
256
|
|
|
@@ -338,7 +297,7 @@ export const ArrowsPlugin: Plugin = {
|
|
|
338
297
|
|
|
339
298
|
const { device } = compute;
|
|
340
299
|
|
|
341
|
-
const arrowsState:
|
|
300
|
+
const arrowsState: Arrows = {
|
|
342
301
|
buffer: device.createBuffer({
|
|
343
302
|
label: "arrows",
|
|
344
303
|
size: MAX_ENTITIES * 4 * 4,
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { MAX_ENTITIES, resource } from "../../core";
|
|
2
2
|
import { setTraits, type FieldAccessor } from "../../core/component";
|
|
3
3
|
import type { Plugin, State, System } from "../../core";
|
|
4
|
-
import { Compute, type ComputeNode, type ExecutionContext } from "../../standard/compute";
|
|
5
|
-
import { Pass } from "../../standard/render/pass";
|
|
4
|
+
import { Canvas, Compute, type ComputeNode, type ExecutionContext } from "../../standard/compute";
|
|
6
5
|
|
|
7
6
|
export type PhysicsConfig = {
|
|
8
7
|
springConstant: number;
|
|
@@ -12,8 +11,8 @@ export type PhysicsConfig = {
|
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
export const DEFAULT_PHYSICS_CONFIG: PhysicsConfig = {
|
|
15
|
-
springConstant: 0.
|
|
16
|
-
damping: 0.
|
|
14
|
+
springConstant: 0.72,
|
|
15
|
+
damping: 0.046,
|
|
17
16
|
bounds: { min: -20, max: 120 },
|
|
18
17
|
targetThreshold: 5,
|
|
19
18
|
};
|
|
@@ -136,8 +135,8 @@ function generateBubbles(
|
|
|
136
135
|
const x = physics.bounds.min + random() * range;
|
|
137
136
|
const y = physics.bounds.min + random() * range;
|
|
138
137
|
const color = generateHslColor(random);
|
|
139
|
-
const vx = (random() - 0.5) *
|
|
140
|
-
const vy = (random() - 0.5) *
|
|
138
|
+
const vx = (random() - 0.5) * 18;
|
|
139
|
+
const vy = (random() - 0.5) * 18;
|
|
141
140
|
const targetX = physics.bounds.min + random() * range;
|
|
142
141
|
const targetY = physics.bounds.min + random() * range;
|
|
143
142
|
bubbles.push({ x, y, color, vx, vy, targetX, targetY });
|
|
@@ -155,17 +154,22 @@ function distance(x1: number, y1: number, x2: number, y2: number): number {
|
|
|
155
154
|
return Math.sqrt(dx * dx + dy * dy);
|
|
156
155
|
}
|
|
157
156
|
|
|
158
|
-
function stepBubble(
|
|
157
|
+
function stepBubble(
|
|
158
|
+
bubble: Bubble,
|
|
159
|
+
dt: number,
|
|
160
|
+
physics: PhysicsConfig = DEFAULT_PHYSICS_CONFIG
|
|
161
|
+
): Bubble {
|
|
159
162
|
let { x, y, vx, vy, targetX, targetY, color } = bubble;
|
|
160
163
|
|
|
161
|
-
vx += (targetX - x) * physics.springConstant;
|
|
162
|
-
vy += (targetY - y) * physics.springConstant;
|
|
164
|
+
vx += (targetX - x) * physics.springConstant * dt;
|
|
165
|
+
vy += (targetY - y) * physics.springConstant * dt;
|
|
163
166
|
|
|
164
|
-
|
|
165
|
-
|
|
167
|
+
const dampingFactor = Math.pow(physics.damping, dt);
|
|
168
|
+
vx *= dampingFactor;
|
|
169
|
+
vy *= dampingFactor;
|
|
166
170
|
|
|
167
|
-
x += vx;
|
|
168
|
-
y += vy;
|
|
171
|
+
x += vx * dt;
|
|
172
|
+
y += vy * dt;
|
|
169
173
|
|
|
170
174
|
x = clamp(x, physics.bounds.min, physics.bounds.max);
|
|
171
175
|
y = clamp(y, physics.bounds.min, physics.bounds.max);
|
|
@@ -427,23 +431,9 @@ setTraits(Gradient, {
|
|
|
427
431
|
boundsMin: DEFAULT_PHYSICS_CONFIG.bounds.min,
|
|
428
432
|
boundsMax: DEFAULT_PHYSICS_CONFIG.bounds.max,
|
|
429
433
|
}),
|
|
430
|
-
accessors: {
|
|
431
|
-
angle: Gradient.angle,
|
|
432
|
-
enabled: Gradient.enabled,
|
|
433
|
-
bubbleSize: Gradient.bubbleSize,
|
|
434
|
-
bubbleBlur: Gradient.bubbleBlur,
|
|
435
|
-
textureEnabled: Gradient.textureEnabled,
|
|
436
|
-
textureOpacity: Gradient.textureOpacity,
|
|
437
|
-
overlayEnabled: Gradient.overlayEnabled,
|
|
438
|
-
bubbleCount: Gradient.bubbleCount,
|
|
439
|
-
springConstant: Gradient.springConstant,
|
|
440
|
-
damping: Gradient.damping,
|
|
441
|
-
boundsMin: Gradient.boundsMin,
|
|
442
|
-
boundsMax: Gradient.boundsMax,
|
|
443
|
-
},
|
|
444
434
|
});
|
|
445
435
|
|
|
446
|
-
export interface
|
|
436
|
+
export interface Gradients {
|
|
447
437
|
bubbles: Map<number, Bubble[]>;
|
|
448
438
|
randoms: Map<number, () => number>;
|
|
449
439
|
width: number;
|
|
@@ -470,23 +460,23 @@ export interface GradientState {
|
|
|
470
460
|
bubbleCount: number;
|
|
471
461
|
}
|
|
472
462
|
|
|
473
|
-
export const
|
|
463
|
+
export const Gradients = resource<Gradients>("gradient");
|
|
474
464
|
|
|
475
465
|
export function clearGradientState(state: State): void {
|
|
476
|
-
const res =
|
|
466
|
+
const res = Gradients.from(state);
|
|
477
467
|
if (!res) return;
|
|
478
468
|
res.bubbles.clear();
|
|
479
469
|
res.randoms.clear();
|
|
480
470
|
}
|
|
481
471
|
|
|
482
472
|
export function getBubbles(state: State, eid: number): Bubble[] | undefined {
|
|
483
|
-
const res =
|
|
473
|
+
const res = Gradients.from(state);
|
|
484
474
|
if (!res) return undefined;
|
|
485
475
|
return res.bubbles.get(eid);
|
|
486
476
|
}
|
|
487
477
|
|
|
488
478
|
export function setBubbles(state: State, eid: number, bubbles: Bubble[]): void {
|
|
489
|
-
const res =
|
|
479
|
+
const res = Gradients.from(state);
|
|
490
480
|
if (!res) return;
|
|
491
481
|
res.bubbles.set(eid, bubbles);
|
|
492
482
|
}
|
|
@@ -497,7 +487,7 @@ export function updateBubble(
|
|
|
497
487
|
index: number,
|
|
498
488
|
updater: (bubble: Bubble) => Bubble
|
|
499
489
|
): void {
|
|
500
|
-
const res =
|
|
490
|
+
const res = Gradients.from(state);
|
|
501
491
|
if (!res) return;
|
|
502
492
|
const bubbles = res.bubbles.get(eid);
|
|
503
493
|
if (!bubbles || index < 0 || index >= bubbles.length) return;
|
|
@@ -644,11 +634,9 @@ fn setSat(c: vec3f, s: f32) -> vec3f {
|
|
|
644
634
|
return vec3f(0.0);
|
|
645
635
|
}
|
|
646
636
|
|
|
647
|
-
// Sort channels and apply saturation
|
|
648
637
|
var result = vec3f(0.0);
|
|
649
638
|
let range = cmax - cmin;
|
|
650
639
|
|
|
651
|
-
// Apply proportional saturation to each channel
|
|
652
640
|
result.r = (c.r - cmin) * s / range;
|
|
653
641
|
result.g = (c.g - cmin) * s / range;
|
|
654
642
|
result.b = (c.b - cmin) * s / range;
|
|
@@ -657,7 +645,6 @@ fn setSat(c: vec3f, s: f32) -> vec3f {
|
|
|
657
645
|
}
|
|
658
646
|
|
|
659
647
|
fn hueBlend(base: vec3f, blend: vec3f) -> vec3f {
|
|
660
|
-
// W3C CSS Compositing spec: Hue = SetLum(SetSat(Cs, Sat(Cb)), Lum(Cb))
|
|
661
648
|
let withSat = setSat(blend, sat(base));
|
|
662
649
|
return setLum(withSat, lum(base));
|
|
663
650
|
}
|
|
@@ -771,10 +758,9 @@ fn fs(input: VertexOutput) -> @location(0) vec4f {
|
|
|
771
758
|
}
|
|
772
759
|
`;
|
|
773
760
|
|
|
774
|
-
function createCompositeNode(res:
|
|
761
|
+
function createCompositeNode(res: Gradients): ComputeNode {
|
|
775
762
|
return {
|
|
776
763
|
id: "gradient",
|
|
777
|
-
pass: Pass.Opaque,
|
|
778
764
|
inputs: [],
|
|
779
765
|
outputs: [{ id: "scene", access: "write" }],
|
|
780
766
|
|
|
@@ -892,15 +878,14 @@ export const GradientSystem: System = {
|
|
|
892
878
|
|
|
893
879
|
update(state: State) {
|
|
894
880
|
const compute = Compute.from(state);
|
|
895
|
-
const res =
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
res.
|
|
903
|
-
res.height = canvas.height;
|
|
881
|
+
const res = Gradients.from(state);
|
|
882
|
+
const canvas = Canvas.from(state);
|
|
883
|
+
if (!compute || !res || !canvas) return;
|
|
884
|
+
|
|
885
|
+
const { element } = canvas;
|
|
886
|
+
if (res.width !== element.width || res.height !== element.height) {
|
|
887
|
+
res.width = element.width;
|
|
888
|
+
res.height = element.height;
|
|
904
889
|
}
|
|
905
890
|
|
|
906
891
|
for (const eid of state.query([Gradient])) {
|
|
@@ -931,8 +916,9 @@ export const GradientSystem: System = {
|
|
|
931
916
|
}
|
|
932
917
|
|
|
933
918
|
const random = res.randoms.get(eid)!;
|
|
919
|
+
const dt = state.time.deltaTime;
|
|
934
920
|
for (let i = 0; i < b.length; i++) {
|
|
935
|
-
b[i] = updateBubbleTarget(stepBubble(b[i], physics), random, physics);
|
|
921
|
+
b[i] = updateBubbleTarget(stepBubble(b[i], dt, physics), random, physics);
|
|
936
922
|
}
|
|
937
923
|
|
|
938
924
|
if (!bubblesMoved(b)) continue;
|
|
@@ -1006,14 +992,12 @@ export const GradientSystem: System = {
|
|
|
1006
992
|
},
|
|
1007
993
|
};
|
|
1008
994
|
|
|
1009
|
-
export { hashString, createSeededRandom, generateBubbles, stepBubble, parseColor };
|
|
1010
|
-
|
|
1011
995
|
export const GradientPlugin: Plugin = {
|
|
1012
996
|
systems: [GradientSystem],
|
|
1013
997
|
components: { Gradient },
|
|
1014
998
|
|
|
1015
999
|
initialize(state: State) {
|
|
1016
|
-
const gradientState:
|
|
1000
|
+
const gradientState: Gradients = {
|
|
1017
1001
|
bubbles: new Map(),
|
|
1018
1002
|
randoms: new Map(),
|
|
1019
1003
|
width: 0,
|
|
@@ -1040,7 +1024,7 @@ export const GradientPlugin: Plugin = {
|
|
|
1040
1024
|
bubbleCount: 4,
|
|
1041
1025
|
};
|
|
1042
1026
|
|
|
1043
|
-
state.setResource(
|
|
1027
|
+
state.setResource(Gradients, gradientState);
|
|
1044
1028
|
|
|
1045
1029
|
const compute = Compute.from(state);
|
|
1046
1030
|
if (compute) {
|