ngwr 15.3.0 → 15.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bits/border-glow/styles/_rules.scss +60 -49
- package/bits/click-spark/click-spark.scss +5 -1
- package/bits/click-spark/styles/_index.scss +10 -15
- package/bits/click-spark/styles/_rules.scss +20 -0
- package/fesm2022/ngwr-bits-aurora.mjs +108 -52
- package/fesm2022/ngwr-bits-aurora.mjs.map +1 -1
- package/fesm2022/ngwr-bits-border-glow-testing.mjs +8 -8
- package/fesm2022/ngwr-bits-border-glow-testing.mjs.map +1 -1
- package/fesm2022/ngwr-bits-border-glow.mjs +29 -26
- package/fesm2022/ngwr-bits-border-glow.mjs.map +1 -1
- package/fesm2022/ngwr-bits-dot-grid.mjs +11 -14
- package/fesm2022/ngwr-bits-dot-grid.mjs.map +1 -1
- package/fesm2022/ngwr-bits-fuzzy-text.mjs +18 -4
- package/fesm2022/ngwr-bits-fuzzy-text.mjs.map +1 -1
- package/fesm2022/ngwr-bits-ripple-grid.mjs +14 -13
- package/fesm2022/ngwr-bits-ripple-grid.mjs.map +1 -1
- package/fesm2022/ngwr-bits-splash-cursor.mjs +21 -10
- package/fesm2022/ngwr-bits-splash-cursor.mjs.map +1 -1
- package/fesm2022/ngwr-bits-waves.mjs +10 -15
- package/fesm2022/ngwr-bits-waves.mjs.map +1 -1
- package/fesm2022/ngwr-pipes.mjs +162 -51
- package/fesm2022/ngwr-pipes.mjs.map +1 -1
- package/fesm2022/ngwr-statistic.mjs +11 -16
- package/fesm2022/ngwr-statistic.mjs.map +1 -1
- package/fesm2022/ngwr-version.mjs +1 -1
- package/fesm2022/ngwr-version.mjs.map +1 -1
- package/llms-full.txt +2 -2
- package/package.json +1 -1
- package/schematics/use/symbol-map.json +1 -0
- package/skills/ngwr/SKILL.md +3 -1
- package/types/ngwr-bits-aurora.d.ts +24 -2
- package/types/ngwr-bits-border-glow-testing.d.ts +9 -5
- package/types/ngwr-bits-border-glow.d.ts +10 -4
- package/types/ngwr-bits-fuzzy-text.d.ts +2 -1
- package/types/ngwr-bits-ripple-grid.d.ts +7 -2
- package/types/ngwr-bits-splash-cursor.d.ts +2 -1
- package/types/ngwr-pipes.d.ts +142 -32
- package/types/ngwr-version.d.ts +1 -1
|
@@ -2,12 +2,37 @@
|
|
|
2
2
|
// All visual state is driven by two custom properties the component writes:
|
|
3
3
|
// --wr-border-glow-edge-proximity 0..100, scales with pointer-to-edge distance
|
|
4
4
|
// --wr-border-glow-angle 0deg..360deg, pointer-from-centre angle
|
|
5
|
-
// Plus a colour/geometry bag set once from inputs (see border-glow.ts).
|
|
5
|
+
// Plus a colour/geometry bag set once from inputs (see border-glow.ts). The three
|
|
6
|
+
// colour inputs write an `--wr-border-glow-input-*` twin of the hook they stand
|
|
7
|
+
// in for, never the hook itself, and every read below prefers the twin.
|
|
6
8
|
|
|
7
9
|
.wr-border-glow {
|
|
8
10
|
--wr-border-glow-edge-proximity: 0;
|
|
9
11
|
--wr-border-glow-angle: 45deg;
|
|
10
|
-
//
|
|
12
|
+
// The card fill: the theme surface, unless an app sets this or `[backgroundColor]`.
|
|
13
|
+
--wr-border-glow-bg: var(--wr-color-surface);
|
|
14
|
+
// What `[backgroundColor]`, `[glowColor]` and `[colors]` write on the host, which
|
|
15
|
+
// the inline value beats. Unset here so a card projected inside another one does
|
|
16
|
+
// not inherit the outer card's inputs — and twins rather than the hooks' own
|
|
17
|
+
// names, so a `--wr-border-glow-bg` an author set on the host stays there and is
|
|
18
|
+
// read again the moment the input is unset.
|
|
19
|
+
--wr-border-glow-input-bg: initial;
|
|
20
|
+
--wr-border-glow-input-color: initial;
|
|
21
|
+
--wr-border-glow-input-color-60: initial;
|
|
22
|
+
--wr-border-glow-input-color-50: initial;
|
|
23
|
+
--wr-border-glow-input-color-40: initial;
|
|
24
|
+
--wr-border-glow-input-color-30: initial;
|
|
25
|
+
--wr-border-glow-input-color-20: initial;
|
|
26
|
+
--wr-border-glow-input-color-10: initial;
|
|
27
|
+
--wr-border-glow-input-gradient-one: initial;
|
|
28
|
+
--wr-border-glow-input-gradient-two: initial;
|
|
29
|
+
--wr-border-glow-input-gradient-three: initial;
|
|
30
|
+
--wr-border-glow-input-gradient-four: initial;
|
|
31
|
+
--wr-border-glow-input-gradient-five: initial;
|
|
32
|
+
--wr-border-glow-input-gradient-six: initial;
|
|
33
|
+
--wr-border-glow-input-gradient-seven: initial;
|
|
34
|
+
--wr-border-glow-input-gradient-base: initial;
|
|
35
|
+
// Theme-default halo (`[glowColor]` writes the `-input-` twins beside it): a deep
|
|
11
36
|
// amber that reads on white, the pale pastel on dark.
|
|
12
37
|
--wr-border-glow-color: light-dark(hsl(40deg 90% 45% / 100%), hsl(40deg 80% 80% / 100%));
|
|
13
38
|
--wr-border-glow-color-60: light-dark(hsl(40deg 90% 45% / 60%), hsl(40deg 80% 80% / 60%));
|
|
@@ -16,8 +41,8 @@
|
|
|
16
41
|
--wr-border-glow-color-30: light-dark(hsl(40deg 90% 45% / 30%), hsl(40deg 80% 80% / 30%));
|
|
17
42
|
--wr-border-glow-color-20: light-dark(hsl(40deg 90% 45% / 20%), hsl(40deg 80% 80% / 20%));
|
|
18
43
|
--wr-border-glow-color-10: light-dark(hsl(40deg 90% 45% / 10%), hsl(40deg 80% 80% / 10%));
|
|
19
|
-
// Theme-default mesh palette (
|
|
20
|
-
// tones that read on white, the reactbits pastels on dark. The geometry is
|
|
44
|
+
// Theme-default mesh palette (`[colors]` writes the `-input-` twins beside it):
|
|
45
|
+
// deep tones that read on white, the reactbits pastels on dark. The geometry is
|
|
21
46
|
// the same in both schemes, so only the one colour stop of each layer moves.
|
|
22
47
|
--wr-border-glow-gradient-one: radial-gradient(
|
|
23
48
|
at 80% 55%,
|
|
@@ -63,19 +88,19 @@
|
|
|
63
88
|
// so an inline `[glowColor]` reaches every layer of it.
|
|
64
89
|
/* stylelint-disable-next-line */
|
|
65
90
|
--wr-border-glow-edge-shadow:
|
|
66
|
-
inset 0 0 0 1px var(--wr-border-glow-color),
|
|
67
|
-
inset 0 0 1px 0 light-dark(transparent, var(--wr-border-glow-color-60)),
|
|
68
|
-
inset 0 0 3px 0 light-dark(transparent, var(--wr-border-glow-color-50)),
|
|
69
|
-
inset 0 0 6px 0 light-dark(transparent, var(--wr-border-glow-color-40)),
|
|
70
|
-
inset 0 0 15px 0 light-dark(transparent, var(--wr-border-glow-color-30)),
|
|
71
|
-
inset 0 0 25px 2px light-dark(transparent, var(--wr-border-glow-color-20)),
|
|
72
|
-
inset 0 0 50px 2px light-dark(transparent, var(--wr-border-glow-color-10)),
|
|
73
|
-
0 0 1px 0 var(--wr-border-glow-color-60),
|
|
74
|
-
0 0 3px 0 var(--wr-border-glow-color-50),
|
|
75
|
-
0 0 6px 0 var(--wr-border-glow-color-40),
|
|
76
|
-
0 0 15px 0 var(--wr-border-glow-color-30),
|
|
77
|
-
0 0 25px 2px var(--wr-border-glow-color-20),
|
|
78
|
-
0 0 50px 2px var(--wr-border-glow-color-10);
|
|
91
|
+
inset 0 0 0 1px var(--wr-border-glow-input-color, var(--wr-border-glow-color)),
|
|
92
|
+
inset 0 0 1px 0 light-dark(transparent, var(--wr-border-glow-input-color-60, var(--wr-border-glow-color-60))),
|
|
93
|
+
inset 0 0 3px 0 light-dark(transparent, var(--wr-border-glow-input-color-50, var(--wr-border-glow-color-50))),
|
|
94
|
+
inset 0 0 6px 0 light-dark(transparent, var(--wr-border-glow-input-color-40, var(--wr-border-glow-color-40))),
|
|
95
|
+
inset 0 0 15px 0 light-dark(transparent, var(--wr-border-glow-input-color-30, var(--wr-border-glow-color-30))),
|
|
96
|
+
inset 0 0 25px 2px light-dark(transparent, var(--wr-border-glow-input-color-20, var(--wr-border-glow-color-20))),
|
|
97
|
+
inset 0 0 50px 2px light-dark(transparent, var(--wr-border-glow-input-color-10, var(--wr-border-glow-color-10))),
|
|
98
|
+
0 0 1px 0 var(--wr-border-glow-input-color-60, var(--wr-border-glow-color-60)),
|
|
99
|
+
0 0 3px 0 var(--wr-border-glow-input-color-50, var(--wr-border-glow-color-50)),
|
|
100
|
+
0 0 6px 0 var(--wr-border-glow-input-color-40, var(--wr-border-glow-color-40)),
|
|
101
|
+
0 0 15px 0 var(--wr-border-glow-input-color-30, var(--wr-border-glow-color-30)),
|
|
102
|
+
0 0 25px 2px var(--wr-border-glow-input-color-20, var(--wr-border-glow-color-20)),
|
|
103
|
+
0 0 50px 2px var(--wr-border-glow-input-color-10, var(--wr-border-glow-color-10));
|
|
79
104
|
// Blend modes and a strength are not colours, so `light-dark()` cannot switch
|
|
80
105
|
// them, and each value below is the one that holds up in both schemes. The
|
|
81
106
|
// additive look dark used — `plus-lighter` on the halo, `soft-light` on the
|
|
@@ -100,7 +125,7 @@
|
|
|
100
125
|
position: relative;
|
|
101
126
|
display: grid;
|
|
102
127
|
border-radius: var(--wr-border-glow-radius);
|
|
103
|
-
background: var(--wr-border-glow-bg, var(--wr-
|
|
128
|
+
background: var(--wr-border-glow-input-bg, var(--wr-border-glow-bg));
|
|
104
129
|
overflow: visible;
|
|
105
130
|
isolation: isolate;
|
|
106
131
|
transform: translate3d(0, 0, 0.01px); // create a new layer to keep blends tidy
|
|
@@ -137,23 +162,16 @@
|
|
|
137
162
|
&::before {
|
|
138
163
|
border: 1px solid transparent;
|
|
139
164
|
background:
|
|
140
|
-
linear-gradient(var(--wr-border-glow-bg, var(--wr-
|
|
165
|
+
linear-gradient(var(--wr-border-glow-input-bg, var(--wr-border-glow-bg)) 0 100%) padding-box,
|
|
141
166
|
linear-gradient(rgb(255 255 255 / 0%) 0 100%) border-box,
|
|
142
|
-
var(--wr-border-glow-gradient-one,
|
|
143
|
-
|
|
144
|
-
var(--wr-border-glow-gradient-
|
|
145
|
-
|
|
146
|
-
var(--wr-border-glow-gradient-
|
|
147
|
-
|
|
148
|
-
var(--wr-border-glow-gradient-
|
|
149
|
-
|
|
150
|
-
var(--wr-border-glow-gradient-five, radial-gradient(at 86% 85%, hsl(186deg 100% 74%) 0px, transparent 50%))
|
|
151
|
-
border-box,
|
|
152
|
-
var(--wr-border-glow-gradient-six, radial-gradient(at 82% 18%, hsl(52deg 100% 65%) 0px, transparent 50%))
|
|
153
|
-
border-box,
|
|
154
|
-
var(--wr-border-glow-gradient-seven, radial-gradient(at 51% 4%, hsl(12deg 100% 72%) 0px, transparent 50%))
|
|
155
|
-
border-box,
|
|
156
|
-
var(--wr-border-glow-gradient-base, linear-gradient(#c299ff 0 100%)) border-box;
|
|
167
|
+
var(--wr-border-glow-input-gradient-one, var(--wr-border-glow-gradient-one)) border-box,
|
|
168
|
+
var(--wr-border-glow-input-gradient-two, var(--wr-border-glow-gradient-two)) border-box,
|
|
169
|
+
var(--wr-border-glow-input-gradient-three, var(--wr-border-glow-gradient-three)) border-box,
|
|
170
|
+
var(--wr-border-glow-input-gradient-four, var(--wr-border-glow-gradient-four)) border-box,
|
|
171
|
+
var(--wr-border-glow-input-gradient-five, var(--wr-border-glow-gradient-five)) border-box,
|
|
172
|
+
var(--wr-border-glow-input-gradient-six, var(--wr-border-glow-gradient-six)) border-box,
|
|
173
|
+
var(--wr-border-glow-input-gradient-seven, var(--wr-border-glow-gradient-seven)) border-box,
|
|
174
|
+
var(--wr-border-glow-input-gradient-base, var(--wr-border-glow-gradient-base)) border-box;
|
|
157
175
|
|
|
158
176
|
opacity: calc(
|
|
159
177
|
(var(--wr-border-glow-edge-proximity) - var(--wr-border-glow-color-sensitivity)) /
|
|
@@ -173,21 +191,14 @@
|
|
|
173
191
|
&::after {
|
|
174
192
|
border: 1px solid transparent;
|
|
175
193
|
background:
|
|
176
|
-
var(--wr-border-glow-gradient-one,
|
|
177
|
-
|
|
178
|
-
var(--wr-border-glow-gradient-
|
|
179
|
-
|
|
180
|
-
var(--wr-border-glow-gradient-
|
|
181
|
-
|
|
182
|
-
var(--wr-border-glow-gradient-
|
|
183
|
-
|
|
184
|
-
var(--wr-border-glow-gradient-five, radial-gradient(at 86% 85%, hsl(186deg 100% 74%) 0px, transparent 50%))
|
|
185
|
-
padding-box,
|
|
186
|
-
var(--wr-border-glow-gradient-six, radial-gradient(at 82% 18%, hsl(52deg 100% 65%) 0px, transparent 50%))
|
|
187
|
-
padding-box,
|
|
188
|
-
var(--wr-border-glow-gradient-seven, radial-gradient(at 51% 4%, hsl(12deg 100% 72%) 0px, transparent 50%))
|
|
189
|
-
padding-box,
|
|
190
|
-
var(--wr-border-glow-gradient-base, linear-gradient(#c299ff 0 100%)) padding-box;
|
|
194
|
+
var(--wr-border-glow-input-gradient-one, var(--wr-border-glow-gradient-one)) padding-box,
|
|
195
|
+
var(--wr-border-glow-input-gradient-two, var(--wr-border-glow-gradient-two)) padding-box,
|
|
196
|
+
var(--wr-border-glow-input-gradient-three, var(--wr-border-glow-gradient-three)) padding-box,
|
|
197
|
+
var(--wr-border-glow-input-gradient-four, var(--wr-border-glow-gradient-four)) padding-box,
|
|
198
|
+
var(--wr-border-glow-input-gradient-five, var(--wr-border-glow-gradient-five)) padding-box,
|
|
199
|
+
var(--wr-border-glow-input-gradient-six, var(--wr-border-glow-gradient-six)) padding-box,
|
|
200
|
+
var(--wr-border-glow-input-gradient-seven, var(--wr-border-glow-gradient-seven)) padding-box,
|
|
201
|
+
var(--wr-border-glow-input-gradient-base, var(--wr-border-glow-gradient-base)) padding-box;
|
|
191
202
|
|
|
192
203
|
mask-image:
|
|
193
204
|
linear-gradient(to bottom, black, black), radial-gradient(ellipse at 50% 50%, black 40%, transparent 65%),
|
|
@@ -1 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
// Component-scoped, but the lib uses `ViewEncapsulation.None` everywhere so
|
|
2
|
+
// the selector starts with `.wr-click-spark` — the same as the public Sass
|
|
3
|
+
// entry. Forwards the rules alone: `styles/_index.scss` is the entry that
|
|
4
|
+
// loads the theme, and a `styleUrl` is its own compilation.
|
|
5
|
+
@forward './styles/rules';
|
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
// Public Sass entry for `@use 'ngwr/bits/click-spark'`.
|
|
2
|
+
//
|
|
3
|
+
// Loads the theme although `_rules` reads no token: the component strokes its
|
|
4
|
+
// sparks in `sparkColor`, whose default is `var(--wr-color-on-surface)` resolved
|
|
5
|
+
// against the canvas, so an app that writes this one `@use` still has the token
|
|
6
|
+
// the default paints with. `click-spark.scss` — the component's `styleUrl` —
|
|
7
|
+
// forwards `_rules` and nothing else, so the compiled component styles carry this
|
|
8
|
+
// component's own CSS and no second copy of the theme layer.
|
|
9
|
+
@use '../../../theme/styles';
|
|
6
10
|
|
|
7
|
-
|
|
8
|
-
position: absolute;
|
|
9
|
-
inset: 0;
|
|
10
|
-
width: 100%;
|
|
11
|
-
height: 100%;
|
|
12
|
-
pointer-events: none;
|
|
13
|
-
user-select: none;
|
|
14
|
-
z-index: 1;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
11
|
+
@forward 'rules';
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Click spark — canvas overlay that ignores pointer events so projected
|
|
2
|
+
// children stay interactive. The sparks themselves are stroked in
|
|
3
|
+
// `click-spark.ts`, in `sparkColor`, which defaults to `var(--wr-color-on-surface)`
|
|
4
|
+
// and is resolved against the canvas: the token is read from TypeScript rather than
|
|
5
|
+
// from a rule here, which is why `_index.scss` loads the theme for a sheet that
|
|
6
|
+
// names no token itself.
|
|
7
|
+
.wr-click-spark {
|
|
8
|
+
position: relative;
|
|
9
|
+
display: block;
|
|
10
|
+
|
|
11
|
+
&__canvas {
|
|
12
|
+
position: absolute;
|
|
13
|
+
inset: 0;
|
|
14
|
+
width: 100%;
|
|
15
|
+
height: 100%;
|
|
16
|
+
pointer-events: none;
|
|
17
|
+
user-select: none;
|
|
18
|
+
z-index: 1;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from "@angular/core";
|
|
2
|
-
import { Component, DestroyRef, ElementRef, NgZone, PLATFORM_ID, ViewEncapsulation, afterNextRender, effect, inject, input, signal, viewChild } from "@angular/core";
|
|
2
|
+
import { Component, DestroyRef, ElementRef, NgZone, PLATFORM_ID, ViewEncapsulation, afterNextRender, afterRenderEffect, effect, inject, input, signal, untracked, viewChild } from "@angular/core";
|
|
3
3
|
import { isPlatformBrowser } from "@angular/common";
|
|
4
4
|
import { numAttr, resolveCssColorChannels, watchColorScheme } from "ngwr/utils";
|
|
5
5
|
import { WrPlatform } from "ngwr/platform";
|
|
@@ -154,7 +154,7 @@ var WrAurora = class WrAurora {
|
|
|
154
154
|
platform = inject(WrPlatform);
|
|
155
155
|
isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
156
156
|
gl = null;
|
|
157
|
-
|
|
157
|
+
gpu = null;
|
|
158
158
|
rafId = 0;
|
|
159
159
|
time = 0;
|
|
160
160
|
booted = signal(false, ...ngDevMode ? [{ debugName: "booted" }] : /* istanbul ignore next */ []);
|
|
@@ -163,16 +163,19 @@ var WrAurora = class WrAurora {
|
|
|
163
163
|
constructor() {
|
|
164
164
|
if (!this.isBrowser) return;
|
|
165
165
|
afterNextRender(() => this.zone.runOutsideAngular(() => this.boot()));
|
|
166
|
-
|
|
166
|
+
afterRenderEffect(() => {
|
|
167
|
+
if (!this.booted()) return;
|
|
168
|
+
const still = this.platform.prefersReducedMotion();
|
|
167
169
|
this.colorStops();
|
|
168
170
|
this.amplitude();
|
|
169
171
|
this.blend();
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
172
|
+
untracked(() => {
|
|
173
|
+
this.pushUniforms();
|
|
174
|
+
if (still) this.draw(0);
|
|
175
|
+
});
|
|
173
176
|
});
|
|
174
177
|
watchColorScheme(() => {
|
|
175
|
-
if (!this.
|
|
178
|
+
if (!this.gpu || !this.platform.prefersReducedMotion()) return;
|
|
176
179
|
this.pushUniforms();
|
|
177
180
|
this.draw(0);
|
|
178
181
|
});
|
|
@@ -196,41 +199,11 @@ var WrAurora = class WrAurora {
|
|
|
196
199
|
});
|
|
197
200
|
if (!gl) return;
|
|
198
201
|
this.gl = gl;
|
|
199
|
-
|
|
200
|
-
gl.
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
gl.shaderSource(shader, source);
|
|
205
|
-
gl.compileShader(shader);
|
|
206
|
-
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) console.error("wr-aurora shader error:", gl.getShaderInfoLog(shader));
|
|
207
|
-
return shader;
|
|
208
|
-
};
|
|
209
|
-
const program = gl.createProgram();
|
|
210
|
-
gl.attachShader(program, compile(gl.VERTEX_SHADER, VERT));
|
|
211
|
-
gl.attachShader(program, compile(gl.FRAGMENT_SHADER, FRAG));
|
|
212
|
-
gl.linkProgram(program);
|
|
213
|
-
gl.useProgram(program);
|
|
214
|
-
for (const name of [
|
|
215
|
-
"uTime",
|
|
216
|
-
"uAmplitude",
|
|
217
|
-
"uColorStops",
|
|
218
|
-
"uResolution",
|
|
219
|
-
"uBlend"
|
|
220
|
-
]) this.uniforms[name] = gl.getUniformLocation(program, name);
|
|
221
|
-
const buffer = gl.createBuffer();
|
|
222
|
-
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
223
|
-
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
|
224
|
-
-1,
|
|
225
|
-
-1,
|
|
226
|
-
3,
|
|
227
|
-
-1,
|
|
228
|
-
-1,
|
|
229
|
-
3
|
|
230
|
-
]), gl.STATIC_DRAW);
|
|
231
|
-
const position = gl.getAttribLocation(program, "position");
|
|
232
|
-
gl.enableVertexAttribArray(position);
|
|
233
|
-
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
|
|
202
|
+
this.gpu = this.build(gl);
|
|
203
|
+
if (!this.gpu && !gl.isContextLost()) {
|
|
204
|
+
this.release(gl);
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
234
207
|
const hostEl = this.host.nativeElement;
|
|
235
208
|
const fit = () => {
|
|
236
209
|
const width = hostEl.clientWidth;
|
|
@@ -239,8 +212,21 @@ var WrAurora = class WrAurora {
|
|
|
239
212
|
canvas.width = Math.max(1, width);
|
|
240
213
|
canvas.height = Math.max(1, height);
|
|
241
214
|
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
242
|
-
gl.uniform2f(this.uniforms["uResolution"], canvas.width, canvas.height);
|
|
215
|
+
if (this.gpu) gl.uniform2f(this.gpu.uniforms["uResolution"], canvas.width, canvas.height);
|
|
216
|
+
};
|
|
217
|
+
const onLost = (event) => {
|
|
218
|
+
event.preventDefault();
|
|
219
|
+
this.gpu = null;
|
|
220
|
+
this.booted.set(false);
|
|
221
|
+
};
|
|
222
|
+
const onRestored = () => {
|
|
223
|
+
this.gpu = this.build(gl);
|
|
224
|
+
if (!this.gpu) return;
|
|
225
|
+
fit();
|
|
226
|
+
this.booted.set(true);
|
|
243
227
|
};
|
|
228
|
+
canvas.addEventListener("webglcontextlost", onLost);
|
|
229
|
+
canvas.addEventListener("webglcontextrestored", onRestored);
|
|
244
230
|
const resize = () => {
|
|
245
231
|
fit();
|
|
246
232
|
this.draw(this.platform.prefersReducedMotion() ? 0 : this.time);
|
|
@@ -260,17 +246,87 @@ var WrAurora = class WrAurora {
|
|
|
260
246
|
window.removeEventListener("resize", resize);
|
|
261
247
|
ro.disconnect();
|
|
262
248
|
io?.disconnect();
|
|
249
|
+
canvas.removeEventListener("webglcontextlost", onLost);
|
|
250
|
+
canvas.removeEventListener("webglcontextrestored", onRestored);
|
|
251
|
+
this.release(gl);
|
|
263
252
|
});
|
|
264
|
-
this.booted.set(true);
|
|
253
|
+
if (this.gpu) this.booted.set(true);
|
|
254
|
+
}
|
|
255
|
+
build(gl) {
|
|
256
|
+
const vert = this.compile(gl, gl.VERTEX_SHADER, VERT);
|
|
257
|
+
const frag = this.compile(gl, gl.FRAGMENT_SHADER, FRAG);
|
|
258
|
+
const program = vert && frag ? gl.createProgram() : null;
|
|
259
|
+
if (vert && frag && program) {
|
|
260
|
+
gl.attachShader(program, vert);
|
|
261
|
+
gl.attachShader(program, frag);
|
|
262
|
+
gl.linkProgram(program);
|
|
263
|
+
}
|
|
264
|
+
gl.deleteShader(vert);
|
|
265
|
+
gl.deleteShader(frag);
|
|
266
|
+
if (!program) return null;
|
|
267
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
268
|
+
if (!gl.isContextLost()) console.error("wr-aurora program error:", gl.getProgramInfoLog(program));
|
|
269
|
+
gl.deleteProgram(program);
|
|
270
|
+
return null;
|
|
271
|
+
}
|
|
272
|
+
gl.useProgram(program);
|
|
273
|
+
gl.clearColor(0, 0, 0, 0);
|
|
274
|
+
gl.enable(gl.BLEND);
|
|
275
|
+
gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
276
|
+
const uniforms = {};
|
|
277
|
+
for (const name of [
|
|
278
|
+
"uTime",
|
|
279
|
+
"uAmplitude",
|
|
280
|
+
"uColorStops",
|
|
281
|
+
"uResolution",
|
|
282
|
+
"uBlend"
|
|
283
|
+
]) uniforms[name] = gl.getUniformLocation(program, name);
|
|
284
|
+
const buffer = gl.createBuffer();
|
|
285
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
|
|
286
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
|
|
287
|
+
-1,
|
|
288
|
+
-1,
|
|
289
|
+
3,
|
|
290
|
+
-1,
|
|
291
|
+
-1,
|
|
292
|
+
3
|
|
293
|
+
]), gl.STATIC_DRAW);
|
|
294
|
+
const position = gl.getAttribLocation(program, "position");
|
|
295
|
+
gl.enableVertexAttribArray(position);
|
|
296
|
+
gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);
|
|
297
|
+
return {
|
|
298
|
+
program,
|
|
299
|
+
buffer,
|
|
300
|
+
uniforms
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
compile(gl, type, source) {
|
|
304
|
+
const shader = gl.createShader(type);
|
|
305
|
+
if (!shader) return null;
|
|
306
|
+
gl.shaderSource(shader, source);
|
|
307
|
+
gl.compileShader(shader);
|
|
308
|
+
if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;
|
|
309
|
+
if (!gl.isContextLost()) console.error("wr-aurora shader error:", gl.getShaderInfoLog(shader));
|
|
310
|
+
gl.deleteShader(shader);
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
release(gl) {
|
|
314
|
+
if (this.gpu) {
|
|
315
|
+
gl.deleteProgram(this.gpu.program);
|
|
316
|
+
gl.deleteBuffer(this.gpu.buffer);
|
|
317
|
+
}
|
|
318
|
+
gl.getExtension("WEBGL_lose_context")?.loseContext();
|
|
319
|
+
this.gpu = null;
|
|
320
|
+
this.gl = null;
|
|
265
321
|
}
|
|
266
322
|
pushUniforms() {
|
|
267
|
-
const gl = this
|
|
268
|
-
if (!gl) return;
|
|
323
|
+
const { gl, gpu } = this;
|
|
324
|
+
if (!gl || !gpu) return;
|
|
269
325
|
const flat = /* @__PURE__ */ new Float32Array(9);
|
|
270
326
|
for (let i = 0; i < 3; i++) flat.set(this.resolveStop(i), i * 3);
|
|
271
|
-
gl.uniform3fv(
|
|
272
|
-
gl.uniform1f(
|
|
273
|
-
gl.uniform1f(
|
|
327
|
+
gl.uniform3fv(gpu.uniforms["uColorStops"], flat);
|
|
328
|
+
gl.uniform1f(gpu.uniforms["uAmplitude"], this.amplitude());
|
|
329
|
+
gl.uniform1f(gpu.uniforms["uBlend"], this.blend());
|
|
274
330
|
}
|
|
275
331
|
resolveStop(index) {
|
|
276
332
|
const explicit = this.colorStops();
|
|
@@ -279,10 +335,10 @@ var WrAurora = class WrAurora {
|
|
|
279
335
|
return resolveCssColorChannels(this.canvasRef().nativeElement, expression, fallback);
|
|
280
336
|
}
|
|
281
337
|
draw(time) {
|
|
282
|
-
const gl = this
|
|
283
|
-
if (!gl || !this.hasBox()) return;
|
|
338
|
+
const { gl, gpu } = this;
|
|
339
|
+
if (!gl || !gpu || !this.hasBox()) return;
|
|
284
340
|
this.time = time;
|
|
285
|
-
gl.uniform1f(
|
|
341
|
+
gl.uniform1f(gpu.uniforms["uTime"], time);
|
|
286
342
|
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
287
343
|
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
288
344
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ngwr-bits-aurora.mjs","names":[],"sources":["../../../projects/lib/bits/aurora/aurora.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the Aurora background by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/backgrounds/aurora\n *\n * The reactbits version renders through the OGL library; this port talks\n * to WebGL2 directly — same vertex/fragment shaders, zero dependencies.\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n NgZone,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n effect,\n inject,\n input,\n signal,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr, resolveCssColorChannels, watchColorScheme } from 'ngwr/utils';\n\nconst VERT = `#version 300 es\nin vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst FRAG = `#version 300 es\nprecision highp float;\n\nuniform float uTime;\nuniform float uAmplitude;\nuniform vec3 uColorStops[3];\nuniform vec2 uResolution;\nuniform float uBlend;\n\nout vec4 fragColor;\n\nvec3 permute(vec3 x) {\n return mod(((x * 34.0) + 1.0) * x, 289.0);\n}\n\nfloat snoise(vec2 v){\n const vec4 C = vec4(\n 0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439\n );\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n\n vec3 p = permute(\n permute(i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0)\n );\n\n vec3 m = max(\n 0.5 - vec3(\n dot(x0, x0),\n dot(x12.xy, x12.xy),\n dot(x12.zw, x12.zw)\n ),\n 0.0\n );\n m = m * m;\n m = m * m;\n\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);\n\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\nstruct ColorStop {\n vec3 color;\n float position;\n};\n\n#define COLOR_RAMP(colors, factor, finalColor) { \\\\\n int index = 0; \\\\\n for (int i = 0; i < 2; i++) { \\\\\n ColorStop currentColor = colors[i]; \\\\\n bool isInBetween = currentColor.position <= factor; \\\\\n index = int(mix(float(index), float(i), float(isInBetween))); \\\\\n } \\\\\n ColorStop currentColor = colors[index]; \\\\\n ColorStop nextColor = colors[index + 1]; \\\\\n float range = nextColor.position - currentColor.position; \\\\\n float lerpFactor = (factor - currentColor.position) / range; \\\\\n finalColor = mix(currentColor.color, nextColor.color, lerpFactor); \\\\\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution;\n\n ColorStop colors[3];\n colors[0] = ColorStop(uColorStops[0], 0.0);\n colors[1] = ColorStop(uColorStops[1], 0.5);\n colors[2] = ColorStop(uColorStops[2], 1.0);\n\n vec3 rampColor;\n COLOR_RAMP(colors, uv.x, rampColor);\n\n float height = snoise(vec2(uv.x * 2.0 + uTime * 0.1, uTime * 0.25)) * 0.5 * uAmplitude;\n height = exp(height);\n height = (uv.y * 2.0 - height + 0.2);\n float intensity = 0.6 * height;\n\n float midPoint = 0.20;\n float auroraAlpha = smoothstep(midPoint - uBlend * 0.5, midPoint + uBlend * 0.5, intensity);\n\n // Clamp the brightness floor: the upstream shader multiplies colour by\n // raw intensity, which fades the ribbon to BLACK while still opaque —\n // invisible on dark pages, a dirty gray halo on light ones. Keeping the\n // hue saturated and letting alpha alone do the fading works on both.\n vec3 auroraColor = rampColor * max(intensity, 0.85);\n\n fragColor = vec4(auroraColor * auroraAlpha, auroraAlpha);\n}\n`;\n\n/** What a stop falls back to when it cannot be read: the reactbits palette. */\nconst DEFAULT_STOPS = ['#5227ff', '#7cff67', '#5227ff'] as const;\n\n/**\n * The theme's stop hooks, written out in full: `gen:css-vars` finds a read by\n * its literal name, and a name built from a template string is invisible to it.\n */\nconst STOP_HOOKS = ['var(--wr-aurora-stop-1)', 'var(--wr-aurora-stop-2)', 'var(--wr-aurora-stop-3)'] as const;\n\n/**\n * Aurora background — flowing northern-lights ribbons rendered with a\n * WebGL2 simplex-noise shader, ramped across three colour stops. Fills\n * its nearest positioned ancestor; renders nothing without WebGL2.\n *\n * Under `prefers-reduced-motion` a single static frame is drawn, and drawn\n * again in the new colours when the page's colour scheme switches.\n *\n * Under forced colours the canvas is hidden and its loop stops with it, leaving the\n * box on the palette's own ground, which is what forced text and marks are chosen\n * against. The loop also stops off screen and with no box to draw on.\n *\n * @example\n * ```html\n * <div style=\"position: relative; min-height: 24rem; overflow: hidden\">\n * <wr-aurora />\n * <h1 style=\"position: relative\">Welcome aboard</h1>\n * </div>\n * ```\n *\n * @see https://ngwr.dev/bits/aurora\n */\n@Component({\n selector: 'wr-aurora',\n template: '<canvas #canvas class=\"wr-aurora__canvas\" aria-hidden=\"true\"></canvas>',\n styleUrl: './aurora.scss',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-aurora' },\n})\nexport class WrAurora {\n /**\n * Exactly three colour stops, ramped left → right — any CSS colour each, a\n * `var()` token or a `light-dark()` pair included. Alpha is ignored; the\n * ribbon fades through its own. When unset, the theme decides: deep\n * violet/emerald on light, the neon reactbits palette on dark.\n */\n readonly colorStops = input<readonly string[] | null>(null);\n\n /** Wave height multiplier. @default 1 */\n readonly amplitude = input(1, { transform: numAttr(1) });\n\n /** Softness of the aurora's lower edge, 0..1. @default 0.5 */\n readonly blend = input(0.5, { transform: numAttr(0.5) });\n\n /** Time multiplier. @default 1 */\n readonly speed = input(1, { transform: numAttr(1) });\n\n private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly zone = inject(NgZone);\n private readonly destroyRef = inject(DestroyRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private gl: WebGL2RenderingContext | null = null;\n private uniforms: Record<string, WebGLUniformLocation | null> = {};\n private rafId = 0;\n /** The shader time last drawn, so a resize can repaint the frame it just cleared. */\n private time = 0;\n\n /** Flips once `boot()` has a context and a program — the loop waits for it. */\n private readonly booted = signal(false);\n /** Whether the host is in the viewport; stays `true` without an observer. */\n private readonly onScreen = signal(true);\n /**\n * Whether the box has an area. The intersection observer calls a zero-area canvas\n * intersecting and sends no entry when it gains a size, so this reads the box instead.\n */\n private readonly hasBox = signal(false);\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => this.zone.runOutsideAngular(() => this.boot()));\n\n // Push input changes into uniforms without restarting the loop. Under\n // reduced motion this also repaints the static frame.\n effect(() => {\n this.colorStops();\n this.amplitude();\n this.blend();\n if (!this.gl) return;\n this.pushUniforms();\n if (this.platform.prefersReducedMotion()) this.draw(0);\n });\n\n // A still frame keeps the colours it was drawn with, so a scheme switch\n // under reduced motion re-resolves the stops and paints it again. The loop\n // needs no help: it re-resolves on every frame it draws.\n watchColorScheme(() => {\n if (!this.gl || !this.platform.prefersReducedMotion()) return;\n this.pushUniforms();\n this.draw(0);\n });\n\n // The frame loop runs only while there is something to see: never under\n // `prefers-reduced-motion`, read live (the effect above paints the static\n // frame when it switches on), and not while the host is off screen or has no\n // box — a background redrawn out of sight still costs a frame every frame.\n effect(onCleanup => {\n if (!this.booted() || !this.onScreen() || !this.hasBox() || this.platform.prefersReducedMotion()) return;\n const loop = (t: number): void => {\n this.rafId = requestAnimationFrame(loop);\n this.pushUniforms();\n this.draw(t * 0.01 * this.speed() * 0.1);\n };\n this.zone.runOutsideAngular(() => (this.rafId = requestAnimationFrame(loop)));\n onCleanup(() => cancelAnimationFrame(this.rafId));\n });\n }\n\n private boot(): void {\n const canvas = this.canvasRef().nativeElement;\n const gl = canvas.getContext('webgl2', { alpha: true, premultipliedAlpha: true, antialias: true });\n if (!gl) return;\n this.gl = gl;\n\n gl.clearColor(0, 0, 0, 0);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n const compile = (type: number, source: string): WebGLShader => {\n const shader = gl.createShader(type)!;\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {\n // eslint-disable-next-line no-console -- GPU shader failures are otherwise invisible\n console.error('wr-aurora shader error:', gl.getShaderInfoLog(shader));\n }\n return shader;\n };\n\n const program = gl.createProgram();\n gl.attachShader(program, compile(gl.VERTEX_SHADER, VERT));\n gl.attachShader(program, compile(gl.FRAGMENT_SHADER, FRAG));\n gl.linkProgram(program);\n gl.useProgram(program);\n\n for (const name of ['uTime', 'uAmplitude', 'uColorStops', 'uResolution', 'uBlend']) {\n this.uniforms[name] = gl.getUniformLocation(program, name);\n }\n\n // One oversized triangle covers the viewport — no index buffer needed.\n const buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);\n const position = gl.getAttribLocation(program, 'position');\n gl.enableVertexAttribArray(position);\n gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);\n\n const hostEl = this.host.nativeElement;\n const fit = (): void => {\n // The layout box and not `getBoundingClientRect()`, which is the box after\n // transforms: no observer hears of a transform, so a host booted under a\n // `scale(0)` would count as having no box for good.\n const width = hostEl.clientWidth;\n const height = hostEl.clientHeight;\n this.hasBox.set(width > 0 && height > 0);\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n gl.viewport(0, 0, canvas.width, canvas.height);\n gl.uniform2f(this.uniforms['uResolution'], canvas.width, canvas.height);\n };\n // Sizing the bitmap clears it, and observer entries arrive after the frame's own\n // callbacks and before its paint, so a repaint left to the loop would leave this\n // frame empty.\n const resize = (): void => {\n fit();\n this.draw(this.platform.prefersReducedMotion() ? 0 : this.time);\n };\n\n window.addEventListener('resize', resize);\n const ro = new ResizeObserver(resize);\n ro.observe(hostEl);\n\n fit();\n this.pushUniforms();\n\n // Static frame — the ribbons hold their t=0 shape. Painted under reduced\n // motion, and as the first frame either way; the loop takes over from here.\n this.draw(0);\n\n // Without an observer (jsdom) the host simply counts as visible. The canvas\n // rather than the host, which fills the same box, so a canvas hidden under forced\n // colours stops the loop too. A box flush against a zero-height clip intersects with\n // nothing showing, and only a second threshold reports the clip moving. It sits below\n // any real ratio, or a clip closing on a transition steps from under it to 0 without\n // crossing anything.\n const io =\n typeof IntersectionObserver === 'undefined'\n ? null\n : new IntersectionObserver(\n entries => {\n const { isIntersecting, intersectionRatio } = entries[entries.length - 1];\n this.onScreen.set(isIntersecting && intersectionRatio > 0);\n },\n { threshold: [0, 1e-9] }\n );\n io?.observe(canvas);\n\n this.destroyRef.onDestroy(() => {\n window.removeEventListener('resize', resize);\n ro.disconnect();\n io?.disconnect();\n });\n this.booted.set(true);\n }\n\n private pushUniforms(): void {\n const gl = this.gl;\n if (!gl) return;\n const flat = new Float32Array(9);\n for (let i = 0; i < 3; i++) flat.set(this.resolveStop(i), i * 3);\n gl.uniform3fv(this.uniforms['uColorStops'], flat);\n gl.uniform1f(this.uniforms['uAmplitude'], this.amplitude());\n gl.uniform1f(this.uniforms['uBlend'], this.blend());\n }\n\n /**\n * Stop `index` as shader channels. Explicit input wins; otherwise the theme's\n * `--wr-aurora-stop-*` hook, which holds a `light-dark()` pair no uniform can\n * take, so either is resolved through the cascade first. Read every frame, so\n * a colour-scheme change reaches the ribbon on the next one.\n */\n private resolveStop(index: number): [number, number, number] {\n const explicit = this.colorStops();\n const fallback = DEFAULT_STOPS[index];\n const expression =\n explicit === null ? STOP_HOOKS[index] : (explicit[Math.min(index, explicit.length - 1)] ?? fallback);\n return resolveCssColorChannels(this.canvasRef().nativeElement, expression, fallback);\n }\n\n private draw(time: number): void {\n const gl = this.gl;\n if (!gl || !this.hasBox()) return;\n this.time = time;\n gl.uniform1f(this.uniforms['uTime'], time);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ngwr-bits-aurora.mjs","names":[],"sources":["../../../projects/lib/bits/aurora/aurora.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the Aurora background by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/backgrounds/aurora\n *\n * The reactbits version renders through the OGL library; this port talks\n * to WebGL2 directly — same vertex/fragment shaders, zero dependencies.\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n Component,\n DestroyRef,\n ElementRef,\n NgZone,\n PLATFORM_ID,\n ViewEncapsulation,\n afterNextRender,\n afterRenderEffect,\n effect,\n inject,\n input,\n signal,\n untracked,\n viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr, resolveCssColorChannels, watchColorScheme } from 'ngwr/utils';\n\nconst VERT = `#version 300 es\nin vec2 position;\nvoid main() {\n gl_Position = vec4(position, 0.0, 1.0);\n}\n`;\n\nconst FRAG = `#version 300 es\nprecision highp float;\n\nuniform float uTime;\nuniform float uAmplitude;\nuniform vec3 uColorStops[3];\nuniform vec2 uResolution;\nuniform float uBlend;\n\nout vec4 fragColor;\n\nvec3 permute(vec3 x) {\n return mod(((x * 34.0) + 1.0) * x, 289.0);\n}\n\nfloat snoise(vec2 v){\n const vec4 C = vec4(\n 0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439\n );\n vec2 i = floor(v + dot(v, C.yy));\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n\n vec3 p = permute(\n permute(i.y + vec3(0.0, i1.y, 1.0))\n + i.x + vec3(0.0, i1.x, 1.0)\n );\n\n vec3 m = max(\n 0.5 - vec3(\n dot(x0, x0),\n dot(x12.xy, x12.xy),\n dot(x12.zw, x12.zw)\n ),\n 0.0\n );\n m = m * m;\n m = m * m;\n\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * (a0*a0 + h*h);\n\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\nstruct ColorStop {\n vec3 color;\n float position;\n};\n\n#define COLOR_RAMP(colors, factor, finalColor) { \\\\\n int index = 0; \\\\\n for (int i = 0; i < 2; i++) { \\\\\n ColorStop currentColor = colors[i]; \\\\\n bool isInBetween = currentColor.position <= factor; \\\\\n index = int(mix(float(index), float(i), float(isInBetween))); \\\\\n } \\\\\n ColorStop currentColor = colors[index]; \\\\\n ColorStop nextColor = colors[index + 1]; \\\\\n float range = nextColor.position - currentColor.position; \\\\\n float lerpFactor = (factor - currentColor.position) / range; \\\\\n finalColor = mix(currentColor.color, nextColor.color, lerpFactor); \\\\\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / uResolution;\n\n ColorStop colors[3];\n colors[0] = ColorStop(uColorStops[0], 0.0);\n colors[1] = ColorStop(uColorStops[1], 0.5);\n colors[2] = ColorStop(uColorStops[2], 1.0);\n\n vec3 rampColor;\n COLOR_RAMP(colors, uv.x, rampColor);\n\n float height = snoise(vec2(uv.x * 2.0 + uTime * 0.1, uTime * 0.25)) * 0.5 * uAmplitude;\n height = exp(height);\n height = (uv.y * 2.0 - height + 0.2);\n float intensity = 0.6 * height;\n\n float midPoint = 0.20;\n float auroraAlpha = smoothstep(midPoint - uBlend * 0.5, midPoint + uBlend * 0.5, intensity);\n\n // Clamp the brightness floor: the upstream shader multiplies colour by\n // raw intensity, which fades the ribbon to BLACK while still opaque —\n // invisible on dark pages, a dirty gray halo on light ones. Keeping the\n // hue saturated and letting alpha alone do the fading works on both.\n vec3 auroraColor = rampColor * max(intensity, 0.85);\n\n fragColor = vec4(auroraColor * auroraAlpha, auroraAlpha);\n}\n`;\n\n/** What the GPU holds for one context. A lost context takes all of it, so a restored one builds it again. */\ninterface Gpu {\n readonly program: WebGLProgram;\n readonly buffer: WebGLBuffer | null;\n readonly uniforms: Readonly<Record<string, WebGLUniformLocation | null>>;\n}\n\n/** What a stop falls back to when it cannot be read: the reactbits palette. */\nconst DEFAULT_STOPS = ['#5227ff', '#7cff67', '#5227ff'] as const;\n\n/**\n * The theme's stop hooks, written out in full: `gen:css-vars` finds a read by\n * its literal name, and a name built from a template string is invisible to it.\n */\nconst STOP_HOOKS = ['var(--wr-aurora-stop-1)', 'var(--wr-aurora-stop-2)', 'var(--wr-aurora-stop-3)'] as const;\n\n/**\n * Aurora background — flowing northern-lights ribbons rendered with a\n * WebGL2 simplex-noise shader, ramped across three colour stops. Fills\n * its nearest positioned ancestor; renders nothing without WebGL2.\n *\n * Under `prefers-reduced-motion` a single static frame is drawn, and drawn\n * again in the new colours when the page's colour scheme switches.\n *\n * Under forced colours the canvas is hidden and its loop stops with it, leaving the\n * box on the palette's own ground, which is what forced text and marks are chosen\n * against. The loop also stops off screen and with no box to draw on.\n *\n * With no WebGL2 context, or a shader the driver refuses, nothing is thrown and\n * the canvas stays empty. A context the browser takes away is rebuilt if it offers\n * one back. A destroyed host hands its GPU resources back at once. Browsers keep a\n * small number of live contexts and kill the oldest: Chromium frees the slot at that\n * point, while WebKit frees it only when the context is collected and offers an\n * evicted one no restore, so there a host that is not drawing can stay empty for good.\n *\n * @example\n * ```html\n * <div style=\"position: relative; min-height: 24rem; overflow: hidden\">\n * <wr-aurora />\n * <h1 style=\"position: relative\">Welcome aboard</h1>\n * </div>\n * ```\n *\n * @see https://ngwr.dev/bits/aurora\n */\n@Component({\n selector: 'wr-aurora',\n template: '<canvas #canvas class=\"wr-aurora__canvas\" aria-hidden=\"true\"></canvas>',\n styleUrl: './aurora.scss',\n encapsulation: ViewEncapsulation.None,\n host: { class: 'wr-aurora' },\n})\nexport class WrAurora {\n /**\n * Exactly three colour stops, ramped left → right — any CSS colour each, a\n * `var()` token or a `light-dark()` pair included. Alpha is ignored; the\n * ribbon fades through its own. When unset, the theme decides: deep\n * violet/emerald on light, the neon reactbits palette on dark.\n */\n readonly colorStops = input<readonly string[] | null>(null);\n\n /** Wave height multiplier. @default 1 */\n readonly amplitude = input(1, { transform: numAttr(1) });\n\n /** Softness of the aurora's lower edge, 0..1. @default 0.5 */\n readonly blend = input(0.5, { transform: numAttr(0.5) });\n\n /** Time multiplier. @default 1 */\n readonly speed = input(1, { transform: numAttr(1) });\n\n private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n private readonly zone = inject(NgZone);\n private readonly destroyRef = inject(DestroyRef);\n private readonly platform = inject(WrPlatform);\n private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n\n private gl: WebGL2RenderingContext | null = null;\n private gpu: Gpu | null = null;\n private rafId = 0;\n /** The shader time last drawn, so a resize can repaint the frame it just cleared. */\n private time = 0;\n\n /** Flips once a program is built, and back when the context goes — everything that draws waits for it. */\n private readonly booted = signal(false);\n /** Whether the host is in the viewport; stays `true` without an observer. */\n private readonly onScreen = signal(true);\n /**\n * Whether the box has an area. The intersection observer calls a zero-area canvas\n * intersecting and sends no entry when it gains a size, so this reads the box instead.\n */\n private readonly hasBox = signal(false);\n\n constructor() {\n if (!this.isBrowser) return;\n\n afterNextRender(() => this.zone.runOutsideAngular(() => this.boot()));\n\n // Push input changes into uniforms without restarting the loop. Under\n // reduced motion this also repaints the static frame — and so does the\n // moment motion stops. After render rather than an `effect`, which runs\n // before a directive's host binding: a still frame drawn then would miss a\n // hook it changes in the same pass.\n afterRenderEffect(() => {\n if (!this.booted()) return;\n const still = this.platform.prefersReducedMotion();\n this.colorStops();\n this.amplitude();\n this.blend();\n untracked(() => {\n this.pushUniforms();\n if (still) this.draw(0);\n });\n });\n\n // A still frame keeps the colours it was drawn with, so a scheme switch\n // under reduced motion re-resolves the stops and paints it again. The loop\n // needs no help: it re-resolves on every frame it draws.\n watchColorScheme(() => {\n if (!this.gpu || !this.platform.prefersReducedMotion()) return;\n this.pushUniforms();\n this.draw(0);\n });\n\n // The frame loop runs only while there is something to see: never under\n // `prefers-reduced-motion`, read live (the effect above paints the static\n // frame when it switches on), and not while the host is off screen or has no\n // box — a background redrawn out of sight still costs a frame every frame.\n effect(onCleanup => {\n if (!this.booted() || !this.onScreen() || !this.hasBox() || this.platform.prefersReducedMotion()) return;\n const loop = (t: number): void => {\n this.rafId = requestAnimationFrame(loop);\n this.pushUniforms();\n this.draw(t * 0.01 * this.speed() * 0.1);\n };\n this.zone.runOutsideAngular(() => (this.rafId = requestAnimationFrame(loop)));\n onCleanup(() => cancelAnimationFrame(this.rafId));\n });\n }\n\n private boot(): void {\n const canvas = this.canvasRef().nativeElement;\n const gl = canvas.getContext('webgl2', { alpha: true, premultipliedAlpha: true, antialias: true });\n if (!gl) return;\n this.gl = gl;\n\n // A context can arrive already lost, past the browser's limit on live ones.\n // That is not a broken shader: the restore below builds it. A shader the\n // driver really refused has logged, and nothing will ever draw on this one.\n this.gpu = this.build(gl);\n if (!this.gpu && !gl.isContextLost()) {\n this.release(gl);\n return;\n }\n\n const hostEl = this.host.nativeElement;\n const fit = (): void => {\n // The layout box and not `getBoundingClientRect()`, which is the box after\n // transforms: no observer hears of a transform, so a host booted under a\n // `scale(0)` would count as having no box for good.\n const width = hostEl.clientWidth;\n const height = hostEl.clientHeight;\n this.hasBox.set(width > 0 && height > 0);\n canvas.width = Math.max(1, width);\n canvas.height = Math.max(1, height);\n gl.viewport(0, 0, canvas.width, canvas.height);\n if (this.gpu) gl.uniform2f(this.gpu.uniforms['uResolution'], canvas.width, canvas.height);\n };\n\n const onLost = (event: Event): void => {\n // Without this the browser never offers the context back.\n event.preventDefault();\n this.gpu = null;\n this.booted.set(false);\n };\n const onRestored = (): void => {\n this.gpu = this.build(gl);\n if (!this.gpu) return;\n // The resolution went with the old program; the effects redraw the rest.\n fit();\n this.booted.set(true);\n };\n canvas.addEventListener('webglcontextlost', onLost);\n canvas.addEventListener('webglcontextrestored', onRestored);\n\n // Sizing the bitmap clears it, and observer entries arrive after the frame's own\n // callbacks and before its paint, so a repaint left to the loop would leave this\n // frame empty.\n const resize = (): void => {\n fit();\n this.draw(this.platform.prefersReducedMotion() ? 0 : this.time);\n };\n\n window.addEventListener('resize', resize);\n const ro = new ResizeObserver(resize);\n ro.observe(hostEl);\n\n fit();\n this.pushUniforms();\n\n // Static frame — the ribbons hold their t=0 shape. Painted under reduced\n // motion, and as the first frame either way; the loop takes over from here.\n this.draw(0);\n\n // Without an observer (jsdom) the host simply counts as visible. The canvas\n // rather than the host, which fills the same box, so a canvas hidden under forced\n // colours stops the loop too. A box flush against a zero-height clip intersects with\n // nothing showing, and only a second threshold reports the clip moving. It sits below\n // any real ratio, or a clip closing on a transition steps from under it to 0 without\n // crossing anything.\n const io =\n typeof IntersectionObserver === 'undefined'\n ? null\n : new IntersectionObserver(\n entries => {\n const { isIntersecting, intersectionRatio } = entries[entries.length - 1];\n this.onScreen.set(isIntersecting && intersectionRatio > 0);\n },\n { threshold: [0, 1e-9] }\n );\n io?.observe(canvas);\n\n this.destroyRef.onDestroy(() => {\n window.removeEventListener('resize', resize);\n ro.disconnect();\n io?.disconnect();\n // These first: losing the context below fires the event they listen for.\n canvas.removeEventListener('webglcontextlost', onLost);\n canvas.removeEventListener('webglcontextrestored', onRestored);\n this.release(gl);\n });\n if (this.gpu) this.booted.set(true);\n }\n\n /**\n * Compile, link and upload what one context needs, and make it current. Returns\n * `null` when it cannot: on a lost context, where every call answers no and\n * nothing is wrong with the shader, it says nothing.\n */\n private build(gl: WebGL2RenderingContext): Gpu | null {\n const vert = this.compile(gl, gl.VERTEX_SHADER, VERT);\n const frag = this.compile(gl, gl.FRAGMENT_SHADER, FRAG);\n const program = vert && frag ? gl.createProgram() : null;\n if (vert && frag && program) {\n gl.attachShader(program, vert);\n gl.attachShader(program, frag);\n gl.linkProgram(program);\n }\n // Only flagged: a shader stays alive as long as a program it is attached to.\n gl.deleteShader(vert);\n gl.deleteShader(frag);\n if (!program) return null;\n if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {\n if (!gl.isContextLost()) {\n // eslint-disable-next-line no-console -- GPU shader failures are otherwise invisible\n console.error('wr-aurora program error:', gl.getProgramInfoLog(program));\n }\n gl.deleteProgram(program);\n return null;\n }\n gl.useProgram(program);\n\n gl.clearColor(0, 0, 0, 0);\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.ONE, gl.ONE_MINUS_SRC_ALPHA);\n\n const uniforms: Record<string, WebGLUniformLocation | null> = {};\n for (const name of ['uTime', 'uAmplitude', 'uColorStops', 'uResolution', 'uBlend']) {\n uniforms[name] = gl.getUniformLocation(program, name);\n }\n\n // One oversized triangle covers the viewport — no index buffer needed.\n const buffer = gl.createBuffer();\n gl.bindBuffer(gl.ARRAY_BUFFER, buffer);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);\n const position = gl.getAttribLocation(program, 'position');\n gl.enableVertexAttribArray(position);\n gl.vertexAttribPointer(position, 2, gl.FLOAT, false, 0, 0);\n\n return { program, buffer, uniforms };\n }\n\n private compile(gl: WebGL2RenderingContext, type: number, source: string): WebGLShader | null {\n const shader = gl.createShader(type);\n if (!shader) return null;\n gl.shaderSource(shader, source);\n gl.compileShader(shader);\n if (gl.getShaderParameter(shader, gl.COMPILE_STATUS)) return shader;\n if (!gl.isContextLost()) {\n // eslint-disable-next-line no-console -- GPU shader failures are otherwise invisible\n console.error('wr-aurora shader error:', gl.getShaderInfoLog(shader));\n }\n gl.deleteShader(shader);\n return null;\n }\n\n /**\n * Give the GPU resources back at once rather than to the garbage collector:\n * browsers keep a small number of live contexts and kill the oldest, so a\n * navigating single-page app would lose the context of a page still on screen.\n * Chromium frees the slot here too. WebKit holds it until the context is collected,\n * and no API frees it sooner, so a still or parked host can still be evicted there.\n */\n private release(gl: WebGL2RenderingContext): void {\n if (this.gpu) {\n gl.deleteProgram(this.gpu.program);\n gl.deleteBuffer(this.gpu.buffer);\n }\n gl.getExtension('WEBGL_lose_context')?.loseContext();\n this.gpu = null;\n this.gl = null;\n }\n\n private pushUniforms(): void {\n const { gl, gpu } = this;\n if (!gl || !gpu) return;\n const flat = new Float32Array(9);\n for (let i = 0; i < 3; i++) flat.set(this.resolveStop(i), i * 3);\n gl.uniform3fv(gpu.uniforms['uColorStops'], flat);\n gl.uniform1f(gpu.uniforms['uAmplitude'], this.amplitude());\n gl.uniform1f(gpu.uniforms['uBlend'], this.blend());\n }\n\n /**\n * Stop `index` as shader channels. Explicit input wins; otherwise the theme's\n * `--wr-aurora-stop-*` hook, which holds a `light-dark()` pair no uniform can\n * take, so either is resolved through the cascade first. Read every frame, so\n * a colour-scheme change reaches the ribbon on the next one.\n */\n private resolveStop(index: number): [number, number, number] {\n const explicit = this.colorStops();\n const fallback = DEFAULT_STOPS[index];\n const expression =\n explicit === null ? STOP_HOOKS[index] : (explicit[Math.min(index, explicit.length - 1)] ?? fallback);\n return resolveCssColorChannels(this.canvasRef().nativeElement, expression, fallback);\n }\n\n private draw(time: number): void {\n const { gl, gpu } = this;\n if (!gl || !gpu || !this.hasBox()) return;\n this.time = time;\n gl.uniform1f(gpu.uniforms['uTime'], time);\n gl.clear(gl.COLOR_BUFFER_BIT);\n gl.drawArrays(gl.TRIANGLES, 0, 3);\n }\n}\n"],"mappings":"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"}
|
|
@@ -59,18 +59,18 @@ var WrBorderGlowHarness = class WrBorderGlowHarness extends ComponentHarness {
|
|
|
59
59
|
return this.readNumberVar("--wr-border-glow-fill-opacity", "getFillOpacity");
|
|
60
60
|
}
|
|
61
61
|
async getBackgroundColor() {
|
|
62
|
-
return this.readVar("--wr-border-glow-bg");
|
|
62
|
+
return this.readVar("--wr-border-glow-input-bg");
|
|
63
63
|
}
|
|
64
64
|
async getGlowColor() {
|
|
65
|
-
return this.readVar("--wr-border-glow-color");
|
|
65
|
+
return this.readVar("--wr-border-glow-input-color");
|
|
66
66
|
}
|
|
67
67
|
async getGlowAlphaRamp() {
|
|
68
68
|
const declarations = await this.declarations();
|
|
69
|
-
const first = declarations.get("--wr-border-glow-color");
|
|
69
|
+
const first = declarations.get("--wr-border-glow-input-color");
|
|
70
70
|
if (first === void 0) return null;
|
|
71
71
|
const form = first.startsWith("color-mix(") ? GLOW_MIX_ALPHA : GLOW_ALPHA;
|
|
72
72
|
return GLOW_VAR_SUFFIXES.map((suffix) => {
|
|
73
|
-
const name = `--wr-border-glow-color${suffix}`;
|
|
73
|
+
const name = `--wr-border-glow-input-color${suffix}`;
|
|
74
74
|
const raw = declarations.get(name);
|
|
75
75
|
const alpha = raw === void 0 ? null : form.exec(raw);
|
|
76
76
|
if (!alpha) throw new Error(`WrBorderGlowHarness.getGlowAlphaRamp(): \`${name}\` reads "${raw ?? "(absent)"}". The seven halo steps are written together from one glow colour, so a step that is missing, carries no alpha, or is not the same \`${form === GLOW_ALPHA ? "hsl(… / N%)" : "color-mix(in srgb, … N%, transparent)"}\` as the first means the ramp stopped being built — the halo would fade in bands the stylesheet cannot use.`);
|
|
@@ -79,9 +79,9 @@ var WrBorderGlowHarness = class WrBorderGlowHarness extends ComponentHarness {
|
|
|
79
79
|
}
|
|
80
80
|
async getGradientColors() {
|
|
81
81
|
const declarations = await this.declarations();
|
|
82
|
-
if (!declarations.has("--wr-border-glow-gradient-one")) return null;
|
|
82
|
+
if (!declarations.has("--wr-border-glow-input-gradient-one")) return null;
|
|
83
83
|
return GRADIENT_VAR_SLOTS.map((slot) => {
|
|
84
|
-
const name = `--wr-border-glow-gradient-${slot}`;
|
|
84
|
+
const name = `--wr-border-glow-input-gradient-${slot}`;
|
|
85
85
|
const raw = declarations.get(name);
|
|
86
86
|
const colour = raw === void 0 ? null : RADIAL_GRADIENT_COLOR.exec(raw);
|
|
87
87
|
if (!colour) throw new Error(`WrBorderGlowHarness.getGradientColors(): \`${name}\` reads "${raw ?? "(absent)"}", which is not the \`radial-gradient(at X% Y%, <colour> 0px, …)\` the component builds. All seven slots are written from one palette, so one of them being different means the mapping broke, not the palette.`);
|
|
@@ -89,10 +89,10 @@ var WrBorderGlowHarness = class WrBorderGlowHarness extends ComponentHarness {
|
|
|
89
89
|
});
|
|
90
90
|
}
|
|
91
91
|
async getBaseGradientColor() {
|
|
92
|
-
const raw = await this.readVar("--wr-border-glow-gradient-base");
|
|
92
|
+
const raw = await this.readVar("--wr-border-glow-input-gradient-base");
|
|
93
93
|
if (raw === null) return null;
|
|
94
94
|
const colour = LINEAR_GRADIENT_COLOR.exec(raw);
|
|
95
|
-
if (!colour) throw new Error(`WrBorderGlowHarness.getBaseGradientColor(): \`--wr-border-glow-gradient-base\` reads "${raw}", which is not the \`linear-gradient(<colour> 0 100%)\` the component builds from the palette.`);
|
|
95
|
+
if (!colour) throw new Error(`WrBorderGlowHarness.getBaseGradientColor(): \`--wr-border-glow-input-gradient-base\` reads "${raw}", which is not the \`linear-gradient(<colour> 0 100%)\` the component builds from the palette.`);
|
|
96
96
|
return colour[1];
|
|
97
97
|
}
|
|
98
98
|
async getPointerAngle() {
|