@toriistudio/shader-ui 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -32,6 +32,7 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  AnimatedDrawingSVG: () => AnimatedDrawingSVG,
34
34
  DitherPulseRing: () => DitherPulseRing,
35
+ DitherStream: () => DitherStream,
35
36
  EFECTO_ASCII_COMPONENT_DEFAULTS: () => EFECTO_ASCII_COMPONENT_DEFAULTS,
36
37
  EFECTO_ASCII_POST_PROCESSING_DEFAULTS: () => EFECTO_ASCII_POST_PROCESSING_DEFAULTS,
37
38
  Efecto: () => Efecto,
@@ -3550,7 +3551,7 @@ var THREE9 = __toESM(require("three"));
3550
3551
  var import_react11 = require("react");
3551
3552
  var THREE8 = __toESM(require("three"));
3552
3553
 
3553
- // src/hooks/SceneProvider.tsx
3554
+ // src/context/SceneProvider.tsx
3554
3555
  var import_react10 = require("react");
3555
3556
  var import_jsx_runtime11 = require("react/jsx-runtime");
3556
3557
  var SceneProviderContext = (0, import_react10.createContext)(null);
@@ -3746,7 +3747,15 @@ function ShaderPass({
3746
3747
  context.renderer.setRenderTarget(prevTarget);
3747
3748
  context.renderer.autoClear = prevAutoClear;
3748
3749
  },
3749
- [clear, clearColor, enabled, resolutionUniform, target, timeUniform, uniforms]
3750
+ [
3751
+ clear,
3752
+ clearColor,
3753
+ enabled,
3754
+ resolutionUniform,
3755
+ target,
3756
+ timeUniform,
3757
+ uniforms
3758
+ ]
3750
3759
  );
3751
3760
  const sharedContextRef = sharedScene?.contextRef;
3752
3761
  const shouldCreateOwnScene = !sharedContextRef;
@@ -3776,13 +3785,10 @@ function ShaderPass({
3776
3785
  renderOnce();
3777
3786
  return;
3778
3787
  }
3779
- const unregister = register(
3780
- (ctx, delta, elapsed) => {
3781
- void elapsed;
3782
- handleRender(ctx, delta);
3783
- },
3784
- priority
3785
- );
3788
+ const unregister = register((ctx, delta, elapsed) => {
3789
+ void elapsed;
3790
+ handleRender(ctx, delta);
3791
+ }, priority);
3786
3792
  return () => {
3787
3793
  unregister?.();
3788
3794
  };
@@ -4238,75 +4244,14 @@ function ExpandingRingPass({
4238
4244
  var import_react19 = require("react");
4239
4245
  var THREE16 = __toESM(require("three"));
4240
4246
 
4241
- // src/components/CombineShaderPass.tsx
4247
+ // src/components/TargetPreview.tsx
4242
4248
  var import_react17 = require("react");
4243
4249
  var THREE14 = __toESM(require("three"));
4244
4250
  var import_jsx_runtime18 = require("react/jsx-runtime");
4245
- var VERT = `
4246
- out vec2 vUv;
4247
-
4248
- void main() {
4249
- vUv = uv;
4250
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
4251
- }
4252
- `;
4253
- var FRAG = `
4254
- precision highp float;
4255
-
4256
- in vec2 vUv;
4257
-
4258
- uniform sampler2D uTextureA;
4259
- uniform sampler2D uTextureB;
4260
-
4261
- out vec4 fragColor;
4262
-
4263
- void main() {
4264
- vec4 a = texture(uTextureA, vUv);
4265
- vec4 b = texture(uTextureB, vUv);
4266
- vec3 rgb = a.rgb + b.rgb;
4267
- float alpha = max(a.a, b.a);
4268
- fragColor = vec4(rgb, alpha);
4269
- }
4270
- `;
4271
- function CombineShaderPass({
4272
- inputA,
4273
- inputB,
4274
- target = null,
4275
- clear = true,
4276
- priority = 0
4277
- }) {
4278
- const uniforms = (0, import_react17.useMemo)(
4279
- () => ({
4280
- uTextureA: { value: inputA },
4281
- uTextureB: { value: inputB }
4282
- }),
4283
- // eslint-disable-next-line react-hooks/exhaustive-deps
4284
- []
4285
- );
4286
- uniforms.uTextureA.value = inputA;
4287
- uniforms.uTextureB.value = inputB;
4288
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4289
- ShaderPass,
4290
- {
4291
- vertexShader: VERT,
4292
- fragmentShader: FRAG,
4293
- uniforms,
4294
- target,
4295
- clear,
4296
- priority,
4297
- blending: THREE14.NoBlending
4298
- }
4299
- );
4300
- }
4301
-
4302
- // src/components/TargetPreview.tsx
4303
- var import_react18 = require("react");
4304
- var THREE15 = __toESM(require("three"));
4305
- var import_jsx_runtime19 = require("react/jsx-runtime");
4306
4251
  function TargetPreview({
4307
4252
  target,
4308
4253
  renderOrder = 0,
4309
- blending = THREE15.NoBlending,
4254
+ blending = THREE14.NoBlending,
4310
4255
  transparent = true,
4311
4256
  toneMapped = false,
4312
4257
  className,
@@ -4315,15 +4260,15 @@ function TargetPreview({
4315
4260
  height,
4316
4261
  ...divProps
4317
4262
  }) {
4318
- const assetsRef = (0, import_react18.useRef)(null);
4263
+ const assetsRef = (0, import_react17.useRef)(null);
4319
4264
  const sharedScene = useSceneContext();
4320
4265
  const sharedReady = sharedScene?.ready ?? true;
4321
- const handleCreate = (0, import_react18.useCallback)(() => {
4322
- const scene = new THREE15.Scene();
4323
- const camera = new THREE15.OrthographicCamera(-1, 1, 1, -1, 0, 1);
4266
+ const handleCreate = (0, import_react17.useCallback)(() => {
4267
+ const scene = new THREE14.Scene();
4268
+ const camera = new THREE14.OrthographicCamera(-1, 1, 1, -1, 0, 1);
4324
4269
  camera.position.z = 1;
4325
- const geometry = new THREE15.PlaneGeometry(2, 2);
4326
- const material = new THREE15.MeshBasicMaterial({
4270
+ const geometry = new THREE14.PlaneGeometry(2, 2);
4271
+ const material = new THREE14.MeshBasicMaterial({
4327
4272
  map: target.texture,
4328
4273
  toneMapped,
4329
4274
  transparent,
@@ -4331,7 +4276,7 @@ function TargetPreview({
4331
4276
  depthWrite: false,
4332
4277
  depthTest: false
4333
4278
  });
4334
- const mesh = new THREE15.Mesh(geometry, material);
4279
+ const mesh = new THREE14.Mesh(geometry, material);
4335
4280
  mesh.renderOrder = renderOrder;
4336
4281
  scene.add(mesh);
4337
4282
  assetsRef.current = { scene, camera, mesh, geometry, material };
@@ -4342,7 +4287,7 @@ function TargetPreview({
4342
4287
  assetsRef.current = null;
4343
4288
  };
4344
4289
  }, [blending, renderOrder, target.texture, toneMapped, transparent]);
4345
- const handleRender = (0, import_react18.useCallback)((context) => {
4290
+ const handleRender = (0, import_react17.useCallback)((context) => {
4346
4291
  const assets = assetsRef.current;
4347
4292
  if (!assets) return;
4348
4293
  const prevTarget = context.renderer.getRenderTarget();
@@ -4356,13 +4301,13 @@ function TargetPreview({
4356
4301
  onCreate: shouldCreateOwnScene ? handleCreate : void 0,
4357
4302
  onRender: shouldCreateOwnScene ? handleRender : void 0
4358
4303
  });
4359
- const containerRef = shouldCreateOwnScene ? ownScene.containerRef : (0, import_react18.useRef)(null);
4360
- (0, import_react18.useEffect)(() => {
4304
+ const containerRef = shouldCreateOwnScene ? ownScene.containerRef : (0, import_react17.useRef)(null);
4305
+ (0, import_react17.useEffect)(() => {
4361
4306
  if (!sharedContextRef || !sharedReady) return;
4362
4307
  const cleanup = handleCreate();
4363
4308
  return cleanup;
4364
4309
  }, [sharedContextRef, handleCreate, sharedReady]);
4365
- (0, import_react18.useEffect)(() => {
4310
+ (0, import_react17.useEffect)(() => {
4366
4311
  if (!sharedContextRef?.current || !sharedReady) return;
4367
4312
  const context = sharedContextRef.current;
4368
4313
  const register = context.registerRenderCallback;
@@ -4370,23 +4315,20 @@ function TargetPreview({
4370
4315
  handleRender(context);
4371
4316
  return;
4372
4317
  }
4373
- const unregister = register(
4374
- (ctx) => {
4375
- handleRender(ctx);
4376
- },
4377
- renderOrder
4378
- );
4318
+ const unregister = register((ctx) => {
4319
+ handleRender(ctx);
4320
+ }, renderOrder);
4379
4321
  return () => {
4380
4322
  unregister?.();
4381
4323
  };
4382
4324
  }, [sharedContextRef, handleRender, renderOrder, sharedReady]);
4383
- (0, import_react18.useEffect)(() => {
4325
+ (0, import_react17.useEffect)(() => {
4384
4326
  const assets = assetsRef.current;
4385
4327
  if (!assets) return;
4386
4328
  assets.material.map = target.texture;
4387
4329
  assets.material.needsUpdate = true;
4388
4330
  }, [target.texture]);
4389
- (0, import_react18.useEffect)(() => {
4331
+ (0, import_react17.useEffect)(() => {
4390
4332
  const assets = assetsRef.current;
4391
4333
  if (!assets) return;
4392
4334
  assets.material.blending = blending;
@@ -4397,7 +4339,7 @@ function TargetPreview({
4397
4339
  if (!shouldCreateOwnScene) {
4398
4340
  return null;
4399
4341
  }
4400
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4342
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
4401
4343
  "div",
4402
4344
  {
4403
4345
  ref: containerRef,
@@ -4412,6 +4354,232 @@ function TargetPreview({
4412
4354
  );
4413
4355
  }
4414
4356
 
4357
+ // src/components/CombineShaderPass.tsx
4358
+ var import_react18 = require("react");
4359
+ var THREE15 = __toESM(require("three"));
4360
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4361
+ var COMBINE_MODE = {
4362
+ add: 0,
4363
+ screen: 1,
4364
+ multiply: 2,
4365
+ overlay: 3,
4366
+ max: 4,
4367
+ min: 5,
4368
+ difference: 6,
4369
+ alphaOver: 7,
4370
+ premultipliedOver: 8,
4371
+ lerp: 9,
4372
+ mask: 10
4373
+ };
4374
+ var TONEMAP = {
4375
+ none: 0,
4376
+ reinhard: 1,
4377
+ aces: 2
4378
+ };
4379
+ var VERT = `
4380
+ out vec2 vUv;
4381
+
4382
+ void main() {
4383
+ vUv = uv;
4384
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
4385
+ }
4386
+ `;
4387
+ var FRAG = `
4388
+ precision highp float;
4389
+
4390
+ in vec2 vUv;
4391
+
4392
+ uniform sampler2D uTextureA;
4393
+ uniform sampler2D uTextureB;
4394
+ uniform sampler2D uMaskTexture;
4395
+
4396
+ uniform int uMode;
4397
+ uniform float uOpacityA;
4398
+ uniform float uOpacityB;
4399
+ uniform float uMix;
4400
+ uniform int uMaskChannel;
4401
+ uniform float uMaskThreshold;
4402
+ uniform bool uInvertMask;
4403
+ uniform bool uClampOutput;
4404
+ uniform int uTonemap;
4405
+ uniform bool uHasMask;
4406
+
4407
+ out vec4 fragColor;
4408
+
4409
+ float overlayChannel(float base, float blend) {
4410
+ return base < 0.5
4411
+ ? (2.0 * base * blend)
4412
+ : (1.0 - 2.0 * (1.0 - base) * (1.0 - blend));
4413
+ }
4414
+
4415
+ vec3 overlayBlend(vec3 base, vec3 blend) {
4416
+ return vec3(
4417
+ overlayChannel(base.r, blend.r),
4418
+ overlayChannel(base.g, blend.g),
4419
+ overlayChannel(base.b, blend.b)
4420
+ );
4421
+ }
4422
+
4423
+ float sampleMask(vec2 uv) {
4424
+ vec4 maskSample = texture(uMaskTexture, uv);
4425
+ float m = maskSample.r;
4426
+ if (uMaskChannel == 1) {
4427
+ m = maskSample.g;
4428
+ } else if (uMaskChannel == 2) {
4429
+ m = maskSample.b;
4430
+ } else if (uMaskChannel == 3) {
4431
+ m = maskSample.a;
4432
+ }
4433
+ if (uInvertMask) {
4434
+ m = 1.0 - m;
4435
+ }
4436
+ return m;
4437
+ }
4438
+
4439
+ vec3 tonemapReinhard(vec3 color) {
4440
+ return color / (color + vec3(1.0));
4441
+ }
4442
+
4443
+ vec3 tonemapAces(vec3 color) {
4444
+ // ACES approximation by Krzysztof Narkowicz
4445
+ float a = 2.51;
4446
+ float b = 0.03;
4447
+ float c = 2.43;
4448
+ float d = 0.59;
4449
+ float e = 0.14;
4450
+ return clamp((color * (a * color + b)) / (color * (c * color + d) + e), 0.0, 1.0);
4451
+ }
4452
+
4453
+ void main() {
4454
+ vec4 a = texture(uTextureA, vUv);
4455
+ vec4 b = texture(uTextureB, vUv);
4456
+
4457
+ a.rgb *= uOpacityA;
4458
+ a.a *= uOpacityA;
4459
+ b.rgb *= uOpacityB;
4460
+ b.a *= uOpacityB;
4461
+
4462
+ vec3 rgb = vec3(0.0);
4463
+ float alpha = 0.0;
4464
+
4465
+ if (uMode == 0) {
4466
+ rgb = a.rgb + b.rgb;
4467
+ alpha = max(a.a, b.a);
4468
+ } else if (uMode == 1) {
4469
+ rgb = 1.0 - (1.0 - a.rgb) * (1.0 - b.rgb);
4470
+ alpha = max(a.a, b.a);
4471
+ } else if (uMode == 2) {
4472
+ rgb = a.rgb * b.rgb;
4473
+ alpha = max(a.a, b.a);
4474
+ } else if (uMode == 3) {
4475
+ rgb = overlayBlend(a.rgb, b.rgb);
4476
+ alpha = max(a.a, b.a);
4477
+ } else if (uMode == 4) {
4478
+ rgb = max(a.rgb, b.rgb);
4479
+ alpha = max(a.a, b.a);
4480
+ } else if (uMode == 5) {
4481
+ rgb = min(a.rgb, b.rgb);
4482
+ alpha = max(a.a, b.a);
4483
+ } else if (uMode == 6) {
4484
+ rgb = abs(a.rgb - b.rgb);
4485
+ alpha = max(a.a, b.a);
4486
+ } else if (uMode == 7) {
4487
+ float outA = a.a + b.a * (1.0 - a.a);
4488
+ vec3 premult = a.rgb * a.a + b.rgb * b.a * (1.0 - a.a);
4489
+ vec3 outRgb = outA > 1e-6 ? premult / outA : vec3(0.0);
4490
+ rgb = outRgb;
4491
+ alpha = outA;
4492
+ } else if (uMode == 8) {
4493
+ rgb = a.rgb + b.rgb * (1.0 - a.a);
4494
+ alpha = a.a + b.a * (1.0 - a.a);
4495
+ } else if (uMode == 9) {
4496
+ float t = uHasMask ? sampleMask(vUv) : uMix;
4497
+ rgb = mix(b.rgb, a.rgb, t);
4498
+ alpha = mix(b.a, a.a, t);
4499
+ } else if (uMode == 10) {
4500
+ float t = uHasMask ? sampleMask(vUv) : uMix;
4501
+ bool chooseA = t > uMaskThreshold;
4502
+ rgb = chooseA ? a.rgb : b.rgb;
4503
+ alpha = chooseA ? a.a : b.a;
4504
+ }
4505
+
4506
+ if (uTonemap == 1) {
4507
+ rgb = tonemapReinhard(rgb);
4508
+ } else if (uTonemap == 2) {
4509
+ rgb = tonemapAces(rgb);
4510
+ }
4511
+
4512
+ if (uClampOutput) {
4513
+ rgb = clamp(rgb, 0.0, 1.0);
4514
+ alpha = clamp(alpha, 0.0, 1.0);
4515
+ }
4516
+
4517
+ fragColor = vec4(rgb, alpha);
4518
+ }
4519
+ `;
4520
+ function CombineShaderPass({
4521
+ inputA,
4522
+ inputB,
4523
+ mode = "add",
4524
+ opacityA = 1,
4525
+ opacityB = 1,
4526
+ clampOutput = true,
4527
+ mix = 0.5,
4528
+ maskTexture,
4529
+ maskChannel = 0,
4530
+ maskThreshold = 0.5,
4531
+ invertMask = false,
4532
+ tonemap = "none",
4533
+ target = null,
4534
+ clear = true,
4535
+ priority = 0
4536
+ }) {
4537
+ const uniforms = (0, import_react18.useMemo)(
4538
+ () => ({
4539
+ uTextureA: { value: inputA },
4540
+ uTextureB: { value: inputB },
4541
+ uMaskTexture: { value: maskTexture ?? inputA },
4542
+ uMode: { value: COMBINE_MODE[mode] },
4543
+ uOpacityA: { value: opacityA },
4544
+ uOpacityB: { value: opacityB },
4545
+ uMix: { value: mix },
4546
+ uMaskChannel: { value: maskChannel },
4547
+ uMaskThreshold: { value: maskThreshold },
4548
+ uInvertMask: { value: invertMask },
4549
+ uClampOutput: { value: clampOutput },
4550
+ uTonemap: { value: TONEMAP[tonemap] },
4551
+ uHasMask: { value: Boolean(maskTexture) }
4552
+ }),
4553
+ // eslint-disable-next-line react-hooks/exhaustive-deps
4554
+ []
4555
+ );
4556
+ uniforms.uTextureA.value = inputA;
4557
+ uniforms.uTextureB.value = inputB;
4558
+ uniforms.uMaskTexture.value = maskTexture ?? inputA;
4559
+ uniforms.uMode.value = COMBINE_MODE[mode];
4560
+ uniforms.uOpacityA.value = opacityA;
4561
+ uniforms.uOpacityB.value = opacityB;
4562
+ uniforms.uMix.value = mix;
4563
+ uniforms.uMaskChannel.value = maskChannel;
4564
+ uniforms.uMaskThreshold.value = maskThreshold;
4565
+ uniforms.uInvertMask.value = invertMask;
4566
+ uniforms.uClampOutput.value = clampOutput;
4567
+ uniforms.uTonemap.value = TONEMAP[tonemap];
4568
+ uniforms.uHasMask.value = Boolean(maskTexture);
4569
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4570
+ ShaderPass,
4571
+ {
4572
+ vertexShader: VERT,
4573
+ fragmentShader: FRAG,
4574
+ uniforms,
4575
+ target,
4576
+ clear,
4577
+ priority,
4578
+ blending: THREE15.NoBlending
4579
+ }
4580
+ );
4581
+ }
4582
+
4415
4583
  // src/components/RenderPipeline.tsx
4416
4584
  var import_jsx_runtime20 = require("react/jsx-runtime");
4417
4585
  var DEFAULT_TARGET_OPTIONS = {
@@ -4420,22 +4588,26 @@ var DEFAULT_TARGET_OPTIONS = {
4420
4588
  };
4421
4589
  function RenderPipeline({
4422
4590
  passes,
4591
+ combine,
4423
4592
  preview = true,
4424
4593
  previewProps
4425
4594
  }) {
4426
4595
  const sharedScene = useSceneContext();
4427
4596
  const size = sharedScene?.size ?? { width: 1, height: 1 };
4597
+ const shouldCombine = Boolean(combine);
4428
4598
  const targets = (0, import_react19.useMemo)(() => {
4429
4599
  const entries = passes.map((_, index) => ({
4430
4600
  key: `pass_${index}`,
4431
4601
  target: new THREE16.WebGLRenderTarget(1, 1, DEFAULT_TARGET_OPTIONS)
4432
4602
  }));
4433
- entries.push({
4434
- key: "combine",
4435
- target: new THREE16.WebGLRenderTarget(1, 1, DEFAULT_TARGET_OPTIONS)
4436
- });
4603
+ if (shouldCombine) {
4604
+ entries.push({
4605
+ key: "combine",
4606
+ target: new THREE16.WebGLRenderTarget(1, 1, DEFAULT_TARGET_OPTIONS)
4607
+ });
4608
+ }
4437
4609
  return entries;
4438
- }, [passes]);
4610
+ }, [passes, shouldCombine]);
4439
4611
  (0, import_react19.useEffect)(() => {
4440
4612
  if (size.width <= 1 || size.height <= 1) return;
4441
4613
  targets.forEach(({ target }) => {
@@ -4453,7 +4625,9 @@ function RenderPipeline({
4453
4625
  throw new Error("RenderPipeline requires at least 2 passes.");
4454
4626
  }
4455
4627
  const passTargets = targets.filter((entry) => entry.key.startsWith("pass_"));
4456
- const combineTarget = targets.find((entry) => entry.key === "combine")?.target;
4628
+ const combineTarget = targets.find(
4629
+ (entry) => entry.key === "combine"
4630
+ )?.target;
4457
4631
  const firstEnabledIndex = passes.findIndex((pass) => pass.enabled !== false);
4458
4632
  const secondEnabledIndex = passes.findIndex(
4459
4633
  (pass, index) => index > firstEnabledIndex && pass.enabled !== false
@@ -4463,7 +4637,7 @@ function RenderPipeline({
4463
4637
  if (!passes.length) return null;
4464
4638
  const lastEnabledIndex = [...passes].map((pass, index) => ({ pass, index })).filter(({ pass }) => pass.enabled !== false).map(({ index }) => index).pop();
4465
4639
  if (lastEnabledIndex === void 0) return null;
4466
- if (lastEnabledIndex <= Math.max(firstEnabledIndex, secondEnabledIndex)) {
4640
+ if (shouldCombine && lastEnabledIndex <= Math.max(firstEnabledIndex, secondEnabledIndex)) {
4467
4641
  return combineTarget ?? null;
4468
4642
  }
4469
4643
  return passOutputTarget(lastEnabledIndex);
@@ -4484,22 +4658,23 @@ function RenderPipeline({
4484
4658
  },
4485
4659
  `pass_${index}`
4486
4660
  );
4487
- if (!combineRendered && combineTarget && index === secondEnabledIndex) {
4661
+ if (shouldCombine && !combineRendered && combineTarget && index === secondEnabledIndex) {
4488
4662
  const inputA = passOutputTarget(firstEnabledIndex)?.texture ?? inputTexture;
4489
4663
  const inputB = passOutputTarget(secondEnabledIndex)?.texture ?? inputTexture;
4490
4664
  combineRendered = true;
4491
4665
  previousOutput = combineTarget;
4492
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_jsx_runtime20.Fragment, { children: [
4666
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(import_react19.Fragment, { children: [
4493
4667
  element,
4494
4668
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
4495
4669
  CombineShaderPass,
4496
4670
  {
4671
+ ...combine,
4497
4672
  inputA,
4498
4673
  inputB,
4499
4674
  target: combineTarget
4500
4675
  }
4501
4676
  )
4502
- ] });
4677
+ ] }, `combine_${index}`);
4503
4678
  }
4504
4679
  previousOutput = target;
4505
4680
  return element;
@@ -4577,20 +4752,23 @@ function useMouse({
4577
4752
  const handleMouseLeave = () => {
4578
4753
  mouse.set(center?.x ?? 0.5, center?.y ?? 0.5);
4579
4754
  };
4580
- const moveTarget = element ?? window;
4581
- moveTarget.addEventListener("mousemove", handleMouseMove);
4582
- moveTarget.addEventListener("mouseleave", handleMouseLeave);
4583
4755
  if (element) {
4756
+ element.addEventListener("mousemove", handleMouseMove);
4757
+ element.addEventListener("mouseleave", handleMouseLeave);
4584
4758
  element.addEventListener("mouseenter", updateRect);
4759
+ } else if (hasWindow) {
4760
+ window.addEventListener("mousemove", handleMouseMove);
4585
4761
  }
4586
4762
  if (hasWindow) {
4587
4763
  window.addEventListener("resize", handleResize);
4588
4764
  }
4589
4765
  return () => {
4590
- moveTarget.removeEventListener("mousemove", handleMouseMove);
4591
- moveTarget.removeEventListener("mouseleave", handleMouseLeave);
4592
4766
  if (element) {
4767
+ element.removeEventListener("mousemove", handleMouseMove);
4768
+ element.removeEventListener("mouseleave", handleMouseLeave);
4593
4769
  element.removeEventListener("mouseenter", updateRect);
4770
+ } else if (hasWindow) {
4771
+ window.removeEventListener("mousemove", handleMouseMove);
4594
4772
  }
4595
4773
  if (hasWindow) {
4596
4774
  window.removeEventListener("resize", handleResize);
@@ -4770,6 +4948,7 @@ function DitherPulseRing({
4770
4948
  diffuseEnabled = false,
4771
4949
  blurEnabled = false,
4772
4950
  noiseWarpEnabled = false,
4951
+ combineMode,
4773
4952
  noiseWarpRadius,
4774
4953
  noiseWarpStrength,
4775
4954
  diffuseRadius,
@@ -4806,6 +4985,7 @@ function DitherPulseRing({
4806
4985
  diffuseEnabled,
4807
4986
  blurEnabled,
4808
4987
  noiseWarpEnabled,
4988
+ combineMode,
4809
4989
  noiseWarpRadius,
4810
4990
  noiseWarpStrength,
4811
4991
  diffuseRadius,
@@ -4831,6 +5011,7 @@ function DitherPulseRingContent({
4831
5011
  diffuseEnabled = false,
4832
5012
  blurEnabled = false,
4833
5013
  noiseWarpEnabled = false,
5014
+ combineMode,
4834
5015
  noiseWarpRadius,
4835
5016
  noiseWarpStrength,
4836
5017
  diffuseRadius,
@@ -4846,6 +5027,22 @@ function DitherPulseRingContent({
4846
5027
  ringPosition,
4847
5028
  ringAlpha
4848
5029
  }) {
5030
+ const normalizeHexColor = (hex) => {
5031
+ if (!hex) return null;
5032
+ const normalized = hex.replace("#", "");
5033
+ if (normalized.length !== 6) return null;
5034
+ const r = parseInt(normalized.slice(0, 2), 16) / 255;
5035
+ const g = parseInt(normalized.slice(2, 4), 16) / 255;
5036
+ const b = parseInt(normalized.slice(4, 6), 16) / 255;
5037
+ return [r, g, b];
5038
+ };
5039
+ const resolveColor = (color) => {
5040
+ if (!color) return null;
5041
+ if (typeof color === "string") {
5042
+ return normalizeHexColor(color);
5043
+ }
5044
+ return color;
5045
+ };
4849
5046
  const glyphUniforms = {};
4850
5047
  glyphUniforms.trackMouse = false;
4851
5048
  const noiseUniforms = {};
@@ -4869,49 +5066,529 @@ function DitherPulseRingContent({
4869
5066
  const borderUniforms = {};
4870
5067
  if (borderThickness !== void 0) borderUniforms.thickness = borderThickness;
4871
5068
  if (borderIntensity !== void 0) borderUniforms.intensity = borderIntensity;
4872
- if (borderColor) borderUniforms.color = borderColor;
5069
+ const resolvedBorderColor = resolveColor(borderColor);
5070
+ if (resolvedBorderColor) borderUniforms.color = resolvedBorderColor;
4873
5071
  if (borderDitherStrength !== void 0) {
4874
5072
  borderUniforms.ditherStrength = borderDitherStrength;
4875
5073
  }
4876
5074
  if (borderTonemap !== void 0) borderUniforms.tonemap = borderTonemap;
4877
5075
  if (borderAlpha !== void 0) borderUniforms.alpha = borderAlpha;
4878
5076
  const ringUniforms = {};
4879
- if (ringColor) ringUniforms.color = ringColor;
5077
+ const resolvedRingColor = resolveColor(ringColor);
5078
+ if (resolvedRingColor) ringUniforms.color = resolvedRingColor;
4880
5079
  if (ringSpeed !== void 0) ringUniforms.speed = ringSpeed;
4881
5080
  if (ringPosition) ringUniforms.position = ringPosition;
4882
5081
  if (ringAlpha !== void 0) ringUniforms.alpha = ringAlpha;
4883
- return /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
4884
- RenderPipeline,
5082
+ return /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
5083
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5084
+ RenderPipeline,
5085
+ {
5086
+ passes: [
5087
+ {
5088
+ component: BorderBeamPass,
5089
+ props: { uniforms: borderUniforms }
5090
+ },
5091
+ {
5092
+ component: GlyphDitherPass,
5093
+ enabled: glyphDitherEnabled,
5094
+ props: { spriteTextureSrc, uniforms: glyphUniforms }
5095
+ }
5096
+ ],
5097
+ combine: combineMode ? { mode: combineMode } : void 0
5098
+ }
5099
+ ),
5100
+ /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
5101
+ RenderPipeline,
5102
+ {
5103
+ passes: [
5104
+ {
5105
+ component: BorderBeamPass,
5106
+ props: { uniforms: borderUniforms }
5107
+ },
5108
+ {
5109
+ component: ExpandingRingPass,
5110
+ props: { uniforms: ringUniforms }
5111
+ },
5112
+ {
5113
+ component: NoiseWarpPass,
5114
+ enabled: noiseWarpEnabled,
5115
+ props: { uniforms: noiseUniforms }
5116
+ },
5117
+ {
5118
+ component: GlyphDitherPass,
5119
+ enabled: glyphDitherEnabled,
5120
+ props: { spriteTextureSrc, uniforms: glyphUniforms }
5121
+ },
5122
+ {
5123
+ component: DiffusePass,
5124
+ enabled: diffuseEnabled,
5125
+ props: { uniforms: diffuseUniforms }
5126
+ },
5127
+ {
5128
+ component: BlurPass,
5129
+ enabled: blurEnabled,
5130
+ props: { uniforms: blurUniforms }
5131
+ }
5132
+ ],
5133
+ combine: combineMode ? { mode: combineMode } : void 0
5134
+ }
5135
+ )
5136
+ ] });
5137
+ }
5138
+
5139
+ // src/components/DitherStreamBeamCompositePass.tsx
5140
+ var import_react23 = require("react");
5141
+ var THREE21 = __toESM(require("three"));
5142
+
5143
+ // src/utils/createFallbackTexture.ts
5144
+ var THREE20 = __toESM(require("three"));
5145
+ function createFallbackTexture() {
5146
+ const data = new Uint8Array([0, 0, 0, 255]);
5147
+ const texture = new THREE20.DataTexture(data, 1, 1, THREE20.RGBAFormat);
5148
+ texture.needsUpdate = true;
5149
+ texture.wrapS = THREE20.ClampToEdgeWrapping;
5150
+ texture.wrapT = THREE20.ClampToEdgeWrapping;
5151
+ texture.minFilter = THREE20.NearestFilter;
5152
+ texture.magFilter = THREE20.NearestFilter;
5153
+ return texture;
5154
+ }
5155
+
5156
+ // src/shaders/dither-godray-beam-composite/fragment.glsl
5157
+ var fragment_default15 = "precision highp float;\nprecision highp int;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform float uTime;\nuniform vec2 uResolution;\nuniform float uBeamSpeed;\nuniform float uBeamDirection;\nuniform vec3 uBeamColor;\nuniform vec2 uBeamCenter;\nuniform float uBeamRadius;\nuniform float uBeamScale;\nuniform int uPathShape;\nuniform vec2 uPathPos;\nuniform float uPathAngle;\n\nout vec4 fragColor;\n\nconst float PI = 3.14159265;\nconst float TWO_PI = 6.28318531;\n\nuvec2 hash2d(uvec2 v) {\n v = v * 1664525u + 1013904223u;\n v.x += v.y * v.y * 1664525u + 1013904223u;\n v.y += v.x * v.x * 1664525u + 1013904223u;\n v ^= v >> 16u;\n v.x += v.y * v.y * 1664525u + 1013904223u;\n v.y += v.x * v.x * 1664525u + 1013904223u;\n return v;\n}\n\nfloat randomFibo(vec2 p) {\n uvec2 v = floatBitsToUint(p);\n v = hash2d(v);\n return float(v.x ^ v.y) / float(0xffffffffu);\n}\n\nfloat calculateAngle(vec2 p, vec2 c) {\n float a = atan(p.y - c.y, p.x - c.x);\n return a < 0.0 ? a + TWO_PI : a;\n}\n\nfloat angularDiff(float a, float b) {\n float d = abs(a - b);\n return d > PI ? TWO_PI - d : d;\n}\n\nfloat angularFade(float pointAngle, float peakAngle, float fadeAmount) {\n return 1.04 - smoothstep(0.0, fadeAmount, angularDiff(pointAngle, peakAngle));\n}\n\nfloat sdEquilateralTriangle(vec2 p) {\n const float k = 1.7320508;\n p.x = abs(p.x) - 1.0;\n p.y = p.y + 1.0 / k;\n if (p.x + k * p.y > 0.0) {\n p = vec2(p.x - k * p.y, -k * p.x - p.y) / 2.0;\n }\n p.x -= clamp(p.x, -2.0, 0.0);\n return -length(p) * sign(p.y);\n}\n\nvec3 dodge(vec3 src, vec3 dst) {\n return vec3(\n src.x >= 1.0 ? 1.0 : min(1.0, dst.x / max(0.001, 1.0 - src.x)),\n src.y >= 1.0 ? 1.0 : min(1.0, dst.y / max(0.001, 1.0 - src.y)),\n src.z >= 1.0 ? 1.0 : min(1.0, dst.z / max(0.001, 1.0 - src.z))\n );\n}\n\nfloat easeExpoIn(float t) {\n return t <= 0.0 ? 0.0 : pow(2.0, 10.0 * (t - 1.0));\n}\n\nvec2 rot2(vec2 v, float a) {\n float c = cos(a);\n float s = sin(a);\n return vec2(v.x * c - v.y * s, v.x * s + v.y * c);\n}\n\nvec3 beamAt(vec2 uv) {\n float aspect = uResolution.x / uResolution.y;\n vec2 center = uBeamCenter;\n\n vec2 u2 = vec2(uv.x * aspect, uv.y);\n vec2 c2 = vec2(center.x * aspect, center.y);\n\n float ringRadius = uBeamRadius;\n vec2 delta = (u2 - c2) / max(uBeamScale, 0.0001);\n float circleDist = abs(length(delta) - ringRadius);\n float squareDist = abs(max(abs(delta.x), abs(delta.y)) - ringRadius);\n float diamondDist = abs(abs(delta.x) + abs(delta.y) - ringRadius);\n float ovalDist =\n abs(length(vec2(delta.x / 1.5, delta.y)) - ringRadius);\n float triangleDist =\n abs(sdEquilateralTriangle(delta / max(ringRadius, 0.0001))) * ringRadius;\n\n float ringDist = circleDist;\n if (uPathShape == 1) {\n ringDist = squareDist;\n } else if (uPathShape == 2) {\n ringDist = diamondDist;\n } else if (uPathShape == 3) {\n ringDist = triangleDist;\n } else if (uPathShape == 4) {\n ringDist = ovalDist;\n }\n\n float b = 0.25 / (1.0 - smoothstep(0.2, 0.002, ringDist + 0.02));\n float ang = fract(0.19 + uTime * uBeamSpeed * uBeamDirection) * TWO_PI;\n b *= angularFade(calculateAngle(u2, c2), ang, PI * 0.5);\n\n vec3 col = b * pow(max(0.0, 1.0 - ringDist), 3.0) * uBeamColor;\n col = tanh(clamp(col, -40.0, 40.0));\n col += (randomFibo(gl_FragCoord.xy) - 0.5) / 255.0;\n\n return col;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n float ang = uPathAngle;\n vec2 pos = uPathPos;\n vec2 off = uv - pos;\n vec2 ro = rot2(off, -ang);\n vec2 so = ro;\n\n if (ro.x > 0.0) {\n float e = easeExpoIn(ro.x);\n so.y = ro.y / (1.0 + 4.0 * e * e);\n }\n\n vec2 st = clamp(pos + rot2(so, ang), 0.0, 1.0);\n\n vec3 beam = beamAt(st);\n vec4 img = texture(uTexture, st);\n vec3 outColor = mix(beam, dodge(img.rgb, beam), img.a);\n\n fragColor = vec4(outColor, 1.0);\n}\n";
5158
+
5159
+ // src/shaders/dither-godray-beam-composite/vertex.glsl
5160
+ var vertex_default14 = "out vec2 vTextureCoord;\n\nvoid main() {\n vTextureCoord = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
5161
+
5162
+ // src/components/DitherStreamBeamCompositePass.tsx
5163
+ var import_jsx_runtime24 = require("react/jsx-runtime");
5164
+ function DitherStreamBeamCompositePass({
5165
+ inputTexture = null,
5166
+ beamSpeed = 0.1,
5167
+ beamDirection = "counterclockwise",
5168
+ beamColor = [0.667, 0.686, 0.941],
5169
+ beamCenter = [0.5, 0.95],
5170
+ beamRadius = 0.6,
5171
+ beamScale = 1,
5172
+ pathShape = "circle",
5173
+ pathPos = [0.5009, 1.0473],
5174
+ pathAngle = (0.999 - 0.25) * -6.28318531,
5175
+ target = null,
5176
+ clear = true,
5177
+ enabled = true,
5178
+ priority = 0
5179
+ }) {
5180
+ const fallbackTexture = (0, import_react23.useMemo)(() => createFallbackTexture(), []);
5181
+ const uniforms = (0, import_react23.useMemo)(
5182
+ () => ({
5183
+ uTexture: { value: inputTexture ?? fallbackTexture },
5184
+ uTime: { value: 0 },
5185
+ uResolution: { value: new THREE21.Vector2(1, 1) },
5186
+ uBeamSpeed: { value: beamSpeed },
5187
+ uBeamDirection: { value: beamDirection === "clockwise" ? -1 : 1 },
5188
+ uBeamColor: {
5189
+ value: new THREE21.Color(beamColor[0], beamColor[1], beamColor[2])
5190
+ },
5191
+ uBeamCenter: { value: new THREE21.Vector2(beamCenter[0], beamCenter[1]) },
5192
+ uBeamRadius: { value: beamRadius },
5193
+ uBeamScale: { value: beamScale },
5194
+ uPathShape: {
5195
+ value: pathShape === "square" ? 1 : pathShape === "diamond" ? 2 : pathShape === "triangle" ? 3 : pathShape === "oval" ? 4 : 0
5196
+ },
5197
+ uPathPos: { value: new THREE21.Vector2(pathPos[0], pathPos[1]) },
5198
+ uPathAngle: { value: pathAngle }
5199
+ }),
5200
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5201
+ []
5202
+ );
5203
+ uniforms.uTexture.value = inputTexture ?? fallbackTexture;
5204
+ uniforms.uBeamSpeed.value = beamSpeed;
5205
+ uniforms.uBeamDirection.value = beamDirection === "clockwise" ? -1 : 1;
5206
+ uniforms.uBeamColor.value.setRGB(
5207
+ beamColor[0],
5208
+ beamColor[1],
5209
+ beamColor[2]
5210
+ );
5211
+ uniforms.uBeamCenter.value.set(
5212
+ beamCenter[0],
5213
+ beamCenter[1]
5214
+ );
5215
+ uniforms.uBeamRadius.value = beamRadius;
5216
+ uniforms.uBeamScale.value = beamScale;
5217
+ uniforms.uPathShape.value = pathShape === "square" ? 1 : pathShape === "diamond" ? 2 : pathShape === "triangle" ? 3 : pathShape === "oval" ? 4 : 0;
5218
+ uniforms.uPathPos.value.set(pathPos[0], pathPos[1]);
5219
+ uniforms.uPathAngle.value = pathAngle;
5220
+ return /* @__PURE__ */ (0, import_jsx_runtime24.jsx)(
5221
+ ShaderPass,
4885
5222
  {
4886
- passes: [
4887
- {
4888
- component: BorderBeamPass,
4889
- props: { uniforms: borderUniforms }
4890
- },
4891
- {
4892
- component: ExpandingRingPass,
4893
- props: { clear: true, uniforms: ringUniforms }
4894
- },
4895
- {
4896
- component: NoiseWarpPass,
4897
- enabled: noiseWarpEnabled,
4898
- props: { uniforms: noiseUniforms }
4899
- },
4900
- {
4901
- component: GlyphDitherPass,
4902
- enabled: glyphDitherEnabled,
4903
- props: { spriteTextureSrc, uniforms: glyphUniforms }
4904
- },
4905
- {
4906
- component: DiffusePass,
4907
- enabled: diffuseEnabled,
4908
- props: { uniforms: diffuseUniforms }
4909
- },
4910
- {
4911
- component: BlurPass,
4912
- enabled: blurEnabled,
4913
- props: { uniforms: blurUniforms }
5223
+ vertexShader: vertex_default14,
5224
+ fragmentShader: fragment_default15,
5225
+ uniforms,
5226
+ inputTexture: inputTexture ?? fallbackTexture,
5227
+ target,
5228
+ clear,
5229
+ enabled,
5230
+ priority,
5231
+ timeUniform: "uTime",
5232
+ resolutionUniform: "uResolution",
5233
+ blending: THREE21.NoBlending
5234
+ }
5235
+ );
5236
+ }
5237
+
5238
+ // src/components/DitherStreamDitherPass.tsx
5239
+ var import_react24 = require("react");
5240
+ var THREE22 = __toESM(require("three"));
5241
+
5242
+ // src/shaders/dither-godray-dither/fragment.glsl
5243
+ var fragment_default16 = "precision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTexture;\nuniform vec2 uResolution;\n\nout vec4 fragColor;\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n float ar = uResolution.x / uResolution.y;\n float ac = mix(ar, 1.0 / ar, 0.5);\n\n float gs = 0.005;\n float bg = 1.0 / gs;\n vec2 cellSize = vec2(1.0 / (bg * ar), 1.0 / bg) * ac;\n\n vec2 pos = vec2(0.5);\n vec2 off = uv - pos;\n vec2 cell = floor(off / cellSize);\n vec2 center = (cell + 0.5) * cellSize;\n vec2 pixelUv = center + pos;\n\n vec4 c = texture(uTexture, pixelUv);\n float lum = dot(c.rgb, vec3(0.2126, 0.7152, 0.0722));\n float gm = pow(mix(0.2, 2.2, 0.3), 2.2);\n\n vec2 local = mod(uv - pos, cellSize) / cellSize;\n vec2 ct = local * 2.0 - 1.0;\n float d = length(ct);\n\n float ns = 16.0;\n float si = clamp(floor(lum * ns * gm), 0.0, ns - 1.0);\n float rad = si / ns;\n float alpha = smoothstep(rad + 0.08, rad - 0.08, d);\n\n vec3 tint = (c.rgb - si * 0.04) * 1.4;\n fragColor = vec4(mix(vec3(0.0), tint, alpha), 1.0);\n}\n";
5244
+
5245
+ // src/shaders/dither-godray-dither/vertex.glsl
5246
+ var vertex_default15 = "out vec2 vTextureCoord;\n\nvoid main() {\n vTextureCoord = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
5247
+
5248
+ // src/components/DitherStreamDitherPass.tsx
5249
+ var import_jsx_runtime25 = require("react/jsx-runtime");
5250
+ function DitherStreamDitherPass({
5251
+ inputTexture = null,
5252
+ target = null,
5253
+ clear = true,
5254
+ enabled = true,
5255
+ priority = 0
5256
+ }) {
5257
+ const fallbackTexture = (0, import_react24.useMemo)(() => createFallbackTexture(), []);
5258
+ const uniforms = (0, import_react24.useMemo)(
5259
+ () => ({
5260
+ uTexture: { value: inputTexture ?? fallbackTexture },
5261
+ uResolution: { value: new THREE22.Vector2(1, 1) }
5262
+ }),
5263
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5264
+ []
5265
+ );
5266
+ uniforms.uTexture.value = inputTexture ?? fallbackTexture;
5267
+ return /* @__PURE__ */ (0, import_jsx_runtime25.jsx)(
5268
+ ShaderPass,
5269
+ {
5270
+ vertexShader: vertex_default15,
5271
+ fragmentShader: fragment_default16,
5272
+ uniforms,
5273
+ inputTexture: inputTexture ?? fallbackTexture,
5274
+ target,
5275
+ clear,
5276
+ enabled,
5277
+ priority,
5278
+ resolutionUniform: "uResolution",
5279
+ blending: THREE22.NoBlending
5280
+ }
5281
+ );
5282
+ }
5283
+
5284
+ // src/components/DitherStreamGodRaysPass.tsx
5285
+ var import_react25 = require("react");
5286
+ var THREE23 = __toESM(require("three"));
5287
+
5288
+ // src/shaders/dither-godray-extract/fragment.glsl
5289
+ var fragment_default17 = "precision highp float;\n\nin vec2 vTextureCoord;\nuniform sampler2D uTexture;\nout vec4 fragColor;\n\nvoid main() {\n vec4 c = texture(uTexture, vTextureCoord);\n float l = dot(c.rgb, vec3(0.299, 0.587, 0.114));\n fragColor = c * smoothstep(-0.1, 0.0, l);\n}\n";
5290
+
5291
+ // src/shaders/dither-godray-extract/vertex.glsl
5292
+ var vertex_default16 = "out vec2 vTextureCoord;\n\nvoid main() {\n vTextureCoord = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
5293
+
5294
+ // src/shaders/dither-godray-final/fragment.glsl
5295
+ var fragment_default18 = "precision highp float;\n\nin vec2 vTextureCoord;\nuniform sampler2D uScene;\nuniform sampler2D uGR;\nuniform float uGodrayIntensity;\nout vec4 fragColor;\n\nvoid main() {\n vec3 bg = texture(uScene, vTextureCoord).rgb;\n vec3 gr = texture(uGR, vTextureCoord).rgb;\n fragColor = vec4(bg + gr * uGodrayIntensity, 1.0);\n}\n";
5296
+
5297
+ // src/shaders/dither-godray-final/vertex.glsl
5298
+ var vertex_default17 = "out vec2 vTextureCoord;\n\nvoid main() {\n vTextureCoord = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
5299
+
5300
+ // src/shaders/dither-godray-march/fragment.glsl
5301
+ var fragment_default19 = "precision highp float;\n\nin vec2 vTextureCoord;\nuniform sampler2D uTexture;\nout vec4 fragColor;\n\nvoid main() {\n vec3 col = vec3(0.0);\n vec2 pos = vec2(0.5);\n vec2 dir = (pos - vTextureCoord) * 0.02;\n float w = 1.0;\n vec2 tc = vTextureCoord;\n\n for (int i = 0; i < 16; i++) {\n col += texture(uTexture, tc).rgb * w;\n w *= 0.94;\n tc += dir;\n }\n\n fragColor = vec4(col / 16.0, length(tc - vTextureCoord));\n}\n";
5302
+
5303
+ // src/shaders/dither-godray-march/vertex.glsl
5304
+ var vertex_default18 = "out vec2 vTextureCoord;\n\nvoid main() {\n vTextureCoord = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
5305
+
5306
+ // src/components/DitherStreamGodRaysPass.tsx
5307
+ var import_jsx_runtime26 = require("react/jsx-runtime");
5308
+ var TARGET_OPTIONS = {
5309
+ depthBuffer: false,
5310
+ stencilBuffer: false
5311
+ };
5312
+ function DitherStreamGodRaysPass({
5313
+ inputTexture = null,
5314
+ intensity = 2.9,
5315
+ target = null,
5316
+ enabled = true,
5317
+ priority = 0
5318
+ }) {
5319
+ const sharedScene = useSceneContext();
5320
+ const size = sharedScene?.size ?? { width: 1, height: 1 };
5321
+ const fallbackTexture = (0, import_react25.useMemo)(() => createFallbackTexture(), []);
5322
+ const extractTarget = (0, import_react25.useMemo)(
5323
+ () => new THREE23.WebGLRenderTarget(1, 1, TARGET_OPTIONS),
5324
+ []
5325
+ );
5326
+ const marchTarget = (0, import_react25.useMemo)(
5327
+ () => new THREE23.WebGLRenderTarget(1, 1, TARGET_OPTIONS),
5328
+ []
5329
+ );
5330
+ (0, import_react25.useEffect)(() => {
5331
+ return () => {
5332
+ extractTarget.dispose();
5333
+ marchTarget.dispose();
5334
+ };
5335
+ }, [extractTarget, marchTarget]);
5336
+ (0, import_react25.useEffect)(() => {
5337
+ if (size.width <= 1 || size.height <= 1) return;
5338
+ extractTarget.setSize(size.width, size.height);
5339
+ marchTarget.setSize(
5340
+ Math.max(1, Math.floor(size.width / 4)),
5341
+ Math.max(1, Math.floor(size.height / 4))
5342
+ );
5343
+ }, [extractTarget, marchTarget, size.height, size.width]);
5344
+ const extractUniforms = (0, import_react25.useMemo)(
5345
+ () => ({
5346
+ uTexture: { value: inputTexture ?? fallbackTexture }
5347
+ }),
5348
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5349
+ []
5350
+ );
5351
+ const marchUniforms = (0, import_react25.useMemo)(
5352
+ () => ({
5353
+ uTexture: { value: extractTarget.texture }
5354
+ }),
5355
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5356
+ []
5357
+ );
5358
+ const finalUniforms = (0, import_react25.useMemo)(
5359
+ () => ({
5360
+ uScene: { value: inputTexture ?? fallbackTexture },
5361
+ uGR: { value: marchTarget.texture },
5362
+ uGodrayIntensity: { value: intensity }
5363
+ }),
5364
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5365
+ []
5366
+ );
5367
+ extractUniforms.uTexture.value = inputTexture ?? fallbackTexture;
5368
+ marchUniforms.uTexture.value = extractTarget.texture;
5369
+ finalUniforms.uScene.value = inputTexture ?? fallbackTexture;
5370
+ finalUniforms.uGR.value = marchTarget.texture;
5371
+ finalUniforms.uGodrayIntensity.value = intensity;
5372
+ return /* @__PURE__ */ (0, import_jsx_runtime26.jsxs)(import_jsx_runtime26.Fragment, { children: [
5373
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5374
+ ShaderPass,
5375
+ {
5376
+ vertexShader: vertex_default16,
5377
+ fragmentShader: fragment_default17,
5378
+ uniforms: extractUniforms,
5379
+ inputTexture: inputTexture ?? fallbackTexture,
5380
+ target: extractTarget,
5381
+ clear: true,
5382
+ enabled,
5383
+ priority,
5384
+ blending: THREE23.NoBlending
5385
+ }
5386
+ ),
5387
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5388
+ ShaderPass,
5389
+ {
5390
+ vertexShader: vertex_default18,
5391
+ fragmentShader: fragment_default19,
5392
+ uniforms: marchUniforms,
5393
+ inputTexture: extractTarget.texture,
5394
+ target: marchTarget,
5395
+ clear: true,
5396
+ enabled,
5397
+ priority: priority + 1,
5398
+ blending: THREE23.NoBlending
5399
+ }
5400
+ ),
5401
+ /* @__PURE__ */ (0, import_jsx_runtime26.jsx)(
5402
+ ShaderPass,
5403
+ {
5404
+ vertexShader: vertex_default17,
5405
+ fragmentShader: fragment_default18,
5406
+ uniforms: finalUniforms,
5407
+ inputTexture: inputTexture ?? fallbackTexture,
5408
+ target,
5409
+ clear: true,
5410
+ enabled,
5411
+ priority: priority + 2,
5412
+ blending: THREE23.NoBlending
5413
+ }
5414
+ )
5415
+ ] });
5416
+ }
5417
+
5418
+ // src/components/DitherStreamProjectionPass.tsx
5419
+ var import_react26 = require("react");
5420
+ var THREE24 = __toESM(require("three"));
5421
+
5422
+ // src/shaders/dither-godray-projection/fragment.glsl
5423
+ var fragment_default20 = "precision highp float;\n\nin vec2 vTextureCoord;\n\nuniform sampler2D uTex;\nuniform float uTime;\nuniform float uProjectionSpeed;\n\nout vec4 fragColor;\n\nconst float PI = 3.14159265;\n\nvec3 ray(vec2 uv, vec2 m, float a) {\n vec2 s = (uv - 0.5) * 2.0;\n s.x *= a;\n s.y *= -1.0;\n\n float f = mix(radians(20.0), radians(120.0), 0.38);\n vec3 r = normalize(vec3(s * tan(f / 2.0), -1.0));\n\n float rx = (m.y - 0.5) * PI;\n float ry = (m.x - 0.5) * PI * 2.0;\n mat3 rY = mat3(cos(ry), 0.0, -sin(ry), 0.0, 1.0, 0.0, sin(ry), 0.0, cos(ry));\n mat3 rX = mat3(1.0, 0.0, 0.0, 0.0, cos(rx), sin(rx), 0.0, -sin(rx), cos(rx));\n\n return normalize(rX * rY * r);\n}\n\nvec2 directionToUv(vec3 d) {\n return vec2(atan(d.z, d.x) / (2.0 * PI) + 0.75, acos(clamp(d.y, -1.0, 1.0)) / PI);\n}\n\nvec4 sampleRepeat(vec2 uv) {\n vec2 f = vec2(uv.x, fract(uv.y));\n vec4 c = texture(uTex, f);\n\n float blendWidth = 0.1;\n float blendFactor = 0.0;\n if (f.y < blendWidth) {\n blendFactor = 1.0 - f.y / blendWidth;\n } else if (f.y > 1.0 - blendWidth) {\n blendFactor = (f.y - (1.0 - blendWidth)) / blendWidth;\n }\n\n if (blendFactor > 0.0) {\n blendFactor = smoothstep(0.0, 1.0, blendFactor);\n vec2 opposite = vec2(f.x, f.y > 0.5 ? f.y - 0.5 : f.y + 0.5);\n c = mix(c, texture(uTex, opposite), blendFactor);\n }\n\n return c;\n}\n\nvoid main() {\n vec2 uv = vTextureCoord;\n\n vec3 rd = ray(uv, vec2(0.5, 0.5056), 2.0);\n vec2 s = directionToUv(rd);\n\n float f = mix(radians(20.0), radians(120.0), 0.38);\n s = (s - 0.5) * (2.0 / tan(f / 2.0)) + 0.5;\n s += vec2(0.0, 0.02) * uTime * uProjectionSpeed;\n\n vec4 c = sampleRepeat(s);\n c.rgb = clamp(c.rgb - 0.14, 0.0, 1.0);\n\n float l = dot(c.rgb, vec3(0.299, 0.587, 0.114));\n c.rgb = mix(vec3(l), c.rgb, 0.79);\n c.rgb = 1.22 * (c.rgb - 0.5) + 0.5;\n c.rgb = clamp(c.rgb, 0.0, 1.0);\n\n fragColor = c;\n}\n";
5424
+
5425
+ // src/shaders/dither-godray-projection/vertex.glsl
5426
+ var vertex_default19 = "out vec2 vTextureCoord;\n\nvoid main() {\n vTextureCoord = uv;\n gl_Position = vec4(position, 1.0);\n}\n";
5427
+
5428
+ // src/components/DitherStreamProjectionPass.tsx
5429
+ var import_jsx_runtime27 = require("react/jsx-runtime");
5430
+ var DEFAULT_IMAGE_SRC = "https://firebasestorage.googleapis.com/v0/b/unicorn-studio.appspot.com/o/Zz28X5RDkvcGGVYLr9X6QdTIhxy1%2FUntitled%20design%20-%202025-10-14T141250.707.webp?alt=media&token=bfcd11a8-6529-41a6-a592-d78147e93840";
5431
+ function DitherStreamProjectionPass({
5432
+ imageTextureSrc = DEFAULT_IMAGE_SRC,
5433
+ projectionSpeed = 0.05,
5434
+ target = null,
5435
+ clear = true,
5436
+ enabled = true,
5437
+ priority = 0
5438
+ }) {
5439
+ const [imageTexture, setImageTexture] = (0, import_react26.useState)(null);
5440
+ const fallbackTexture = (0, import_react26.useMemo)(() => createFallbackTexture(), []);
5441
+ (0, import_react26.useEffect)(() => {
5442
+ let active = true;
5443
+ const loader = new THREE24.TextureLoader();
5444
+ loader.load(
5445
+ imageTextureSrc,
5446
+ (texture) => {
5447
+ if (!active) {
5448
+ texture.dispose();
5449
+ return;
4914
5450
  }
5451
+ texture.wrapS = THREE24.RepeatWrapping;
5452
+ texture.wrapT = THREE24.RepeatWrapping;
5453
+ texture.minFilter = THREE24.LinearFilter;
5454
+ texture.magFilter = THREE24.LinearFilter;
5455
+ texture.generateMipmaps = true;
5456
+ texture.colorSpace = THREE24.NoColorSpace;
5457
+ texture.needsUpdate = true;
5458
+ setImageTexture(texture);
5459
+ },
5460
+ void 0,
5461
+ () => {
5462
+ if (!active) return;
5463
+ setImageTexture(fallbackTexture);
5464
+ }
5465
+ );
5466
+ return () => {
5467
+ active = false;
5468
+ };
5469
+ }, [fallbackTexture, imageTextureSrc]);
5470
+ const uniforms = (0, import_react26.useMemo)(
5471
+ () => ({
5472
+ uTex: { value: imageTexture ?? fallbackTexture },
5473
+ uTime: { value: 0 },
5474
+ uProjectionSpeed: { value: projectionSpeed }
5475
+ }),
5476
+ // eslint-disable-next-line react-hooks/exhaustive-deps
5477
+ []
5478
+ );
5479
+ uniforms.uTex.value = imageTexture ?? fallbackTexture;
5480
+ uniforms.uProjectionSpeed.value = projectionSpeed;
5481
+ return /* @__PURE__ */ (0, import_jsx_runtime27.jsx)(
5482
+ ShaderPass,
5483
+ {
5484
+ vertexShader: vertex_default19,
5485
+ fragmentShader: fragment_default20,
5486
+ uniforms,
5487
+ target,
5488
+ clear,
5489
+ enabled,
5490
+ priority,
5491
+ timeUniform: "uTime",
5492
+ blending: THREE24.NoBlending
5493
+ }
5494
+ );
5495
+ }
5496
+
5497
+ // src/components/DitherStreamRendererConfig.tsx
5498
+ var import_react27 = require("react");
5499
+ var THREE25 = __toESM(require("three"));
5500
+ function DitherStreamRendererConfig() {
5501
+ const sharedScene = useSceneContext();
5502
+ (0, import_react27.useEffect)(() => {
5503
+ const context = sharedScene?.contextRef.current;
5504
+ if (!context) return;
5505
+ const renderer = context.renderer;
5506
+ const prevOutputColorSpace = renderer.outputColorSpace;
5507
+ const prevToneMapping = renderer.toneMapping;
5508
+ renderer.outputColorSpace = THREE25.LinearSRGBColorSpace;
5509
+ renderer.toneMapping = THREE25.NoToneMapping;
5510
+ return () => {
5511
+ renderer.outputColorSpace = prevOutputColorSpace;
5512
+ renderer.toneMapping = prevToneMapping;
5513
+ };
5514
+ }, [sharedScene]);
5515
+ return null;
5516
+ }
5517
+
5518
+ // src/components/DitherStream.tsx
5519
+ var import_jsx_runtime28 = require("react/jsx-runtime");
5520
+ function DitherStream({
5521
+ width = "100%",
5522
+ height = "100%",
5523
+ className = "relative h-full w-full",
5524
+ style,
5525
+ imageTextureSrc,
5526
+ projectionSpeed = 0.05,
5527
+ beamSpeed = 0.1,
5528
+ beamDirection = "counterclockwise",
5529
+ beamColor = [0.667, 0.686, 0.941],
5530
+ beamCenter = [0.5, 0.95],
5531
+ beamRadius = 0.6,
5532
+ beamScale = 1,
5533
+ beamPathShape = "circle",
5534
+ pathPos = [0.5009, 1.0473],
5535
+ pathAngle = (0.999 - 0.25) * -6.28318531,
5536
+ godrayIntensity = 2.9
5537
+ }) {
5538
+ const resolveColor = (color) => {
5539
+ if (Array.isArray(color)) return color;
5540
+ const normalized = color.replace("#", "");
5541
+ if (normalized.length !== 6)
5542
+ return [0.667, 0.686, 0.941];
5543
+ return [
5544
+ parseInt(normalized.slice(0, 2), 16) / 255,
5545
+ parseInt(normalized.slice(2, 4), 16) / 255,
5546
+ parseInt(normalized.slice(4, 6), 16) / 255
5547
+ ];
5548
+ };
5549
+ const resolvedBeamColor = resolveColor(beamColor);
5550
+ return /* @__PURE__ */ (0, import_jsx_runtime28.jsxs)(
5551
+ SceneProvider,
5552
+ {
5553
+ width,
5554
+ height,
5555
+ className,
5556
+ style,
5557
+ manualRender: true,
5558
+ children: [
5559
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(DitherStreamRendererConfig, {}),
5560
+ /* @__PURE__ */ (0, import_jsx_runtime28.jsx)(
5561
+ RenderPipeline,
5562
+ {
5563
+ passes: [
5564
+ {
5565
+ component: DitherStreamProjectionPass,
5566
+ props: { imageTextureSrc, projectionSpeed }
5567
+ },
5568
+ {
5569
+ component: DitherStreamBeamCompositePass,
5570
+ props: {
5571
+ beamSpeed,
5572
+ beamDirection,
5573
+ beamColor: resolvedBeamColor,
5574
+ beamCenter,
5575
+ beamRadius,
5576
+ beamScale,
5577
+ pathShape: beamPathShape,
5578
+ pathPos,
5579
+ pathAngle
5580
+ }
5581
+ },
5582
+ {
5583
+ component: DitherStreamDitherPass
5584
+ },
5585
+ {
5586
+ component: DitherStreamGodRaysPass,
5587
+ props: { intensity: godrayIntensity }
5588
+ }
5589
+ ]
5590
+ }
5591
+ )
4915
5592
  ]
4916
5593
  }
4917
5594
  );
@@ -4920,6 +5597,7 @@ function DitherPulseRingContent({
4920
5597
  0 && (module.exports = {
4921
5598
  AnimatedDrawingSVG,
4922
5599
  DitherPulseRing,
5600
+ DitherStream,
4923
5601
  EFECTO_ASCII_COMPONENT_DEFAULTS,
4924
5602
  EFECTO_ASCII_POST_PROCESSING_DEFAULTS,
4925
5603
  Efecto,