yp-rubix/index1.html
2025-09-02 16:42:53 +05:30

299 lines
11 KiB
HTML
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Water-like Cursor Ripples — Strong Chromatic Dispersion</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
width: 100%;
height: 100%;
font-family: Inter, system-ui, -apple-system, Segoe UI, Roboto, "Helvetica Neue", Arial;
background: #000000; /* black background */
color: #ffefcc; /* keep nav/footer readable */
overflow: hidden;
}
nav {
position: fixed; top: 0; left: 0; right: 0;
display: flex; justify-content: space-between; align-items: center;
padding: 16px 24px; z-index: 2; pointer-events: none;
}
.nav-left, .nav-right { display: flex; gap: 16px; align-items: center; pointer-events: auto; }
.logo { font-weight: 700; letter-spacing: 0.5px; }
.nav-right button {
background: transparent; color: #ffefcc; border: 1px solid #ffefcc66;
border-radius: 999px; padding: 8px 14px; cursor: pointer;
}
footer {
position: fixed; bottom: 0; left: 0; right: 0;
display: flex; justify-content: space-between; align-items: center;
padding: 16px 24px; z-index: 2; pointer-events: none;
}
footer .title { width: 40%; font-size: clamp(24px, 6vw, 64px); line-height: 1.1; font-weight: 800; }
footer .links { display: flex; gap: 20px; pointer-events: auto; }
canvas.webgl { position: fixed; inset: 0; width: 100vw; height: 100vh; display: block; z-index: 0; }
</style>
</head>
<body>
<nav>
<div class="nav-left">
<div class="logo">YP</div>
<p>Work</p><p>About</p><p>Contact</p>
</div>
<div class="nav-right"><button>Get Started</button></div>
</nav>
<footer>
<div class="title">YP</div>
<div class="links">
<a href="#" style="color:#ffefcc;">Twitter</a>
<a href="#" style="color:#ffefcc;">Instagram</a>
<a href="#" style="color:#ffefcc;">Discord</a>
</div>
</footer>
<canvas class="webgl"></canvas>
<script type="module">
import * as THREE from 'https://unpkg.com/three@0.160.0/build/three.module.js';
// Config
const DPR_MAX = 2;
const BASE_TEXT = 'YOUNG PANDAS';
const BG_COLOR = '#000000'; // black background on canvas texture
const TEXT_COLOR = '#ffffff'; // white center text
// Renderer
const canvas = document.querySelector('canvas.webgl');
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true, alpha: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, DPR_MAX));
renderer.setSize(window.innerWidth, window.innerHeight);
// Scenes & Camera
const simScene = new THREE.Scene();
const mainScene = new THREE.Scene();
const camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);
// Render targets
let width = Math.floor(window.innerWidth * renderer.getPixelRatio());
let height = Math.floor(window.innerHeight * renderer.getPixelRatio());
const rtOptions = {
minFilter: THREE.LinearFilter, magFilter: THREE.LinearFilter,
wrapS: THREE.ClampToEdgeWrapping, wrapT: THREE.ClampToEdgeWrapping,
type: THREE.HalfFloatType ?? THREE.FloatType, format: THREE.RGBAFormat,
depthBuffer: false, stencilBuffer: false
};
let rta = new THREE.WebGLRenderTarget(width, height, rtOptions);
let rtb = new THREE.WebGLRenderTarget(width, height, rtOptions);
// Text Canvas -> Texture
let textCanvas, textCtx, textTexture;
function makeTextTexture() {
const dpr = renderer.getPixelRatio();
width = Math.floor(window.innerWidth * dpr);
height = Math.floor(window.innerHeight * dpr);
textCanvas = document.createElement('canvas');
textCanvas.width = width; textCanvas.height = height;
textCtx = textCanvas.getContext('2d', { alpha: true });
// Black background
textCtx.fillStyle = BG_COLOR;
textCtx.fillRect(0, 0, width, height);
// Orange center text
const fontPx = Math.floor(Math.min(width, height) * 0.18);
textCtx.fillStyle = TEXT_COLOR;
textCtx.textAlign = 'center'; textCtx.textBaseline = 'middle';
textCtx.font = `800 ${fontPx}px Inter, system-ui, -apple-system, Segoe UI, Roboto, Arial`;
textCtx.fillText(BASE_TEXT, width * 0.5, height * 0.5);
if (textTexture) textTexture.dispose();
textTexture = new THREE.CanvasTexture(textCanvas);
textTexture.needsUpdate = true;
textTexture.minFilter = THREE.LinearFilter;
textTexture.magFilter = THREE.LinearFilter;
textTexture.format = THREE.RGBAFormat;
}
makeTextTexture();
// Geometry
const quad = new THREE.PlaneGeometry(2, 2);
// Shaders
const passThroughVert = `
varying vec2 vUv;
void main(){ vUv = uv; gl_Position = vec4(position, 1.0); }
`;
// Ripple simulation (tight brush, fast decay)
const simFrag = `
precision highp float;
varying vec2 vUv;
uniform sampler2D uTexture;
uniform vec2 uResolution;
uniform vec2 uMouse;
uniform float uTime;
void main(){
vec2 texel = 1.0 / uResolution;
vec2 data = texture2D(uTexture, vUv).xy;
float h = data.x;
float hPrev = data.y;
float hL = texture2D(uTexture, vUv - vec2(texel.x, 0.0)).x;
float hR = texture2D(uTexture, vUv + vec2(texel.x, 0.0)).x;
float hT = texture2D(uTexture, vUv + vec2(0.0, texel.y)).x;
float hB = texture2D(uTexture, vUv - vec2(0.0, texel.y)).x;
float sum = hL + hR + hT + hB;
float hNew = (sum * 0.5 - hPrev);
hNew *= 0.985;
vec2 frag = vUv * uResolution;
float radius = 8.0;
float dist = length(frag - uMouse);
float impulse = exp(-dist*dist/(2.0*radius*radius));
hNew += 0.25 * impulse;
hNew = mix(hNew, 0.0, 0.01);
gl_FragColor = vec4(hNew, h, 0.0, 1.0);
}
`;
// Render with strong, masked chromatic dispersion (offsets in pixels)
const renderFrag = `
precision highp float;
varying vec2 vUv;
uniform sampler2D uSim;
uniform sampler2D uText;
uniform vec2 uResolution;
uniform float uRefract;
uniform float uCAPixels; // RGB shift in pixels (large for strong separation)
uniform vec2 uCAMask; // gradient thresholds for where CA applies
void main(){
vec2 texel = 1.0 / uResolution;
// Height gradients
float hX = texture2D(uSim, vUv + vec2(texel.x, 0.0)).x
- texture2D(uSim, vUv - vec2(texel.x, 0.0)).x;
float hY = texture2D(uSim, vUv + vec2(0.0, texel.y)).x
- texture2D(uSim, vUv - vec2(0.0, texel.y)).x;
// Normal and base refraction
vec3 normal = normalize(vec3(-hX, -hY, 1.0));
vec2 baseUV = vUv + normal.xy * uRefract;
// Ripple strength mask (lower thresholds -> more CA on ripples)
float g = length(vec2(hX, hY));
float mask = smoothstep(uCAMask.x, uCAMask.y, g);
// Direction along gradient and large pixel-based offsets
vec2 dir = normalize(vec2(hX, hY) + 1e-6);
vec2 px = texel * uCAPixels;
// Exaggerated dispersion: push red/blue more than green
// Red goes +dir, Blue goes -dir, Green slightly centered/offset
vec2 rUV = baseUV + dir * (px * 1.30);
vec2 gUV = baseUV + dir * (px * 0.20);
vec2 bUV = baseUV - dir * (px * 1.35);
float r = texture2D(uText, rUV).r;
float gC = texture2D(uText, gUV).g;
float b = texture2D(uText, bUV).b;
vec4 caColor = vec4(r, gC, b, 1.0);
vec4 base = texture2D(uText, baseUV);
// Mix CA in only on ripples
vec4 color = mix(base, caColor, mask);
// Mild lighting accent
float light = dot(normal, normalize(vec3(0.0, 0.0, 1.0)));
color.rgb += 0.08 * light;
gl_FragColor = color;
}
`;
// Materials & meshes
const simUniforms = {
uTexture: { value: rta.texture },
uResolution: { value: new THREE.Vector2(width, height) },
uMouse: { value: new THREE.Vector2(-1.0, -1.0) },
uTime: { value: 0 }
};
const simMat = new THREE.ShaderMaterial({ vertexShader: passThroughVert, fragmentShader: simFrag, uniforms: simUniforms });
simScene.add(new THREE.Mesh(quad, simMat));
const renderUniforms = {
uSim: { value: rta.texture },
uText: { value: textTexture },
uResolution: { value: new THREE.Vector2(width, height) },
uRefract: { value: 0.8 },
uCAPixels: { value: 8.0 }, // big shift: increase to 1014 for even more
uCAMask: { value: new THREE.Vector2(0.00008, 0.0005) } // lower => CA engages more
};
const renderMat = new THREE.ShaderMaterial({
vertexShader: passThroughVert, fragmentShader: renderFrag, uniforms: renderUniforms, transparent: true
});
mainScene.add(new THREE.Mesh(quad, renderMat));
// Mouse input
const mouse = new THREE.Vector2(-1, -1);
function setMouseFromEvent(e){
const dpr = renderer.getPixelRatio();
const rect = renderer.domElement.getBoundingClientRect();
const x = (e.clientX - rect.left) * dpr;
const y = (e.clientY - rect.top) * dpr;
mouse.set(x, (rect.height * dpr) - y);
}
renderer.domElement.addEventListener('mousemove', (e)=>{ setMouseFromEvent(e); simUniforms.uMouse.value.copy(mouse); });
renderer.domElement.addEventListener('mouseleave', ()=>{ simUniforms.uMouse.value.set(-1.0, -1.0); });
// Resize
function onResize(){
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, DPR_MAX));
renderer.setSize(window.innerWidth, window.innerHeight);
const dpr = renderer.getPixelRatio();
width = Math.floor(window.innerWidth * dpr);
height = Math.floor(window.innerHeight * dpr);
rta.dispose(); rtb.dispose();
rta = new THREE.WebGLRenderTarget(width, height, rtOptions);
rtb = new THREE.WebGLRenderTarget(width, height, rtOptions);
simUniforms.uResolution.value.set(width, height);
renderUniforms.uResolution.value.set(width, height);
makeTextTexture();
renderUniforms.uText.value = textTexture;
}
window.addEventListener('resize', onResize);
// Animate
const clock = new THREE.Clock();
function animate(){
simUniforms.uTime.value = clock.getElapsedTime();
// Sim: rta -> rtb
simUniforms.uTexture.value = rta.texture;
renderer.setRenderTarget(rtb);
renderer.render(simScene, camera);
// Render with latest sim
renderUniforms.uSim.value = rtb.texture;
renderer.setRenderTarget(null);
renderer.render(mainScene, camera);
// Swap
const tmp = rta; rta = rtb; rtb = tmp;
requestAnimationFrame(animate);
}
animate();
</script>
</body>
</html>