@dopaminefx/effect-checkmate 0.1.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/dist/checkmate-shader.d.ts +32 -0
- package/dist/checkmate-shader.d.ts.map +1 -0
- package/dist/checkmate-shader.js +253 -0
- package/dist/checkmate-shader.js.map +1 -0
- package/dist/checkmate.dope.json +354 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +24 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
- package/src/checkmate-shader.ts +263 -0
- package/src/checkmate.dope.json +354 -0
- package/src/index.ts +39 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkmate — a fabulous winning move: a chess QUEEN pops into place and the
|
|
3
|
+
* frame erupts in LGBTQ+ pride (rainbow swoosh shockwave + spinning sunburst +
|
|
4
|
+
* twinkling sparkle bling). A success effect (serene / celebratory / electric).
|
|
5
|
+
*
|
|
6
|
+
* FULLY DATA-DRIVEN: params/palette/tempo come from checkmate.dope.json via the
|
|
7
|
+
* loader; the per-frame logic (the held-breath `amp` + the easeOutBack `pop`
|
|
8
|
+
* bounce) is `tempo.frame`; the uniform binding is the `.dope` `binding`
|
|
9
|
+
* contract. `registerDopeEffect` derives the whole pass config from the data —
|
|
10
|
+
* this module is just the rainbow SHADER + the registration call. The chess
|
|
11
|
+
* queen is analytic (2D SDFs), so the effect ships no swift/ or android/ folder.
|
|
12
|
+
*/
|
|
13
|
+
import { type EffectFactory, type PassParams } from "@dopaminefx/core";
|
|
14
|
+
/** The resolved render params Checkmate's shader consumes. */
|
|
15
|
+
export interface CheckmateParams extends PassParams {
|
|
16
|
+
exposure: number;
|
|
17
|
+
bling: number;
|
|
18
|
+
swoosh: number;
|
|
19
|
+
rays: number;
|
|
20
|
+
spin: number;
|
|
21
|
+
sizeFrac: number;
|
|
22
|
+
overshoot: number;
|
|
23
|
+
checkmateSeed: number;
|
|
24
|
+
}
|
|
25
|
+
export declare const checkmate: EffectFactory<CheckmateParams>;
|
|
26
|
+
export default checkmate;
|
|
27
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAiC,KAAK,aAAa,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAKtG,8DAA8D;AAC9D,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAID,eAAO,MAAM,SAAS,EAGa,aAAa,CAAC,eAAe,CAAC,CAAC;AAElE,eAAe,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checkmate — a fabulous winning move: a chess QUEEN pops into place and the
|
|
3
|
+
* frame erupts in LGBTQ+ pride (rainbow swoosh shockwave + spinning sunburst +
|
|
4
|
+
* twinkling sparkle bling). A success effect (serene / celebratory / electric).
|
|
5
|
+
*
|
|
6
|
+
* FULLY DATA-DRIVEN: params/palette/tempo come from checkmate.dope.json via the
|
|
7
|
+
* loader; the per-frame logic (the held-breath `amp` + the easeOutBack `pop`
|
|
8
|
+
* bounce) is `tempo.frame`; the uniform binding is the `.dope` `binding`
|
|
9
|
+
* contract. `registerDopeEffect` derives the whole pass config from the data —
|
|
10
|
+
* this module is just the rainbow SHADER + the registration call. The chess
|
|
11
|
+
* queen is analytic (2D SDFs), so the effect ships no swift/ or android/ folder.
|
|
12
|
+
*/
|
|
13
|
+
import { CHECKMATE_FRAGMENT_SRC, CHECKMATE_VERTEX_SRC } from "./checkmate-shader.js";
|
|
14
|
+
import { parseDope, registerDopeEffect } from "@dopaminefx/core";
|
|
15
|
+
import doc from "./checkmate.dope.json";
|
|
16
|
+
const DOPE = parseDope(doc);
|
|
17
|
+
// The whole factory (resolve / create / reducedMotion / program registration)
|
|
18
|
+
// is data: checkmate.dope.json interpreted by the core backbone.
|
|
19
|
+
export const checkmate = registerDopeEffect(DOPE, {
|
|
20
|
+
vertex: CHECKMATE_VERTEX_SRC,
|
|
21
|
+
fragment: CHECKMATE_FRAGMENT_SRC,
|
|
22
|
+
});
|
|
23
|
+
export default checkmate;
|
|
24
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AACrF,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAuC,MAAM,kBAAkB,CAAC;AACtG,OAAO,GAAG,MAAM,uBAAuB,CAAC;AAExC,MAAM,IAAI,GAAG,SAAS,CAAC,GAAa,CAAC,CAAC;AActC,8EAA8E;AAC9E,iEAAiE;AACjE,MAAM,CAAC,MAAM,SAAS,GAAG,kBAAkB,CAAC,IAAI,EAAE;IAChD,MAAM,EAAE,oBAAoB;IAC5B,QAAQ,EAAE,sBAAsB;CACjC,CAAgE,CAAC;AAElE,eAAe,SAAS,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@dopaminefx/effect-checkmate",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Checkmate — a pride-rainbow chess-queen success celebration for Dopamine.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"dopamine-effect"
|
|
7
|
+
],
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"module": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"default": "./dist/index.js"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"files": [
|
|
19
|
+
"dist",
|
|
20
|
+
"src"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": [
|
|
23
|
+
"./src/index.ts",
|
|
24
|
+
"./dist/index.js"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsc -p tsconfig.json"
|
|
28
|
+
},
|
|
29
|
+
"dependencies": {
|
|
30
|
+
"@dopaminefx/core": "^0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"author": "10in30",
|
|
34
|
+
"homepage": "https://github.com/10in30/dopamine#readme",
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/10in30/dopamine.git",
|
|
38
|
+
"directory": "effects/checkmate/web"
|
|
39
|
+
},
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/10in30/dopamine/issues"
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLSL ES 3.00 source for **Checkmate** — an unapologetically fabulous winning
|
|
3
|
+
* move. A chess QUEEN pops into place with an overshoot bounce and the whole
|
|
4
|
+
* frame ERUPTS in LGBTQ+ pride: an expanding rainbow swoosh-shockwave, a
|
|
5
|
+
* spinning pride sunburst, and a mob of twinkling 4-point sparkle bling.
|
|
6
|
+
*
|
|
7
|
+
* Authored ONCE here; the toolchain transpiles the MSL + Kotlin variants from
|
|
8
|
+
* this single GLSL (`x-build.shader`). The chess queen is drawn ANALYTICALLY
|
|
9
|
+
* from 2D SDF primitives (a flared trapezoid body + base, a collar bar and five
|
|
10
|
+
* crown balls on stems) so it is byte-identical on every backend — no baked SDF,
|
|
11
|
+
* no sampler, no per-platform fallback.
|
|
12
|
+
*
|
|
13
|
+
* Layers, summed as light (canvas is black, `mix-blend-mode: screen`, so black
|
|
14
|
+
* == no change, bright == cast light onto the page beneath):
|
|
15
|
+
* 1. SUNBURST — radial pride rays spinning behind the queen (uSpin/uRays).
|
|
16
|
+
* 2. SWOOSH — an expanding rainbow shockwave ring whose hue cycles with
|
|
17
|
+
* angle; it bursts outward over life (the "swoosh").
|
|
18
|
+
* 3. QUEEN — the chess piece, filled with a vertical rainbow gradient +
|
|
19
|
+
* a hot white edge, popped in by uPop (overshoot bounce).
|
|
20
|
+
* 4. BLING — a scatter of twinkling 4-point star glints riding outward
|
|
21
|
+
* with the swoosh (the sparkle "bling"), tinted by the palette.
|
|
22
|
+
* 5. FLASH — a hot radial flash at the instant of the pop.
|
|
23
|
+
*
|
|
24
|
+
* whimsy == uStyle: 0 = smooth photoreal spectral glow; 1 = cel POP-ART — the
|
|
25
|
+
* rainbow posterizes into the canonical 6-stripe pride flag and the bling reads
|
|
26
|
+
* as chunky comic stars. The pass runner already snaps the clock "on twos".
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
import {
|
|
30
|
+
GLSL_CONSTANTS,
|
|
31
|
+
GLSL_DITHER,
|
|
32
|
+
GLSL_HASH,
|
|
33
|
+
GLSL_PALETTE_MIX,
|
|
34
|
+
GLSL_SD_SEG,
|
|
35
|
+
GLSL_TONEMAP_ACES,
|
|
36
|
+
} from "@dopaminefx/core";
|
|
37
|
+
|
|
38
|
+
/** Scatter count for the sparkle bling. Single source of truth for the loop cap. */
|
|
39
|
+
export const MAX_SPARKLES = 16;
|
|
40
|
+
|
|
41
|
+
export const CHECKMATE_VERTEX_SRC = /* glsl */ `#version 300 es
|
|
42
|
+
void main() {
|
|
43
|
+
// Single full-screen triangle from gl_VertexID — no vertex buffers needed.
|
|
44
|
+
vec2 pos = vec2(float((gl_VertexID << 1) & 2), float(gl_VertexID & 2));
|
|
45
|
+
gl_Position = vec4(pos * 2.0 - 1.0, 0.0, 1.0);
|
|
46
|
+
}`;
|
|
47
|
+
|
|
48
|
+
export const CHECKMATE_FRAGMENT_SRC = /* glsl */ `#version 300 es
|
|
49
|
+
precision highp float;
|
|
50
|
+
out vec4 fragColor;
|
|
51
|
+
|
|
52
|
+
uniform vec2 uResolution; // device pixels
|
|
53
|
+
uniform vec2 uOrigin; // queen anchor, gl coords (y up)
|
|
54
|
+
uniform float uAmp; // held-breath envelope amplitude (brightness gate)
|
|
55
|
+
uniform float uPop; // easeOutBack pop scale (overshoot bounce -> 1)
|
|
56
|
+
uniform float uLife; // whole-effect progress 0..1
|
|
57
|
+
uniform float uTimeS; // elapsed seconds (snapped "on twos" by style)
|
|
58
|
+
uniform float uExposure; // overall light gain (intensity)
|
|
59
|
+
uniform float uBling; // sparkle density/brightness (intensity)
|
|
60
|
+
uniform float uSwoosh; // rainbow shockwave reach (intensity)
|
|
61
|
+
uniform float uRays; // pride sunburst ray count (integer)
|
|
62
|
+
uniform float uSpin; // sunburst/swoosh rotation speed
|
|
63
|
+
uniform float uSizeFrac; // queen box size as a fraction of min viewport dim
|
|
64
|
+
uniform float uSeed; // per-fire scatter/hue offset
|
|
65
|
+
uniform float uStyle; // 0..1 photoreal spectral -> cel pop-art pride flag
|
|
66
|
+
uniform float uShadow; // 0 = light pass (screen), 1 = shadow pass (multiply)
|
|
67
|
+
uniform vec2 uShadowOffset; // device-px offset of the cast silhouette
|
|
68
|
+
uniform float uShadowSoft; // penumbra softness in device px (blur tap radius)
|
|
69
|
+
uniform float uShadowStrength;// 0..1 max darkening of the multiply layer
|
|
70
|
+
uniform vec3 uC0; // accent palette (sparkle tint) — per fire
|
|
71
|
+
uniform vec3 uC1; // mid
|
|
72
|
+
uniform vec3 uC2; // outer accent
|
|
73
|
+
|
|
74
|
+
#define MAX_SPARKLES ${MAX_SPARKLES}
|
|
75
|
+
${GLSL_CONSTANTS}
|
|
76
|
+
${GLSL_HASH}
|
|
77
|
+
${GLSL_PALETTE_MIX}
|
|
78
|
+
${GLSL_SD_SEG}
|
|
79
|
+
${GLSL_TONEMAP_ACES}
|
|
80
|
+
${GLSL_DITHER}
|
|
81
|
+
|
|
82
|
+
// ---- The pride spectrum -----------------------------------------------------
|
|
83
|
+
// Smooth IQ-cosine rainbow: a continuous, saturated spectral sweep over [0,1).
|
|
84
|
+
vec3 prideSmooth(float t){
|
|
85
|
+
t = fract(t);
|
|
86
|
+
return 0.5 + 0.5 * cos(TAU * (t + vec3(0.0, 0.33, 0.67)));
|
|
87
|
+
}
|
|
88
|
+
// The canonical 6-stripe pride FLAG, posterized from t (red→violet).
|
|
89
|
+
vec3 prideFlag(float t){
|
|
90
|
+
t = fract(t);
|
|
91
|
+
if (t < 0.16667) return vec3(0.94, 0.10, 0.12); // red
|
|
92
|
+
if (t < 0.33333) return vec3(1.00, 0.55, 0.06); // orange
|
|
93
|
+
if (t < 0.50000) return vec3(1.00, 0.93, 0.10); // yellow
|
|
94
|
+
if (t < 0.66667) return vec3(0.18, 0.70, 0.22); // green
|
|
95
|
+
if (t < 0.83333) return vec3(0.10, 0.36, 0.90); // blue
|
|
96
|
+
return vec3(0.46, 0.12, 0.62); // violet
|
|
97
|
+
}
|
|
98
|
+
// Blend smooth↔flag by whimsy (style): cel end snaps to the 6 flag stripes.
|
|
99
|
+
vec3 prideColor(float t, float style){
|
|
100
|
+
return mix(prideSmooth(t), prideFlag(t), style);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// ---- 2D SDF primitives for the chess QUEEN silhouette -----------------------
|
|
104
|
+
float sdBox(vec2 p, vec2 b){
|
|
105
|
+
vec2 d = abs(p) - b;
|
|
106
|
+
return length(max(d, 0.0)) + min(max(d.x, d.y), 0.0);
|
|
107
|
+
}
|
|
108
|
+
// Inigo Quilez trapezoid SDF: half-widths r1 (bottom) and r2 (top), half-height he.
|
|
109
|
+
float sdTrapezoid(vec2 p, float r1, float r2, float he){
|
|
110
|
+
vec2 k1 = vec2(r2, he);
|
|
111
|
+
vec2 k2 = vec2(r2 - r1, 2.0 * he);
|
|
112
|
+
p.x = abs(p.x);
|
|
113
|
+
vec2 ca = vec2(p.x - min(p.x, (p.y < 0.0) ? r1 : r2), abs(p.y) - he);
|
|
114
|
+
vec2 cb = p - k1 + k2 * clamp(dot(k1 - p, k2) / dot(k2, k2), 0.0, 1.0);
|
|
115
|
+
float s = (cb.x < 0.0 && ca.y < 0.0) ? -1.0 : 1.0;
|
|
116
|
+
return s * sqrt(min(dot(ca, ca), dot(cb, cb)));
|
|
117
|
+
}
|
|
118
|
+
// Signed distance to the queen, in LOCAL units (q centered, y up, ~[-1,1]).
|
|
119
|
+
// Union (min) of: base foot, flared body, collar band, five crown balls + stems.
|
|
120
|
+
float queenDist(vec2 q){
|
|
121
|
+
float d = sdTrapezoid(q - vec2(0.0, -0.74), 0.60, 0.40, 0.12); // base foot
|
|
122
|
+
d = min(d, sdTrapezoid(q - vec2(0.0, -0.10), 0.46, 0.15, 0.50)); // flared body
|
|
123
|
+
d = min(d, sdBox(q - vec2(0.0, 0.40), vec2(0.32, 0.05)) - 0.02); // collar band
|
|
124
|
+
// crown balls (center tallest) + the stems joining them to the band
|
|
125
|
+
d = min(d, length(q - vec2(-0.46, 0.55)) - 0.115);
|
|
126
|
+
d = min(d, length(q - vec2(-0.23, 0.62)) - 0.125);
|
|
127
|
+
d = min(d, length(q - vec2( 0.00, 0.71)) - 0.145);
|
|
128
|
+
d = min(d, length(q - vec2( 0.23, 0.62)) - 0.125);
|
|
129
|
+
d = min(d, length(q - vec2( 0.46, 0.55)) - 0.115);
|
|
130
|
+
d = min(d, sdSeg(q, vec2(-0.46, 0.55), vec2(-0.28, 0.42)) - 0.045);
|
|
131
|
+
d = min(d, sdSeg(q, vec2(-0.23, 0.62), vec2(-0.14, 0.42)) - 0.045);
|
|
132
|
+
d = min(d, sdSeg(q, vec2( 0.00, 0.71), vec2( 0.00, 0.42)) - 0.055);
|
|
133
|
+
d = min(d, sdSeg(q, vec2( 0.23, 0.62), vec2( 0.14, 0.42)) - 0.045);
|
|
134
|
+
d = min(d, sdSeg(q, vec2( 0.46, 0.55), vec2( 0.28, 0.42)) - 0.045);
|
|
135
|
+
return d;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// A twinkling 4-point star glint: hot core + two soft anisotropic spikes.
|
|
139
|
+
float starGlint(vec2 p, vec2 c, float size){
|
|
140
|
+
vec2 d = (p - c) / max(size, 1e-3);
|
|
141
|
+
float r = length(d);
|
|
142
|
+
float core = exp(-r * r * 5.0);
|
|
143
|
+
float sx = exp(-abs(d.x) * 6.0) * exp(-abs(d.y) * 1.4);
|
|
144
|
+
float sy = exp(-abs(d.y) * 6.0) * exp(-abs(d.x) * 1.4);
|
|
145
|
+
return core + (sx + sy) * 0.7;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// ---- Queen coverage (0..1 fill) at a fragment, with the pop scale applied ----
|
|
149
|
+
float queenFill(vec2 frag){
|
|
150
|
+
float R = min(uResolution.x, uResolution.y) * uSizeFrac;
|
|
151
|
+
float scale = mix(0.34, 1.0, clamp(uPop, 0.0, 1.4)); // bounce-in scale
|
|
152
|
+
vec2 q = (frag - uOrigin) / max(R, 1e-3) / max(scale, 1e-3);
|
|
153
|
+
float d = queenDist(q);
|
|
154
|
+
float aa = 1.6 / max(R, 1e-3); // ~1.6 device px, local units
|
|
155
|
+
return smoothstep(aa, -aa, d);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
// ---- SHADOW silhouette — the queen casts a soft offset occlusion. -----------
|
|
159
|
+
float occlusion(vec2 frag){
|
|
160
|
+
return clamp(queenFill(frag) * uAmp, 0.0, 1.0);
|
|
161
|
+
}
|
|
162
|
+
vec4 shadowColor(vec2 frag){
|
|
163
|
+
vec2 sp = frag - uShadowOffset;
|
|
164
|
+
float s = uShadowSoft;
|
|
165
|
+
float occ = occlusion(sp);
|
|
166
|
+
occ += occlusion(sp + vec2(s, 0.0));
|
|
167
|
+
occ += occlusion(sp + vec2(-s, 0.0));
|
|
168
|
+
occ += occlusion(sp + vec2(0.0, s));
|
|
169
|
+
occ += occlusion(sp + vec2(0.0, -s));
|
|
170
|
+
occ /= 5.0;
|
|
171
|
+
float dark = clamp(occ, 0.0, 1.0) * uShadowStrength;
|
|
172
|
+
// A faintly warm, regal shadow tint (not a flat grey).
|
|
173
|
+
vec3 tint = mix(vec3(1.0), vec3(0.74, 0.70, 0.78), 1.0);
|
|
174
|
+
vec3 mul = mix(vec3(1.0), tint, dark);
|
|
175
|
+
return vec4(mul, 1.0);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
void main(){
|
|
179
|
+
vec2 frag = gl_FragCoord.xy;
|
|
180
|
+
float minDim = min(uResolution.x, uResolution.y);
|
|
181
|
+
|
|
182
|
+
if (uShadow > 0.5) { fragColor = shadowColor(frag); return; }
|
|
183
|
+
|
|
184
|
+
vec2 rel = frag - uOrigin;
|
|
185
|
+
float r = length(rel);
|
|
186
|
+
float rn = r / minDim; // normalized radius
|
|
187
|
+
float theta = atan(rel.y, rel.x); // -PI..PI
|
|
188
|
+
float gain = uAmp * uExposure;
|
|
189
|
+
float style = uStyle;
|
|
190
|
+
|
|
191
|
+
vec3 col = vec3(0.0);
|
|
192
|
+
|
|
193
|
+
// ---- 1. PRIDE SUNBURST: spinning radial rays behind the queen. ----
|
|
194
|
+
float rayN = max(uRays, 1.0);
|
|
195
|
+
float rays = 0.5 + 0.5 * cos(theta * rayN - uTimeS * uSpin * 2.4);
|
|
196
|
+
rays = pow(clamp(rays, 0.0, 1.0), mix(2.2, 5.0, style)); // crisper on the cel end
|
|
197
|
+
float rayMask = smoothstep(0.02, 0.16, rn) * (1.0 - smoothstep(0.30, 0.62, rn));
|
|
198
|
+
vec3 rayCol = prideColor(theta / TAU + 0.5 + uSeed, style);
|
|
199
|
+
col += rayCol * rays * rayMask * gain * 0.5;
|
|
200
|
+
|
|
201
|
+
// ---- 2. RAINBOW SWOOSH: an expanding shockwave ring whose hue cycles with
|
|
202
|
+
// angle. It bursts outward over life and widens as it goes — the "swoosh". ----
|
|
203
|
+
float front = uSwoosh * (0.10 + 0.78 * uLife);
|
|
204
|
+
float width = 0.035 + 0.16 * uLife;
|
|
205
|
+
float dr = (rn - front) / max(width, 1e-3);
|
|
206
|
+
float ring = exp(-dr * dr);
|
|
207
|
+
vec3 ringCol = prideColor(theta / TAU + uSpin * uTimeS * 0.15 + uSeed, style);
|
|
208
|
+
col += ringCol * ring * gain * 1.35;
|
|
209
|
+
// a brighter leading lip on the ring's outer edge (the wet swoosh shine)
|
|
210
|
+
col += vec3(1.0) * smoothstep(0.0, 1.0, ring) * smoothstep(0.0, -1.2, dr) * gain * 0.35;
|
|
211
|
+
|
|
212
|
+
// ---- 3. THE QUEEN: filled with a vertical rainbow + a hot white edge. ----
|
|
213
|
+
float R = minDim * uSizeFrac;
|
|
214
|
+
float scale = mix(0.34, 1.0, clamp(uPop, 0.0, 1.4));
|
|
215
|
+
vec2 q = rel / max(R, 1e-3) / max(scale, 1e-3);
|
|
216
|
+
float dq = queenDist(q);
|
|
217
|
+
float aa = 1.6 / max(R, 1e-3);
|
|
218
|
+
float fill = smoothstep(aa, -aa, dq);
|
|
219
|
+
float edge = smoothstep(aa * 2.5, 0.0, abs(dq)); // bright rim line
|
|
220
|
+
float halo = exp(-max(dq, 0.0) / 0.06); // soft outer glow
|
|
221
|
+
// vertical rainbow over the piece + a slow shimmer; whimsy → flag stripes.
|
|
222
|
+
float qt = q.y * 0.42 + 0.5 + uSeed + uTimeS * 0.05;
|
|
223
|
+
vec3 body = prideColor(qt, style);
|
|
224
|
+
vec3 queenCol = body * fill * 1.45 // saturated rainbow fill
|
|
225
|
+
+ mix(body, vec3(1.0), 0.6) * edge * 0.8 // bright (tinted) edge
|
|
226
|
+
+ body * halo * 0.55; // coloured glow
|
|
227
|
+
// a brief white core just after the bounce so she "lands" with a flash
|
|
228
|
+
queenCol += vec3(1.0) * fill * (1.0 - smoothstep(0.0, 0.22, uLife)) * 0.35;
|
|
229
|
+
col += queenCol * (uExposure * (0.35 + 0.65 * uAmp));
|
|
230
|
+
|
|
231
|
+
// ---- 4. SPARKLE BLING: twinkling 4-point stars riding outward. ----
|
|
232
|
+
float sparkleReach = (0.16 + 0.62 * uLife) * minDim;
|
|
233
|
+
vec3 bling = vec3(0.0);
|
|
234
|
+
for (int i = 0; i < MAX_SPARKLES; i++) {
|
|
235
|
+
float fi = float(i);
|
|
236
|
+
vec2 h = hash21(fi * 3.17 + uSeed * 31.0);
|
|
237
|
+
float ang = h.x * TAU;
|
|
238
|
+
float rad = (0.45 + 0.55 * h.y) * sparkleReach; // spread out as life grows
|
|
239
|
+
vec2 pos = uOrigin + vec2(cos(ang), sin(ang)) * rad;
|
|
240
|
+
// twinkle: each sparkle blinks on its own phase
|
|
241
|
+
float ph = h.x * 17.0 + h.y * 9.0;
|
|
242
|
+
float tw = pow(0.5 + 0.5 * sin(uTimeS * 7.0 + ph), mix(3.0, 7.0, style));
|
|
243
|
+
float sz = minDim * (0.012 + 0.018 * h.y) * (0.8 + 0.5 * uBling);
|
|
244
|
+
float g = starGlint(frag, pos, sz) * tw;
|
|
245
|
+
// tint with the per-fire accent palette, biased bright (white-hot core).
|
|
246
|
+
vec3 tint = mix(vec3(1.0), paletteMix(fract(fi * 0.137 + uSeed)), 0.55);
|
|
247
|
+
bling += tint * g;
|
|
248
|
+
}
|
|
249
|
+
col += bling * uBling * gain * 0.9;
|
|
250
|
+
|
|
251
|
+
// ---- 5. POP FLASH: a hot radial flash at the instant of the bounce. ----
|
|
252
|
+
float flashT = 1.0 - smoothstep(0.0, 0.22, uLife);
|
|
253
|
+
float flash = exp(-rn * rn * 26.0) * flashT;
|
|
254
|
+
col += mix(vec3(1.0), prideColor(uTimeS * 0.3 + uSeed, style), 0.4) * flash * uExposure * 1.4;
|
|
255
|
+
|
|
256
|
+
// ---- Filmic tonemap + finishing ----
|
|
257
|
+
col = tonemapACES(col * 0.95);
|
|
258
|
+
// Ordered dither (~1/255) to kill banding the screen blend reveals; faded out
|
|
259
|
+
// toward the cel/pop-art end where hard flag bands are intended.
|
|
260
|
+
col = ditherAdd(col, frag, uTimeS, 1.0 - style);
|
|
261
|
+
|
|
262
|
+
fragColor = vec4(max(col, 0.0), 1.0);
|
|
263
|
+
}`;
|