@autumnsgrove/gossamer 0.1.0 → 0.1.1

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
@@ -16,6 +16,8 @@ class GossamerRenderer {
16
16
  this.animationId = null;
17
17
  this.lastFrameTime = 0;
18
18
  this.isRunning = false;
19
+ this.charAtlas = null;
20
+ this.atlasCharacters = "";
19
21
  const context = canvas.getContext("2d");
20
22
  if (!context) {
21
23
  throw new Error("Failed to get 2D rendering context");
@@ -27,6 +29,43 @@ class GossamerRenderer {
27
29
  ...config
28
30
  };
29
31
  this.setupCanvas();
32
+ this.buildCharacterAtlas();
33
+ }
34
+ /**
35
+ * Build character texture atlas for fast rendering
36
+ * Pre-renders all characters to an offscreen canvas, then uses drawImage
37
+ * instead of fillText for 5-10x faster rendering
38
+ */
39
+ buildCharacterAtlas() {
40
+ const { characters, cellWidth, cellHeight, color, fontFamily } = this.config;
41
+ if (this.atlasCharacters === characters && this.charAtlas) {
42
+ return;
43
+ }
44
+ const atlasWidth = characters.length * cellWidth;
45
+ const atlasHeight = cellHeight;
46
+ if (typeof OffscreenCanvas !== "undefined") {
47
+ this.charAtlas = new OffscreenCanvas(atlasWidth, atlasHeight);
48
+ } else {
49
+ this.charAtlas = document.createElement("canvas");
50
+ this.charAtlas.width = atlasWidth;
51
+ this.charAtlas.height = atlasHeight;
52
+ }
53
+ const ctx = this.charAtlas.getContext("2d");
54
+ if (!ctx) {
55
+ this.charAtlas = null;
56
+ return;
57
+ }
58
+ ctx.clearRect(0, 0, atlasWidth, atlasHeight);
59
+ ctx.fillStyle = color;
60
+ ctx.font = `${cellHeight}px ${fontFamily}`;
61
+ ctx.textBaseline = "top";
62
+ for (let i = 0; i < characters.length; i++) {
63
+ const char = characters[i];
64
+ if (char !== " ") {
65
+ ctx.fillText(char, i * cellWidth, 0);
66
+ }
67
+ }
68
+ this.atlasCharacters = characters;
30
69
  }
31
70
  /**
32
71
  * Set up the canvas with optimal rendering settings
@@ -42,8 +81,13 @@ class GossamerRenderer {
42
81
  * Update the renderer configuration
43
82
  */
44
83
  updateConfig(config) {
84
+ const needsAtlasRebuild = config.characters !== void 0 || config.color !== void 0 || config.cellWidth !== void 0 || config.cellHeight !== void 0 || config.fontFamily !== void 0;
45
85
  this.config = { ...this.config, ...config };
46
86
  this.setupCanvas();
87
+ if (needsAtlasRebuild) {
88
+ this.atlasCharacters = "";
89
+ this.buildCharacterAtlas();
90
+ }
47
91
  }
48
92
  /**
49
93
  * Resize the canvas to match new dimensions
@@ -135,6 +179,95 @@ class GossamerRenderer {
135
179
  }
136
180
  }
137
181
  }
182
+ /**
183
+ * PERFORMANCE: Render from BrightnessBuffer using texture atlas
184
+ *
185
+ * Uses pre-rendered character sprites instead of fillText calls.
186
+ * 5-10x faster than renderFromBrightnessGrid for large canvases.
187
+ *
188
+ * @param buffer - BrightnessBuffer from fillBrightnessBuffer
189
+ */
190
+ renderFromBuffer(buffer) {
191
+ const { characters, cellWidth, cellHeight } = this.config;
192
+ this.clear();
193
+ if (!this.charAtlas) {
194
+ this.ctx.fillStyle = this.config.color;
195
+ const charLen2 = characters.length - 1;
196
+ let idx2 = 0;
197
+ for (let row = 0; row < buffer.rows; row++) {
198
+ for (let col = 0; col < buffer.cols; col++) {
199
+ const brightness = buffer.data[idx2++];
200
+ const charIndex = brightness / 255 * charLen2 | 0;
201
+ const char = characters[Math.min(charIndex, charLen2)];
202
+ if (char !== " ") {
203
+ this.ctx.fillText(char, col * cellWidth, row * cellHeight);
204
+ }
205
+ }
206
+ }
207
+ return;
208
+ }
209
+ const charLen = characters.length - 1;
210
+ let idx = 0;
211
+ for (let row = 0; row < buffer.rows; row++) {
212
+ const y = row * cellHeight;
213
+ for (let col = 0; col < buffer.cols; col++) {
214
+ const brightness = buffer.data[idx++];
215
+ const charIndex = brightness / 255 * charLen | 0;
216
+ if (charIndex === 0 && characters[0] === " ") {
217
+ continue;
218
+ }
219
+ this.ctx.drawImage(
220
+ this.charAtlas,
221
+ charIndex * cellWidth,
222
+ 0,
223
+ cellWidth,
224
+ cellHeight,
225
+ // source
226
+ col * cellWidth,
227
+ y,
228
+ cellWidth,
229
+ cellHeight
230
+ // destination
231
+ );
232
+ }
233
+ }
234
+ }
235
+ /**
236
+ * PERFORMANCE: Render brightness grid using atlas (legacy grid format)
237
+ *
238
+ * @param grid - 2D array of brightness values
239
+ */
240
+ renderGridFast(grid) {
241
+ const { characters, cellWidth, cellHeight } = this.config;
242
+ this.clear();
243
+ if (!this.charAtlas) {
244
+ this.renderFromBrightnessGrid(grid);
245
+ return;
246
+ }
247
+ const charLen = characters.length - 1;
248
+ for (let row = 0; row < grid.length; row++) {
249
+ const y = row * cellHeight;
250
+ const rowData = grid[row];
251
+ for (let col = 0; col < rowData.length; col++) {
252
+ const brightness = rowData[col];
253
+ const charIndex = brightness / 255 * charLen | 0;
254
+ if (charIndex === 0 && characters[0] === " ") {
255
+ continue;
256
+ }
257
+ this.ctx.drawImage(
258
+ this.charAtlas,
259
+ charIndex * cellWidth,
260
+ 0,
261
+ cellWidth,
262
+ cellHeight,
263
+ col * cellWidth,
264
+ y,
265
+ cellWidth,
266
+ cellHeight
267
+ );
268
+ }
269
+ }
270
+ }
138
271
  /**
139
272
  * Calculate average brightness for a cell region
140
273
  */
@@ -544,6 +677,97 @@ function seededNoise2D(x, y, seed = 0) {
544
677
  const n = Math.sin(x * 12.9898 + y * 78.233 + seed) * 43758.5453;
545
678
  return n - Math.floor(n);
546
679
  }
680
+ function cloudsPattern(x, y, time, config = DEFAULT_PATTERN_CONFIG) {
681
+ const { frequency, amplitude, speed } = config;
682
+ const drift = time * speed * 0.02;
683
+ const nx = x * frequency * 0.5 + drift;
684
+ const ny = y * frequency * 0.5 + drift * 0.7;
685
+ const base = fbmNoise(nx, ny, 5, 0.6);
686
+ const detail = fbmNoise(nx * 2 + drift * 0.5, ny * 2 - drift * 0.3, 3, 0.5) * 0.3;
687
+ const combined = base + detail;
688
+ return Math.tanh(combined * 1.5) * amplitude;
689
+ }
690
+ function plasmaPattern(x, y, time, config = DEFAULT_PATTERN_CONFIG) {
691
+ const { frequency, amplitude, speed } = config;
692
+ const t = time * speed;
693
+ const v1 = Math.sin(x * frequency + t);
694
+ const v2 = Math.sin(y * frequency + t * 0.7);
695
+ const v3 = Math.sin((x + y) * frequency * 0.5 + t * 0.5);
696
+ const v4 = Math.sin(Math.sqrt(x * x + y * y) * frequency * 0.3 + t * 0.8);
697
+ const cx = x - 40;
698
+ const cy = y - 20;
699
+ const v5 = Math.sin(Math.atan2(cy, cx) * 3 + t * 0.4);
700
+ return (v1 + v2 + v3 + v4 + v5) / 5 * amplitude;
701
+ }
702
+ function vortexPattern(x, y, centerX, centerY, time, config = DEFAULT_PATTERN_CONFIG) {
703
+ const { frequency, amplitude, speed } = config;
704
+ const dx = x - centerX;
705
+ const dy = y - centerY;
706
+ const distance = Math.sqrt(dx * dx + dy * dy);
707
+ const angle = Math.atan2(dy, dx);
708
+ const spiral = angle + distance * frequency * 0.1 - time * speed;
709
+ const turbulence = perlinNoise2D(distance * 0.1, time * speed * 0.5) * 0.3;
710
+ return (Math.sin(spiral * 3) + turbulence) * amplitude;
711
+ }
712
+ function matrixPattern(x, y, time, config = DEFAULT_PATTERN_CONFIG) {
713
+ const { frequency, amplitude, speed } = config;
714
+ const columnSeed = seededNoise2D(x, 0, 42);
715
+ const columnSpeed = 0.5 + columnSeed * 1.5;
716
+ const columnPhase = columnSeed * 100;
717
+ const fallPosition = (y * frequency + time * speed * columnSpeed + columnPhase) % 20;
718
+ const headBrightness = fallPosition < 1 ? 1 : 0;
719
+ const trailLength = 8;
720
+ const trailBrightness = fallPosition < trailLength ? Math.pow(1 - fallPosition / trailLength, 2) : 0;
721
+ const flicker = seededNoise2D(x, Math.floor(time * 10), y) * 0.2;
722
+ const value = Math.max(headBrightness, trailBrightness) + flicker;
723
+ return (value * 2 - 1) * amplitude;
724
+ }
725
+ function gradientPattern(x, y, cols, rows, time, config = DEFAULT_PATTERN_CONFIG) {
726
+ const { frequency, amplitude, speed } = config;
727
+ const nx = x / cols;
728
+ const ny = y / rows;
729
+ const angle = time * speed * 0.2;
730
+ const cos = Math.cos(angle);
731
+ const sin = Math.sin(angle);
732
+ const rotated = nx * cos + ny * sin;
733
+ const distortion = Math.sin(ny * Math.PI * 2 * frequency + time * speed) * 0.1;
734
+ const value = (rotated + distortion) * 2 - 1;
735
+ return Math.sin(value * Math.PI) * amplitude;
736
+ }
737
+ function diamondPattern(x, y, time, config = DEFAULT_PATTERN_CONFIG) {
738
+ const { frequency, amplitude, speed } = config;
739
+ const t = time * speed;
740
+ const wave1 = Math.sin((Math.abs(x - 40) + Math.abs(y - 20)) * frequency + t);
741
+ const wave2 = Math.sin((Math.abs(x - 40) - Math.abs(y - 20)) * frequency * 0.7 - t * 0.8);
742
+ const angle = t * 0.1;
743
+ const rx = x * Math.cos(angle) - y * Math.sin(angle);
744
+ const ry = x * Math.sin(angle) + y * Math.cos(angle);
745
+ const wave3 = Math.sin((Math.abs(rx) + Math.abs(ry)) * frequency * 0.5 + t * 0.5);
746
+ return (wave1 + wave2 + wave3) / 3 * amplitude;
747
+ }
748
+ function fractalPattern(x, y, cols, rows, time, config = DEFAULT_PATTERN_CONFIG) {
749
+ const { frequency, amplitude, speed } = config;
750
+ const scale = 3.5 * frequency;
751
+ const zx = x / cols * scale - scale / 2 + Math.sin(time * speed * 0.1) * 0.2;
752
+ const zy = y / rows * scale - scale / 2 + Math.cos(time * speed * 0.1) * 0.2;
753
+ const cx = -0.7 + Math.sin(time * speed * 0.05) * 0.1;
754
+ const cy = 0.27 + Math.cos(time * speed * 0.07) * 0.1;
755
+ let zrx = zx;
756
+ let zry = zy;
757
+ const maxIter = 20;
758
+ let iter = 0;
759
+ while (zrx * zrx + zry * zry < 4 && iter < maxIter) {
760
+ const tmp = zrx * zrx - zry * zry + cx;
761
+ zry = 2 * zrx * zry + cy;
762
+ zrx = tmp;
763
+ iter++;
764
+ }
765
+ if (iter === maxIter) {
766
+ return -1 * amplitude;
767
+ }
768
+ const smooth = iter - Math.log2(Math.log2(zrx * zrx + zry * zry));
769
+ return (smooth / maxIter * 2 - 1) * amplitude;
770
+ }
547
771
  function generateBrightnessGrid(cols, rows, pattern, time = 0, config = DEFAULT_PATTERN_CONFIG) {
548
772
  const grid = [];
549
773
  const { frequency, amplitude, speed } = config;
@@ -573,6 +797,29 @@ function generateBrightnessGrid(cols, rows, pattern, time = 0, config = DEFAULT_
573
797
  value = ripplePattern(col, row, cols / 2, rows / 2, time, config);
574
798
  break;
575
799
  case "static":
800
+ value = seededNoise2D(col, row, Math.floor(time * speed * 10)) * 2 - 1;
801
+ break;
802
+ case "clouds":
803
+ value = cloudsPattern(col, row, time, config);
804
+ break;
805
+ case "plasma":
806
+ value = plasmaPattern(col, row, time, config);
807
+ break;
808
+ case "vortex":
809
+ value = vortexPattern(col, row, cols / 2, rows / 2, time, config);
810
+ break;
811
+ case "matrix":
812
+ value = matrixPattern(col, row, time, config);
813
+ break;
814
+ case "gradient":
815
+ value = gradientPattern(col, row, cols, rows, time, config);
816
+ break;
817
+ case "diamond":
818
+ value = diamondPattern(col, row, time, config);
819
+ break;
820
+ case "fractal":
821
+ value = fractalPattern(col, row, cols, rows, time, config);
822
+ break;
576
823
  default:
577
824
  value = seededNoise2D(col, row, Math.floor(time * speed * 10)) * 2 - 1;
578
825
  break;
@@ -607,6 +854,77 @@ function gridToImageData(grid, cellWidth, cellHeight) {
607
854
  }
608
855
  return new ImageData(data, width, height);
609
856
  }
857
+ function createBrightnessBuffer(cols, rows) {
858
+ return {
859
+ data: new Uint8Array(cols * rows),
860
+ cols,
861
+ rows
862
+ };
863
+ }
864
+ function fillBrightnessBuffer(buffer, pattern, time = 0, config = DEFAULT_PATTERN_CONFIG) {
865
+ const { data, cols, rows } = buffer;
866
+ const { frequency, amplitude, speed } = config;
867
+ let idx = 0;
868
+ for (let row = 0; row < rows; row++) {
869
+ for (let col = 0; col < cols; col++) {
870
+ let value;
871
+ switch (pattern) {
872
+ case "perlin":
873
+ value = perlinNoise2D(
874
+ col * frequency + time * speed * 0.1,
875
+ row * frequency + time * speed * 0.05
876
+ );
877
+ break;
878
+ case "fbm":
879
+ value = fbmNoise(
880
+ col * frequency + time * speed * 0.1,
881
+ row * frequency + time * speed * 0.05,
882
+ 4,
883
+ 0.5
884
+ );
885
+ break;
886
+ case "waves":
887
+ value = wavePattern(col, row, time, config);
888
+ break;
889
+ case "ripple":
890
+ value = ripplePattern(col, row, cols / 2, rows / 2, time, config);
891
+ break;
892
+ case "static":
893
+ value = seededNoise2D(col, row, Math.floor(time * speed * 10)) * 2 - 1;
894
+ break;
895
+ case "clouds":
896
+ value = cloudsPattern(col, row, time, config);
897
+ break;
898
+ case "plasma":
899
+ value = plasmaPattern(col, row, time, config);
900
+ break;
901
+ case "vortex":
902
+ value = vortexPattern(col, row, cols / 2, rows / 2, time, config);
903
+ break;
904
+ case "matrix":
905
+ value = matrixPattern(col, row, time, config);
906
+ break;
907
+ case "gradient":
908
+ value = gradientPattern(col, row, cols, rows, time, config);
909
+ break;
910
+ case "diamond":
911
+ value = diamondPattern(col, row, time, config);
912
+ break;
913
+ case "fractal":
914
+ value = fractalPattern(col, row, cols, rows, time, config);
915
+ break;
916
+ default:
917
+ value = seededNoise2D(col, row, Math.floor(time * speed * 10)) * 2 - 1;
918
+ break;
919
+ }
920
+ const normalized = (value + 1) * 0.5 * amplitude;
921
+ data[idx++] = normalized * 255 | 0;
922
+ }
923
+ }
924
+ }
925
+ function getBufferValue(buffer, col, row) {
926
+ return buffer.data[row * buffer.cols + col];
927
+ }
610
928
  const CHARACTER_SETS = {
611
929
  standard: {
612
930
  name: "Standard",
@@ -679,6 +997,53 @@ const CHARACTER_SETS = {
679
997
  description: "Mathematical symbols",
680
998
  characters: " +-×÷=≠≈∞",
681
999
  bestFor: ["abstract patterns", "tech themes", "decorative"]
1000
+ },
1001
+ // ==========================================================================
1002
+ // GLASS-OPTIMIZED CHARACTER SETS
1003
+ // Designed for subtle overlays on Glass components
1004
+ // More characters = more visible gradations
1005
+ // ==========================================================================
1006
+ "glass-dots": {
1007
+ name: "Glass Dots",
1008
+ description: "Soft dot gradations for glass overlays",
1009
+ characters: " ·∘∙○•●",
1010
+ bestFor: ["glass overlays", "subtle backgrounds", "mist effects"]
1011
+ },
1012
+ "glass-mist": {
1013
+ name: "Glass Mist",
1014
+ description: "Ethereal mist effect for glass",
1015
+ characters: " .·∙•◦○◉●",
1016
+ bestFor: ["glass overlays", "fog effects", "ambient backgrounds"]
1017
+ },
1018
+ "glass-dust": {
1019
+ name: "Glass Dust",
1020
+ description: "Floating dust particles",
1021
+ characters: " ˙·∘°•◦○",
1022
+ bestFor: ["glass overlays", "particle effects", "light scatter"]
1023
+ },
1024
+ "glass-soft": {
1025
+ name: "Glass Soft",
1026
+ description: "Soft block gradations for glass",
1027
+ characters: " ·░▒▓",
1028
+ bestFor: ["glass overlays", "soft gradients", "frosted effect"]
1029
+ },
1030
+ "glass-sparkle": {
1031
+ name: "Glass Sparkle",
1032
+ description: "Subtle sparkles for glass",
1033
+ characters: " ·.✧✦✫★",
1034
+ bestFor: ["glass overlays", "highlight effects", "magical themes"]
1035
+ },
1036
+ "glass-wave": {
1037
+ name: "Glass Wave",
1038
+ description: "Flowing wave patterns for glass",
1039
+ characters: " .~∼≈≋",
1040
+ bestFor: ["glass overlays", "water effects", "flowing motion"]
1041
+ },
1042
+ "glass-organic": {
1043
+ name: "Glass Organic",
1044
+ description: "Natural, organic feel for glass",
1045
+ characters: " .·:;∘○◦•●",
1046
+ bestFor: ["glass overlays", "nature themes", "grove aesthetic"]
682
1047
  }
683
1048
  };
684
1049
  function getCharacterSet(name) {
@@ -707,6 +1072,162 @@ function validateCharacterSet(characters) {
707
1072
  function invertCharacters(characters) {
708
1073
  return characters.split("").reverse().join("");
709
1074
  }
1075
+ const GROVE_GREEN = {
1076
+ 50: { hex: "#f0fdf4", name: "Grove Green 50", glassOpacity: 0.3 },
1077
+ 100: { hex: "#dcfce7", name: "Grove Green 100", glassOpacity: 0.25 },
1078
+ 200: { hex: "#bbf7d0", name: "Grove Green 200", glassOpacity: 0.2 },
1079
+ 300: { hex: "#86efac", name: "Grove Green 300", glassOpacity: 0.18 },
1080
+ 400: { hex: "#4ade80", name: "Grove Green 400", glassOpacity: 0.15 },
1081
+ 500: { hex: "#22c55e", name: "Grove Green 500", glassOpacity: 0.12 },
1082
+ 600: { hex: "#16a34a", name: "Grove Green 600", glassOpacity: 0.1 },
1083
+ 700: { hex: "#15803d", name: "Grove Green 700", glassOpacity: 0.1 },
1084
+ 800: { hex: "#166534", name: "Grove Green 800", glassOpacity: 0.08 },
1085
+ 900: { hex: "#14532d", name: "Grove Green 900", glassOpacity: 0.08 }
1086
+ };
1087
+ const CREAM = {
1088
+ 50: { hex: "#fefdfb", name: "Cream 50", glassOpacity: 0.4 },
1089
+ 100: { hex: "#fdfcf8", name: "Cream 100", glassOpacity: 0.35 },
1090
+ 200: { hex: "#faf8f3", name: "Cream 200", glassOpacity: 0.3 },
1091
+ 300: { hex: "#f5f2ea", name: "Cream 300", glassOpacity: 0.25 },
1092
+ 400: { hex: "#ede9de", name: "Cream 400", glassOpacity: 0.2 },
1093
+ 500: { hex: "#e2ddd0", name: "Cream 500", glassOpacity: 0.18 },
1094
+ 600: { hex: "#d4cec0", name: "Cream 600", glassOpacity: 0.15 },
1095
+ 700: { hex: "#c4bdb0", name: "Cream 700", glassOpacity: 0.12 },
1096
+ 800: { hex: "#b0a99c", name: "Cream 800", glassOpacity: 0.1 },
1097
+ 900: { hex: "#9a9387", name: "Cream 900", glassOpacity: 0.08 }
1098
+ };
1099
+ const BARK = {
1100
+ 50: { hex: "#faf7f5", name: "Bark 50", glassOpacity: 0.3 },
1101
+ 100: { hex: "#f0ebe6", name: "Bark 100", glassOpacity: 0.25 },
1102
+ 200: { hex: "#e0d5cc", name: "Bark 200", glassOpacity: 0.2 },
1103
+ 300: { hex: "#ccb59c", name: "Bark 300", glassOpacity: 0.18 },
1104
+ 400: { hex: "#b89a7a", name: "Bark 400", glassOpacity: 0.15 },
1105
+ 500: { hex: "#a57c5a", name: "Bark 500", glassOpacity: 0.12 },
1106
+ 600: { hex: "#8a6344", name: "Bark 600", glassOpacity: 0.1 },
1107
+ 700: { hex: "#6f4d39", name: "Bark 700", glassOpacity: 0.1 },
1108
+ 800: { hex: "#553a2a", name: "Bark 800", glassOpacity: 0.08 },
1109
+ 900: { hex: "#3d2914", name: "Bark 900", glassOpacity: 0.06 }
1110
+ };
1111
+ const STATUS = {
1112
+ success: { hex: "#22c55e", name: "Success", glassOpacity: 0.12 },
1113
+ warning: { hex: "#f59e0b", name: "Warning", glassOpacity: 0.12 },
1114
+ error: { hex: "#dc2626", name: "Error", glassOpacity: 0.1 },
1115
+ info: { hex: "#0ea5e9", name: "Info", glassOpacity: 0.12 }
1116
+ };
1117
+ const GROVE_COLORS = {
1118
+ // Greens
1119
+ grove: GROVE_GREEN[500].hex,
1120
+ "grove-light": GROVE_GREEN[300].hex,
1121
+ "grove-dark": GROVE_GREEN[700].hex,
1122
+ "grove-muted": GROVE_GREEN[400].hex,
1123
+ // Creams
1124
+ cream: CREAM[50].hex,
1125
+ "cream-warm": CREAM[200].hex,
1126
+ "cream-deep": CREAM[500].hex,
1127
+ // Barks
1128
+ bark: BARK[900].hex,
1129
+ "bark-light": BARK[500].hex,
1130
+ "bark-medium": BARK[700].hex,
1131
+ // Utility
1132
+ white: "#ffffff",
1133
+ black: "#000000",
1134
+ transparent: "transparent"
1135
+ };
1136
+ const GLASS_SCHEMES = {
1137
+ // Light mode schemes (on light backgrounds)
1138
+ "grove-mist": {
1139
+ color: GROVE_GREEN[500].hex,
1140
+ background: "transparent",
1141
+ opacity: 0.12,
1142
+ description: "Subtle green mist for light glass"
1143
+ },
1144
+ "cream-haze": {
1145
+ color: CREAM[600].hex,
1146
+ background: "transparent",
1147
+ opacity: 0.15,
1148
+ description: "Warm cream haze for cozy glass"
1149
+ },
1150
+ "bark-shadow": {
1151
+ color: BARK[700].hex,
1152
+ background: "transparent",
1153
+ opacity: 0.08,
1154
+ description: "Soft earth shadow for depth"
1155
+ },
1156
+ // Dark mode schemes (on dark backgrounds)
1157
+ "grove-glow": {
1158
+ color: GROVE_GREEN[400].hex,
1159
+ background: "#1a1915",
1160
+ opacity: 0.15,
1161
+ description: "Glowing green for dark glass"
1162
+ },
1163
+ "cream-dust": {
1164
+ color: CREAM[300].hex,
1165
+ background: "#1a1915",
1166
+ opacity: 0.1,
1167
+ description: "Dusty cream particles in dark"
1168
+ },
1169
+ "moonlight": {
1170
+ color: "#e2e8f0",
1171
+ background: "#1a1915",
1172
+ opacity: 0.08,
1173
+ description: "Cool moonlight glow"
1174
+ },
1175
+ // Accent schemes
1176
+ "spring-fresh": {
1177
+ color: GROVE_GREEN[300].hex,
1178
+ background: "transparent",
1179
+ opacity: 0.18,
1180
+ description: "Fresh spring green overlay"
1181
+ },
1182
+ "autumn-warm": {
1183
+ color: "#d97706",
1184
+ background: "transparent",
1185
+ opacity: 0.1,
1186
+ description: "Warm autumn amber tones"
1187
+ },
1188
+ "winter-frost": {
1189
+ color: "#93c5fd",
1190
+ background: "transparent",
1191
+ opacity: 0.12,
1192
+ description: "Cool frost blue overlay"
1193
+ }
1194
+ };
1195
+ function getGroveColor(name) {
1196
+ if (name in GROVE_COLORS) {
1197
+ return GROVE_COLORS[name];
1198
+ }
1199
+ if (name.startsWith("#")) {
1200
+ return name;
1201
+ }
1202
+ return GROVE_COLORS.grove;
1203
+ }
1204
+ function getGlassScheme(name) {
1205
+ if (name in GLASS_SCHEMES) {
1206
+ const scheme = GLASS_SCHEMES[name];
1207
+ return {
1208
+ color: scheme.color,
1209
+ background: scheme.background,
1210
+ opacity: scheme.opacity
1211
+ };
1212
+ }
1213
+ return {
1214
+ color: GLASS_SCHEMES["grove-mist"].color,
1215
+ background: GLASS_SCHEMES["grove-mist"].background,
1216
+ opacity: GLASS_SCHEMES["grove-mist"].opacity
1217
+ };
1218
+ }
1219
+ function getGroveColorNames() {
1220
+ return Object.keys(GROVE_COLORS);
1221
+ }
1222
+ function getGlassSchemeNames() {
1223
+ return Object.keys(GLASS_SCHEMES);
1224
+ }
1225
+ function hexToRgba(hex, opacity) {
1226
+ const r = parseInt(hex.slice(1, 3), 16);
1227
+ const g = parseInt(hex.slice(3, 5), 16);
1228
+ const b = parseInt(hex.slice(5, 7), 16);
1229
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
1230
+ }
710
1231
  function createAnimationLoop(options) {
711
1232
  const { fps = 30, onStart, onStop, onFrame } = options;
712
1233
  const state = {
@@ -1244,11 +1765,17 @@ function brightnessToChar(brightness, characters = DEFAULT_CHARACTERS) {
1244
1765
  }
1245
1766
  const VERSION = "0.1.0";
1246
1767
  export {
1768
+ BARK,
1247
1769
  CHARACTER_SETS,
1770
+ CREAM,
1248
1771
  DEFAULT_CHARACTERS,
1249
1772
  DEFAULT_CONFIG,
1250
1773
  DEFAULT_PATTERN_CONFIG,
1774
+ GLASS_SCHEMES,
1775
+ GROVE_COLORS,
1776
+ GROVE_GREEN,
1251
1777
  GossamerRenderer,
1778
+ STATUS,
1252
1779
  VERSION,
1253
1780
  adjustBrightness,
1254
1781
  adjustContrast,
@@ -1258,7 +1785,9 @@ export {
1258
1785
  calculateFPS,
1259
1786
  cancelIdleCallback,
1260
1787
  clearCanvas,
1788
+ cloudsPattern,
1261
1789
  createAnimationLoop,
1790
+ createBrightnessBuffer,
1262
1791
  createCanvas,
1263
1792
  createCharacterSet,
1264
1793
  createFPSCounter,
@@ -1266,18 +1795,28 @@ export {
1266
1795
  createResizeObserver,
1267
1796
  createVisibilityObserver,
1268
1797
  debounce,
1798
+ diamondPattern,
1269
1799
  easings,
1270
1800
  extractBrightness,
1271
1801
  fbmNoise,
1802
+ fillBrightnessBuffer,
1803
+ fractalPattern,
1272
1804
  generateBrightnessGrid,
1805
+ getBufferValue,
1273
1806
  getCharacterSet,
1274
1807
  getCharacterSetNames,
1275
1808
  getCharacters,
1276
1809
  getDevicePixelRatio,
1810
+ getGlassScheme,
1811
+ getGlassSchemeNames,
1812
+ getGroveColor,
1813
+ getGroveColorNames,
1277
1814
  getImageData,
1278
1815
  getRecommendedFPS,
1816
+ gradientPattern,
1279
1817
  gridToImageData,
1280
1818
  hexToRgb,
1819
+ hexToRgba,
1281
1820
  imageToPixelData,
1282
1821
  invertCharacters,
1283
1822
  invertColors,
@@ -1287,10 +1826,12 @@ export {
1287
1826
  isOffscreenCanvasSupported,
1288
1827
  loadAndScaleImage,
1289
1828
  loadImage,
1829
+ matrixPattern,
1290
1830
  measureTextWidth,
1291
1831
  onReducedMotionChange,
1292
1832
  optimizeContext,
1293
1833
  perlinNoise2D,
1834
+ plasmaPattern,
1294
1835
  prefersReducedMotion,
1295
1836
  requestIdleCallback,
1296
1837
  resizeCanvasToContainer,
@@ -1304,6 +1845,7 @@ export {
1304
1845
  throttle,
1305
1846
  toGrayscale,
1306
1847
  validateCharacterSet,
1848
+ vortexPattern,
1307
1849
  wavePattern
1308
1850
  };
1309
1851
  //# sourceMappingURL=index.js.map