Skip to content

Instantly share code, notes, and snippets.

@Archetapp
Created August 25, 2025 22:48
Show Gist options
  • Select an option

  • Save Archetapp/81a6cb89ea95f48d59f06e472755f850 to your computer and use it in GitHub Desktop.

Select an option

Save Archetapp/81a6cb89ea95f48d59f06e472755f850 to your computer and use it in GitHub Desktop.
import SwiftUI
struct ContentView: View {
@State private var startDate = Date()
var body: some View {
VStack(spacing: 40) {
// TV Frame
VStack {
Spacer()
ZStack {
// TV Outer Frame
RoundedRectangle(cornerRadius: 15)
.fill(
LinearGradient(
colors: [
Color.black,
],
startPoint: .topLeading,
endPoint: .bottomTrailing
)
)
.shadow(color: .black.opacity(0.8), radius: 10, x: 0, y: 10)
// CRT Screen Container
VStack {
GeometryReader { geo in
ZStack {
// Black screen background
RoundedRectangle(cornerRadius: 8)
.fill(Color.white.opacity(0.1))
// CRT Content
ZStack {
TimelineView(.animation) { _ in
Image("someImage")
.resizable()
.scaledToFill()
.blur(radius: 1.2)
.layerEffect(
ShaderLibrary.crtEffect(
.float(-startDate.timeIntervalSinceNow),
.float2(geo.size)
),
maxSampleOffset: .zero
)
.opacity(0.4)
}
Text("Brand")
.fontWidth(.expanded)
.font(.system(size: 32, weight: .heavy, design: .default))
.foregroundStyle(.white)
.shadow(radius: 10)
.layerEffect(
ShaderLibrary.crtEffect(
.float(-startDate.timeIntervalSinceNow),
.float2(geo.size)
),
maxSampleOffset: .zero
)
}
}
.clipShape(RoundedRectangle(cornerRadius: 10))
}
.aspectRatio(4/3, contentMode: .fit)
}
.padding(5)
}
.aspectRatio(4/3, contentMode: .fit)
}
.padding(.horizontal, 20)
// Buttons Section
VStack(spacing: 16) {
Spacer()
Button("Create Account") {
// Action
}
.frame(maxWidth: .infinity)
.frame(height: 50)
.background(
RoundedRectangle(cornerRadius: 25)
.fill(
LinearGradient(
colors: [Color.white, Color.gray.opacity(0.9)],
startPoint: .top,
endPoint: .bottom
)
)
)
.foregroundColor(.black)
.font(.headline)
.fontWeight(.semibold)
Button("Sign In") {
// Action
}
.frame(maxWidth: .infinity)
.frame(height: 50)
.background(
RoundedRectangle(cornerRadius: 25)
.stroke(Color.white, lineWidth: 2)
)
.foregroundColor(.white)
.font(.headline)
.fontWeight(.semibold)
}
.padding(.horizontal, 40)
Spacer()
}
.background(
RadialGradient(stops: [
.init(color: Color(red: 0.1, green: 0.1, blue: 0.15), location: 0),
.init(color: .black, location: 1)
], center: .center, startRadius: 10, endRadius: 1000)
)
}
}
#Preview {
ContentView()
}
#include <metal_stdlib>
#include <SwiftUI/SwiftUI.h>
using namespace metal;
float2 distort(float2 uv, float strength) {
float2 dist = 0.5 - uv;
uv.x = (uv.x - dist.y * dist.y * dist.x * strength);
uv.y = (uv.y - dist.x * dist.x * dist.y * strength);
return uv;
}
[[stitchable]]
half4 crtEffect(float2 position, SwiftUI::Layer layer, float time, float2 size) {
float2 uv = position / size;
// Add subtle screen shake/movement with more waviness
float shake = 0.0005 * sin(time * 15.0 + uv.y * 3.0) + 0.0003 * sin(time * 23.0 + uv.x * 8.0);
float verticalWave = 0.0004 * sin(time * 12.0 + uv.x * 5.0);
uv.x += shake;
uv.y += verticalWave;
// Add occasional horizontal distortion lines with more variation
float distortLine = step(0.996, sin(uv.y * 50.0 + time * 4.0));
uv.x += distortLine * 0.012 * sin(time * 60.0);
// RGB color separation for authentic CRT look
float separation = 0.004;
half4 col;
col.r = layer.sample(float2(uv.x - separation, uv.y) * size).r;
col.g = layer.sample(float2(uv.x, uv.y) * size).g;
col.b = layer.sample(float2(uv.x + separation, uv.y) * size).b;
col.a = layer.sample(float2(uv.x, uv.y) * size).a;
// Add phosphor-like RGB dots pattern
float dotSize = 4.5;
float2 dotPos = fmod(position, dotSize);
float3 phosphor = float3(1.0);
if (dotPos.x < dotSize * 0.33) {
phosphor = float3(1.4, 0.6, 0.6); // Red phosphor
} else if (dotPos.x < dotSize * 0.66) {
phosphor = float3(0.6, 1.4, 0.6); // Green phosphor
} else {
phosphor = float3(0.6, 0.6, 1.4); // Blue phosphor
}
col.rgb *= half3(phosphor);
// brighten image
col *= half4(0.95, 1.05, 0.95, 1);
col *= 2.8;
// add scan lines with movement
float scans = clamp(0.35 + 0.35 * sin(3.5 * time + uv.y * size.y * 1.5), 0.0, 1.0);
float s = pow(scans, 1.7);
float sn = 0.4 + 0.7 * s;
col = col * half4(sn, sn, sn, 1);
// Add flickering and subtle brightness variation
float flicker = 1.0 + 0.02 * sin(110.0 * time) + 0.005 * sin(60.0 * time);
col *= flicker;
// Add occasional brightness dips (like old CRT interference)
float interference = 1.0 - 0.3 * step(0.997, sin(time * 2.0 + uv.y * 10.0));
col *= interference;
return col;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment