interactive-bg 0.1.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (122) hide show
  1. package/README.md +55 -7
  2. package/dist/fluid/canvas2d.cjs +14 -0
  3. package/dist/fluid/canvas2d.cjs.map +1 -0
  4. package/dist/fluid/canvas2d.d.cts +5 -0
  5. package/dist/fluid/canvas2d.d.ts +5 -0
  6. package/dist/fluid/canvas2d.js +13 -0
  7. package/dist/fluid/canvas2d.js.map +1 -0
  8. package/dist/fluid/index.cjs +16 -0
  9. package/dist/fluid/index.cjs.map +1 -0
  10. package/dist/fluid/index.d.cts +5 -0
  11. package/dist/fluid/index.d.ts +5 -0
  12. package/dist/fluid/index.js +15 -0
  13. package/dist/fluid/index.js.map +1 -0
  14. package/dist/fluid/webgl.cjs +14 -0
  15. package/dist/fluid/webgl.cjs.map +1 -0
  16. package/dist/fluid/webgl.d.cts +5 -0
  17. package/dist/fluid/webgl.d.ts +5 -0
  18. package/dist/fluid/webgl.js +13 -0
  19. package/dist/fluid/webgl.js.map +1 -0
  20. package/dist/index.cjs +4 -0
  21. package/dist/index.d.cts +4 -0
  22. package/dist/index.d.ts +4 -0
  23. package/dist/index.js +3 -1
  24. package/dist/index.umd.js +255 -12
  25. package/dist/index.umd.js.map +1 -1
  26. package/dist/shimmer/canvas2d.cjs +14 -0
  27. package/dist/shimmer/canvas2d.cjs.map +1 -0
  28. package/dist/shimmer/canvas2d.d.cts +5 -0
  29. package/dist/shimmer/canvas2d.d.ts +5 -0
  30. package/dist/shimmer/canvas2d.js +13 -0
  31. package/dist/shimmer/canvas2d.js.map +1 -0
  32. package/dist/shimmer/index.cjs +16 -0
  33. package/dist/shimmer/index.cjs.map +1 -0
  34. package/dist/shimmer/index.d.cts +5 -0
  35. package/dist/shimmer/index.d.ts +5 -0
  36. package/dist/shimmer/index.js +15 -0
  37. package/dist/shimmer/index.js.map +1 -0
  38. package/dist/shimmer/webgl.cjs +14 -0
  39. package/dist/shimmer/webgl.cjs.map +1 -0
  40. package/dist/shimmer/webgl.d.cts +5 -0
  41. package/dist/shimmer/webgl.d.ts +5 -0
  42. package/dist/shimmer/webgl.js +13 -0
  43. package/dist/shimmer/webgl.js.map +1 -0
  44. package/dist/styles/fluid/canvas2d.cjs +155 -0
  45. package/dist/styles/fluid/canvas2d.cjs.map +1 -0
  46. package/dist/styles/fluid/canvas2d.d.cts +8 -0
  47. package/dist/styles/fluid/canvas2d.d.ts +8 -0
  48. package/dist/styles/fluid/canvas2d.js +155 -0
  49. package/dist/styles/fluid/canvas2d.js.map +1 -0
  50. package/dist/styles/fluid/color.cjs +40 -0
  51. package/dist/styles/fluid/color.cjs.map +1 -0
  52. package/dist/styles/fluid/color.d.cts +4 -0
  53. package/dist/styles/fluid/color.d.ts +4 -0
  54. package/dist/styles/fluid/color.js +40 -0
  55. package/dist/styles/fluid/color.js.map +1 -0
  56. package/dist/styles/fluid/definition.cjs +14 -0
  57. package/dist/styles/fluid/definition.cjs.map +1 -0
  58. package/dist/styles/fluid/definition.d.cts +8 -0
  59. package/dist/styles/fluid/definition.d.ts +8 -0
  60. package/dist/styles/fluid/definition.js +15 -0
  61. package/dist/styles/fluid/definition.js.map +1 -0
  62. package/dist/styles/fluid/options.cjs +29 -0
  63. package/dist/styles/fluid/options.cjs.map +1 -0
  64. package/dist/styles/fluid/options.d.cts +31 -0
  65. package/dist/styles/fluid/options.d.ts +31 -0
  66. package/dist/styles/fluid/options.js +28 -0
  67. package/dist/styles/fluid/options.js.map +1 -0
  68. package/dist/styles/fluid/settings.cjs +32 -0
  69. package/dist/styles/fluid/settings.cjs.map +1 -0
  70. package/dist/styles/fluid/settings.d.cts +24 -0
  71. package/dist/styles/fluid/settings.d.ts +24 -0
  72. package/dist/styles/fluid/settings.js +23 -0
  73. package/dist/styles/fluid/settings.js.map +1 -0
  74. package/dist/styles/fluid/simulation.cjs +183 -0
  75. package/dist/styles/fluid/simulation.cjs.map +1 -0
  76. package/dist/styles/fluid/simulation.d.cts +22 -0
  77. package/dist/styles/fluid/simulation.d.ts +22 -0
  78. package/dist/styles/fluid/simulation.js +183 -0
  79. package/dist/styles/fluid/simulation.js.map +1 -0
  80. package/dist/styles/fluid/size.cjs +17 -0
  81. package/dist/styles/fluid/size.cjs.map +1 -0
  82. package/dist/styles/fluid/size.d.cts +5 -0
  83. package/dist/styles/fluid/size.d.ts +5 -0
  84. package/dist/styles/fluid/size.js +17 -0
  85. package/dist/styles/fluid/size.js.map +1 -0
  86. package/dist/styles/fluid/webgl.cjs +607 -0
  87. package/dist/styles/fluid/webgl.cjs.map +1 -0
  88. package/dist/styles/fluid/webgl.d.cts +3 -0
  89. package/dist/styles/fluid/webgl.d.ts +3 -0
  90. package/dist/styles/fluid/webgl.js +607 -0
  91. package/dist/styles/fluid/webgl.js.map +1 -0
  92. package/dist/styles/shimmer/canvas2d.cjs +84 -0
  93. package/dist/styles/shimmer/canvas2d.cjs.map +1 -0
  94. package/dist/styles/shimmer/canvas2d.d.cts +3 -0
  95. package/dist/styles/shimmer/canvas2d.d.ts +3 -0
  96. package/dist/styles/shimmer/canvas2d.js +84 -0
  97. package/dist/styles/shimmer/canvas2d.js.map +1 -0
  98. package/dist/styles/shimmer/definition.cjs +15 -0
  99. package/dist/styles/shimmer/definition.cjs.map +1 -0
  100. package/dist/styles/shimmer/definition.d.cts +8 -0
  101. package/dist/styles/shimmer/definition.d.ts +8 -0
  102. package/dist/styles/shimmer/definition.js +16 -0
  103. package/dist/styles/shimmer/definition.js.map +1 -0
  104. package/dist/styles/shimmer/field.cjs +79 -0
  105. package/dist/styles/shimmer/field.cjs.map +1 -0
  106. package/dist/styles/shimmer/field.d.cts +11 -0
  107. package/dist/styles/shimmer/field.d.ts +11 -0
  108. package/dist/styles/shimmer/field.js +78 -0
  109. package/dist/styles/shimmer/field.js.map +1 -0
  110. package/dist/styles/shimmer/options.cjs +28 -0
  111. package/dist/styles/shimmer/options.cjs.map +1 -0
  112. package/dist/styles/shimmer/options.d.cts +22 -0
  113. package/dist/styles/shimmer/options.d.ts +22 -0
  114. package/dist/styles/shimmer/options.js +27 -0
  115. package/dist/styles/shimmer/options.js.map +1 -0
  116. package/dist/styles/shimmer/webgl.cjs +89 -0
  117. package/dist/styles/shimmer/webgl.cjs.map +1 -0
  118. package/dist/styles/shimmer/webgl.d.cts +4 -0
  119. package/dist/styles/shimmer/webgl.d.ts +4 -0
  120. package/dist/styles/shimmer/webgl.js +89 -0
  121. package/dist/styles/shimmer/webgl.js.map +1 -0
  122. package/package.json +75 -1
@@ -0,0 +1,14 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_canvas2d_renderer = require("../core/canvas2d-renderer.cjs");
3
+ const require_style = require("../core/style.cjs");
4
+ const require_canvas2d = require("../styles/shimmer/canvas2d.cjs");
5
+ const require_definition = require("../styles/shimmer/definition.cjs");
6
+ // src/shimmer/canvas2d.ts
7
+ /** Iridescent light bands, drawn with Canvas 2D only. */
8
+ var shimmer = require_style.defineStyle({
9
+ ...require_definition.shimmerStyle,
10
+ renderers: [require_canvas2d_renderer.canvas2dRenderer(require_canvas2d.createShimmerCanvas2D)]
11
+ });
12
+ exports.shimmer = shimmer;
13
+
14
+ //# sourceMappingURL=canvas2d.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas2d.cjs","names":["defineStyle","shimmerStyle","canvas2dRenderer","createShimmerCanvas2D"],"sources":["../../src/shimmer/canvas2d.ts"],"sourcesContent":["import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { createShimmerCanvas2D } from '../styles/shimmer/canvas2d';\nimport { shimmerStyle } from '../styles/shimmer/definition';\nimport type { ShimmerOptions } from '../styles/shimmer/options';\n\nexport type { ShimmerOptions };\n\n/** Iridescent light bands, drawn with Canvas 2D only. */\nexport const shimmer: StyleFactory<ShimmerOptions> = defineStyle({\n ...shimmerStyle,\n renderers: [canvas2dRenderer(createShimmerCanvas2D)],\n});\n"],"mappings":";;;;;;;AASA,IAAa,UAAwCA,cAAAA,YAAY;CAC/D,GAAGC,mBAAAA;CACH,WAAW,CAACC,0BAAAA,iBAAiBC,iBAAAA,qBAAqB,CAAC;AACrD,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type StyleFactory } from '../core/style.cjs';
2
+ import type { ShimmerOptions } from '../styles/shimmer/options.cjs';
3
+ export type { ShimmerOptions };
4
+ /** Iridescent light bands, drawn with Canvas 2D only. */
5
+ export declare const shimmer: StyleFactory<ShimmerOptions>;
@@ -0,0 +1,5 @@
1
+ import { type StyleFactory } from '../core/style.js';
2
+ import type { ShimmerOptions } from '../styles/shimmer/options.js';
3
+ export type { ShimmerOptions };
4
+ /** Iridescent light bands, drawn with Canvas 2D only. */
5
+ export declare const shimmer: StyleFactory<ShimmerOptions>;
@@ -0,0 +1,13 @@
1
+ import { canvas2dRenderer } from "../core/canvas2d-renderer.js";
2
+ import { defineStyle } from "../core/style.js";
3
+ import { createShimmerCanvas2D } from "../styles/shimmer/canvas2d.js";
4
+ import { shimmerStyle } from "../styles/shimmer/definition.js";
5
+ // src/shimmer/canvas2d.ts
6
+ /** Iridescent light bands, drawn with Canvas 2D only. */
7
+ var shimmer = defineStyle({
8
+ ...shimmerStyle,
9
+ renderers: [canvas2dRenderer(createShimmerCanvas2D)]
10
+ });
11
+ export { shimmer };
12
+
13
+ //# sourceMappingURL=canvas2d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas2d.js","names":[],"sources":["../../src/shimmer/canvas2d.ts"],"sourcesContent":["import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { createShimmerCanvas2D } from '../styles/shimmer/canvas2d';\nimport { shimmerStyle } from '../styles/shimmer/definition';\nimport type { ShimmerOptions } from '../styles/shimmer/options';\n\nexport type { ShimmerOptions };\n\n/** Iridescent light bands, drawn with Canvas 2D only. */\nexport const shimmer: StyleFactory<ShimmerOptions> = defineStyle({\n ...shimmerStyle,\n renderers: [canvas2dRenderer(createShimmerCanvas2D)],\n});\n"],"mappings":";;;;;;AASA,IAAa,UAAwC,YAAY;CAC/D,GAAG;CACH,WAAW,CAAC,iBAAiB,qBAAqB,CAAC;AACrD,CAAC"}
@@ -0,0 +1,16 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_canvas2d_renderer = require("../core/canvas2d-renderer.cjs");
3
+ const require_style = require("../core/style.cjs");
4
+ const require_webgl_renderer = require("../core/webgl-renderer.cjs");
5
+ const require_canvas2d = require("../styles/shimmer/canvas2d.cjs");
6
+ const require_definition = require("../styles/shimmer/definition.cjs");
7
+ const require_webgl = require("../styles/shimmer/webgl.cjs");
8
+ // src/shimmer/index.ts
9
+ /** Iridescent light bands, drawn with WebGL2 where available and Canvas 2D otherwise. */
10
+ var shimmer = require_style.defineStyle({
11
+ ...require_definition.shimmerStyle,
12
+ renderers: [require_webgl_renderer.webglRenderer(require_webgl.createShimmerWebGL), require_canvas2d_renderer.canvas2dRenderer(require_canvas2d.createShimmerCanvas2D)]
13
+ });
14
+ exports.shimmer = shimmer;
15
+
16
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["defineStyle","shimmerStyle","webglRenderer","createShimmerWebGL","canvas2dRenderer","createShimmerCanvas2D"],"sources":["../../src/shimmer/index.ts"],"sourcesContent":["import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createShimmerCanvas2D } from '../styles/shimmer/canvas2d';\nimport { shimmerStyle } from '../styles/shimmer/definition';\nimport type { ShimmerOptions } from '../styles/shimmer/options';\nimport { createShimmerWebGL } from '../styles/shimmer/webgl';\n\nexport type { ShimmerOptions };\n\n/** Iridescent light bands, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const shimmer: StyleFactory<ShimmerOptions> = defineStyle({\n ...shimmerStyle,\n renderers: [webglRenderer(createShimmerWebGL), canvas2dRenderer(createShimmerCanvas2D)],\n});\n"],"mappings":";;;;;;;;;AAWA,IAAa,UAAwCA,cAAAA,YAAY;CAC/D,GAAGC,mBAAAA;CACH,WAAW,CAACC,uBAAAA,cAAcC,cAAAA,kBAAkB,GAAGC,0BAAAA,iBAAiBC,iBAAAA,qBAAqB,CAAC;AACxF,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type StyleFactory } from '../core/style.cjs';
2
+ import type { ShimmerOptions } from '../styles/shimmer/options.cjs';
3
+ export type { ShimmerOptions };
4
+ /** Iridescent light bands, drawn with WebGL2 where available and Canvas 2D otherwise. */
5
+ export declare const shimmer: StyleFactory<ShimmerOptions>;
@@ -0,0 +1,5 @@
1
+ import { type StyleFactory } from '../core/style.js';
2
+ import type { ShimmerOptions } from '../styles/shimmer/options.js';
3
+ export type { ShimmerOptions };
4
+ /** Iridescent light bands, drawn with WebGL2 where available and Canvas 2D otherwise. */
5
+ export declare const shimmer: StyleFactory<ShimmerOptions>;
@@ -0,0 +1,15 @@
1
+ import { canvas2dRenderer } from "../core/canvas2d-renderer.js";
2
+ import { defineStyle } from "../core/style.js";
3
+ import { webglRenderer } from "../core/webgl-renderer.js";
4
+ import { createShimmerCanvas2D } from "../styles/shimmer/canvas2d.js";
5
+ import { shimmerStyle } from "../styles/shimmer/definition.js";
6
+ import { createShimmerWebGL } from "../styles/shimmer/webgl.js";
7
+ // src/shimmer/index.ts
8
+ /** Iridescent light bands, drawn with WebGL2 where available and Canvas 2D otherwise. */
9
+ var shimmer = defineStyle({
10
+ ...shimmerStyle,
11
+ renderers: [webglRenderer(createShimmerWebGL), canvas2dRenderer(createShimmerCanvas2D)]
12
+ });
13
+ export { shimmer };
14
+
15
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/shimmer/index.ts"],"sourcesContent":["import { canvas2dRenderer } from '../core/canvas2d-renderer';\nimport { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { createShimmerCanvas2D } from '../styles/shimmer/canvas2d';\nimport { shimmerStyle } from '../styles/shimmer/definition';\nimport type { ShimmerOptions } from '../styles/shimmer/options';\nimport { createShimmerWebGL } from '../styles/shimmer/webgl';\n\nexport type { ShimmerOptions };\n\n/** Iridescent light bands, drawn with WebGL2 where available and Canvas 2D otherwise. */\nexport const shimmer: StyleFactory<ShimmerOptions> = defineStyle({\n ...shimmerStyle,\n renderers: [webglRenderer(createShimmerWebGL), canvas2dRenderer(createShimmerCanvas2D)],\n});\n"],"mappings":";;;;;;;;AAWA,IAAa,UAAwC,YAAY;CAC/D,GAAG;CACH,WAAW,CAAC,cAAc,kBAAkB,GAAG,iBAAiB,qBAAqB,CAAC;AACxF,CAAC"}
@@ -0,0 +1,14 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_style = require("../core/style.cjs");
3
+ const require_webgl_renderer = require("../core/webgl-renderer.cjs");
4
+ const require_definition = require("../styles/shimmer/definition.cjs");
5
+ const require_webgl = require("../styles/shimmer/webgl.cjs");
6
+ // src/shimmer/webgl.ts
7
+ /** Iridescent light bands, drawn with WebGL2 only. */
8
+ var shimmer = require_style.defineStyle({
9
+ ...require_definition.shimmerStyle,
10
+ renderers: [require_webgl_renderer.webglRenderer(require_webgl.createShimmerWebGL)]
11
+ });
12
+ exports.shimmer = shimmer;
13
+
14
+ //# sourceMappingURL=webgl.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl.cjs","names":["defineStyle","shimmerStyle","webglRenderer","createShimmerWebGL"],"sources":["../../src/shimmer/webgl.ts"],"sourcesContent":["import { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { shimmerStyle } from '../styles/shimmer/definition';\nimport type { ShimmerOptions } from '../styles/shimmer/options';\nimport { createShimmerWebGL } from '../styles/shimmer/webgl';\n\nexport type { ShimmerOptions };\n\n/** Iridescent light bands, drawn with WebGL2 only. */\nexport const shimmer: StyleFactory<ShimmerOptions> = defineStyle({\n ...shimmerStyle,\n renderers: [webglRenderer(createShimmerWebGL)],\n});\n"],"mappings":";;;;;;;AASA,IAAa,UAAwCA,cAAAA,YAAY;CAC/D,GAAGC,mBAAAA;CACH,WAAW,CAACC,uBAAAA,cAAcC,cAAAA,kBAAkB,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { type StyleFactory } from '../core/style.cjs';
2
+ import type { ShimmerOptions } from '../styles/shimmer/options.cjs';
3
+ export type { ShimmerOptions };
4
+ /** Iridescent light bands, drawn with WebGL2 only. */
5
+ export declare const shimmer: StyleFactory<ShimmerOptions>;
@@ -0,0 +1,5 @@
1
+ import { type StyleFactory } from '../core/style.js';
2
+ import type { ShimmerOptions } from '../styles/shimmer/options.js';
3
+ export type { ShimmerOptions };
4
+ /** Iridescent light bands, drawn with WebGL2 only. */
5
+ export declare const shimmer: StyleFactory<ShimmerOptions>;
@@ -0,0 +1,13 @@
1
+ import { defineStyle } from "../core/style.js";
2
+ import { webglRenderer } from "../core/webgl-renderer.js";
3
+ import { shimmerStyle } from "../styles/shimmer/definition.js";
4
+ import { createShimmerWebGL } from "../styles/shimmer/webgl.js";
5
+ // src/shimmer/webgl.ts
6
+ /** Iridescent light bands, drawn with WebGL2 only. */
7
+ var shimmer = defineStyle({
8
+ ...shimmerStyle,
9
+ renderers: [webglRenderer(createShimmerWebGL)]
10
+ });
11
+ export { shimmer };
12
+
13
+ //# sourceMappingURL=webgl.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webgl.js","names":[],"sources":["../../src/shimmer/webgl.ts"],"sourcesContent":["import { defineStyle, type StyleFactory } from '../core/style';\nimport { webglRenderer } from '../core/webgl-renderer';\nimport { shimmerStyle } from '../styles/shimmer/definition';\nimport type { ShimmerOptions } from '../styles/shimmer/options';\nimport { createShimmerWebGL } from '../styles/shimmer/webgl';\n\nexport type { ShimmerOptions };\n\n/** Iridescent light bands, drawn with WebGL2 only. */\nexport const shimmer: StyleFactory<ShimmerOptions> = defineStyle({\n ...shimmerStyle,\n renderers: [webglRenderer(createShimmerWebGL)],\n});\n"],"mappings":";;;;;;AASA,IAAa,UAAwC,YAAY;CAC/D,GAAG;CACH,WAAW,CAAC,cAAc,kBAAkB,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,155 @@
1
+ const require_color = require("./color.cjs");
2
+ const require_options = require("./options.cjs");
3
+ const require_settings = require("./settings.cjs");
4
+ const require_simulation = require("./simulation.cjs");
5
+ const require_size = require("./size.cjs");
6
+ // src/styles/fluid/canvas2d.ts
7
+ var TAU = Math.PI * 2;
8
+ /**
9
+ * The CPU fallback: the same stable-fluids simulation as the WebGL renderer,
10
+ * on a small grid, upscaled as one image. It is softer than the GPU version but
11
+ * keeps the style working without WebGL2 (or the float render-target extension).
12
+ */
13
+ function createFluidCanvas2D(ctx, initial) {
14
+ let options = require_options.resolveFluidOptions(initial);
15
+ let sim = null;
16
+ let image = null;
17
+ let target = null;
18
+ let targetCtx = null;
19
+ let builtWidth = 0;
20
+ let builtHeight = 0;
21
+ let builtResolution = -1;
22
+ let clock = 0;
23
+ let active = 0;
24
+ let idleTime = 0;
25
+ let lastX = 0;
26
+ let lastY = 0;
27
+ let wasInside = false;
28
+ let burstPending = true;
29
+ function allocate(width, height) {
30
+ const grid = require_size.simulationSize(options.resolution, width, height);
31
+ sim = require_simulation.createFluidSimulation(grid.width, grid.height);
32
+ target = document.createElement("canvas");
33
+ target.width = grid.width;
34
+ target.height = grid.height;
35
+ targetCtx = target.getContext("2d");
36
+ image = targetCtx?.createImageData(grid.width, grid.height) ?? null;
37
+ builtWidth = width;
38
+ builtHeight = height;
39
+ builtResolution = options.resolution;
40
+ burstPending = true;
41
+ }
42
+ function wake() {
43
+ active = Math.max(active, require_settings.IDLE_CLEAR + .5);
44
+ idleTime = 0;
45
+ }
46
+ function splatAt(frame, x, y, vx, vy, colour, radius) {
47
+ sim?.splat(x, y, vx, vy, colour, radius, frame.width, frame.height);
48
+ }
49
+ function burst(frame) {
50
+ const colour = require_color.splatColor(options, clock);
51
+ const dye = [
52
+ colour[0] * require_settings.BURST_DYE,
53
+ colour[1] * require_settings.BURST_DYE,
54
+ colour[2] * require_settings.BURST_DYE
55
+ ];
56
+ const angle = Math.random() * TAU;
57
+ const speed = options.force * require_settings.BURST_FORCE;
58
+ splatAt(frame, frame.width * (.34 + Math.random() * .18), frame.height * (.4 + Math.random() * .2), Math.cos(angle) * speed, Math.sin(angle) * speed, dye, options.radius * require_settings.BURST_RADIUS);
59
+ wake();
60
+ }
61
+ function click(frame, x, y) {
62
+ const colour = require_color.splatColor(options, clock);
63
+ const dye = [
64
+ colour[0] * 10,
65
+ colour[1] * 10,
66
+ colour[2] * 10
67
+ ];
68
+ splatAt(frame, x, y, 10 * (Math.random() - .5), 30 * (Math.random() - .5), dye, options.radius);
69
+ wake();
70
+ }
71
+ function draw(frame) {
72
+ if (!sim || !image || !target || !targetCtx) return;
73
+ const { dyeR, dyeG, dyeB } = sim;
74
+ const data = image.data;
75
+ for (let k = 0; k < dyeR.length; k++) {
76
+ const r = Math.min(1, Math.max(0, dyeR[k]));
77
+ const g = Math.min(1, Math.max(0, dyeG[k]));
78
+ const b = Math.min(1, Math.max(0, dyeB[k]));
79
+ const density = Math.max(r, Math.max(g, b));
80
+ const scale = density > 1e-4 ? 255 / density : 0;
81
+ const o = k * 4;
82
+ data[o] = Math.round(r * scale);
83
+ data[o + 1] = Math.round(g * scale);
84
+ data[o + 2] = Math.round(b * scale);
85
+ data[o + 3] = Math.round(density * 255);
86
+ }
87
+ targetCtx.putImageData(image, 0, 0);
88
+ ctx.globalAlpha = options.opacity;
89
+ ctx.imageSmoothingEnabled = true;
90
+ ctx.drawImage(target, 0, 0, frame.width, frame.height);
91
+ ctx.globalAlpha = 1;
92
+ }
93
+ return {
94
+ update(next) {
95
+ options = require_options.resolveFluidOptions(next);
96
+ },
97
+ render(frame) {
98
+ if (!sim || frame.width !== builtWidth || frame.height !== builtHeight || options.resolution !== builtResolution) allocate(frame.width, frame.height);
99
+ if (frame.reducedMotion) {
100
+ if (burstPending) {
101
+ burstPending = false;
102
+ burst(frame);
103
+ }
104
+ draw(frame);
105
+ return false;
106
+ }
107
+ const dt = Math.min(frame.dt, 1 / 60);
108
+ const { pointer } = frame;
109
+ if (burstPending) {
110
+ burstPending = false;
111
+ burst(frame);
112
+ }
113
+ if (pointer.influence > 0) {
114
+ if (wasInside) {
115
+ const moveX = pointer.x - lastX;
116
+ const moveY = pointer.y - lastY;
117
+ const dx = moveX / Math.max(1, frame.width);
118
+ const dy = moveY / Math.max(1, frame.height);
119
+ if (Math.hypot(moveX, moveY) > .5) {
120
+ const colour = require_color.splatColor(options, clock);
121
+ const strength = options.force * pointer.influence;
122
+ splatAt(frame, pointer.x, pointer.y, dx * strength, dy * strength, colour, options.radius);
123
+ wake();
124
+ }
125
+ }
126
+ lastX = pointer.x;
127
+ lastY = pointer.y;
128
+ wasInside = true;
129
+ } else wasInside = false;
130
+ for (const clickPoint of frame.clicks) click(frame, clickPoint.x, clickPoint.y);
131
+ if (dt > 0) {
132
+ idleTime += dt;
133
+ if (idleTime >= 3.5) {
134
+ sim?.clear();
135
+ idleTime = 0;
136
+ active = 0;
137
+ draw(frame);
138
+ return false;
139
+ }
140
+ const effective = idleTime > .5 ? {
141
+ ...options,
142
+ fade: Math.min(options.fade, require_settings.IDLE_DECAY)
143
+ } : options;
144
+ sim?.step(dt, effective);
145
+ clock += dt;
146
+ active = Math.max(0, active - dt);
147
+ }
148
+ draw(frame);
149
+ return active > 0;
150
+ }
151
+ };
152
+ }
153
+ exports.createFluidCanvas2D = createFluidCanvas2D;
154
+
155
+ //# sourceMappingURL=canvas2d.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas2d.cjs","names":["resolveFluidOptions","simulationSize","createFluidSimulation","IDLE_CLEAR","splatColor","BURST_DYE","BURST_FORCE","BURST_RADIUS","IDLE_DECAY"],"sources":["../../../src/styles/fluid/canvas2d.ts"],"sourcesContent":["import type { Frame, StyleRenderer } from '../../core/style';\nimport { splatColor, type RGB } from './color';\nimport { resolveFluidOptions, type FluidOptions } from './options';\nimport { BURST_DYE, BURST_FORCE, BURST_RADIUS, IDLE_CLEAR, IDLE_DECAY, IDLE_DELAY } from './settings';\nimport { createFluidSimulation, type FluidSimulation } from './simulation';\nimport { simulationSize } from './size';\n\nconst TAU = Math.PI * 2;\n\n/**\n * The CPU fallback: the same stable-fluids simulation as the WebGL renderer,\n * on a small grid, upscaled as one image. It is softer than the GPU version but\n * keeps the style working without WebGL2 (or the float render-target extension).\n */\nexport function createFluidCanvas2D(ctx: CanvasRenderingContext2D, initial: FluidOptions): StyleRenderer<FluidOptions> {\n let options = resolveFluidOptions(initial);\n let sim: FluidSimulation | null = null;\n let image: ImageData | null = null;\n let target: HTMLCanvasElement | null = null;\n let targetCtx: CanvasRenderingContext2D | null = null;\n let builtWidth = 0;\n let builtHeight = 0;\n let builtResolution = -1;\n\n let clock = 0;\n let active = 0;\n let idleTime = 0;\n let lastX = 0;\n let lastY = 0;\n let wasInside = false;\n let burstPending = true;\n\n function allocate(width: number, height: number): void {\n const grid = simulationSize(options.resolution, width, height);\n sim = createFluidSimulation(grid.width, grid.height);\n target = document.createElement('canvas');\n target.width = grid.width;\n target.height = grid.height;\n targetCtx = target.getContext('2d');\n image = targetCtx?.createImageData(grid.width, grid.height) ?? null;\n builtWidth = width;\n builtHeight = height;\n builtResolution = options.resolution;\n burstPending = true;\n }\n\n function wake(): void {\n active = Math.max(active, IDLE_CLEAR + 0.5);\n idleTime = 0;\n }\n\n function splatAt(\n frame: Frame,\n x: number,\n y: number,\n vx: number,\n vy: number,\n colour: RGB,\n radius: number,\n ): void {\n sim?.splat(x, y, vx, vy, colour, radius, frame.width, frame.height);\n }\n\n function burst(frame: Frame): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * BURST_DYE, colour[1] * BURST_DYE, colour[2] * BURST_DYE];\n const angle = Math.random() * TAU;\n const speed = options.force * BURST_FORCE;\n splatAt(\n frame,\n frame.width * (0.34 + Math.random() * 0.18),\n frame.height * (0.4 + Math.random() * 0.2),\n Math.cos(angle) * speed,\n Math.sin(angle) * speed,\n dye,\n options.radius * BURST_RADIUS,\n );\n wake();\n }\n\n function click(frame: Frame, x: number, y: number): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * 10, colour[1] * 10, colour[2] * 10];\n const dx = 10 * (Math.random() - 0.5);\n const dy = 30 * (Math.random() - 0.5);\n splatAt(frame, x, y, dx, dy, dye, options.radius);\n wake();\n }\n\n function draw(frame: Frame): void {\n if (!sim || !image || !target || !targetCtx) return;\n const { dyeR, dyeG, dyeB } = sim;\n const data = image.data;\n for (let k = 0; k < dyeR.length; k++) {\n const r = Math.min(1, Math.max(0, dyeR[k]));\n const g = Math.min(1, Math.max(0, dyeG[k]));\n const b = Math.min(1, Math.max(0, dyeB[k]));\n const density = Math.max(r, Math.max(g, b));\n const scale = density > 0.0001 ? 255 / density : 0;\n const o = k * 4;\n data[o] = Math.round(r * scale);\n data[o + 1] = Math.round(g * scale);\n data[o + 2] = Math.round(b * scale);\n data[o + 3] = Math.round(density * 255);\n }\n targetCtx.putImageData(image, 0, 0);\n ctx.globalAlpha = options.opacity;\n ctx.imageSmoothingEnabled = true;\n ctx.drawImage(target, 0, 0, frame.width, frame.height);\n ctx.globalAlpha = 1;\n }\n\n return {\n update(next) {\n options = resolveFluidOptions(next);\n },\n render(frame) {\n if (\n !sim ||\n frame.width !== builtWidth ||\n frame.height !== builtHeight ||\n options.resolution !== builtResolution\n ) {\n allocate(frame.width, frame.height);\n }\n\n if (frame.reducedMotion) {\n // One static splash, then hold it: no simulation steps and no pointer splats.\n if (burstPending) {\n burstPending = false;\n burst(frame);\n }\n draw(frame);\n return false;\n }\n\n const dt = Math.min(frame.dt, 1 / 60);\n const { pointer } = frame;\n\n if (burstPending) {\n burstPending = false;\n burst(frame);\n }\n\n if (pointer.influence > 0) {\n if (wasInside) {\n const moveX = pointer.x - lastX;\n const moveY = pointer.y - lastY;\n const dx = moveX / Math.max(1, frame.width);\n const dy = moveY / Math.max(1, frame.height);\n // Like a real mousemove stream: don't keep adding dye to a resting pointer.\n if (Math.hypot(moveX, moveY) > 0.5) {\n const colour = splatColor(options, clock);\n const strength = options.force * pointer.influence;\n splatAt(frame, pointer.x, pointer.y, dx * strength, dy * strength, colour, options.radius);\n wake();\n }\n }\n lastX = pointer.x;\n lastY = pointer.y;\n wasInside = true;\n } else {\n wasInside = false;\n }\n\n for (const clickPoint of frame.clicks) click(frame, clickPoint.x, clickPoint.y);\n\n if (dt > 0) {\n idleTime += dt;\n if (idleTime >= IDLE_CLEAR) {\n sim?.clear();\n idleTime = 0;\n active = 0;\n draw(frame);\n return false;\n }\n const effective =\n idleTime > IDLE_DELAY ? { ...options, fade: Math.min(options.fade, IDLE_DECAY) } : options;\n sim?.step(dt, effective);\n clock += dt;\n active = Math.max(0, active - dt);\n }\n\n draw(frame);\n return active > 0;\n },\n };\n}\n"],"mappings":";;;;;;AAOA,IAAM,MAAM,KAAK,KAAK;;;;;;AAOtB,SAAgB,oBAAoB,KAA+B,SAAoD;CACrH,IAAI,UAAUA,gBAAAA,oBAAoB,OAAO;CACzC,IAAI,MAA8B;CAClC,IAAI,QAA0B;CAC9B,IAAI,SAAmC;CACvC,IAAI,YAA6C;CACjD,IAAI,aAAa;CACjB,IAAI,cAAc;CAClB,IAAI,kBAAkB;CAEtB,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,YAAY;CAChB,IAAI,eAAe;CAEnB,SAAS,SAAS,OAAe,QAAsB;EACrD,MAAM,OAAOC,aAAAA,eAAe,QAAQ,YAAY,OAAO,MAAM;EAC7D,MAAMC,mBAAAA,sBAAsB,KAAK,OAAO,KAAK,MAAM;EACnD,SAAS,SAAS,cAAc,QAAQ;EACxC,OAAO,QAAQ,KAAK;EACpB,OAAO,SAAS,KAAK;EACrB,YAAY,OAAO,WAAW,IAAI;EAClC,QAAQ,WAAW,gBAAgB,KAAK,OAAO,KAAK,MAAM,KAAK;EAC/D,aAAa;EACb,cAAc;EACd,kBAAkB,QAAQ;EAC1B,eAAe;CACjB;CAEA,SAAS,OAAa;EACpB,SAAS,KAAK,IAAI,QAAQC,iBAAAA,aAAa,EAAG;EAC1C,WAAW;CACb;CAEA,SAAS,QACP,OACA,GACA,GACA,IACA,IACA,QACA,QACM;EACN,KAAK,MAAM,GAAG,GAAG,IAAI,IAAI,QAAQ,QAAQ,MAAM,OAAO,MAAM,MAAM;CACpE;CAEA,SAAS,MAAM,OAAoB;EACjC,MAAM,SAASC,cAAAA,WAAW,SAAS,KAAK;EACxC,MAAM,MAAW;GAAC,OAAO,KAAKC,iBAAAA;GAAW,OAAO,KAAKA,iBAAAA;GAAW,OAAO,KAAKA,iBAAAA;EAAS;EACrF,MAAM,QAAQ,KAAK,OAAO,IAAI;EAC9B,MAAM,QAAQ,QAAQ,QAAQC,iBAAAA;EAC9B,QACE,OACA,MAAM,SAAS,MAAO,KAAK,OAAO,IAAI,MACtC,MAAM,UAAU,KAAM,KAAK,OAAO,IAAI,KACtC,KAAK,IAAI,KAAK,IAAI,OAClB,KAAK,IAAI,KAAK,IAAI,OAClB,KACA,QAAQ,SAASC,iBAAAA,YACnB;EACA,KAAK;CACP;CAEA,SAAS,MAAM,OAAc,GAAW,GAAiB;EACvD,MAAM,SAASH,cAAAA,WAAW,SAAS,KAAK;EACxC,MAAM,MAAW;GAAC,OAAO,KAAK;GAAI,OAAO,KAAK;GAAI,OAAO,KAAK;EAAE;EAGhE,QAAQ,OAAO,GAAG,GAFP,MAAM,KAAK,OAAO,IAAI,KACtB,MAAM,KAAK,OAAO,IAAI,KACJ,KAAK,QAAQ,MAAM;EAChD,KAAK;CACP;CAEA,SAAS,KAAK,OAAoB;EAChC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW;EAC7C,MAAM,EAAE,MAAM,MAAM,SAAS;EAC7B,MAAM,OAAO,MAAM;EACnB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,EAAE,CAAC;GAC1C,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,EAAE,CAAC;GAC1C,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,EAAE,CAAC;GAC1C,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;GAC1C,MAAM,QAAQ,UAAU,OAAS,MAAM,UAAU;GACjD,MAAM,IAAI,IAAI;GACd,KAAK,KAAK,KAAK,MAAM,IAAI,KAAK;GAC9B,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK;GAClC,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK;GAClC,KAAK,IAAI,KAAK,KAAK,MAAM,UAAU,GAAG;EACxC;EACA,UAAU,aAAa,OAAO,GAAG,CAAC;EAClC,IAAI,cAAc,QAAQ;EAC1B,IAAI,wBAAwB;EAC5B,IAAI,UAAU,QAAQ,GAAG,GAAG,MAAM,OAAO,MAAM,MAAM;EACrD,IAAI,cAAc;CACpB;CAEA,OAAO;EACL,OAAO,MAAM;GACX,UAAUJ,gBAAAA,oBAAoB,IAAI;EACpC;EACA,OAAO,OAAO;GACZ,IACE,CAAC,OACD,MAAM,UAAU,cAChB,MAAM,WAAW,eACjB,QAAQ,eAAe,iBAEvB,SAAS,MAAM,OAAO,MAAM,MAAM;GAGpC,IAAI,MAAM,eAAe;IAEvB,IAAI,cAAc;KAChB,eAAe;KACf,MAAM,KAAK;IACb;IACA,KAAK,KAAK;IACV,OAAO;GACT;GAEA,MAAM,KAAK,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE;GACpC,MAAM,EAAE,YAAY;GAEpB,IAAI,cAAc;IAChB,eAAe;IACf,MAAM,KAAK;GACb;GAEA,IAAI,QAAQ,YAAY,GAAG;IACzB,IAAI,WAAW;KACb,MAAM,QAAQ,QAAQ,IAAI;KAC1B,MAAM,QAAQ,QAAQ,IAAI;KAC1B,MAAM,KAAK,QAAQ,KAAK,IAAI,GAAG,MAAM,KAAK;KAC1C,MAAM,KAAK,QAAQ,KAAK,IAAI,GAAG,MAAM,MAAM;KAE3C,IAAI,KAAK,MAAM,OAAO,KAAK,IAAI,IAAK;MAClC,MAAM,SAASI,cAAAA,WAAW,SAAS,KAAK;MACxC,MAAM,WAAW,QAAQ,QAAQ,QAAQ;MACzC,QAAQ,OAAO,QAAQ,GAAG,QAAQ,GAAG,KAAK,UAAU,KAAK,UAAU,QAAQ,QAAQ,MAAM;MACzF,KAAK;KACP;IACF;IACA,QAAQ,QAAQ;IAChB,QAAQ,QAAQ;IAChB,YAAY;GACd,OACE,YAAY;GAGd,KAAK,MAAM,cAAc,MAAM,QAAQ,MAAM,OAAO,WAAW,GAAG,WAAW,CAAC;GAE9E,IAAI,KAAK,GAAG;IACV,YAAY;IACZ,IAAI,YAAA,KAAwB;KAC1B,KAAK,MAAM;KACX,WAAW;KACX,SAAS;KACT,KAAK,KAAK;KACV,OAAO;IACT;IACA,MAAM,YACJ,WAAA,KAAwB;KAAE,GAAG;KAAS,MAAM,KAAK,IAAI,QAAQ,MAAMI,iBAAAA,UAAU;IAAE,IAAI;IACrF,KAAK,KAAK,IAAI,SAAS;IACvB,SAAS;IACT,SAAS,KAAK,IAAI,GAAG,SAAS,EAAE;GAClC;GAEA,KAAK,KAAK;GACV,OAAO,SAAS;EAClB;CACF;AACF"}
@@ -0,0 +1,8 @@
1
+ import type { StyleRenderer } from '../../core/style.cjs';
2
+ import { type FluidOptions } from './options.cjs';
3
+ /**
4
+ * The CPU fallback: the same stable-fluids simulation as the WebGL renderer,
5
+ * on a small grid, upscaled as one image. It is softer than the GPU version but
6
+ * keeps the style working without WebGL2 (or the float render-target extension).
7
+ */
8
+ export declare function createFluidCanvas2D(ctx: CanvasRenderingContext2D, initial: FluidOptions): StyleRenderer<FluidOptions>;
@@ -0,0 +1,8 @@
1
+ import type { StyleRenderer } from '../../core/style.js';
2
+ import { type FluidOptions } from './options.js';
3
+ /**
4
+ * The CPU fallback: the same stable-fluids simulation as the WebGL renderer,
5
+ * on a small grid, upscaled as one image. It is softer than the GPU version but
6
+ * keeps the style working without WebGL2 (or the float render-target extension).
7
+ */
8
+ export declare function createFluidCanvas2D(ctx: CanvasRenderingContext2D, initial: FluidOptions): StyleRenderer<FluidOptions>;
@@ -0,0 +1,155 @@
1
+ import { splatColor } from "./color.js";
2
+ import { resolveFluidOptions } from "./options.js";
3
+ import { BURST_DYE, BURST_FORCE, BURST_RADIUS, IDLE_CLEAR, IDLE_DECAY } from "./settings.js";
4
+ import { createFluidSimulation } from "./simulation.js";
5
+ import { simulationSize } from "./size.js";
6
+ // src/styles/fluid/canvas2d.ts
7
+ var TAU = Math.PI * 2;
8
+ /**
9
+ * The CPU fallback: the same stable-fluids simulation as the WebGL renderer,
10
+ * on a small grid, upscaled as one image. It is softer than the GPU version but
11
+ * keeps the style working without WebGL2 (or the float render-target extension).
12
+ */
13
+ function createFluidCanvas2D(ctx, initial) {
14
+ let options = resolveFluidOptions(initial);
15
+ let sim = null;
16
+ let image = null;
17
+ let target = null;
18
+ let targetCtx = null;
19
+ let builtWidth = 0;
20
+ let builtHeight = 0;
21
+ let builtResolution = -1;
22
+ let clock = 0;
23
+ let active = 0;
24
+ let idleTime = 0;
25
+ let lastX = 0;
26
+ let lastY = 0;
27
+ let wasInside = false;
28
+ let burstPending = true;
29
+ function allocate(width, height) {
30
+ const grid = simulationSize(options.resolution, width, height);
31
+ sim = createFluidSimulation(grid.width, grid.height);
32
+ target = document.createElement("canvas");
33
+ target.width = grid.width;
34
+ target.height = grid.height;
35
+ targetCtx = target.getContext("2d");
36
+ image = targetCtx?.createImageData(grid.width, grid.height) ?? null;
37
+ builtWidth = width;
38
+ builtHeight = height;
39
+ builtResolution = options.resolution;
40
+ burstPending = true;
41
+ }
42
+ function wake() {
43
+ active = Math.max(active, IDLE_CLEAR + .5);
44
+ idleTime = 0;
45
+ }
46
+ function splatAt(frame, x, y, vx, vy, colour, radius) {
47
+ sim?.splat(x, y, vx, vy, colour, radius, frame.width, frame.height);
48
+ }
49
+ function burst(frame) {
50
+ const colour = splatColor(options, clock);
51
+ const dye = [
52
+ colour[0] * BURST_DYE,
53
+ colour[1] * BURST_DYE,
54
+ colour[2] * BURST_DYE
55
+ ];
56
+ const angle = Math.random() * TAU;
57
+ const speed = options.force * BURST_FORCE;
58
+ splatAt(frame, frame.width * (.34 + Math.random() * .18), frame.height * (.4 + Math.random() * .2), Math.cos(angle) * speed, Math.sin(angle) * speed, dye, options.radius * BURST_RADIUS);
59
+ wake();
60
+ }
61
+ function click(frame, x, y) {
62
+ const colour = splatColor(options, clock);
63
+ const dye = [
64
+ colour[0] * 10,
65
+ colour[1] * 10,
66
+ colour[2] * 10
67
+ ];
68
+ splatAt(frame, x, y, 10 * (Math.random() - .5), 30 * (Math.random() - .5), dye, options.radius);
69
+ wake();
70
+ }
71
+ function draw(frame) {
72
+ if (!sim || !image || !target || !targetCtx) return;
73
+ const { dyeR, dyeG, dyeB } = sim;
74
+ const data = image.data;
75
+ for (let k = 0; k < dyeR.length; k++) {
76
+ const r = Math.min(1, Math.max(0, dyeR[k]));
77
+ const g = Math.min(1, Math.max(0, dyeG[k]));
78
+ const b = Math.min(1, Math.max(0, dyeB[k]));
79
+ const density = Math.max(r, Math.max(g, b));
80
+ const scale = density > 1e-4 ? 255 / density : 0;
81
+ const o = k * 4;
82
+ data[o] = Math.round(r * scale);
83
+ data[o + 1] = Math.round(g * scale);
84
+ data[o + 2] = Math.round(b * scale);
85
+ data[o + 3] = Math.round(density * 255);
86
+ }
87
+ targetCtx.putImageData(image, 0, 0);
88
+ ctx.globalAlpha = options.opacity;
89
+ ctx.imageSmoothingEnabled = true;
90
+ ctx.drawImage(target, 0, 0, frame.width, frame.height);
91
+ ctx.globalAlpha = 1;
92
+ }
93
+ return {
94
+ update(next) {
95
+ options = resolveFluidOptions(next);
96
+ },
97
+ render(frame) {
98
+ if (!sim || frame.width !== builtWidth || frame.height !== builtHeight || options.resolution !== builtResolution) allocate(frame.width, frame.height);
99
+ if (frame.reducedMotion) {
100
+ if (burstPending) {
101
+ burstPending = false;
102
+ burst(frame);
103
+ }
104
+ draw(frame);
105
+ return false;
106
+ }
107
+ const dt = Math.min(frame.dt, 1 / 60);
108
+ const { pointer } = frame;
109
+ if (burstPending) {
110
+ burstPending = false;
111
+ burst(frame);
112
+ }
113
+ if (pointer.influence > 0) {
114
+ if (wasInside) {
115
+ const moveX = pointer.x - lastX;
116
+ const moveY = pointer.y - lastY;
117
+ const dx = moveX / Math.max(1, frame.width);
118
+ const dy = moveY / Math.max(1, frame.height);
119
+ if (Math.hypot(moveX, moveY) > .5) {
120
+ const colour = splatColor(options, clock);
121
+ const strength = options.force * pointer.influence;
122
+ splatAt(frame, pointer.x, pointer.y, dx * strength, dy * strength, colour, options.radius);
123
+ wake();
124
+ }
125
+ }
126
+ lastX = pointer.x;
127
+ lastY = pointer.y;
128
+ wasInside = true;
129
+ } else wasInside = false;
130
+ for (const clickPoint of frame.clicks) click(frame, clickPoint.x, clickPoint.y);
131
+ if (dt > 0) {
132
+ idleTime += dt;
133
+ if (idleTime >= 3.5) {
134
+ sim?.clear();
135
+ idleTime = 0;
136
+ active = 0;
137
+ draw(frame);
138
+ return false;
139
+ }
140
+ const effective = idleTime > .5 ? {
141
+ ...options,
142
+ fade: Math.min(options.fade, IDLE_DECAY)
143
+ } : options;
144
+ sim?.step(dt, effective);
145
+ clock += dt;
146
+ active = Math.max(0, active - dt);
147
+ }
148
+ draw(frame);
149
+ return active > 0;
150
+ }
151
+ };
152
+ }
153
+ export { createFluidCanvas2D };
154
+
155
+ //# sourceMappingURL=canvas2d.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canvas2d.js","names":[],"sources":["../../../src/styles/fluid/canvas2d.ts"],"sourcesContent":["import type { Frame, StyleRenderer } from '../../core/style';\nimport { splatColor, type RGB } from './color';\nimport { resolveFluidOptions, type FluidOptions } from './options';\nimport { BURST_DYE, BURST_FORCE, BURST_RADIUS, IDLE_CLEAR, IDLE_DECAY, IDLE_DELAY } from './settings';\nimport { createFluidSimulation, type FluidSimulation } from './simulation';\nimport { simulationSize } from './size';\n\nconst TAU = Math.PI * 2;\n\n/**\n * The CPU fallback: the same stable-fluids simulation as the WebGL renderer,\n * on a small grid, upscaled as one image. It is softer than the GPU version but\n * keeps the style working without WebGL2 (or the float render-target extension).\n */\nexport function createFluidCanvas2D(ctx: CanvasRenderingContext2D, initial: FluidOptions): StyleRenderer<FluidOptions> {\n let options = resolveFluidOptions(initial);\n let sim: FluidSimulation | null = null;\n let image: ImageData | null = null;\n let target: HTMLCanvasElement | null = null;\n let targetCtx: CanvasRenderingContext2D | null = null;\n let builtWidth = 0;\n let builtHeight = 0;\n let builtResolution = -1;\n\n let clock = 0;\n let active = 0;\n let idleTime = 0;\n let lastX = 0;\n let lastY = 0;\n let wasInside = false;\n let burstPending = true;\n\n function allocate(width: number, height: number): void {\n const grid = simulationSize(options.resolution, width, height);\n sim = createFluidSimulation(grid.width, grid.height);\n target = document.createElement('canvas');\n target.width = grid.width;\n target.height = grid.height;\n targetCtx = target.getContext('2d');\n image = targetCtx?.createImageData(grid.width, grid.height) ?? null;\n builtWidth = width;\n builtHeight = height;\n builtResolution = options.resolution;\n burstPending = true;\n }\n\n function wake(): void {\n active = Math.max(active, IDLE_CLEAR + 0.5);\n idleTime = 0;\n }\n\n function splatAt(\n frame: Frame,\n x: number,\n y: number,\n vx: number,\n vy: number,\n colour: RGB,\n radius: number,\n ): void {\n sim?.splat(x, y, vx, vy, colour, radius, frame.width, frame.height);\n }\n\n function burst(frame: Frame): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * BURST_DYE, colour[1] * BURST_DYE, colour[2] * BURST_DYE];\n const angle = Math.random() * TAU;\n const speed = options.force * BURST_FORCE;\n splatAt(\n frame,\n frame.width * (0.34 + Math.random() * 0.18),\n frame.height * (0.4 + Math.random() * 0.2),\n Math.cos(angle) * speed,\n Math.sin(angle) * speed,\n dye,\n options.radius * BURST_RADIUS,\n );\n wake();\n }\n\n function click(frame: Frame, x: number, y: number): void {\n const colour = splatColor(options, clock);\n const dye: RGB = [colour[0] * 10, colour[1] * 10, colour[2] * 10];\n const dx = 10 * (Math.random() - 0.5);\n const dy = 30 * (Math.random() - 0.5);\n splatAt(frame, x, y, dx, dy, dye, options.radius);\n wake();\n }\n\n function draw(frame: Frame): void {\n if (!sim || !image || !target || !targetCtx) return;\n const { dyeR, dyeG, dyeB } = sim;\n const data = image.data;\n for (let k = 0; k < dyeR.length; k++) {\n const r = Math.min(1, Math.max(0, dyeR[k]));\n const g = Math.min(1, Math.max(0, dyeG[k]));\n const b = Math.min(1, Math.max(0, dyeB[k]));\n const density = Math.max(r, Math.max(g, b));\n const scale = density > 0.0001 ? 255 / density : 0;\n const o = k * 4;\n data[o] = Math.round(r * scale);\n data[o + 1] = Math.round(g * scale);\n data[o + 2] = Math.round(b * scale);\n data[o + 3] = Math.round(density * 255);\n }\n targetCtx.putImageData(image, 0, 0);\n ctx.globalAlpha = options.opacity;\n ctx.imageSmoothingEnabled = true;\n ctx.drawImage(target, 0, 0, frame.width, frame.height);\n ctx.globalAlpha = 1;\n }\n\n return {\n update(next) {\n options = resolveFluidOptions(next);\n },\n render(frame) {\n if (\n !sim ||\n frame.width !== builtWidth ||\n frame.height !== builtHeight ||\n options.resolution !== builtResolution\n ) {\n allocate(frame.width, frame.height);\n }\n\n if (frame.reducedMotion) {\n // One static splash, then hold it: no simulation steps and no pointer splats.\n if (burstPending) {\n burstPending = false;\n burst(frame);\n }\n draw(frame);\n return false;\n }\n\n const dt = Math.min(frame.dt, 1 / 60);\n const { pointer } = frame;\n\n if (burstPending) {\n burstPending = false;\n burst(frame);\n }\n\n if (pointer.influence > 0) {\n if (wasInside) {\n const moveX = pointer.x - lastX;\n const moveY = pointer.y - lastY;\n const dx = moveX / Math.max(1, frame.width);\n const dy = moveY / Math.max(1, frame.height);\n // Like a real mousemove stream: don't keep adding dye to a resting pointer.\n if (Math.hypot(moveX, moveY) > 0.5) {\n const colour = splatColor(options, clock);\n const strength = options.force * pointer.influence;\n splatAt(frame, pointer.x, pointer.y, dx * strength, dy * strength, colour, options.radius);\n wake();\n }\n }\n lastX = pointer.x;\n lastY = pointer.y;\n wasInside = true;\n } else {\n wasInside = false;\n }\n\n for (const clickPoint of frame.clicks) click(frame, clickPoint.x, clickPoint.y);\n\n if (dt > 0) {\n idleTime += dt;\n if (idleTime >= IDLE_CLEAR) {\n sim?.clear();\n idleTime = 0;\n active = 0;\n draw(frame);\n return false;\n }\n const effective =\n idleTime > IDLE_DELAY ? { ...options, fade: Math.min(options.fade, IDLE_DECAY) } : options;\n sim?.step(dt, effective);\n clock += dt;\n active = Math.max(0, active - dt);\n }\n\n draw(frame);\n return active > 0;\n },\n };\n}\n"],"mappings":";;;;;;AAOA,IAAM,MAAM,KAAK,KAAK;;;;;;AAOtB,SAAgB,oBAAoB,KAA+B,SAAoD;CACrH,IAAI,UAAU,oBAAoB,OAAO;CACzC,IAAI,MAA8B;CAClC,IAAI,QAA0B;CAC9B,IAAI,SAAmC;CACvC,IAAI,YAA6C;CACjD,IAAI,aAAa;CACjB,IAAI,cAAc;CAClB,IAAI,kBAAkB;CAEtB,IAAI,QAAQ;CACZ,IAAI,SAAS;CACb,IAAI,WAAW;CACf,IAAI,QAAQ;CACZ,IAAI,QAAQ;CACZ,IAAI,YAAY;CAChB,IAAI,eAAe;CAEnB,SAAS,SAAS,OAAe,QAAsB;EACrD,MAAM,OAAO,eAAe,QAAQ,YAAY,OAAO,MAAM;EAC7D,MAAM,sBAAsB,KAAK,OAAO,KAAK,MAAM;EACnD,SAAS,SAAS,cAAc,QAAQ;EACxC,OAAO,QAAQ,KAAK;EACpB,OAAO,SAAS,KAAK;EACrB,YAAY,OAAO,WAAW,IAAI;EAClC,QAAQ,WAAW,gBAAgB,KAAK,OAAO,KAAK,MAAM,KAAK;EAC/D,aAAa;EACb,cAAc;EACd,kBAAkB,QAAQ;EAC1B,eAAe;CACjB;CAEA,SAAS,OAAa;EACpB,SAAS,KAAK,IAAI,QAAQ,aAAa,EAAG;EAC1C,WAAW;CACb;CAEA,SAAS,QACP,OACA,GACA,GACA,IACA,IACA,QACA,QACM;EACN,KAAK,MAAM,GAAG,GAAG,IAAI,IAAI,QAAQ,QAAQ,MAAM,OAAO,MAAM,MAAM;CACpE;CAEA,SAAS,MAAM,OAAoB;EACjC,MAAM,SAAS,WAAW,SAAS,KAAK;EACxC,MAAM,MAAW;GAAC,OAAO,KAAK;GAAW,OAAO,KAAK;GAAW,OAAO,KAAK;EAAS;EACrF,MAAM,QAAQ,KAAK,OAAO,IAAI;EAC9B,MAAM,QAAQ,QAAQ,QAAQ;EAC9B,QACE,OACA,MAAM,SAAS,MAAO,KAAK,OAAO,IAAI,MACtC,MAAM,UAAU,KAAM,KAAK,OAAO,IAAI,KACtC,KAAK,IAAI,KAAK,IAAI,OAClB,KAAK,IAAI,KAAK,IAAI,OAClB,KACA,QAAQ,SAAS,YACnB;EACA,KAAK;CACP;CAEA,SAAS,MAAM,OAAc,GAAW,GAAiB;EACvD,MAAM,SAAS,WAAW,SAAS,KAAK;EACxC,MAAM,MAAW;GAAC,OAAO,KAAK;GAAI,OAAO,KAAK;GAAI,OAAO,KAAK;EAAE;EAGhE,QAAQ,OAAO,GAAG,GAFP,MAAM,KAAK,OAAO,IAAI,KACtB,MAAM,KAAK,OAAO,IAAI,KACJ,KAAK,QAAQ,MAAM;EAChD,KAAK;CACP;CAEA,SAAS,KAAK,OAAoB;EAChC,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW;EAC7C,MAAM,EAAE,MAAM,MAAM,SAAS;EAC7B,MAAM,OAAO,MAAM;EACnB,KAAK,IAAI,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;GACpC,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,EAAE,CAAC;GAC1C,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,EAAE,CAAC;GAC1C,MAAM,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,EAAE,CAAC;GAC1C,MAAM,UAAU,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,CAAC,CAAC;GAC1C,MAAM,QAAQ,UAAU,OAAS,MAAM,UAAU;GACjD,MAAM,IAAI,IAAI;GACd,KAAK,KAAK,KAAK,MAAM,IAAI,KAAK;GAC9B,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK;GAClC,KAAK,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK;GAClC,KAAK,IAAI,KAAK,KAAK,MAAM,UAAU,GAAG;EACxC;EACA,UAAU,aAAa,OAAO,GAAG,CAAC;EAClC,IAAI,cAAc,QAAQ;EAC1B,IAAI,wBAAwB;EAC5B,IAAI,UAAU,QAAQ,GAAG,GAAG,MAAM,OAAO,MAAM,MAAM;EACrD,IAAI,cAAc;CACpB;CAEA,OAAO;EACL,OAAO,MAAM;GACX,UAAU,oBAAoB,IAAI;EACpC;EACA,OAAO,OAAO;GACZ,IACE,CAAC,OACD,MAAM,UAAU,cAChB,MAAM,WAAW,eACjB,QAAQ,eAAe,iBAEvB,SAAS,MAAM,OAAO,MAAM,MAAM;GAGpC,IAAI,MAAM,eAAe;IAEvB,IAAI,cAAc;KAChB,eAAe;KACf,MAAM,KAAK;IACb;IACA,KAAK,KAAK;IACV,OAAO;GACT;GAEA,MAAM,KAAK,KAAK,IAAI,MAAM,IAAI,IAAI,EAAE;GACpC,MAAM,EAAE,YAAY;GAEpB,IAAI,cAAc;IAChB,eAAe;IACf,MAAM,KAAK;GACb;GAEA,IAAI,QAAQ,YAAY,GAAG;IACzB,IAAI,WAAW;KACb,MAAM,QAAQ,QAAQ,IAAI;KAC1B,MAAM,QAAQ,QAAQ,IAAI;KAC1B,MAAM,KAAK,QAAQ,KAAK,IAAI,GAAG,MAAM,KAAK;KAC1C,MAAM,KAAK,QAAQ,KAAK,IAAI,GAAG,MAAM,MAAM;KAE3C,IAAI,KAAK,MAAM,OAAO,KAAK,IAAI,IAAK;MAClC,MAAM,SAAS,WAAW,SAAS,KAAK;MACxC,MAAM,WAAW,QAAQ,QAAQ,QAAQ;MACzC,QAAQ,OAAO,QAAQ,GAAG,QAAQ,GAAG,KAAK,UAAU,KAAK,UAAU,QAAQ,QAAQ,MAAM;MACzF,KAAK;KACP;IACF;IACA,QAAQ,QAAQ;IAChB,QAAQ,QAAQ;IAChB,YAAY;GACd,OACE,YAAY;GAGd,KAAK,MAAM,cAAc,MAAM,QAAQ,MAAM,OAAO,WAAW,GAAG,WAAW,CAAC;GAE9E,IAAI,KAAK,GAAG;IACV,YAAY;IACZ,IAAI,YAAA,KAAwB;KAC1B,KAAK,MAAM;KACX,WAAW;KACX,SAAS;KACT,KAAK,KAAK;KACV,OAAO;IACT;IACA,MAAM,YACJ,WAAA,KAAwB;KAAE,GAAG;KAAS,MAAM,KAAK,IAAI,QAAQ,MAAM,UAAU;IAAE,IAAI;IACrF,KAAK,KAAK,IAAI,SAAS;IACvB,SAAS;IACT,SAAS,KAAK,IAAI,GAAG,SAAS,EAAE;GAClC;GAEA,KAAK,KAAK;GACV,OAAO,SAAS;EAClB;CACF;AACF"}
@@ -0,0 +1,40 @@
1
+ const require_color = require("../../core/color.cjs");
2
+ // src/styles/fluid/color.ts
3
+ /** HSL (all in 0–1) to straight RGB. */
4
+ function hslToRgb(h, s, l) {
5
+ if (s === 0) return [
6
+ l,
7
+ l,
8
+ l
9
+ ];
10
+ const q = l < .5 ? l * (1 + s) : l + s - l * s;
11
+ const p = 2 * l - q;
12
+ const channel = (t) => {
13
+ let k = t % 1;
14
+ if (k < 0) k += 1;
15
+ if (k < 1 / 6) return p + (q - p) * 6 * k;
16
+ if (k < 1 / 2) return q;
17
+ if (k < 2 / 3) return p + (q - p) * (2 / 3 - k) * 6;
18
+ return p;
19
+ };
20
+ return [
21
+ channel(h + 1 / 3),
22
+ channel(h),
23
+ channel(h - 1 / 3)
24
+ ];
25
+ }
26
+ /** The colour of a splash made at `clock` seconds: the fixed colour, or the cycling hue. */
27
+ function splatColor(options, clock) {
28
+ if (options.color) {
29
+ const [r, g, b, a] = require_color.parseColor(options.color);
30
+ return [
31
+ r * a,
32
+ g * a,
33
+ b * a
34
+ ];
35
+ }
36
+ return hslToRgb(((.55 + Math.floor(clock * options.colorSpeed) * .61803398875) % 1 + 1) % 1, 1, .5);
37
+ }
38
+ exports.splatColor = splatColor;
39
+
40
+ //# sourceMappingURL=color.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"color.cjs","names":["parseColor"],"sources":["../../../src/styles/fluid/color.ts"],"sourcesContent":["import { parseColor } from '../../core/color';\nimport type { ResolvedFluidOptions } from './options';\n\nexport type RGB = readonly [number, number, number];\n\n/** HSL (all in 0–1) to straight RGB. */\nfunction hslToRgb(h: number, s: number, l: number): RGB {\n if (s === 0) return [l, l, l];\n const q = l < 0.5 ? l * (1 + s) : l + s - l * s;\n const p = 2 * l - q;\n const channel = (t: number) => {\n let k = t % 1;\n if (k < 0) k += 1;\n if (k < 1 / 6) return p + (q - p) * 6 * k;\n if (k < 1 / 2) return q;\n if (k < 2 / 3) return p + (q - p) * (2 / 3 - k) * 6;\n return p;\n };\n return [channel(h + 1 / 3), channel(h), channel(h - 1 / 3)];\n}\n\n/** The colour of a splash made at `clock` seconds: the fixed colour, or the cycling hue. */\nexport function splatColor(options: ResolvedFluidOptions, clock: number): RGB {\n if (options.color) {\n const [r, g, b, a] = parseColor(options.color);\n return [r * a, g * a, b * a];\n }\n const step = Math.floor(clock * options.colorSpeed);\n const hue = (((0.55 + step * 0.61803398875) % 1) + 1) % 1;\n return hslToRgb(hue, 1, 0.5);\n}\n"],"mappings":";;;AAMA,SAAS,SAAS,GAAW,GAAW,GAAgB;CACtD,IAAI,MAAM,GAAG,OAAO;EAAC;EAAG;EAAG;CAAC;CAC5B,MAAM,IAAI,IAAI,KAAM,KAAK,IAAI,KAAK,IAAI,IAAI,IAAI;CAC9C,MAAM,IAAI,IAAI,IAAI;CAClB,MAAM,WAAW,MAAc;EAC7B,IAAI,IAAI,IAAI;EACZ,IAAI,IAAI,GAAG,KAAK;EAChB,IAAI,IAAI,IAAI,GAAG,OAAO,KAAK,IAAI,KAAK,IAAI;EACxC,IAAI,IAAI,IAAI,GAAG,OAAO;EACtB,IAAI,IAAI,IAAI,GAAG,OAAO,KAAK,IAAI,MAAM,IAAI,IAAI,KAAK;EAClD,OAAO;CACT;CACA,OAAO;EAAC,QAAQ,IAAI,IAAI,CAAC;EAAG,QAAQ,CAAC;EAAG,QAAQ,IAAI,IAAI,CAAC;CAAC;AAC5D;;AAGA,SAAgB,WAAW,SAA+B,OAAoB;CAC5E,IAAI,QAAQ,OAAO;EACjB,MAAM,CAAC,GAAG,GAAG,GAAG,KAAKA,cAAAA,WAAW,QAAQ,KAAK;EAC7C,OAAO;GAAC,IAAI;GAAG,IAAI;GAAG,IAAI;EAAC;CAC7B;CAGA,OAAO,WADQ,MADF,KAAK,MAAM,QAAQ,QAAQ,UAClB,IAAO,gBAAiB,IAAK,KAAK,GACnC,GAAG,EAAG;AAC7B"}
@@ -0,0 +1,4 @@
1
+ import type { ResolvedFluidOptions } from './options.cjs';
2
+ export type RGB = readonly [number, number, number];
3
+ /** The colour of a splash made at `clock` seconds: the fixed colour, or the cycling hue. */
4
+ export declare function splatColor(options: ResolvedFluidOptions, clock: number): RGB;
@@ -0,0 +1,4 @@
1
+ import type { ResolvedFluidOptions } from './options.js';
2
+ export type RGB = readonly [number, number, number];
3
+ /** The colour of a splash made at `clock` seconds: the fixed colour, or the cycling hue. */
4
+ export declare function splatColor(options: ResolvedFluidOptions, clock: number): RGB;
@@ -0,0 +1,40 @@
1
+ import { parseColor } from "../../core/color.js";
2
+ // src/styles/fluid/color.ts
3
+ /** HSL (all in 0–1) to straight RGB. */
4
+ function hslToRgb(h, s, l) {
5
+ if (s === 0) return [
6
+ l,
7
+ l,
8
+ l
9
+ ];
10
+ const q = l < .5 ? l * (1 + s) : l + s - l * s;
11
+ const p = 2 * l - q;
12
+ const channel = (t) => {
13
+ let k = t % 1;
14
+ if (k < 0) k += 1;
15
+ if (k < 1 / 6) return p + (q - p) * 6 * k;
16
+ if (k < 1 / 2) return q;
17
+ if (k < 2 / 3) return p + (q - p) * (2 / 3 - k) * 6;
18
+ return p;
19
+ };
20
+ return [
21
+ channel(h + 1 / 3),
22
+ channel(h),
23
+ channel(h - 1 / 3)
24
+ ];
25
+ }
26
+ /** The colour of a splash made at `clock` seconds: the fixed colour, or the cycling hue. */
27
+ function splatColor(options, clock) {
28
+ if (options.color) {
29
+ const [r, g, b, a] = parseColor(options.color);
30
+ return [
31
+ r * a,
32
+ g * a,
33
+ b * a
34
+ ];
35
+ }
36
+ return hslToRgb(((.55 + Math.floor(clock * options.colorSpeed) * .61803398875) % 1 + 1) % 1, 1, .5);
37
+ }
38
+ export { splatColor };
39
+
40
+ //# sourceMappingURL=color.js.map