diff options
| author | Gabriel Schneider <[email protected]> | 2026-08-17 16:12:56 -0300 |
|---|---|---|
| committer | Gabriel Schneider <[email protected]> | 2026-08-18 23:45:04 -0300 |
| commit | 31fece62f56aa2311e2325de83659edbc9e641db (patch) | |
| tree | 13eee1e542d9670ad3fb7badad353265121d668f /shaders/crt.ci.metal | |
| parent | 1551e409c31992437cb2fa864f576d45c8433801 (diff) | |
| download | pardes-31fece62f56aa2311e2325de83659edbc9e641db.tar.gz pardes-31fece62f56aa2311e2325de83659edbc9e641db.zip | |
animation: core publishes transition records; gui evaluates via shaders, tty over grid cells
Diffstat (limited to 'shaders/crt.ci.metal')
| -rw-r--r-- | shaders/crt.ci.metal | 78 |
1 files changed, 14 insertions, 64 deletions
diff --git a/shaders/crt.ci.metal b/shaders/crt.ci.metal index 32e26b21..e1db5770 100644 --- a/shaders/crt.ci.metal +++ b/shaders/crt.ci.metal @@ -106,7 +106,6 @@ float pardesPanelProgress(float effect, float frame) { float frames = effect == 1.0 ? 12.0 : effect == 2.0 ? 14.0 : effect == 3.0 ? 10.0 : - effect == 4.0 ? 16.0 : effect == 5.0 ? 12.0 : 1.0; if (frames <= 1.0 || frame >= frames - 1.0) return 1.0; float t = clamp(frame / (frames - 1.0), 0.0, 1.0); @@ -121,33 +120,7 @@ float pardesPanelProgress(float effect, float frame) { return 1.0 + c3 * u * u * u + c1 * u * u; } if (effect == 3.0) return t * t * (3.0 - 2.0 * t); // dissolve - return t; // ASCII materialization -} - -float pardesAsciiGlyph(float2 uv, int glyph) { - float2 p = uv * 2.0 - 1.0; - const float thin = 0.12; - float dotShape = 1.0 - smoothstep(0.10, 0.20, length(p - float2(0.0, 0.45))); - float barH = 1.0 - smoothstep(thin, thin + 0.08, abs(p.y)); - float barV = 1.0 - smoothstep(thin, thin + 0.08, abs(p.x)); - if (glyph == 0) return dotShape; - if (glyph == 1) return max(dotShape, - 1.0 - smoothstep(0.10, 0.20, length(p + float2(0.0, 0.45)))); - if (glyph == 2) return max(barH, barV); - if (glyph == 3) { - float d0 = 1.0 - smoothstep(thin, thin + 0.08, abs(p.x - p.y)); - float d1 = 1.0 - smoothstep(thin, thin + 0.08, abs(p.x + p.y)); - return max(max(d0, d1), max(barH, barV)); - } - if (glyph == 4) { - float rails = max( - 1.0 - smoothstep(thin, thin + 0.08, abs(abs(p.x) - 0.34)), - 1.0 - smoothstep(thin, thin + 0.08, abs(abs(p.y) - 0.34))); - return rails; - } - float ring = 1.0 - smoothstep(thin, thin + 0.08, - abs(length(p * float2(0.8, 1.0)) - 0.48)); - return max(ring, glyph == 6 ? dotShape : 0.0); + return t; // ASCII cells are already composed; retained for ABI completeness } // Prepare every geometric target before any translated panel is drawn. A @@ -195,10 +168,18 @@ extern "C" float4 pardesPanel( float progress = pardesPanelProgress(effect, frame); float2 safeCell = max(cellSize, float2(1.0)); - // Content transitions stay at canonical geometry. Unchanged cells bypass - // the effect completely; changed cells retain the exact old raster until - // their deterministic wave reaches them. - if (effect == 3.0 || effect == 4.0) { + // ASCII bytes were already composed in Pardes core before CoreText built + // `current`. Pixel attachments have no character value and intentionally + // pass through unchanged, so this kernel only clips the pane batch. + if (effect == 4.0) { + if (!pardesInside(coord, target)) return underneath; + return current.sample(current.transform(coord)); + } + + // Dissolve stays at canonical geometry. Unchanged cells bypass the effect + // completely; changed cells retain the exact old raster until their + // deterministic threshold is crossed. + if (effect == 3.0) { if (!pardesInside(coord, target)) return underneath; // During a live resize the grid is still anchored at the view's top, // leaving a partial strip below its final logical row. Account for @@ -223,38 +204,7 @@ extern "C" float4 pardesPanel( float2 cellCount = max(round(target.zw / safeCell), float2(1.0)); cell = clamp(cell, float2(0.0), cellCount - 1.0); float noise = pardesCellNoise(serialParts, cell.x, cell.y); - if (effect == 3.0) - return noise < progress ? newPixel : oldPixel; - - float diagonal = fmod(cell.x + cell.y * 2.0, 17.0) / 17.0; - float threshold = noise * 0.72 + diagonal * 0.28; - if (progress >= threshold) return newPixel; - if (progress + 0.22 < threshold) return oldPixel; - - float2 cellUV = fract(float2( - (coord.x - target.x) / safeCell.x, - (target.y + target.w - coord.y) / safeCell.y)); - int glyph = min(int(floor(noise * 7.0)), 6); - float ink = pardesAsciiGlyph(cellUV, glyph); - float2 cellOrigin = float2( - target.x + cell.x * safeCell.x, - target.y + target.w - (cell.y + 1.0) * safeCell.y); - float4 bgSample = current.sample(current.transform( - cellOrigin + safeCell * float2(0.12, 0.12))); - float4 bg = coreimage::unpremultiply(bgSample); - float4 fg = coreimage::unpremultiply(newPixel); - // A procedural mark usually crosses pixels where the target glyph has - // no ink, so sampling `newPixel` alone can make it background-on- - // background and erase the ASCII phase. Preserve target ink where it - // is present; otherwise derive restrained contrast from the cell's - // own background instead of imposing a fixed palette. - float3 contrastInk = dot(bg.rgb, float3(0.2126, 0.7152, 0.0722)) > 0.5 - ? float3(0.0) : float3(1.0); - float sourceContrast = smoothstep(0.025, 0.14, length(fg.rgb - bg.rgb)); - float3 inkColor = mix(contrastInk, fg.rgb, sourceContrast); - float3 dimInk = mix(bg.rgb, inkColor, 0.62); - return coreimage::premultiply(float4( - mix(bg.rgb, dimInk, ink), max(bg.a, newPixel.a))); + return noise < progress ? newPixel : oldPixel; } float4 shown = mix(from, to, progress); |
