shardlight 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/LICENSE +21 -0
- package/README.md +328 -0
- package/dist/baker-BmlWqsXG.d.ts +290 -0
- package/dist/chunk-MARSXMGB.js +263 -0
- package/dist/chunk-MARSXMGB.js.map +1 -0
- package/dist/chunk-W7WG7K5R.js +67 -0
- package/dist/chunk-W7WG7K5R.js.map +1 -0
- package/dist/chunk-ZWPHIC3K.js +1786 -0
- package/dist/chunk-ZWPHIC3K.js.map +1 -0
- package/dist/core/index.d.ts +901 -0
- package/dist/core/index.js +3 -0
- package/dist/core/index.js.map +1 -0
- package/dist/createShardLight-DTUyJQML.d.ts +56 -0
- package/dist/effects-bjjSnDyP.d.ts +287 -0
- package/dist/r3f/index.d.ts +59 -0
- package/dist/r3f/index.js +164 -0
- package/dist/r3f/index.js.map +1 -0
- package/dist/react/index.d.ts +62 -0
- package/dist/react/index.js +204 -0
- package/dist/react/index.js.map +1 -0
- package/dist/testing/index.d.ts +44 -0
- package/dist/testing/index.js +81 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/three/index.d.ts +13 -0
- package/dist/three/index.js +4 -0
- package/dist/three/index.js.map +1 -0
- package/package.json +121 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { definedOnly, createLightModel, collapseTrigger } from './chunk-ZWPHIC3K.js';
|
|
2
|
+
import * as THREE2 from 'three';
|
|
3
|
+
|
|
4
|
+
var cache = /* @__PURE__ */ new Map();
|
|
5
|
+
function acquireTexture(key, source) {
|
|
6
|
+
const existing = cache.get(key);
|
|
7
|
+
if (existing) {
|
|
8
|
+
existing.refs += 1;
|
|
9
|
+
return existing.texture;
|
|
10
|
+
}
|
|
11
|
+
const texture = createTexture(source);
|
|
12
|
+
cache.set(key, { texture, refs: 1 });
|
|
13
|
+
return texture;
|
|
14
|
+
}
|
|
15
|
+
function releaseTexture(key) {
|
|
16
|
+
const entry = cache.get(key);
|
|
17
|
+
if (!entry) return;
|
|
18
|
+
entry.refs -= 1;
|
|
19
|
+
if (entry.refs <= 0) {
|
|
20
|
+
cache.delete(key);
|
|
21
|
+
entry.texture.dispose();
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
function textureCacheSize() {
|
|
25
|
+
return cache.size;
|
|
26
|
+
}
|
|
27
|
+
function clearTextureCache() {
|
|
28
|
+
for (const entry of cache.values()) entry.texture.dispose();
|
|
29
|
+
cache.clear();
|
|
30
|
+
}
|
|
31
|
+
function createTexture(source) {
|
|
32
|
+
if (source.type === "bitmap") {
|
|
33
|
+
const texture2 = new THREE2.Texture(source.bitmap);
|
|
34
|
+
texture2.needsUpdate = true;
|
|
35
|
+
texture2.colorSpace = THREE2.SRGBColorSpace;
|
|
36
|
+
return texture2;
|
|
37
|
+
}
|
|
38
|
+
if (source.type === "canvas") {
|
|
39
|
+
const texture2 = new THREE2.CanvasTexture(source.canvas);
|
|
40
|
+
texture2.colorSpace = THREE2.SRGBColorSpace;
|
|
41
|
+
texture2.needsUpdate = true;
|
|
42
|
+
return texture2;
|
|
43
|
+
}
|
|
44
|
+
const texture = new THREE2.TextureLoader().load(source.url);
|
|
45
|
+
texture.colorSpace = THREE2.SRGBColorSpace;
|
|
46
|
+
return texture;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// src/three/createShardLight.ts
|
|
50
|
+
function createShardLight(options = {}) {
|
|
51
|
+
let opts = {
|
|
52
|
+
size: 0.5,
|
|
53
|
+
resolution: 1024,
|
|
54
|
+
autoUpdate: true,
|
|
55
|
+
billboard: false,
|
|
56
|
+
...definedOnly(options)
|
|
57
|
+
};
|
|
58
|
+
const object = new THREE2.Group();
|
|
59
|
+
let geometry = new THREE2.PlaneGeometry(opts.size, opts.size);
|
|
60
|
+
const entries = /* @__PURE__ */ new Map();
|
|
61
|
+
const clock = new THREE2.Clock();
|
|
62
|
+
let disposed = false;
|
|
63
|
+
const model = createLightModel({
|
|
64
|
+
preset: opts.preset,
|
|
65
|
+
config: opts.config,
|
|
66
|
+
shards: opts.shards,
|
|
67
|
+
effects: opts.effects,
|
|
68
|
+
color: opts.color,
|
|
69
|
+
resolution: opts.resolution,
|
|
70
|
+
rayScale: opts.rayScale,
|
|
71
|
+
baker: opts.baker,
|
|
72
|
+
hoverEase: opts.hoverEase,
|
|
73
|
+
collapseEase: opts.collapseEase,
|
|
74
|
+
accepts: ["bitmap", "canvas"],
|
|
75
|
+
onError: (error) => {
|
|
76
|
+
console.error("[shardlight] bake error", error);
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
let hitMesh = null;
|
|
80
|
+
ensureHitMesh();
|
|
81
|
+
function createMaterial(layer) {
|
|
82
|
+
if (opts.material) return opts.material(layer);
|
|
83
|
+
const material = new THREE2.MeshBasicMaterial({
|
|
84
|
+
transparent: true,
|
|
85
|
+
depthWrite: false,
|
|
86
|
+
toneMapped: opts.toneMapped ?? false,
|
|
87
|
+
depthTest: opts.depthTest ?? true,
|
|
88
|
+
side: THREE2.DoubleSide,
|
|
89
|
+
blending: layer.blend === "add" ? THREE2.AdditiveBlending : THREE2.NormalBlending
|
|
90
|
+
});
|
|
91
|
+
return material;
|
|
92
|
+
}
|
|
93
|
+
function createHitMesh(size, hitRadius) {
|
|
94
|
+
const hitGeometry = new THREE2.CircleGeometry(hitRadius * size / 2, 24);
|
|
95
|
+
const hitMaterial = new THREE2.MeshBasicMaterial({
|
|
96
|
+
transparent: true,
|
|
97
|
+
opacity: 0,
|
|
98
|
+
depthWrite: false
|
|
99
|
+
});
|
|
100
|
+
const mesh = new THREE2.Mesh(hitGeometry, hitMaterial);
|
|
101
|
+
mesh.name = "shardlight-hit";
|
|
102
|
+
object.add(mesh);
|
|
103
|
+
return mesh;
|
|
104
|
+
}
|
|
105
|
+
function ensureHitMesh() {
|
|
106
|
+
const wanted = opts.hitRadius !== void 0 || model.resolved.effects.some((effect) => effect.type === "hover") || collapseTrigger(model.resolved.effects) !== "none";
|
|
107
|
+
if (!wanted) {
|
|
108
|
+
if (hitMesh) {
|
|
109
|
+
hitMesh.geometry.dispose();
|
|
110
|
+
hitMesh.material.dispose();
|
|
111
|
+
hitMesh.removeFromParent();
|
|
112
|
+
hitMesh = null;
|
|
113
|
+
}
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const radius = opts.hitRadius ?? 1;
|
|
117
|
+
if (!hitMesh) hitMesh = createHitMesh(opts.size, radius);
|
|
118
|
+
else resizeHitMesh(hitMesh, opts.size, radius);
|
|
119
|
+
}
|
|
120
|
+
function applyTexture(entry, layer) {
|
|
121
|
+
if (!layer.source) return;
|
|
122
|
+
if (entry.textureKey) releaseTexture(entry.textureKey);
|
|
123
|
+
entry.textureKey = layer.key;
|
|
124
|
+
entry.material.map = acquireTexture(layer.key, layer.source);
|
|
125
|
+
entry.material.needsUpdate = true;
|
|
126
|
+
entry.mesh.visible = true;
|
|
127
|
+
}
|
|
128
|
+
function beforeRender(_renderer, _scene, camera) {
|
|
129
|
+
if (disposed) return;
|
|
130
|
+
if (opts.billboard) {
|
|
131
|
+
const position = new THREE2.Vector3();
|
|
132
|
+
camera.getWorldPosition(position);
|
|
133
|
+
object.lookAt(position);
|
|
134
|
+
}
|
|
135
|
+
if (opts.autoUpdate) {
|
|
136
|
+
const dt = clock.getDelta();
|
|
137
|
+
if (dt > 0) model.tick(dt);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function syncLayers(layers) {
|
|
141
|
+
const byId = new Map(layers.map((layer) => [layer.id, layer]));
|
|
142
|
+
for (const [id, entry] of [...entries]) {
|
|
143
|
+
if (byId.has(id)) continue;
|
|
144
|
+
removeEntry(id, entry);
|
|
145
|
+
}
|
|
146
|
+
for (const layer of layers) {
|
|
147
|
+
let entry = entries.get(layer.id);
|
|
148
|
+
if (entry && entry.key !== layer.key) {
|
|
149
|
+
if (entry.textureKey) releaseTexture(entry.textureKey);
|
|
150
|
+
entry.textureKey = null;
|
|
151
|
+
entry.key = layer.key;
|
|
152
|
+
entry.material.map = null;
|
|
153
|
+
entry.material.needsUpdate = true;
|
|
154
|
+
entry.mesh.visible = false;
|
|
155
|
+
if (layer.source) applyTexture(entry, layer);
|
|
156
|
+
} else if (entry) {
|
|
157
|
+
if (!entry.textureKey && layer.source) applyTexture(entry, layer);
|
|
158
|
+
} else {
|
|
159
|
+
const material = createMaterial(layer);
|
|
160
|
+
const mesh = new THREE2.Mesh(geometry, material);
|
|
161
|
+
mesh.name = layer.id;
|
|
162
|
+
mesh.visible = false;
|
|
163
|
+
mesh.renderOrder = opts.renderOrder ?? 0;
|
|
164
|
+
mesh.onBeforeRender = beforeRender;
|
|
165
|
+
entry = {
|
|
166
|
+
mesh,
|
|
167
|
+
material,
|
|
168
|
+
key: layer.key,
|
|
169
|
+
textureKey: null,
|
|
170
|
+
channel: layer.channel
|
|
171
|
+
};
|
|
172
|
+
entries.set(layer.id, entry);
|
|
173
|
+
if (layer.source) applyTexture(entry, layer);
|
|
174
|
+
object.add(mesh);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
function removeEntry(id, entry) {
|
|
179
|
+
entries.delete(id);
|
|
180
|
+
if (entry.textureKey) releaseTexture(entry.textureKey);
|
|
181
|
+
entry.mesh.removeFromParent();
|
|
182
|
+
entry.material.dispose();
|
|
183
|
+
}
|
|
184
|
+
function applyFrame(values) {
|
|
185
|
+
for (const entry of entries.values()) {
|
|
186
|
+
const channel = values.channel(entry.channel);
|
|
187
|
+
entry.mesh.scale.set(channel.scale, channel.scale, 1);
|
|
188
|
+
entry.mesh.rotation.z = channel.rotation * Math.PI / 180;
|
|
189
|
+
entry.material.opacity = channel.opacity * values.opacity;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
const unsubscribeLayers = model.subscribe(syncLayers);
|
|
193
|
+
const unsubscribeFrame = model.onFrame(applyFrame);
|
|
194
|
+
model.ready.then(() => opts.onReady?.());
|
|
195
|
+
const controller = {
|
|
196
|
+
object,
|
|
197
|
+
model,
|
|
198
|
+
set(values) {
|
|
199
|
+
model.set(values);
|
|
200
|
+
},
|
|
201
|
+
setHover(hovered) {
|
|
202
|
+
model.setHover(hovered);
|
|
203
|
+
},
|
|
204
|
+
setCollapsed(collapsed) {
|
|
205
|
+
model.setCollapsed(collapsed);
|
|
206
|
+
},
|
|
207
|
+
toggleCollapsed() {
|
|
208
|
+
model.toggleCollapsed();
|
|
209
|
+
},
|
|
210
|
+
update(patch) {
|
|
211
|
+
if (disposed) return;
|
|
212
|
+
const previousSize = opts.size;
|
|
213
|
+
opts = { ...opts, ...definedOnly(patch) };
|
|
214
|
+
if (patch.size !== void 0 && patch.size !== previousSize) {
|
|
215
|
+
geometry.dispose();
|
|
216
|
+
geometry = new THREE2.PlaneGeometry(opts.size, opts.size);
|
|
217
|
+
for (const entry of entries.values()) entry.mesh.geometry = geometry;
|
|
218
|
+
}
|
|
219
|
+
model.update({
|
|
220
|
+
preset: opts.preset,
|
|
221
|
+
config: opts.config,
|
|
222
|
+
shards: opts.shards,
|
|
223
|
+
effects: opts.effects,
|
|
224
|
+
color: opts.color,
|
|
225
|
+
resolution: opts.resolution,
|
|
226
|
+
rayScale: opts.rayScale,
|
|
227
|
+
baker: opts.baker,
|
|
228
|
+
hoverEase: opts.hoverEase,
|
|
229
|
+
collapseEase: opts.collapseEase
|
|
230
|
+
});
|
|
231
|
+
ensureHitMesh();
|
|
232
|
+
},
|
|
233
|
+
tick(dt) {
|
|
234
|
+
model.tick(dt);
|
|
235
|
+
},
|
|
236
|
+
ready: model.ready,
|
|
237
|
+
dispose() {
|
|
238
|
+
if (disposed) return;
|
|
239
|
+
disposed = true;
|
|
240
|
+
unsubscribeLayers();
|
|
241
|
+
unsubscribeFrame();
|
|
242
|
+
model.dispose();
|
|
243
|
+
for (const [id, entry] of [...entries]) removeEntry(id, entry);
|
|
244
|
+
geometry.dispose();
|
|
245
|
+
if (hitMesh) {
|
|
246
|
+
hitMesh.geometry.dispose();
|
|
247
|
+
hitMesh.material.dispose();
|
|
248
|
+
hitMesh.removeFromParent();
|
|
249
|
+
hitMesh = null;
|
|
250
|
+
}
|
|
251
|
+
object.removeFromParent();
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
return controller;
|
|
255
|
+
}
|
|
256
|
+
function resizeHitMesh(mesh, size, hitRadius) {
|
|
257
|
+
mesh.geometry.dispose();
|
|
258
|
+
mesh.geometry = new THREE2.CircleGeometry(hitRadius * size / 2, 24);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export { acquireTexture, clearTextureCache, createShardLight, releaseTexture, textureCacheSize };
|
|
262
|
+
//# sourceMappingURL=chunk-MARSXMGB.js.map
|
|
263
|
+
//# sourceMappingURL=chunk-MARSXMGB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/three/texture-cache.ts","../src/three/createShardLight.ts"],"names":["texture","THREE"],"mappings":"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","file":"chunk-MARSXMGB.js","sourcesContent":["import * as THREE from 'three';\nimport type { LayerSource } from '../core/index.js';\n\n/**\n * Instance-shared, ref-counted textures. Every light with the same\n * baked layer reuses one texture; each light still gets its own material, so\n * opacity can fade per instance. Textures are disposed when their last user is.\n */\ninterface Entry {\n texture: THREE.Texture;\n refs: number;\n}\n\nconst cache = new Map<string, Entry>();\n\nexport function acquireTexture(key: string, source: LayerSource): THREE.Texture {\n const existing = cache.get(key);\n if (existing) {\n existing.refs += 1;\n return existing.texture;\n }\n const texture = createTexture(source);\n cache.set(key, { texture, refs: 1 });\n return texture;\n}\n\nexport function releaseTexture(key: string): void {\n const entry = cache.get(key);\n if (!entry) return;\n entry.refs -= 1;\n if (entry.refs <= 0) {\n cache.delete(key);\n entry.texture.dispose();\n }\n}\n\n/** Live texture count; used by the memory tests. */\nexport function textureCacheSize(): number {\n return cache.size;\n}\n\nexport function clearTextureCache(): void {\n for (const entry of cache.values()) entry.texture.dispose();\n cache.clear();\n}\n\nfunction createTexture(source: LayerSource): THREE.Texture {\n if (source.type === 'bitmap') {\n const texture = new THREE.Texture(source.bitmap as unknown as HTMLImageElement);\n texture.needsUpdate = true;\n texture.colorSpace = THREE.SRGBColorSpace;\n return texture;\n }\n if (source.type === 'canvas') {\n const texture = new THREE.CanvasTexture(source.canvas as HTMLCanvasElement);\n texture.colorSpace = THREE.SRGBColorSpace;\n texture.needsUpdate = true;\n return texture;\n }\n // 'url': three has to load it; only used if an adapter requests url sources.\n const texture = new THREE.TextureLoader().load(source.url);\n texture.colorSpace = THREE.SRGBColorSpace;\n return texture;\n}\n","import * as THREE from 'three';\nimport {\n collapseTrigger,\n createLightModel,\n definedOnly,\n type Baker,\n type EffectConfig,\n type FrameValues,\n type Layer,\n type LightModel,\n type Preset,\n type SetValues,\n type ShardInput,\n type ShardLightConfig,\n} from '../core/index.js';\nimport { acquireTexture, releaseTexture } from './texture-cache.js';\n\nexport interface CreateShardLightOptions {\n preset?: Preset | null;\n config?: Partial<ShardLightConfig>;\n shards?: ShardInput[];\n effects?: EffectConfig[];\n color?: string;\n /** World units (plane edge). */\n size?: number;\n /** Texture edge. Default 1024. */\n resolution?: number;\n rayScale?: number;\n baker?: Baker;\n /** Default true: effects run from `onBeforeRender`. */\n autoUpdate?: boolean;\n /** Faces the camera. Default false. */\n billboard?: boolean;\n /** Circular hit radius at the centre, as a fraction of the half-edge. */\n hitRadius?: number;\n /** Seconds for hover to ease in/out. Default 0.25; 0 snaps. */\n hoverEase?: number;\n /** Seconds for the click collapse to ease in/out. Default 0.3; 0 snaps. */\n collapseEase?: number;\n /** Custom material factory, for custom shading. */\n material?: (layer: Layer) => THREE.Material;\n renderOrder?: number;\n depthTest?: boolean;\n toneMapped?: boolean;\n onReady?: () => void;\n}\n\nexport interface ShardLightController {\n object: THREE.Group;\n model: LightModel;\n set(values: SetValues): void;\n /** Ease the whole-light hover amount toward 0 or 1. */\n setHover(hovered: boolean): void;\n /** Ease the collapse toward expanded / collapsed. */\n setCollapsed(collapsed: boolean): void;\n /** Flip between expanded and collapsed. */\n toggleCollapsed(): void;\n update(patch: Partial<CreateShardLightOptions>): void;\n tick(dt: number): void;\n ready: Promise<void>;\n dispose(): void;\n}\n\ninterface MeshEntry {\n mesh: THREE.Mesh;\n material: THREE.Material & { map?: THREE.Texture | null; transparent?: boolean };\n key: string;\n textureKey: string | null;\n channel: string;\n}\n\n/**\n * The three.js adapter: one additive plane per layer. It wraps a\n * `createLightModel()` and turns the model's layers and frame values into\n * meshes, scales and opacities.\n */\nexport function createShardLight(options: CreateShardLightOptions = {}): ShardLightController {\n let opts = {\n size: 0.5,\n resolution: 1024,\n autoUpdate: true,\n billboard: false,\n ...definedOnly(options),\n };\n const object = new THREE.Group();\n\n let geometry = new THREE.PlaneGeometry(opts.size, opts.size);\n const entries = new Map<string, MeshEntry>();\n const clock = new THREE.Clock();\n let disposed = false;\n\n const model = createLightModel({\n preset: opts.preset,\n config: opts.config,\n shards: opts.shards,\n effects: opts.effects,\n color: opts.color,\n resolution: opts.resolution,\n rayScale: opts.rayScale,\n baker: opts.baker,\n hoverEase: opts.hoverEase,\n collapseEase: opts.collapseEase,\n accepts: ['bitmap', 'canvas'],\n onError: (error) => {\n console.error('[shardlight] bake error', error);\n },\n });\n\n let hitMesh: THREE.Mesh | null = null;\n ensureHitMesh();\n\n function createMaterial(layer: Layer): MeshEntry['material'] {\n if (opts.material) return opts.material(layer) as MeshEntry['material'];\n const material = new THREE.MeshBasicMaterial({\n transparent: true,\n depthWrite: false,\n toneMapped: opts.toneMapped ?? false,\n depthTest: opts.depthTest ?? true,\n side: THREE.DoubleSide,\n blending: layer.blend === 'add' ? THREE.AdditiveBlending : THREE.NormalBlending,\n });\n return material as MeshEntry['material'];\n }\n\n function createHitMesh(size: number, hitRadius: number): THREE.Mesh {\n const hitGeometry = new THREE.CircleGeometry((hitRadius * size) / 2, 24);\n const hitMaterial = new THREE.MeshBasicMaterial({\n transparent: true,\n opacity: 0,\n depthWrite: false,\n });\n const mesh = new THREE.Mesh(hitGeometry, hitMaterial);\n mesh.name = 'shardlight-hit';\n object.add(mesh);\n return mesh;\n }\n\n /**\n * Keep a raycast target around: an explicit `hitRadius`, or (sized to the\n * whole light) whenever any shard reacts to hover.\n */\n function ensureHitMesh(): void {\n const wanted =\n opts.hitRadius !== undefined ||\n model.resolved.effects.some((effect) => effect.type === 'hover') ||\n collapseTrigger(model.resolved.effects) !== 'none';\n if (!wanted) {\n if (hitMesh) {\n hitMesh.geometry.dispose();\n (hitMesh.material as THREE.Material).dispose();\n hitMesh.removeFromParent();\n hitMesh = null;\n }\n return;\n }\n const radius = opts.hitRadius ?? 1;\n if (!hitMesh) hitMesh = createHitMesh(opts.size, radius);\n else resizeHitMesh(hitMesh, opts.size, radius);\n }\n\n function applyTexture(entry: MeshEntry, layer: Layer): void {\n if (!layer.source) return;\n if (entry.textureKey) releaseTexture(entry.textureKey);\n entry.textureKey = layer.key;\n entry.material.map = acquireTexture(layer.key, layer.source);\n entry.material.needsUpdate = true;\n entry.mesh.visible = true;\n }\n\n function beforeRender(\n _renderer: THREE.WebGLRenderer,\n _scene: THREE.Scene,\n camera: THREE.Camera,\n ): void {\n if (disposed) return;\n if (opts.billboard) {\n const position = new THREE.Vector3();\n camera.getWorldPosition(position);\n object.lookAt(position);\n }\n if (opts.autoUpdate) {\n const dt = clock.getDelta();\n if (dt > 0) model.tick(dt);\n }\n }\n\n function syncLayers(layers: readonly Layer[]): void {\n const byId = new Map(layers.map((layer) => [layer.id, layer] as const));\n\n // Remove meshes whose layer is gone.\n for (const [id, entry] of [...entries]) {\n if (byId.has(id)) continue;\n removeEntry(id, entry);\n }\n\n for (const layer of layers) {\n let entry = entries.get(layer.id);\n if (entry && entry.key !== layer.key) {\n // Re-bake in place: swap the texture, keep the mesh.\n if (entry.textureKey) releaseTexture(entry.textureKey);\n entry.textureKey = null;\n entry.key = layer.key;\n // Hide until the new texture is ready, so a stale/absent map never\n // shows as a white quad.\n entry.material.map = null;\n entry.material.needsUpdate = true;\n entry.mesh.visible = false;\n if (layer.source) applyTexture(entry, layer);\n } else if (entry) {\n // The layer was created before its source finished baking.\n if (!entry.textureKey && layer.source) applyTexture(entry, layer);\n } else {\n const material = createMaterial(layer);\n const mesh = new THREE.Mesh(geometry, material);\n mesh.name = layer.id;\n mesh.visible = false;\n mesh.renderOrder = opts.renderOrder ?? 0;\n mesh.onBeforeRender = beforeRender;\n entry = {\n mesh,\n material,\n key: layer.key,\n textureKey: null,\n channel: layer.channel,\n };\n entries.set(layer.id, entry);\n if (layer.source) applyTexture(entry, layer);\n object.add(mesh);\n }\n }\n }\n\n function removeEntry(id: string, entry: MeshEntry): void {\n entries.delete(id);\n if (entry.textureKey) releaseTexture(entry.textureKey);\n entry.mesh.removeFromParent();\n entry.material.dispose();\n }\n\n function applyFrame(values: FrameValues): void {\n for (const entry of entries.values()) {\n const channel = values.channel(entry.channel);\n entry.mesh.scale.set(channel.scale, channel.scale, 1);\n entry.mesh.rotation.z = (channel.rotation * Math.PI) / 180;\n entry.material.opacity = channel.opacity * values.opacity;\n }\n }\n\n const unsubscribeLayers = model.subscribe(syncLayers);\n const unsubscribeFrame = model.onFrame(applyFrame);\n model.ready.then(() => opts.onReady?.());\n\n const controller: ShardLightController = {\n object,\n model,\n set(values) {\n model.set(values);\n },\n setHover(hovered) {\n model.setHover(hovered);\n },\n setCollapsed(collapsed) {\n model.setCollapsed(collapsed);\n },\n toggleCollapsed() {\n model.toggleCollapsed();\n },\n update(patch) {\n if (disposed) return;\n const previousSize = opts.size;\n opts = { ...opts, ...definedOnly(patch) };\n if (patch.size !== undefined && patch.size !== previousSize) {\n geometry.dispose();\n geometry = new THREE.PlaneGeometry(opts.size, opts.size);\n for (const entry of entries.values()) entry.mesh.geometry = geometry;\n }\n model.update({\n preset: opts.preset,\n config: opts.config,\n shards: opts.shards,\n effects: opts.effects,\n color: opts.color,\n resolution: opts.resolution,\n rayScale: opts.rayScale,\n baker: opts.baker,\n hoverEase: opts.hoverEase,\n collapseEase: opts.collapseEase,\n });\n ensureHitMesh();\n },\n tick(dt) {\n model.tick(dt);\n },\n ready: model.ready,\n dispose() {\n if (disposed) return;\n disposed = true;\n unsubscribeLayers();\n unsubscribeFrame();\n model.dispose();\n for (const [id, entry] of [...entries]) removeEntry(id, entry);\n geometry.dispose();\n if (hitMesh) {\n hitMesh.geometry.dispose();\n (hitMesh.material as THREE.Material).dispose();\n hitMesh.removeFromParent();\n hitMesh = null;\n }\n object.removeFromParent();\n },\n };\n\n return controller;\n}\n\nfunction resizeHitMesh(mesh: THREE.Mesh, size: number, hitRadius: number): void {\n mesh.geometry.dispose();\n mesh.geometry = new THREE.CircleGeometry((hitRadius * size) / 2, 24);\n}\n"]}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { blob, fan, clusters, halo } from './chunk-ZWPHIC3K.js';
|
|
2
|
+
import { createContext, useContext, useMemo, useLayoutEffect, useEffect, useRef, useState, useCallback } from 'react';
|
|
3
|
+
import { jsx } from 'react/jsx-runtime';
|
|
4
|
+
|
|
5
|
+
var ShardLightContext = createContext(null);
|
|
6
|
+
var useIsomorphicLayoutEffect = typeof window !== "undefined" ? useLayoutEffect : useEffect;
|
|
7
|
+
|
|
8
|
+
// src/shared-react/Shard.tsx
|
|
9
|
+
function Shard(props) {
|
|
10
|
+
const registry = useContext(ShardLightContext);
|
|
11
|
+
const key = JSON.stringify(props);
|
|
12
|
+
const input = useMemo(() => ({ ...props }), [key]);
|
|
13
|
+
useIsomorphicLayoutEffect(() => {
|
|
14
|
+
if (!registry) return;
|
|
15
|
+
return registry.register(input);
|
|
16
|
+
}, [registry, input]);
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
function createShardComponent(def) {
|
|
20
|
+
function ShardComponent(props) {
|
|
21
|
+
const shardProps = { ...props, kind: def.kind };
|
|
22
|
+
return /* @__PURE__ */ jsx(Shard, { ...shardProps });
|
|
23
|
+
}
|
|
24
|
+
ShardComponent.displayName = `Shard(${def.kind})`;
|
|
25
|
+
return ShardComponent;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/shared-react/shards.tsx
|
|
29
|
+
var Glow = createShardComponent(blob);
|
|
30
|
+
var Rays = createShardComponent(fan);
|
|
31
|
+
var Streaks = createShardComponent(clusters);
|
|
32
|
+
var Halo = createShardComponent(halo);
|
|
33
|
+
|
|
34
|
+
// src/shared-react/effects.ts
|
|
35
|
+
function normalizeEffects(effects, flicker, collapse) {
|
|
36
|
+
const out = effects ? [...effects] : [];
|
|
37
|
+
if (flicker) out.push({ type: "flicker", ...typeof flicker === "object" ? flicker : {} });
|
|
38
|
+
if (collapse) out.push({ type: "collapse", ...typeof collapse === "object" ? collapse : {} });
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
function useShardRegistry() {
|
|
42
|
+
const mapRef = useRef(/* @__PURE__ */ new Map());
|
|
43
|
+
const [version, setVersion] = useState(0);
|
|
44
|
+
const bump = useCallback(() => setVersion((v) => v + 1), []);
|
|
45
|
+
const registry = useMemo(
|
|
46
|
+
() => ({
|
|
47
|
+
register(input) {
|
|
48
|
+
const id = input.id;
|
|
49
|
+
if (typeof id !== "string") return () => {
|
|
50
|
+
};
|
|
51
|
+
mapRef.current.set(id, input);
|
|
52
|
+
bump();
|
|
53
|
+
return () => {
|
|
54
|
+
mapRef.current.delete(id);
|
|
55
|
+
bump();
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}),
|
|
59
|
+
[bump]
|
|
60
|
+
);
|
|
61
|
+
const shards = useMemo(() => [...mapRef.current.values()], [version]);
|
|
62
|
+
return { registry, shards, version };
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { Glow, Halo, Rays, Shard, ShardLightContext, Streaks, createShardComponent, normalizeEffects, useShardRegistry };
|
|
66
|
+
//# sourceMappingURL=chunk-W7WG7K5R.js.map
|
|
67
|
+
//# sourceMappingURL=chunk-W7WG7K5R.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/shared-react/context.ts","../src/shared-react/useIsomorphicLayoutEffect.ts","../src/shared-react/Shard.tsx","../src/shared-react/createShardComponent.tsx","../src/shared-react/shards.tsx","../src/shared-react/effects.ts","../src/shared-react/useShardRegistry.ts"],"names":["useMemo"],"mappings":"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","file":"chunk-W7WG7K5R.js","sourcesContent":["import { createContext } from 'react';\nimport type { ShardInput } from '../core/index.js';\n\n/**\n * Lets `<Shard>` children register their props with the nearest light through\n * context, instead of parsing `React.Children`. The same context\n * works in the DOM and R3F trees.\n */\nexport interface ShardLightRegistry {\n register(input: ShardInput): () => void;\n}\n\nexport const ShardLightContext = createContext<ShardLightRegistry | null>(null);\n","import { useEffect, useLayoutEffect } from 'react';\n\n/** `useLayoutEffect` on the client, `useEffect` on the server (SSR-safe). */\nexport const useIsomorphicLayoutEffect =\n typeof window !== 'undefined' ? useLayoutEffect : useEffect;\n","import { useContext, useMemo } from 'react';\nimport type { ShardInput } from '../core/index.js';\nimport { ShardLightContext } from './context.js';\nimport { useIsomorphicLayoutEffect } from './useIsomorphicLayoutEffect.js';\n\n/**\n * `<Shard>` props: a stable `id`, an optional `kind`, and any of that kind's\n * flat parameters. Returns `null` and registers itself with the nearest\n * `<ShardLight>` / `<ShardLightMesh>`.\n */\nexport interface ShardProps {\n id: string;\n kind?: string;\n [param: string]: unknown;\n}\n\nexport function Shard(props: ShardProps): null {\n const registry = useContext(ShardLightContext);\n const key = JSON.stringify(props);\n // A stable input per prop-change so the layout effect re-runs only then.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const input = useMemo(() => ({ ...props }) as ShardInput, [key]);\n\n useIsomorphicLayoutEffect(() => {\n if (!registry) return;\n return registry.register(input);\n }, [registry, input]);\n\n return null;\n}\n","import type { ComponentType } from 'react';\nimport type { ParamsOf, ShardBase, ShardKindDefinition } from '../core/index.js';\nimport { Shard, type ShardProps } from './Shard.js';\n\n/** Props for a component made by `createShardComponent`. */\nexport type ShardComponentProps<D> = Omit<ShardBase, 'kind'> & { id: string } & Partial<\n ParamsOf<D>\n >;\n\n/**\n * Make a typed component for a shard kind: `const Dots = createShardComponent(dots)`\n *. Works in both React entries.\n */\nexport function createShardComponent<D extends ShardKindDefinition<any, any>>(\n def: D,\n): ComponentType<ShardComponentProps<D>> {\n function ShardComponent(props: ShardComponentProps<D>) {\n const shardProps = { ...(props as object), kind: def.kind } as ShardProps;\n return <Shard {...shardProps} />;\n }\n ShardComponent.displayName = `Shard(${def.kind})`;\n return ShardComponent as ComponentType<ShardComponentProps<D>>;\n}\n","import { blob, clusters, fan, halo } from '../core/index.js';\nimport { createShardComponent } from './createShardComponent.js';\n\n/** The built-in kinds as typed components. Shared by DOM and R3F. */\nexport const Glow = createShardComponent(blob);\nexport const Rays = createShardComponent(fan);\nexport const Streaks = createShardComponent(clusters);\nexport const Halo = createShardComponent(halo);\n","import type { EffectConfig } from '../core/index.js';\n\n/** `true` adds the effect with its defaults; an object adds it with those params. */\nexport type EffectShorthand = boolean | Record<string, unknown>;\n\n/**\n * Turn the `flicker` / `collapse` shorthands into effect configs and append them\n * to any explicit `effects`.\n */\nexport function normalizeEffects(\n effects?: readonly EffectConfig[] | null,\n flicker?: EffectShorthand,\n collapse?: EffectShorthand,\n): EffectConfig[] {\n const out: EffectConfig[] = effects ? [...effects] : [];\n if (flicker) out.push({ type: 'flicker', ...(typeof flicker === 'object' ? flicker : {}) });\n if (collapse) out.push({ type: 'collapse', ...(typeof collapse === 'object' ? collapse : {}) });\n return out;\n}\n","import { useCallback, useMemo, useRef, useState } from 'react';\nimport type { ShardInput } from '../core/index.js';\nimport type { ShardLightRegistry } from './context.js';\n\nexport interface ShardRegistryState {\n registry: ShardLightRegistry;\n /** Overrides collected from `<Shard>` children, in registration order. */\n shards: ShardInput[];\n /** Bumps whenever the collected set changes. */\n version: number;\n}\n\n/**\n * Collects `<Shard>` registrations for one light. A plain `Map` preserves\n * insertion order and lets shards sit inside fragments, conditionals and\n * wrapper components.\n */\nexport function useShardRegistry(): ShardRegistryState {\n const mapRef = useRef(new Map<string, ShardInput>());\n const [version, setVersion] = useState(0);\n const bump = useCallback(() => setVersion((v) => v + 1), []);\n\n const registry = useMemo<ShardLightRegistry>(\n () => ({\n register(input: ShardInput) {\n const id = (input as { id?: unknown }).id;\n if (typeof id !== 'string') return () => {};\n mapRef.current.set(id, input);\n bump();\n return () => {\n mapRef.current.delete(id);\n bump();\n };\n },\n }),\n [bump],\n );\n\n // `version` is the dependency that makes this recompute on registration.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const shards = useMemo(() => [...mapRef.current.values()], [version]);\n\n return { registry, shards, version };\n}\n"]}
|