mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
chore(skills): remove 1,685 lines of redundant skill content (#283)
* chore(skills): remove 1,685 lines of redundant and irrelevant skill content - Remove 5 GSAP references irrelevant to HyperFrames (scrolltrigger, plugins, react, frameworks, utils) — no scroll, no frameworks, no interactive plugins in video compositions - Remove shader-setup.md and shader-transitions.md — duplicated by @hyperframes/shader-transitions package (packages/shader-transitions/) - Remove marker-highlight.md and examples.md — JS library docs superseded by css-patterns.md (deterministic, GSAP-driven, fully seekable) - Trim CLAUDE.md to dev-only instructions — move product docs (transcription, TTS, player) to skills where they belong - Deduplicate house-style.md typography/motion sections — point to dedicated references instead of repeating rules - Clean up stale references to deleted files across SKILL.md and catalog.md - Update gsap skill description to reflect HyperFrames-only scope Skills: 5,230 → 3,714 lines (29% reduction) CLAUDE.md: 204 → 50 lines (75% reduction) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(skills): update broken marker-highlight.md references in captions.md Point to css-patterns.md instead of deleted marker-highlight.md. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(skills): update stale shader CSS rule to reference package API BG_COLOR was from the old manual setup. Now it's bgColor in the @hyperframes/shader-transitions init() config. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(skills): address 6 doc gaps surfaced by eval agents P0: Document HyperShader as IIFE global name in shader-transitions README P1: Replace async fetch() with sync XHR in effects.md audio data loading (fetch violates synchronous timeline construction rule in SKILL.md) P1: Change <div> to <span> in css-patterns.md marker highlight patterns (<div> inside <p> is invalid HTML, breaks layout in inline contexts) P2: Clarify bgColor as fallback color in shader-transitions README P2: Add data-start to Composition Clips table in SKILL.md (root composition element needs data-start="0", linter enforces it) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(templates): update init templates to match trimmed skill scope - Remove ScrollTrigger/plugins/React/Vue/Svelte from gsap skill description - Replace class="clip" with accurate pattern examples in skill intro text (class="clip" is still in Key Rules where it belongs) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix(skills): remove contradictory 5:1 contrast threshold from house-style house-style.md said 5:1 minimum, but hyperframes validate enforces WCAG AA (4.5:1 normal text, 3:1 large text). Now defers to validate instead of stating a conflicting number. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
acf8223171
commit
a262ad59f3
@@ -28,19 +28,9 @@ These cause real bugs if violated.
|
||||
|
||||
**Don't use:** Star iris (polygon interpolation broken), tilt-shift (no selective CSS blur), lens flare (visible shape, not optical), hinge/door (distorts too fast).
|
||||
|
||||
## Hard Rules (Shader)
|
||||
## Shader Transitions
|
||||
|
||||
Read [shader-setup.md](./shader-setup.md) for the full setup code these rules apply to.
|
||||
|
||||
**WebGL setup:** `gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false)` — NOT true. Vertex shader flips Y: `v_uv.y = 1.0 - v_uv.y`. `preserveDrawingBuffer: true` required for HyperFrames capture. No `fwidth()` without extension — use constant `0.003`.
|
||||
|
||||
**Rendering model:** DOM scenes play normally with GSAP animations during holds — canvas is hidden (`display:none`). When a transition starts: capture outgoing scene with full content, capture incoming scene with `.scene-content` hidden (background + decoratives only), show canvas, run shader. When transition ends: hide canvas, show next DOM scene. GSAP entrance animations play on the live DOM. The incoming scene's content is never visible in the shader — it only shows the background layer, preventing un-animated elements from flashing.
|
||||
|
||||
**Scene capture:** Canvas `fillText` doesn't match CSS fonts exactly (known, not a bug). No CSS gradients or SVGs. Images and videos ARE supported via `ctx.drawImage()`. Video scenes re-capture every frame during transitions via `recaptureVideoScene()`.
|
||||
|
||||
**Timeline:** Use `tl.call()` for begin/end — NOT `onStart`/`onComplete`. Each tween proxy `{p:0}` must be unique. Never boomerang (`u_progress*(1.-u_progress)*4.`). Morph both scenes.
|
||||
|
||||
**Shader code:** One noise library per shader (NQ or ND, not both). Always `clamp(uv, 0., 1.)`.
|
||||
Shader setup, WebGL init, capture, and fragment shaders are handled by `@hyperframes/shader-transitions` (`packages/shader-transitions/`). Read the package source for API details. Compositions using shaders must follow the CSS rules in [transitions.md](../transitions.md) § "Shader-Compatible CSS Rules".
|
||||
|
||||
## Scene Template
|
||||
|
||||
@@ -124,9 +114,4 @@ All code examples use `old` for the outgoing scene-inner selector and `new` for
|
||||
|
||||
## Shader Transitions
|
||||
|
||||
WebGL fragment shaders that composite between scene textures per-pixel. Require setup boilerplate.
|
||||
|
||||
| What | Reference |
|
||||
| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ |
|
||||
| Setup (canvas, capture, WebGL init, render loop, GSAP integration) | [shader-setup.md](./shader-setup.md) |
|
||||
| Fragment shaders (13 transitions: domain warp, ridged burn, whip pan, SDF iris, ripple waves, gravitational lens, cinematic zoom, chromatic split, glitch, swirl vortex, thermal distortion, cross-warp morph, light leak) | [shader-transitions.md](./shader-transitions.md) |
|
||||
WebGL shader transitions are provided by `@hyperframes/shader-transitions` (`packages/shader-transitions/`). The package handles setup, capture, WebGL init, render loop, and GSAP integration. Read the package source for available shaders and API — do not copy raw GLSL manually.
|
||||
|
||||
@@ -1,282 +0,0 @@
|
||||
# Shader Transition Setup
|
||||
|
||||
Complete boilerplate for WebGL shader transitions in HyperFrames. Copy the setup code, then plug in the fragment shader from the catalog.
|
||||
|
||||
**Rendering model:** DOM scenes play normally with GSAP animations. The WebGL canvas is hidden (`display:none`) between transitions. When a transition starts, `beginTrans` uses html2canvas to capture the outgoing scene with full content, and the incoming scene with `.scene-content` hidden (background + decorative elements only). This prevents un-animated content from flashing during the transition. When the transition ends, `endTrans` hides the canvas and reveals the incoming DOM scene — GSAP entrance animations then play on live elements.
|
||||
|
||||
**Shader-compatible CSS:** Compositions using shader transitions must follow the rules in transitions.md § "Shader-Compatible CSS Rules" — no `transparent` in gradients, no gradient backgrounds on sub-4px elements, no `var()` on captured elements, `data-no-capture` on uncapturable decoratives.
|
||||
|
||||
## HTML
|
||||
|
||||
```html
|
||||
<canvas
|
||||
id="gl-canvas"
|
||||
width="1920"
|
||||
height="1080"
|
||||
style="position:absolute;top:0;left:0;width:1920px;height:1080px;z-index:100;pointer-events:none;display:none;"
|
||||
>
|
||||
</canvas>
|
||||
```
|
||||
|
||||
## WebGL Init
|
||||
|
||||
```js
|
||||
var sceneTextures = {};
|
||||
var glCanvas = document.getElementById("gl-canvas");
|
||||
var gl = glCanvas.getContext("webgl", { preserveDrawingBuffer: true });
|
||||
gl.viewport(0, 0, 1920, 1080);
|
||||
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
|
||||
```
|
||||
|
||||
## Shader Compilation + Shared Constants
|
||||
|
||||
```js
|
||||
var vertSrc =
|
||||
"attribute vec2 a_pos; varying vec2 v_uv; void main(){" +
|
||||
"v_uv=a_pos*0.5+0.5; v_uv.y=1.0-v_uv.y; gl_Position=vec4(a_pos,0,1);}";
|
||||
|
||||
var quadBuf = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, 1, 1]), gl.STATIC_DRAW);
|
||||
|
||||
function compileShader(src, type) {
|
||||
var s = gl.createShader(type);
|
||||
gl.shaderSource(s, src);
|
||||
gl.compileShader(s);
|
||||
if (!gl.getShaderParameter(s, gl.COMPILE_STATUS))
|
||||
console.error("Shader:", gl.getShaderInfoLog(s));
|
||||
return s;
|
||||
}
|
||||
|
||||
function mkProg(fragSrc) {
|
||||
var p = gl.createProgram();
|
||||
gl.attachShader(p, compileShader(vertSrc, gl.VERTEX_SHADER));
|
||||
gl.attachShader(p, compileShader(fragSrc, gl.FRAGMENT_SHADER));
|
||||
gl.linkProgram(p);
|
||||
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) console.error("Link:", gl.getProgramInfoLog(p));
|
||||
return p;
|
||||
}
|
||||
|
||||
// Shared uniform header — every fragment shader starts with this
|
||||
var H =
|
||||
"precision mediump float;" +
|
||||
"varying vec2 v_uv;" +
|
||||
"uniform sampler2D u_from, u_to;" +
|
||||
"uniform float u_progress;" +
|
||||
"uniform vec2 u_resolution;\n";
|
||||
```
|
||||
|
||||
## Noise Libraries
|
||||
|
||||
Include only what each shader needs. Do NOT include multiple libraries that redefine `hash()` in the same shader.
|
||||
|
||||
```js
|
||||
// Quintic C2 noise + inter-octave rotation FBM
|
||||
var NQ =
|
||||
"float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}" +
|
||||
"float vnoise(vec2 p){vec2 i=floor(p),f=fract(p);" +
|
||||
"f=f*f*f*(f*(f*6.-15.)+10.);" + // quintic interpolation — C2 continuous
|
||||
"return mix(mix(hash(i),hash(i+vec2(1,0)),f.x)," +
|
||||
"mix(hash(i+vec2(0,1)),hash(i+vec2(1,1)),f.x),f.y);}" +
|
||||
"float fbm(vec2 p){float v=0.,a=.5;" +
|
||||
"mat2 R=mat2(.8,.6,-.6,.8);" + // inter-octave rotation (~37deg)
|
||||
"for(int i=0;i<5;i++){v+=a*vnoise(p);p=R*p*2.02;a*=.5;}return v;}";
|
||||
|
||||
// Noise with analytical derivatives (quintic) + erosion FBM
|
||||
// Use for transitions that need gradient-based edge lighting
|
||||
var ND =
|
||||
"float hash(vec2 p){return fract(sin(dot(p,vec2(127.1,311.7)))*43758.5453);}" +
|
||||
"vec3 noised(vec2 p){vec2 i=floor(p),f=fract(p);" +
|
||||
"vec2 u=f*f*f*(f*(f*6.-15.)+10.),du=30.*f*f*(f*(f-2.)+1.);" +
|
||||
"float a=hash(i),b=hash(i+vec2(1,0)),c=hash(i+vec2(0,1)),d=hash(i+vec2(1,1));" +
|
||||
"return vec3(a+(b-a)*u.x+(c-a)*u.y+(a-b-c+d)*u.x*u.y," +
|
||||
"du*vec2(b-a+(a-b-c+d)*u.y,c-a+(a-b-c+d)*u.x));}" +
|
||||
"float erosionFBM(vec2 p){float v=0.,a=.5;vec2 d=vec2(0);mat2 R=mat2(.8,.6,-.6,.8);" +
|
||||
"for(int i=0;i<6;i++){vec3 n=noised(p);d+=n.yz;v+=a*n.x/(1.+dot(d,d));p=R*p*2.02;a*=.5;}return v;}";
|
||||
|
||||
// Cosine palette: a + b*cos(2pi(c*t + d))
|
||||
var CP = "vec3 palette(float t,vec3 a,vec3 b,vec3 c,vec3 d){" + "return a+b*cos(6.2832*(c*t+d));}";
|
||||
```
|
||||
|
||||
## Render + State Machine
|
||||
|
||||
DOM scenes play normally with GSAP animations during holds. The canvas is only visible during shader transitions — hidden the rest of the time. Capture uses html2canvas (loaded from CDN alongside GSAP).
|
||||
|
||||
Add this script tag alongside GSAP:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.jsdelivr.net/npm/html2canvas@1.4.1/dist/html2canvas.min.js"></script>
|
||||
```
|
||||
|
||||
```js
|
||||
// Patch createPattern for html2canvas bug with 0-dimension elements
|
||||
var _origCP = CanvasRenderingContext2D.prototype.createPattern;
|
||||
CanvasRenderingContext2D.prototype.createPattern = function (img, rep) {
|
||||
if (img && (img.width === 0 || img.height === 0)) return null;
|
||||
return _origCP.call(this, img, rep);
|
||||
};
|
||||
|
||||
function uploadTexture(sceneId, canvas) {
|
||||
if (!sceneTextures[sceneId]) {
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
||||
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
||||
sceneTextures[sceneId] = tex;
|
||||
}
|
||||
gl.bindTexture(gl.TEXTURE_2D, sceneTextures[sceneId]);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
|
||||
}
|
||||
|
||||
// BG_COLOR must match your composition's background color (e.g. "#0a0a1a").
|
||||
// html2canvas backgroundColor: null means transparent, which renders as black
|
||||
// in WebGL textures. Always pass the explicit color.
|
||||
var BG_COLOR = "#000"; // ← set to your composition's background
|
||||
|
||||
function captureScene(sceneEl) {
|
||||
return html2canvas(sceneEl, {
|
||||
width: 1920,
|
||||
height: 1080,
|
||||
scale: 1,
|
||||
backgroundColor: BG_COLOR,
|
||||
logging: false,
|
||||
ignoreElements: function (el) {
|
||||
return el.tagName === "CANVAS" || el.hasAttribute("data-no-capture");
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
function renderShader(prog, texFrom, texTo, progress) {
|
||||
gl.useProgram(prog);
|
||||
gl.activeTexture(gl.TEXTURE0);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texFrom);
|
||||
gl.uniform1i(gl.getUniformLocation(prog, "u_from"), 0);
|
||||
gl.activeTexture(gl.TEXTURE1);
|
||||
gl.bindTexture(gl.TEXTURE_2D, texTo);
|
||||
gl.uniform1i(gl.getUniformLocation(prog, "u_to"), 1);
|
||||
gl.uniform1f(gl.getUniformLocation(prog, "u_progress"), progress);
|
||||
gl.uniform2f(gl.getUniformLocation(prog, "u_resolution"), 1920, 1080);
|
||||
var pos = gl.getAttribLocation(prog, "a_pos");
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, quadBuf);
|
||||
gl.enableVertexAttribArray(pos);
|
||||
gl.vertexAttribPointer(pos, 2, gl.FLOAT, false, 0, 0);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
}
|
||||
|
||||
var trans = {
|
||||
active: false,
|
||||
prog: null,
|
||||
fromId: null,
|
||||
toId: null,
|
||||
progress: 0,
|
||||
};
|
||||
|
||||
function beginTrans(prog, fromId, toId) {
|
||||
if (!gl) return;
|
||||
var fromScene = document.getElementById(fromId);
|
||||
var toScene = document.getElementById(toId);
|
||||
|
||||
// Capture outgoing scene (DOM stays visible during async capture)
|
||||
captureScene(fromScene)
|
||||
.then(function (fromCanvas) {
|
||||
uploadTexture(fromId, fromCanvas);
|
||||
|
||||
// Show incoming scene BEHIND outgoing (z-index -1) for capture
|
||||
toScene.style.zIndex = "-1";
|
||||
toScene.style.opacity = "1";
|
||||
var contentEl = toScene.querySelector(".scene-content");
|
||||
if (contentEl) contentEl.style.visibility = "hidden";
|
||||
|
||||
// Wait 2 rAFs for browser to render with correct fonts
|
||||
return new Promise(function (resolve) {
|
||||
requestAnimationFrame(function () {
|
||||
requestAnimationFrame(function () {
|
||||
captureScene(toScene).then(function (toCanvas) {
|
||||
if (contentEl) contentEl.style.visibility = "";
|
||||
toScene.style.opacity = "0";
|
||||
toScene.style.zIndex = "";
|
||||
uploadTexture(toId, toCanvas);
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.then(function () {
|
||||
// Both textures ready — swap DOM for canvas
|
||||
document.querySelectorAll(".scene").forEach(function (s) {
|
||||
s.style.opacity = "0";
|
||||
});
|
||||
glCanvas.style.display = "block";
|
||||
trans.prog = prog;
|
||||
trans.fromId = fromId;
|
||||
trans.toId = toId;
|
||||
trans.progress = 0;
|
||||
trans.active = true;
|
||||
});
|
||||
}
|
||||
|
||||
function updateTrans() {
|
||||
if (!trans.active || !gl) return;
|
||||
renderShader(trans.prog, sceneTextures[trans.fromId], sceneTextures[trans.toId], trans.progress);
|
||||
}
|
||||
|
||||
function endTrans(showId) {
|
||||
trans.active = false;
|
||||
glCanvas.style.display = "none";
|
||||
document.getElementById(showId).style.opacity = "1";
|
||||
}
|
||||
```
|
||||
|
||||
## GSAP Timeline Integration
|
||||
|
||||
Scene 1 starts visible on the DOM. GSAP animates elements normally. The canvas is hidden until a transition begins. After each transition, the canvas hides and the next scene's DOM takes over.
|
||||
|
||||
```js
|
||||
// Canvas starts hidden — DOM scene 1 is visible
|
||||
glCanvas.style.display = "none";
|
||||
|
||||
var tl = gsap.timeline({
|
||||
paused: true,
|
||||
onUpdate: function () {
|
||||
updateTrans();
|
||||
},
|
||||
});
|
||||
|
||||
// Scene 1 entrance animations go here (normal GSAP on DOM)...
|
||||
|
||||
// Transition 1→2:
|
||||
tl.call(
|
||||
function () {
|
||||
beginTrans(myShaderProg, "scene1", "scene2");
|
||||
},
|
||||
null,
|
||||
T,
|
||||
);
|
||||
var tw1 = { p: 0 };
|
||||
tl.to(
|
||||
tw1,
|
||||
{
|
||||
p: 1,
|
||||
duration: DUR,
|
||||
ease: "power2.inOut",
|
||||
onUpdate: function () {
|
||||
trans.progress = tw1.p;
|
||||
},
|
||||
},
|
||||
T,
|
||||
);
|
||||
tl.call(
|
||||
function () {
|
||||
endTrans("scene2");
|
||||
},
|
||||
null,
|
||||
T + DUR,
|
||||
);
|
||||
|
||||
// Scene 2 entrance animations go here (normal GSAP on DOM)...
|
||||
|
||||
window.__timelines["main"] = tl;
|
||||
```
|
||||
@@ -1,329 +0,0 @@
|
||||
# Shader Transition Fragment Shaders
|
||||
|
||||
Each shader below is just the GLSL fragment body. Plug it into `mkProg(H + NQ + "...")` using the setup from [shader-setup.md](./shader-setup.md).
|
||||
|
||||
### Domain Warp Dissolve
|
||||
|
||||
Cascaded `fbm(p + fbm(p))` — both scenes displace along the warp field in opposite directions. Iridescent cosine palette edge glow.
|
||||
|
||||
```glsl
|
||||
// Requires: NQ + CP
|
||||
void main() {
|
||||
vec2 q = vec2(fbm(v_uv * 3.), fbm(v_uv * 3. + vec2(5.2, 1.3)));
|
||||
vec2 r = vec2(fbm(v_uv * 3. + q * 4. + vec2(1.7, 9.2)),
|
||||
fbm(v_uv * 3. + q * 4. + vec2(8.3, 2.8)));
|
||||
float n = fbm(v_uv * 3. + r * 2.);
|
||||
vec2 warpDir = (q - .5) * .4;
|
||||
vec4 A = texture2D(u_from, clamp(v_uv + warpDir * u_progress, 0., 1.));
|
||||
vec4 B = texture2D(u_to, clamp(v_uv - warpDir * (1. - u_progress), 0., 1.));
|
||||
float e = smoothstep(u_progress - .08, u_progress + .08, n);
|
||||
float ed = abs(n - u_progress);
|
||||
float em = smoothstep(.1, 0., ed) * (1. - step(1., u_progress));
|
||||
vec3 ec = palette(ed * 8., vec3(.5), vec3(.5), vec3(1.), vec3(0., .33, .67));
|
||||
gl_FragColor = vec4(mix(B, A, e).rgb + ec * em * 2., 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Ridged Burn
|
||||
|
||||
`abs(noise)` creates sharp lightning-crack edges. Blackbody color gradient (dark red → orange → yellow → white) + high-frequency ember sparks near the edge.
|
||||
|
||||
```glsl
|
||||
// Requires: NQ
|
||||
float ridged(vec2 p) {
|
||||
float v = 0., a = .5;
|
||||
mat2 R = mat2(.8, .6, -.6, .8);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
v += a * abs(vnoise(p) * 2. - 1.);
|
||||
p = R * p * 2.02; a *= .5;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
void main() {
|
||||
vec4 A = texture2D(u_from, v_uv), B = texture2D(u_to, v_uv);
|
||||
float n = ridged(v_uv * 4.);
|
||||
float e = smoothstep(u_progress - .04, u_progress + .04, n);
|
||||
float heat = smoothstep(.12, 0., abs(n - u_progress)) * (1. - step(1., u_progress));
|
||||
vec3 burn = mix(vec3(.4, 0, 0), vec3(1, .4, 0), smoothstep(0., .25, heat));
|
||||
burn = mix(burn, vec3(1, .85, .3), smoothstep(.25, .5, heat));
|
||||
burn = mix(burn, vec3(1), smoothstep(.5, 1., heat));
|
||||
float sparks = step(.92, vnoise(v_uv * 80.)) * heat * 3.;
|
||||
gl_FragColor = vec4(mix(B, A, e).rgb + burn * heat * 3.5
|
||||
+ vec3(1., .7, .3) * sparks, 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Whip Pan
|
||||
|
||||
Both scenes slide horizontally in opposite directions with 10-sample directional motion blur. No noise needed.
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
float fromOff = u_progress * 1.5;
|
||||
vec3 fromC = vec3(0.);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
float f = float(i) / 10.;
|
||||
vec2 fuv = vec2(v_uv.x + fromOff + u_progress * .08 * f, v_uv.y);
|
||||
fromC += texture2D(u_from, clamp(fuv, 0., 1.)).rgb;
|
||||
}
|
||||
fromC /= 10.;
|
||||
float toOff = (1. - u_progress) * 1.5;
|
||||
vec3 toC = vec3(0.);
|
||||
for (int i = 0; i < 10; i++) {
|
||||
float f = float(i) / 10.;
|
||||
vec2 tuv = vec2(v_uv.x - toOff - (1. - u_progress) * .08 * f, v_uv.y);
|
||||
toC += texture2D(u_to, clamp(tuv, 0., 1.)).rgb;
|
||||
}
|
||||
toC /= 10.;
|
||||
gl_FragColor = vec4(mix(fromC, toC, u_progress), 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### SDF Iris
|
||||
|
||||
Aspect-corrected circle SDF opening from center. Triple onion ring glow.
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
vec4 A = texture2D(u_from, v_uv), B = texture2D(u_to, v_uv);
|
||||
vec2 uv = (v_uv - .5) * vec2(u_resolution.x / u_resolution.y, 1.);
|
||||
float d = length(uv);
|
||||
float radius = u_progress * 1.2;
|
||||
float fw = .003;
|
||||
float edge = smoothstep(radius + fw, radius - fw, d);
|
||||
float ring1 = exp(-abs(d - radius) * 25.);
|
||||
float ring2 = exp(-abs(d - radius + .04) * 20.) * .5;
|
||||
float ring3 = exp(-abs(d - radius + .08) * 15.) * .25;
|
||||
float glow = (ring1 + ring2 + ring3) * u_progress * (1. - u_progress) * 4.;
|
||||
gl_FragColor = vec4(mix(A, B, edge).rgb + vec3(1., .85, .6) * glow * .6, 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Ripple Waves
|
||||
|
||||
Exponential sine waves (`exp(sin(x)-1)`) — sharp crests, broad troughs. Both scenes ripple in opposite phases.
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
vec2 uv = v_uv - .5;
|
||||
float dist = length(uv);
|
||||
vec2 dir = normalize(uv + .001);
|
||||
float fromAmp = u_progress * .04;
|
||||
float fw1 = exp(sin(dist * 25. - u_progress * 12.) - 1.);
|
||||
float fw2 = exp(sin(dist * 50. - u_progress * 18.) - 1.) * .5;
|
||||
vec2 fromUv = clamp(v_uv + dir * (fw1 + fw2) * fromAmp, 0., 1.);
|
||||
float toAmp = (1. - u_progress) * .04;
|
||||
float tw1 = exp(sin(dist * 25. + u_progress * 12.) - 1.);
|
||||
float tw2 = exp(sin(dist * 50. + u_progress * 18.) - 1.) * .5;
|
||||
vec2 toUv = clamp(v_uv - dir * (tw1 + tw2) * toAmp, 0., 1.);
|
||||
vec4 A = texture2D(u_from, fromUv);
|
||||
vec4 B = texture2D(u_to, toUv);
|
||||
float peak = fw1 * u_progress;
|
||||
vec3 tint = vec3(.9, .95, 1.) * peak * .1;
|
||||
gl_FragColor = vec4(mix(A.rgb + tint, B.rgb, u_progress), 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Gravitational Lens
|
||||
|
||||
Content warps toward gravity well with chromatic aberration + event horizon darkening. Pull is monotonic — never reverses.
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
vec4 B = texture2D(u_to, v_uv);
|
||||
vec2 uv = v_uv - .5;
|
||||
float dist = length(uv);
|
||||
float pull = u_progress * 2.;
|
||||
float warpStr = pull * .3 / (dist + .1);
|
||||
vec2 warped = clamp(v_uv - uv * warpStr, 0., 1.);
|
||||
vec4 A = texture2D(u_from, warped);
|
||||
float horizon = smoothstep(0., .3, dist / (1. - u_progress * .85 + .001));
|
||||
float shift = pull * .02 / (dist + .2);
|
||||
float r = texture2D(u_from, clamp(v_uv - uv * (warpStr + shift), 0., 1.)).r;
|
||||
float b = texture2D(u_from, clamp(v_uv - uv * (warpStr - shift), 0., 1.)).b;
|
||||
vec3 lensed = vec3(r, A.g, b) * horizon;
|
||||
gl_FragColor = vec4(mix(lensed, B.rgb, smoothstep(.3, .9, u_progress)), 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Cinematic Zoom
|
||||
|
||||
Both scenes zoom-blur in opposite directions with per-channel radial offset (chromatic aberration). From zooms outward, to zooms inward from tight.
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
vec2 d = v_uv - vec2(.5);
|
||||
float fromS = u_progress * .08;
|
||||
float toS = (1. - u_progress) * .06;
|
||||
float fr = 0., fg = 0., fb = 0.;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
float f = float(i) / 12.;
|
||||
fr += texture2D(u_from, v_uv - d * (fromS * 1.06) * f).r;
|
||||
fg += texture2D(u_from, v_uv - d * fromS * f).g;
|
||||
fb += texture2D(u_from, v_uv - d * (fromS * .94) * f).b;
|
||||
}
|
||||
vec3 fromBl = vec3(fr, fg, fb) / 12.;
|
||||
float tr = 0., tg = 0., tb = 0.;
|
||||
for (int i = 0; i < 12; i++) {
|
||||
float f = float(i) / 12.;
|
||||
tr += texture2D(u_to, v_uv + d * (toS * 1.06) * f).r;
|
||||
tg += texture2D(u_to, v_uv + d * toS * f).g;
|
||||
tb += texture2D(u_to, v_uv + d * (toS * .94) * f).b;
|
||||
}
|
||||
vec3 toBl = vec3(tr, tg, tb) / 12.;
|
||||
gl_FragColor = vec4(mix(fromBl, toBl, u_progress), 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Chromatic Radial Split
|
||||
|
||||
Both scenes' RGB channels separate/converge radially. From-scene splits outward, to-scene converges inward.
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
vec2 c = v_uv - .5;
|
||||
float fromShift = u_progress * .06;
|
||||
float fr = texture2D(u_from, clamp(v_uv + c * fromShift, 0., 1.)).r;
|
||||
float fg = texture2D(u_from, v_uv).g;
|
||||
float fb = texture2D(u_from, clamp(v_uv - c * fromShift, 0., 1.)).b;
|
||||
vec3 fromSplit = vec3(fr, fg, fb);
|
||||
float toShift = (1. - u_progress) * .06;
|
||||
float tr = texture2D(u_to, clamp(v_uv - c * toShift, 0., 1.)).r;
|
||||
float tg = texture2D(u_to, v_uv).g;
|
||||
float tb = texture2D(u_to, clamp(v_uv + c * toShift, 0., 1.)).b;
|
||||
vec3 toSplit = vec3(tr, tg, tb);
|
||||
gl_FragColor = vec4(mix(fromSplit, toSplit, u_progress), 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Glitch (shader)
|
||||
|
||||
Scan lines + block scramble + chromatic aberration + brightness flicker + color posterization. More aggressive than the CSS glitch.
|
||||
|
||||
```glsl
|
||||
float rand(vec2 co) {
|
||||
return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);
|
||||
}
|
||||
void main() {
|
||||
float inten = u_progress * (1. - u_progress) * 4.;
|
||||
float lineY = floor(v_uv.y * 60.) / 60.;
|
||||
float lineDisp = (rand(vec2(lineY, floor(u_progress * 17.))) - .5) * .18 * inten;
|
||||
vec2 block = floor(v_uv * vec2(12., 8.));
|
||||
float br = rand(block + vec2(floor(u_progress * 11.)));
|
||||
float ba = step(.83, br) * inten;
|
||||
vec2 bd = (vec2(rand(block * 2.1), rand(block * 3.7)) - .5) * .35 * ba;
|
||||
vec2 uv = clamp(v_uv + vec2(lineDisp, 0.) + bd, 0., 1.);
|
||||
float shift = inten * .035;
|
||||
float r = texture2D(u_from, uv + vec2(shift, 0.)).r;
|
||||
float g = texture2D(u_from, uv).g;
|
||||
float b = texture2D(u_from, uv - vec2(shift, 0.)).b;
|
||||
vec3 col = vec3(r, g, b);
|
||||
col -= step(.5, fract(v_uv.y * u_resolution.y * .5)) * .05 * inten;
|
||||
col *= 1. + (rand(vec2(floor(u_progress * 23.))) - .5) * .3 * inten;
|
||||
float levels = mix(256., 8., inten * .5);
|
||||
col = floor(col * levels) / levels;
|
||||
gl_FragColor = mix(vec4(col, 1.), texture2D(u_to, v_uv), u_progress);
|
||||
}
|
||||
```
|
||||
|
||||
### Swirl Vortex
|
||||
|
||||
Both scenes swirl in opposite directions with FBM-warped spiral path.
|
||||
|
||||
```glsl
|
||||
// Requires: NQ
|
||||
void main() {
|
||||
vec2 uv = v_uv - .5;
|
||||
float dist = length(uv);
|
||||
float warp = fbm(v_uv * 4.) * .5;
|
||||
float fromAng = u_progress * (1. - dist) * 10. + warp * u_progress * 3.;
|
||||
float fs = sin(fromAng), fc = cos(fromAng);
|
||||
vec2 fromUv = clamp(vec2(uv.x*fc - uv.y*fs, uv.x*fs + uv.y*fc) + .5, 0., 1.);
|
||||
float toAng = -(1. - u_progress) * (1. - dist) * 10.
|
||||
- warp * (1. - u_progress) * 3.;
|
||||
float ts = sin(toAng), tc = cos(toAng);
|
||||
vec2 toUv = clamp(vec2(uv.x*tc - uv.y*ts, uv.x*ts + uv.y*tc) + .5, 0., 1.);
|
||||
vec4 A = texture2D(u_from, fromUv);
|
||||
vec4 B = texture2D(u_to, toUv);
|
||||
gl_FragColor = mix(A, B, u_progress);
|
||||
}
|
||||
```
|
||||
|
||||
### Thermal Distortion
|
||||
|
||||
FBM-driven heat shimmer rising from bottom. Warps both scenes with sine displacement modulated by noise. Slight warm overexposure haze.
|
||||
|
||||
```glsl
|
||||
// Requires: NQ
|
||||
void main() {
|
||||
float heat = u_progress * 1.5;
|
||||
float yFade = smoothstep(1., 0., v_uv.y);
|
||||
float shimmer = sin(v_uv.y * 40. + fbm(v_uv * 6.) * 8.)
|
||||
* fbm(v_uv * 3. + vec2(0., u_progress * 2.));
|
||||
float dispX = shimmer * heat * .03 * yFade;
|
||||
vec2 fromUv = clamp(v_uv + vec2(dispX, 0.), 0., 1.);
|
||||
vec4 A = texture2D(u_from, fromUv);
|
||||
float invShimmer = sin(v_uv.y * 40. + fbm(v_uv * 6. + 3.) * 8.)
|
||||
* fbm(v_uv * 3. + vec2(3., u_progress * 2.));
|
||||
float dispX2 = invShimmer * (1. - u_progress) * .03 * yFade;
|
||||
vec2 toUv = clamp(v_uv + vec2(dispX2, 0.), 0., 1.);
|
||||
vec4 B = texture2D(u_to, toUv);
|
||||
float haze = heat * yFade * .15 * (1. - u_progress);
|
||||
gl_FragColor = vec4(mix(A.rgb, B.rgb, u_progress)
|
||||
+ vec3(1., .9, .7) * haze, 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Flash Through White
|
||||
|
||||
Both scenes brighten to white midpoint. Works on dark backgrounds where color-dip-to-black is invisible.
|
||||
|
||||
```glsl
|
||||
void main() {
|
||||
vec4 A = texture2D(u_from, v_uv), B = texture2D(u_to, v_uv);
|
||||
float toWhite = smoothstep(0., .45, u_progress);
|
||||
vec3 fromC = mix(A.rgb, vec3(1.), toWhite);
|
||||
float fromWhite = 1. - smoothstep(.5, 1., u_progress);
|
||||
vec3 toC = mix(B.rgb, vec3(1.), fromWhite);
|
||||
gl_FragColor = vec4(mix(fromC, toC, smoothstep(.35, .65, u_progress)), 1.);
|
||||
}
|
||||
```
|
||||
|
||||
### Cross-Warp Morph
|
||||
|
||||
Both scenes displace along a shared FBM noise field in opposite directions. Noise-driven blend boundary. Neither scene just sits there.
|
||||
|
||||
```glsl
|
||||
// Requires: NQ
|
||||
void main() {
|
||||
vec2 disp = vec2(fbm(v_uv * 3.), fbm(v_uv * 3. + vec2(7.3, 3.7))) - .5;
|
||||
vec2 fromUv = clamp(v_uv + disp * u_progress * .5, 0., 1.);
|
||||
vec2 toUv = clamp(v_uv - disp * (1. - u_progress) * .5, 0., 1.);
|
||||
vec4 A = texture2D(u_from, fromUv);
|
||||
vec4 B = texture2D(u_to, toUv);
|
||||
float n = fbm(v_uv * 4. + vec2(3.1, 1.7));
|
||||
float blend = smoothstep(.4, .6, n + u_progress * 1.2 - .6);
|
||||
gl_FragColor = mix(A, B, blend);
|
||||
}
|
||||
```
|
||||
|
||||
### Light Leak (shader)
|
||||
|
||||
Beer-Lambert exponential falloff + ACES tone mapping + directional flare streak. More physically accurate than the CSS overlay version.
|
||||
|
||||
```glsl
|
||||
vec3 aces(vec3 x) {
|
||||
return clamp((x * (2.51 * x + .03)) / (x * (2.43 * x + .59) + .14), 0., 1.);
|
||||
}
|
||||
void main() {
|
||||
vec4 A = texture2D(u_from, v_uv), B = texture2D(u_to, v_uv);
|
||||
vec2 lp = vec2(1.3, -.2);
|
||||
float dist = length(v_uv - lp);
|
||||
float leak = clamp(exp(-dist * 1.8) * u_progress * 4., 0., 1.);
|
||||
vec3 warmColor = mix(vec3(1., .5, .15), vec3(1., .9, .75), dist * .7);
|
||||
float flare = exp(-abs(v_uv.y - (-.2 + v_uv.x * .3)) * 15.) * leak * .3;
|
||||
vec3 overexposed = A.rgb + warmColor * leak * 3. + vec3(1., .8, .5) * flare;
|
||||
overexposed = aces(overexposed);
|
||||
gl_FragColor = vec4(mix(overexposed, B.rgb, smoothstep(.15, .85, u_progress)), 1.);
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user