vista-core-js 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/dist/ErrorOverlay.d.ts +7 -0
  2. package/dist/ErrorOverlay.js +68 -0
  3. package/dist/app.d.ts +21 -0
  4. package/dist/app.js +119 -0
  5. package/dist/client/link.d.ts +23 -0
  6. package/dist/client/link.js +42 -0
  7. package/dist/client.d.ts +2 -0
  8. package/dist/client.js +290 -0
  9. package/dist/components/PixelBlast.d.ts +28 -0
  10. package/dist/components/PixelBlast.js +584 -0
  11. package/dist/entry-client.d.ts +1 -0
  12. package/dist/entry-client.js +56 -0
  13. package/dist/entry-server.d.ts +9 -0
  14. package/dist/entry-server.js +33 -0
  15. package/dist/error-overlay.d.ts +1 -0
  16. package/dist/error-overlay.js +166 -0
  17. package/dist/font/google/index.d.ts +1923 -0
  18. package/dist/font/google/index.js +1948 -0
  19. package/dist/image/get-img-props.d.ts +20 -0
  20. package/dist/image/get-img-props.js +46 -0
  21. package/dist/image/image-config.d.ts +20 -0
  22. package/dist/image/image-config.js +17 -0
  23. package/dist/image/image-loader.d.ts +7 -0
  24. package/dist/image/image-loader.js +10 -0
  25. package/dist/image/index.d.ts +12 -0
  26. package/dist/image/index.js +12 -0
  27. package/dist/index.d.ts +6 -0
  28. package/dist/index.js +4 -0
  29. package/dist/plugin.d.ts +5 -0
  30. package/dist/plugin.js +88 -0
  31. package/dist/router.d.ts +18 -0
  32. package/dist/router.js +55 -0
  33. package/package.json +47 -0
  34. package/src/ErrorOverlay.tsx +194 -0
  35. package/src/app.tsx +138 -0
  36. package/src/assets/vista.gif +0 -0
  37. package/src/client/link.tsx +85 -0
  38. package/src/client.tsx +368 -0
  39. package/src/entry-client.tsx +70 -0
  40. package/src/entry-server.tsx +58 -0
  41. package/src/error-overlay.ts +187 -0
  42. package/src/font/google/index.d.ts +19011 -0
  43. package/src/font/google/index.ts +1968 -0
  44. package/src/font/types.d.ts +13 -0
  45. package/src/image/get-img-props.ts +100 -0
  46. package/src/image/image-config.ts +22 -0
  47. package/src/image/image-loader.ts +23 -0
  48. package/src/image/index.tsx +21 -0
  49. package/src/index.ts +7 -0
  50. package/src/plugin.ts +100 -0
  51. package/src/router-loader.ts +51 -0
  52. package/src/router.tsx +80 -0
  53. package/tsconfig.json +23 -0
@@ -0,0 +1,584 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from 'react';
3
+ import * as THREE from 'three';
4
+ import { EffectComposer, EffectPass, RenderPass, Effect } from 'postprocessing';
5
+ const createTouchTexture = () => {
6
+ const size = 64;
7
+ const canvas = document.createElement('canvas');
8
+ canvas.width = size;
9
+ canvas.height = size;
10
+ const ctx = canvas.getContext('2d');
11
+ if (!ctx)
12
+ throw new Error('2D context not available');
13
+ ctx.fillStyle = 'black';
14
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
15
+ const texture = new THREE.Texture(canvas);
16
+ texture.minFilter = THREE.LinearFilter;
17
+ texture.magFilter = THREE.LinearFilter;
18
+ texture.generateMipmaps = false;
19
+ const trail = [];
20
+ let last = null;
21
+ const maxAge = 64;
22
+ let radius = 0.1 * size;
23
+ const speed = 1 / maxAge;
24
+ const clear = () => {
25
+ ctx.fillStyle = 'black';
26
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
27
+ };
28
+ const drawPoint = (p) => {
29
+ const pos = { x: p.x * size, y: (1 - p.y) * size };
30
+ let intensity = 1;
31
+ const easeOutSine = (t) => Math.sin((t * Math.PI) / 2);
32
+ const easeOutQuad = (t) => -t * (t - 2);
33
+ if (p.age < maxAge * 0.3)
34
+ intensity = easeOutSine(p.age / (maxAge * 0.3));
35
+ else
36
+ intensity = easeOutQuad(1 - (p.age - maxAge * 0.3) / (maxAge * 0.7)) || 0;
37
+ intensity *= p.force;
38
+ const color = `${((p.vx + 1) / 2) * 255}, ${((p.vy + 1) / 2) * 255}, ${intensity * 255}`;
39
+ const offset = size * 5;
40
+ ctx.shadowOffsetX = offset;
41
+ ctx.shadowOffsetY = offset;
42
+ ctx.shadowBlur = radius;
43
+ ctx.shadowColor = `rgba(${color},${0.22 * intensity})`;
44
+ ctx.beginPath();
45
+ ctx.fillStyle = 'rgba(255,0,0,1)';
46
+ ctx.arc(pos.x - offset, pos.y - offset, radius, 0, Math.PI * 2);
47
+ ctx.fill();
48
+ };
49
+ const addTouch = (norm) => {
50
+ let force = 0;
51
+ let vx = 0;
52
+ let vy = 0;
53
+ if (last) {
54
+ const dx = norm.x - last.x;
55
+ const dy = norm.y - last.y;
56
+ if (dx === 0 && dy === 0)
57
+ return;
58
+ const dd = dx * dx + dy * dy;
59
+ const d = Math.sqrt(dd);
60
+ vx = dx / (d || 1);
61
+ vy = dy / (d || 1);
62
+ force = Math.min(dd * 10000, 1);
63
+ }
64
+ last = { x: norm.x, y: norm.y };
65
+ trail.push({ x: norm.x, y: norm.y, age: 0, force, vx, vy });
66
+ };
67
+ const update = () => {
68
+ clear();
69
+ for (let i = trail.length - 1; i >= 0; i--) {
70
+ const point = trail[i];
71
+ const f = point.force * speed * (1 - point.age / maxAge);
72
+ point.x += point.vx * f;
73
+ point.y += point.vy * f;
74
+ point.age++;
75
+ if (point.age > maxAge)
76
+ trail.splice(i, 1);
77
+ }
78
+ for (let i = 0; i < trail.length; i++)
79
+ drawPoint(trail[i]);
80
+ texture.needsUpdate = true;
81
+ };
82
+ return {
83
+ canvas,
84
+ texture,
85
+ addTouch,
86
+ update,
87
+ set radiusScale(v) {
88
+ radius = 0.1 * size * v;
89
+ },
90
+ get radiusScale() {
91
+ return radius / (0.1 * size);
92
+ },
93
+ size
94
+ };
95
+ };
96
+ const createLiquidEffect = (texture, opts) => {
97
+ const fragment = `
98
+ uniform sampler2D uTexture;
99
+ uniform float uStrength;
100
+ uniform float uTime;
101
+ uniform float uFreq;
102
+
103
+ void mainUv(inout vec2 uv) {
104
+ vec4 tex = texture2D(uTexture, uv);
105
+ float vx = tex.r * 2.0 - 1.0;
106
+ float vy = tex.g * 2.0 - 1.0;
107
+ float intensity = tex.b;
108
+
109
+ float wave = 0.5 + 0.5 * sin(uTime * uFreq + intensity * 6.2831853);
110
+
111
+ float amt = uStrength * intensity * wave;
112
+
113
+ uv += vec2(vx, vy) * amt;
114
+ }
115
+ `;
116
+ return new Effect('LiquidEffect', fragment, {
117
+ uniforms: new Map([
118
+ ['uTexture', new THREE.Uniform(texture)],
119
+ ['uStrength', new THREE.Uniform(opts?.strength ?? 0.025)],
120
+ ['uTime', new THREE.Uniform(0)],
121
+ ['uFreq', new THREE.Uniform(opts?.freq ?? 4.5)]
122
+ ])
123
+ });
124
+ };
125
+ const SHAPE_MAP = {
126
+ square: 0,
127
+ circle: 1,
128
+ triangle: 2,
129
+ diamond: 3
130
+ };
131
+ const VERTEX_SRC = `
132
+ void main() {
133
+ gl_Position = vec4(position, 1.0);
134
+ }
135
+ `;
136
+ const FRAGMENT_SRC = `
137
+ precision highp float;
138
+
139
+ uniform vec3 uColor;
140
+ uniform vec2 uResolution;
141
+ uniform float uTime;
142
+ uniform float uPixelSize;
143
+ uniform float uScale;
144
+ uniform float uDensity;
145
+ uniform float uPixelJitter;
146
+ uniform int uEnableRipples;
147
+ uniform float uRippleSpeed;
148
+ uniform float uRippleThickness;
149
+ uniform float uRippleIntensity;
150
+ uniform float uEdgeFade;
151
+
152
+ uniform int uShapeType;
153
+ const int SHAPE_SQUARE = 0;
154
+ const int SHAPE_CIRCLE = 1;
155
+ const int SHAPE_TRIANGLE = 2;
156
+ const int SHAPE_DIAMOND = 3;
157
+
158
+ const int MAX_CLICKS = 10;
159
+
160
+ uniform vec2 uClickPos [MAX_CLICKS];
161
+ uniform float uClickTimes[MAX_CLICKS];
162
+
163
+ out vec4 fragColor;
164
+
165
+ float Bayer2(vec2 a) {
166
+ a = floor(a);
167
+ return fract(a.x / 2. + a.y * a.y * .75);
168
+ }
169
+ #define Bayer4(a) (Bayer2(.5*(a))*0.25 + Bayer2(a))
170
+ #define Bayer8(a) (Bayer4(.5*(a))*0.25 + Bayer2(a))
171
+
172
+ #define FBM_OCTAVES 5
173
+ #define FBM_LACUNARITY 1.25
174
+ #define FBM_GAIN 1.0
175
+
176
+ float hash11(float n){ return fract(sin(n)*43758.5453); }
177
+
178
+ float vnoise(vec3 p){
179
+ vec3 ip = floor(p);
180
+ vec3 fp = fract(p);
181
+ float n000 = hash11(dot(ip + vec3(0.0,0.0,0.0), vec3(1.0,57.0,113.0)));
182
+ float n100 = hash11(dot(ip + vec3(1.0,0.0,0.0), vec3(1.0,57.0,113.0)));
183
+ float n010 = hash11(dot(ip + vec3(0.0,1.0,0.0), vec3(1.0,57.0,113.0)));
184
+ float n110 = hash11(dot(ip + vec3(1.0,1.0,0.0), vec3(1.0,57.0,113.0)));
185
+ float n001 = hash11(dot(ip + vec3(0.0,0.0,1.0), vec3(1.0,57.0,113.0)));
186
+ float n101 = hash11(dot(ip + vec3(1.0,0.0,1.0), vec3(1.0,57.0,113.0)));
187
+ float n011 = hash11(dot(ip + vec3(0.0,1.0,1.0), vec3(1.0,57.0,113.0)));
188
+ float n111 = hash11(dot(ip + vec3(1.0,1.0,1.0), vec3(1.0,57.0,113.0)));
189
+ vec3 w = fp*fp*fp*(fp*(fp*6.0-15.0)+10.0);
190
+ float x00 = mix(n000, n100, w.x);
191
+ float x10 = mix(n010, n110, w.x);
192
+ float x01 = mix(n001, n101, w.x);
193
+ float x11 = mix(n011, n111, w.x);
194
+ float y0 = mix(x00, x10, w.y);
195
+ float y1 = mix(x01, x11, w.y);
196
+ return mix(y0, y1, w.z) * 2.0 - 1.0;
197
+ }
198
+
199
+ float fbm2(vec2 uv, float t){
200
+ vec3 p = vec3(uv * uScale, t);
201
+ float amp = 1.0;
202
+ float freq = 1.0;
203
+ float sum = 1.0;
204
+ for (int i = 0; i < FBM_OCTAVES; ++i){
205
+ sum += amp * vnoise(p * freq);
206
+ freq *= FBM_LACUNARITY;
207
+ amp *= FBM_GAIN;
208
+ }
209
+ return sum * 0.5 + 0.5;
210
+ }
211
+
212
+ float maskCircle(vec2 p, float cov){
213
+ float r = sqrt(cov) * .25;
214
+ float d = length(p - 0.5) - r;
215
+ float aa = 0.5 * fwidth(d);
216
+ return cov * (1.0 - smoothstep(-aa, aa, d * 2.0));
217
+ }
218
+
219
+ float maskTriangle(vec2 p, vec2 id, float cov){
220
+ bool flip = mod(id.x + id.y, 2.0) > 0.5;
221
+ if (flip) p.x = 1.0 - p.x;
222
+ float r = sqrt(cov);
223
+ float d = p.y - r*(1.0 - p.x);
224
+ float aa = fwidth(d);
225
+ return cov * clamp(0.5 - d/aa, 0.0, 1.0);
226
+ }
227
+
228
+ float maskDiamond(vec2 p, float cov){
229
+ float r = sqrt(cov) * 0.564;
230
+ return step(abs(p.x - 0.49) + abs(p.y - 0.49), r);
231
+ }
232
+
233
+ void main(){
234
+ float pixelSize = uPixelSize;
235
+ vec2 fragCoord = gl_FragCoord.xy - uResolution * .5;
236
+ float aspectRatio = uResolution.x / uResolution.y;
237
+
238
+ vec2 pixelId = floor(fragCoord / pixelSize);
239
+ vec2 pixelUV = fract(fragCoord / pixelSize);
240
+
241
+ float cellPixelSize = 8.0 * pixelSize;
242
+ vec2 cellId = floor(fragCoord / cellPixelSize);
243
+ vec2 cellCoord = cellId * cellPixelSize;
244
+ vec2 uv = cellCoord / uResolution * vec2(aspectRatio, 1.0);
245
+
246
+ float base = fbm2(uv, uTime * 0.05);
247
+ base = base * 0.5 - 0.65;
248
+
249
+ float feed = base + (uDensity - 0.5) * 0.3;
250
+
251
+ float speed = uRippleSpeed;
252
+ float thickness = uRippleThickness;
253
+ const float dampT = 1.0;
254
+ const float dampR = 10.0;
255
+
256
+ if (uEnableRipples == 1) {
257
+ for (int i = 0; i < MAX_CLICKS; ++i){
258
+ vec2 pos = uClickPos[i];
259
+ if (pos.x < 0.0) continue;
260
+ float cellPixelSize = 8.0 * pixelSize;
261
+ vec2 cuv = (((pos - uResolution * .5 - cellPixelSize * .5) / (uResolution))) * vec2(aspectRatio, 1.0);
262
+ float t = max(uTime - uClickTimes[i], 0.0);
263
+ float r = distance(uv, cuv);
264
+ float waveR = speed * t;
265
+ float ring = exp(-pow((r - waveR) / thickness, 2.0));
266
+ float atten = exp(-dampT * t) * exp(-dampR * r);
267
+ feed = max(feed, ring * atten * uRippleIntensity);
268
+ }
269
+ }
270
+
271
+ float bayer = Bayer8(fragCoord / uPixelSize) - 0.5;
272
+ float bw = step(0.5, feed + bayer);
273
+
274
+ float h = fract(sin(dot(floor(fragCoord / uPixelSize), vec2(127.1, 311.7))) * 43758.5453);
275
+ float jitterScale = 1.0 + (h - 0.5) * uPixelJitter;
276
+ float coverage = bw * jitterScale;
277
+ float M;
278
+ if (uShapeType == SHAPE_CIRCLE) M = maskCircle (pixelUV, coverage);
279
+ else if (uShapeType == SHAPE_TRIANGLE) M = maskTriangle(pixelUV, pixelId, coverage);
280
+ else if (uShapeType == SHAPE_DIAMOND) M = maskDiamond(pixelUV, coverage);
281
+ else M = coverage;
282
+
283
+ if (uEdgeFade > 0.0) {
284
+ vec2 norm = gl_FragCoord.xy / uResolution;
285
+ float edge = min(min(norm.x, norm.y), min(1.0 - norm.x, 1.0 - norm.y));
286
+ float fade = smoothstep(0.0, uEdgeFade, edge);
287
+ M *= fade;
288
+ }
289
+
290
+ vec3 color = uColor;
291
+ fragColor = vec4(color, M);
292
+ }
293
+ `;
294
+ const MAX_CLICKS = 10;
295
+ const PixelBlast = ({ variant = 'square', pixelSize = 3, color = '#B19EEF', className, style, antialias = true, patternScale = 2, patternDensity = 1, liquid = false, liquidStrength = 0.1, liquidRadius = 1, pixelSizeJitter = 0, enableRipples = true, rippleIntensityScale = 1, rippleThickness = 0.1, rippleSpeed = 0.3, liquidWobbleSpeed = 4.5, autoPauseOffscreen = true, speed = 0.5, transparent = true, edgeFade = 0.5, noiseAmount = 0 }) => {
296
+ const containerRef = useRef(null);
297
+ const visibilityRef = useRef({ visible: true });
298
+ const speedRef = useRef(speed);
299
+ const threeRef = useRef(null);
300
+ const prevConfigRef = useRef(null);
301
+ useEffect(() => {
302
+ const container = containerRef.current;
303
+ if (!container)
304
+ return;
305
+ speedRef.current = speed;
306
+ const needsReinitKeys = ['antialias', 'liquid', 'noiseAmount'];
307
+ const cfg = { antialias, liquid, noiseAmount };
308
+ let mustReinit = false;
309
+ if (!threeRef.current)
310
+ mustReinit = true;
311
+ else if (prevConfigRef.current) {
312
+ for (const k of needsReinitKeys)
313
+ if (prevConfigRef.current[k] !== cfg[k]) {
314
+ mustReinit = true;
315
+ break;
316
+ }
317
+ }
318
+ if (mustReinit) {
319
+ if (threeRef.current) {
320
+ const t = threeRef.current;
321
+ t.resizeObserver?.disconnect();
322
+ cancelAnimationFrame(t.raf);
323
+ t.quad?.geometry.dispose();
324
+ t.material.dispose();
325
+ t.composer?.dispose();
326
+ t.renderer.dispose();
327
+ if (t.renderer.domElement.parentElement === container)
328
+ container.removeChild(t.renderer.domElement);
329
+ threeRef.current = null;
330
+ }
331
+ const canvas = document.createElement('canvas');
332
+ const renderer = new THREE.WebGLRenderer({
333
+ canvas,
334
+ antialias,
335
+ alpha: true,
336
+ powerPreference: 'high-performance'
337
+ });
338
+ renderer.domElement.style.width = '100%';
339
+ renderer.domElement.style.height = '100%';
340
+ renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
341
+ container.appendChild(renderer.domElement);
342
+ if (transparent)
343
+ renderer.setClearAlpha(0);
344
+ else
345
+ renderer.setClearColor(0x000000, 1);
346
+ const uniforms = {
347
+ uResolution: { value: new THREE.Vector2(0, 0) },
348
+ uTime: { value: 0 },
349
+ uColor: { value: new THREE.Color(color) },
350
+ uClickPos: {
351
+ value: Array.from({ length: MAX_CLICKS }, () => new THREE.Vector2(-1, -1))
352
+ },
353
+ uClickTimes: { value: new Float32Array(MAX_CLICKS) },
354
+ uShapeType: { value: SHAPE_MAP[variant] ?? 0 },
355
+ uPixelSize: { value: pixelSize * renderer.getPixelRatio() },
356
+ uScale: { value: patternScale },
357
+ uDensity: { value: patternDensity },
358
+ uPixelJitter: { value: pixelSizeJitter },
359
+ uEnableRipples: { value: enableRipples ? 1 : 0 },
360
+ uRippleSpeed: { value: rippleSpeed },
361
+ uRippleThickness: { value: rippleThickness },
362
+ uRippleIntensity: { value: rippleIntensityScale },
363
+ uEdgeFade: { value: edgeFade }
364
+ };
365
+ const scene = new THREE.Scene();
366
+ const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
367
+ const material = new THREE.ShaderMaterial({
368
+ vertexShader: VERTEX_SRC,
369
+ fragmentShader: FRAGMENT_SRC,
370
+ uniforms,
371
+ transparent: true,
372
+ depthTest: false,
373
+ depthWrite: false,
374
+ glslVersion: THREE.GLSL3
375
+ });
376
+ const quadGeom = new THREE.PlaneGeometry(2, 2);
377
+ const quad = new THREE.Mesh(quadGeom, material);
378
+ scene.add(quad);
379
+ const clock = new THREE.Clock();
380
+ const setSize = () => {
381
+ const w = container.clientWidth || 1;
382
+ const h = container.clientHeight || 1;
383
+ renderer.setSize(w, h, false);
384
+ uniforms.uResolution.value.set(renderer.domElement.width, renderer.domElement.height);
385
+ if (threeRef.current?.composer)
386
+ threeRef.current.composer.setSize(renderer.domElement.width, renderer.domElement.height);
387
+ uniforms.uPixelSize.value = pixelSize * renderer.getPixelRatio();
388
+ };
389
+ setSize();
390
+ const ro = new ResizeObserver(setSize);
391
+ ro.observe(container);
392
+ const randomFloat = () => {
393
+ if (typeof window !== 'undefined' && window.crypto?.getRandomValues) {
394
+ const u32 = new Uint32Array(1);
395
+ window.crypto.getRandomValues(u32);
396
+ return u32[0] / 0xffffffff;
397
+ }
398
+ return Math.random();
399
+ };
400
+ const timeOffset = randomFloat() * 1000;
401
+ let composer;
402
+ let touch;
403
+ let liquidEffect;
404
+ if (liquid) {
405
+ touch = createTouchTexture();
406
+ touch.radiusScale = liquidRadius;
407
+ composer = new EffectComposer(renderer);
408
+ const renderPass = new RenderPass(scene, camera);
409
+ liquidEffect = createLiquidEffect(touch.texture, {
410
+ strength: liquidStrength,
411
+ freq: liquidWobbleSpeed
412
+ });
413
+ const effectPass = new EffectPass(camera, liquidEffect);
414
+ effectPass.renderToScreen = true;
415
+ composer.addPass(renderPass);
416
+ composer.addPass(effectPass);
417
+ }
418
+ if (noiseAmount > 0) {
419
+ if (!composer) {
420
+ composer = new EffectComposer(renderer);
421
+ composer.addPass(new RenderPass(scene, camera));
422
+ }
423
+ const noiseEffect = new Effect('NoiseEffect', `uniform float uTime; uniform float uAmount; float hash(vec2 p){ return fract(sin(dot(p, vec2(127.1,311.7))) * 43758.5453);} void mainUv(inout vec2 uv){} void mainImage(const in vec4 inputColor,const in vec2 uv,out vec4 outputColor){ float n=hash(floor(uv*vec2(1920.0,1080.0))+floor(uTime*60.0)); float g=(n-0.5)*uAmount; outputColor=inputColor+vec4(vec3(g),0.0);} `, {
424
+ uniforms: new Map([
425
+ ['uTime', new THREE.Uniform(0)],
426
+ ['uAmount', new THREE.Uniform(noiseAmount)]
427
+ ])
428
+ });
429
+ const noisePass = new EffectPass(camera, noiseEffect);
430
+ noisePass.renderToScreen = true;
431
+ if (composer && composer.passes.length > 0)
432
+ composer.passes.forEach(p => (p.renderToScreen = false));
433
+ composer.addPass(noisePass);
434
+ }
435
+ if (composer)
436
+ composer.setSize(renderer.domElement.width, renderer.domElement.height);
437
+ const mapToPixels = (e) => {
438
+ const rect = renderer.domElement.getBoundingClientRect();
439
+ const scaleX = renderer.domElement.width / rect.width;
440
+ const scaleY = renderer.domElement.height / rect.height;
441
+ const fx = (e.clientX - rect.left) * scaleX;
442
+ const fy = (rect.height - (e.clientY - rect.top)) * scaleY;
443
+ return {
444
+ fx,
445
+ fy,
446
+ w: renderer.domElement.width,
447
+ h: renderer.domElement.height
448
+ };
449
+ };
450
+ const onPointerDown = (e) => {
451
+ const { fx, fy } = mapToPixels(e);
452
+ const ix = threeRef.current?.clickIx ?? 0;
453
+ uniforms.uClickPos.value[ix].set(fx, fy);
454
+ uniforms.uClickTimes.value[ix] = uniforms.uTime.value;
455
+ if (threeRef.current)
456
+ threeRef.current.clickIx = (ix + 1) % MAX_CLICKS;
457
+ };
458
+ const onPointerMove = (e) => {
459
+ if (!touch)
460
+ return;
461
+ const { fx, fy, w, h } = mapToPixels(e);
462
+ touch.addTouch({ x: fx / w, y: fy / h });
463
+ };
464
+ renderer.domElement.addEventListener('pointerdown', onPointerDown, {
465
+ passive: true
466
+ });
467
+ renderer.domElement.addEventListener('pointermove', onPointerMove, {
468
+ passive: true
469
+ });
470
+ let raf = 0;
471
+ const animate = () => {
472
+ if (autoPauseOffscreen && !visibilityRef.current.visible) {
473
+ raf = requestAnimationFrame(animate);
474
+ return;
475
+ }
476
+ uniforms.uTime.value = timeOffset + clock.getElapsedTime() * speedRef.current;
477
+ if (liquidEffect)
478
+ liquidEffect.uniforms.get('uTime').value = uniforms.uTime.value;
479
+ if (composer) {
480
+ if (touch)
481
+ touch.update();
482
+ composer.passes.forEach(p => {
483
+ const effs = p.effects;
484
+ if (effs)
485
+ effs.forEach((eff) => {
486
+ const u = eff.uniforms?.get('uTime');
487
+ if (u)
488
+ u.value = uniforms.uTime.value;
489
+ });
490
+ });
491
+ composer.render();
492
+ }
493
+ else
494
+ renderer.render(scene, camera);
495
+ raf = requestAnimationFrame(animate);
496
+ };
497
+ raf = requestAnimationFrame(animate);
498
+ threeRef.current = {
499
+ renderer,
500
+ scene,
501
+ camera,
502
+ material,
503
+ clock,
504
+ clickIx: 0,
505
+ uniforms,
506
+ resizeObserver: ro,
507
+ raf,
508
+ quad,
509
+ timeOffset,
510
+ composer,
511
+ touch,
512
+ liquidEffect
513
+ };
514
+ }
515
+ else {
516
+ const t = threeRef.current;
517
+ t.uniforms.uShapeType.value = SHAPE_MAP[variant] ?? 0;
518
+ t.uniforms.uPixelSize.value = pixelSize * t.renderer.getPixelRatio();
519
+ t.uniforms.uColor.value.set(color);
520
+ t.uniforms.uScale.value = patternScale;
521
+ t.uniforms.uDensity.value = patternDensity;
522
+ t.uniforms.uPixelJitter.value = pixelSizeJitter;
523
+ t.uniforms.uEnableRipples.value = enableRipples ? 1 : 0;
524
+ t.uniforms.uRippleIntensity.value = rippleIntensityScale;
525
+ t.uniforms.uRippleThickness.value = rippleThickness;
526
+ t.uniforms.uRippleSpeed.value = rippleSpeed;
527
+ t.uniforms.uEdgeFade.value = edgeFade;
528
+ if (transparent)
529
+ t.renderer.setClearAlpha(0);
530
+ else
531
+ t.renderer.setClearColor(0x000000, 1);
532
+ if (t.liquidEffect) {
533
+ const uStrength = t.liquidEffect.uniforms.get('uStrength');
534
+ if (uStrength)
535
+ uStrength.value = liquidStrength;
536
+ const uFreq = t.liquidEffect.uniforms.get('uFreq');
537
+ if (uFreq)
538
+ uFreq.value = liquidWobbleSpeed;
539
+ }
540
+ if (t.touch)
541
+ t.touch.radiusScale = liquidRadius;
542
+ }
543
+ prevConfigRef.current = cfg;
544
+ return () => {
545
+ if (threeRef.current && mustReinit)
546
+ return;
547
+ if (!threeRef.current)
548
+ return;
549
+ const t = threeRef.current;
550
+ t.resizeObserver?.disconnect();
551
+ cancelAnimationFrame(t.raf);
552
+ t.quad?.geometry.dispose();
553
+ t.material.dispose();
554
+ t.composer?.dispose();
555
+ t.renderer.dispose();
556
+ if (t.renderer.domElement.parentElement === container)
557
+ container.removeChild(t.renderer.domElement);
558
+ threeRef.current = null;
559
+ };
560
+ }, [
561
+ antialias,
562
+ liquid,
563
+ noiseAmount,
564
+ pixelSize,
565
+ patternScale,
566
+ patternDensity,
567
+ enableRipples,
568
+ rippleIntensityScale,
569
+ rippleThickness,
570
+ rippleSpeed,
571
+ pixelSizeJitter,
572
+ edgeFade,
573
+ transparent,
574
+ liquidStrength,
575
+ liquidRadius,
576
+ liquidWobbleSpeed,
577
+ autoPauseOffscreen,
578
+ variant,
579
+ color,
580
+ speed
581
+ ]);
582
+ return (_jsx("div", { ref: containerRef, className: `w-full h-full relative overflow-hidden ${className ?? ''}`, style: style, "aria-label": "PixelBlast interactive background" }));
583
+ };
584
+ export default PixelBlast;
@@ -0,0 +1 @@
1
+ export declare function mount(): Promise<void>;
@@ -0,0 +1,56 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import ReactDOM from 'react-dom/client';
3
+ import { RouterProvider } from './router';
4
+ import App from './app';
5
+ import { showErrorOverlay } from './error-overlay';
6
+ import { loadRoute, loadRootLayout } from './app';
7
+ export async function mount() {
8
+ // For Full Document Hydration (RootLayout provides html/body)
9
+ // we hydrate 'document' directly.
10
+ const root = document;
11
+ let initialComponent;
12
+ let initialRootLayout;
13
+ let initialMetadata = {};
14
+ try {
15
+ const [component, layoutResult] = await Promise.all([
16
+ loadRoute(window.location.pathname),
17
+ loadRootLayout()
18
+ ]);
19
+ initialComponent = component || undefined;
20
+ initialRootLayout = layoutResult?.Component || undefined;
21
+ initialMetadata = layoutResult?.metadata || {};
22
+ }
23
+ catch (e) {
24
+ // We hydrate the full document because we are doing full SSR with HTML shell.
25
+ }
26
+ // @ts-ignore
27
+ ReactDOM.hydrateRoot(window.document,
28
+ // <React.StrictMode>
29
+ _jsx(RouterProvider, { children: _jsx(App, { initialComponent: initialComponent, initialRootLayout: initialRootLayout, metadata: initialMetadata, assets: window.__VISTA_ASSETS__ || [] }) }),
30
+ // </React.StrictMode>
31
+ {
32
+ onRecoverableError: (error) => {
33
+ console.error('Hydration failed:', error);
34
+ // Only show overlay if it's a real error, not just a cancelled transition
35
+ // showErrorOverlay(error as Error, 'Hydration Mismatch');
36
+ }
37
+ });
38
+ }
39
+ // Auto-mount if in browser environment and not already mounted
40
+ if (typeof window !== 'undefined') {
41
+ window.addEventListener('error', (event) => {
42
+ console.error('Global Error Caught:', event.error);
43
+ showErrorOverlay(event.error, 'Runtime Error');
44
+ });
45
+ // Wrapped in async IIFE to handle await
46
+ (async () => {
47
+ try {
48
+ console.log('Mounting Vista App...');
49
+ await mount();
50
+ }
51
+ catch (e) {
52
+ console.error('Mounting failed:', e);
53
+ showErrorOverlay(e, 'Mount Error');
54
+ }
55
+ })();
56
+ }
@@ -0,0 +1,9 @@
1
+ import ReactDOMServer from 'react-dom/server';
2
+ export declare function render(url: string, options?: {
3
+ onShellReady?: () => void;
4
+ onAllReady?: () => void;
5
+ onError?: (err: unknown) => void;
6
+ bootstrapModules?: string[];
7
+ stylesheets?: string[];
8
+ preamble?: string;
9
+ }): Promise<ReactDOMServer.PipeableStream>;
@@ -0,0 +1,33 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { renderToPipeableStream } from 'react-dom/server';
3
+ import { RouterProvider } from './router';
4
+ import App from './app';
5
+ import { loadRootLayout } from './app';
6
+ export async function render(url, options = {}) {
7
+ // Preload Root Layout synchronously for the render pass
8
+ let initialRootLayout;
9
+ let initialMetadata = {};
10
+ try {
11
+ const result = await loadRootLayout();
12
+ initialRootLayout = result.Component;
13
+ initialMetadata = result.metadata;
14
+ }
15
+ catch (e) {
16
+ console.error('Server failed to load root layout', e);
17
+ }
18
+ // Construct Assets Array
19
+ const assets = [];
20
+ // 1. Preamble (if any)
21
+ if (options.preamble) {
22
+ assets.push({ type: 'preamble', content: options.preamble, key: 'preamble' });
23
+ }
24
+ // 2. Stylesheets
25
+ options.stylesheets?.forEach(src => {
26
+ assets.push({ type: 'style', src, key: src });
27
+ });
28
+ // 3. Bootstrap Scripts
29
+ options.bootstrapModules?.forEach(src => {
30
+ assets.push({ type: 'script', src, key: src });
31
+ });
32
+ return renderToPipeableStream(_jsx(RouterProvider, { url: url, children: _jsx(App, { initialRootLayout: initialRootLayout || undefined, metadata: initialMetadata, assets: assets }) }), options);
33
+ }
@@ -0,0 +1 @@
1
+ export declare function showErrorOverlay(err: Error, title?: string): void;