ashish rajwani

3D ocean infinite

Shaders

About

relaxing 2d tropical ocean

Built with React and Tailwind. Copy the prompt and paste it into Claude Code, Cursor or Lovable: your agent adds 3D ocean infinite to your project and fits it to your theme.

Code

How 3D ocean infinite is used: the demo's code. The component's own source comes with a free account.

Usage.tsx

import React, { useEffect, useRef, useState } from 'react';

const VERTEX_SHADER = `
    attribute vec2 position;
    void main() {
        gl_Position = vec4(position, 0.0, 1.0);
    }
`;

const FRAGMENT_SHADER = `
    precision highp float;

    uniform float u_time;
    uniform vec2 u_resolution;
    uniform vec2 u_mouse;

    #define ITERATIONS 6
    #define SEA_HEIGHT 0.6
    #define SEA_CHOPPY 4.0
    #define SEA_SPEED 0.8
    #define SEA_FREQ 0.16
    #define SEA_BASE vec3(0.1, 0.19, 0.22)
    #define SEA_WATER_COLOR vec3(0.8, 0.9, 0.6)

    float hash(vec2 p) {
        return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);
    }

    float noise(vec2 p) {
        vec2 i = floor(p);
        vec2 f = fract(p);
        vec2 u = f * f * (3.0 - 2.0 * f);
        return mix(mix(hash(i + vec2(0.0, 0.0)), hash(i + vec2(1.0, 0.0)), u.x),
                   mix(hash(i + vec2(0.0, 1.0)), hash(i + vec2(1.0, 1.0)), u.x), u.y);
    }

    float sea_octave(vec2 uv, float choppy) {
        uv += noise(uv);        
        vec2 wv = 1.0 - abs(sin(uv));
        vec2 swv = abs(cos(uv));    
        wv = mix(wv, swv, wv);
        return pow(1.0 - pow(wv.x * wv.y, 0.65), choppy);
    }

    float map(vec3 p, float time, vec2 resolution, vec2 mouse) {
        float freq = SEA_FREQ;
        float amp = SEA_HEIGHT;
        float choppy = SEA_CHOPPY;
        vec2 uv = p.xz; uv.x *= 0.75;
        
        vec2 mouseDir = (mouse / resolution.xy) - 0.5;
        uv += mouseDir * 2.0;

        float d, h = 0.0;    
        for(int i = 0; i < ITERATIONS; i++) {        
            d = sea_octave((uv + time * SEA_SPEED) * freq, choppy);
            d += sea_octave((uv - time * SEA_SPEED) * freq, choppy);
            h += d * amp;        
            uv *= mat2(1.6, 1.2, -1.2, 1.6);
            freq *= 1.9; amp *= 0.22;
            choppy = mix(choppy, 1.0, 0.2);
        }
        return p.y - h;
    }

    void main() {
        vec2 uv = (gl_FragCoord.xy - 0.5 * u_resolution.xy) / min(u_resolution.y, u_resolution.x);
        
        vec3 eye = vec3(0.0, 3.5, 5.0);
        vec3 target = vec3(0.0, 0.0, 0.0);
        vec3 forward = normalize(target - eye);
        vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0)));
        vec3 up = cross(right, forward);
        vec3 rayDir = normalize(uv.x * right + uv.y * up + 1.5 * forward);

        float t = 0.0;
        for(int i = 0; i < 64; i++) {
            vec3 p = eye + rayDir * t;
            float d = map(p, u_time, u_resolution, u_mouse);
            if(d < 0.01 || t > 20.0) break;
            t += d;
        }

        vec3 p = eye + rayDir * t;
        vec3 color;

        if (t > 20.0) {
            float skyFactor = (rayDir.y + 0.1) * 0.8;
            color = mix(vec3(0.4, 0.7, 1.0), vec3(0.7, 0.9, 1.0), skyFactor);
        } else {
            vec3 n = normalize(vec3(
                map(vec3(p.x + 0.01, p.y, p.z), u_time, u_resolution, u_mouse) - map(vec3(p.x - 0.01, p.y, p.z), u_time, u_resolution, u_mouse),
                0.02,
                map(vec3(p.x, p.y, p.z + 0.01), u_time, u_resolution, u_mouse) - map(vec3(p.x, p.y, p.z - 0.01), u_time, u_resolution, u_mouse)
            ));
            
            float fresnel = pow(1.0 - max(0.0, dot(n, -rayDir)), 5.0);
            vec3 waterColor = mix(vec3(0.0, 0.45, 0.55), vec3(0.0, 0.8, 0.8), p.y * 0.5 + 0.5);
            vec3 skyReflect = vec3(0.8, 0.95, 1.0);
            color = mix(waterColor, skyReflect, fresnel);
            
            vec3 lightDir = normalize(vec3(0.5, 1.0, 0.5));
            float spec = pow(max(0.0, dot(reflect(-lightDir, n), -rayDir)), 60.0);
            color += vec3(1.0, 1.0, 0.9) * spec * 0.6;
            color += (1.0 - fresnel) * 0.1 * vec3(0.5, 1.0, 0.9);
        }

        color = mix(color, vec3(0.6, 0.85, 0.9), smoothstep(10.0, 25.0, t));
        gl_FragColor = vec4(color, 1.0);
    }
`;

const GeneratedComponent: React.FC = () => {
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const fallbackCanvasRef = useRef<HTMLCanvasElement>(null);
    const [useFallback, setUseFallback] = useState(false);
    const mouseRef = useRef({ x: 0, y: 0 });
    const requestRef = useRef<number>();
    const startTimeRef = useRef<number>(Date.now());

    useEffect(() => {
        const canvas = canvasRef.current;
        if (!canvas) return;

        const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') as WebGLRenderingContext | null;

        if (!gl) {
            setUseFallback(true);
            return;
        }

        const createShader = (gl: WebGLRenderingContext, type: number, source: string) => {
            const shader = gl.createShader(type);
            if (!shader) return null;
            gl.shaderSource(shader, source);
            gl.compileShader(shader);
            if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
                console.error(gl.getShaderInfoLog(shader));
                gl.deleteShader(shader);
                return null;
            }
            return shader;
        };

        const createProgram = (gl: WebGLRenderingContext, vs: WebGLShader, fs: WebGLShader) => {
            const program = gl.createProgram();
            if (!program) return null;
            gl.attachShader(program, vs);
            gl.attachShader(program, fs);
            gl.linkProgram(program);
            if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
                console.error(gl.getProgramInfoLog(program));
                return null;
            }
            return program;
        };

        const vShader = createShader(gl, gl.VERTEX_SHADER, VERTEX_SHADER);
        const fShader = createShader(gl, gl.FRAGMENT_SHADER, FRAGMENT_SHADER);
        if (!vShader || !fShader) {
            setUseFallback(true);
            return;
        }

        const program = createProgram(gl, vShader, fShader);
        if (!program) {
            setUseFallback(true);
            return;
        }

        const positionBuffer = gl.createBuffer();
        gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
        const positions = new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]);
        gl.bufferData(gl.ARRAY_BUFFER, positions, gl.STATIC_DRAW);

        const resize = () => {
            canvas.width = window.innerWidth * window.devicePixelRatio;
            canvas.height = window.innerHeight * window.devicePixelRatio;
            gl.viewport(0, 0, canvas.width, canvas.height);
        };

        const handleMouseMove = (e: MouseEvent) => {
            mouseRef.current = { x: e.clientX, y: e.clientY };
        };

        const render = () => {
            gl.clearColor(0, 0, 0, 1);
            gl.clear(gl.COLOR_BUFFER_BIT);

            gl.useProgram(program);

            const positionLoc = gl.getAttribLocation(program, "position");
            gl.enableVertexAttribArray(positionLoc);
            gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, false, 0, 0);

            const timeLoc = gl.getUniformLocation(program, "u_time");
            gl.uniform1f(timeLoc, (Date.now() - startTimeRef.current) / 1000.0);

            const resLoc = gl.getUniformLocation(program, "u_resolution");
            gl.uniform2f(resLoc, canvas.width, canvas.height);

            const mouseLoc = gl.getUniformLocation(program, "u_mouse");
            gl.uniform2f(mouseLoc, mouseRef.current.x * window.devicePixelRatio, (window.innerHeight - mouseRef.current.y) * window.devicePixelRatio);

            gl.drawArrays(gl.TRIANGLES, 0, 6);
            requestRef.current = requestAnimationFrame(render);
        };

        window.addEventListener('resize', resize);
        window.addEventListener('mousemove', handleMouseMove);
        resize();
        requestRef.current = requestAnimationFrame(render);

        return () => {
            window.removeEventListener('resize', resize);
            window.removeEventListener('mousemove', handleMouseMove);
            if (requestRef.current) cancelAnimationFrame(requestRef.current);
        };
    }, []);

    useEffect(() => {
        if (!useFallback) return;

        const canvas = fallbackCanvasRef.current;
        if (!canvas) return;
        const ctx = canvas.getContext('2d');
        if (!ctx) return;

        let fallbackReq: number;

        const resizeFallback = () => {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
        };

        const drawFallback = () => {
            const time = Date.now() * 0.001;
            const grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
            grad.addColorStop(0, '#4facfe');
            grad.addColorStop(1, '#00f2fe');
            ctx.fillStyle = grad;
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            ctx.fillStyle = 'rgba(255, 255, 255, 0.2)';
            for (let i = 0; i < 50; i++) {
                const x = (Math.sin(time + i) * 0.5 + 0.5) * canvas.width;
                const y = (Math.cos(time * 0.5 + i) * 0.5 + 0.5) * canvas.height;
                ctx.beginPath();
                ctx.arc(x, y, 2 + Math.sin(time + i) * 2, 0, Math.PI * 2);
                ctx.fill();
            }
            fallbackReq = requestAnimationFrame(drawFallback);
        };

        window.addEventListener('resize', resizeFallback);
        resizeFallback();
        fallbackReq = requestAnimationFrame(drawFallback);

        return () => {
            window.removeEventListener('resize', resizeFallback);
            cancelAnimationFrame(fallbackReq);
        };
    }, [useFallback]);

    return (
        <div className="relative w-full h-screen overflow-hidden bg-zinc-950">
            {!useFallback ? (
                <canvas 
                    ref={canvasRef} 
                    className="block w-full h-full cursor-crosshair"
                />
            ) : (
                <>
                    <canvas 
                        ref={fallbackCanvasRef} 
                        className="fixed top-0 left-0 w-full h-full -z-10"
                    />
                    <div className="flex flex-col items-center justify-center w-full h-full text-white font-sans bg-transparent">
                        <h1 className="text-4xl font-bold mb-4">Tropical Ocean</h1>
                        <p>WebGL is not supported in your browser. Using fallback animation.</p>
                    </div>
                </>
            )}
        </div>
    );
};

export default GeneratedComponent;

More by ashish rajwani

View all
  • ASMR background

    ASMR background

    685
  • animated pattern cloud

    animated pattern cloud

    616
  • Balloons Pop background

    Balloons Pop background

    362
  • realistic fog background

    realistic fog background

    309
  • 3d animated stars background

    3d animated stars background

    3
  • Matrix background

    Matrix background

    1
  • tab pages

    tab pages

    1
  • sleek text input

    sleek text input

More in Shaders

View all
  • Glass Fold

    Glass Fold

    213
  • Neural Noise

    Neural Noise

    718
  • Water Caustic

    Water Caustic

    44
  • Shader Background

    Shader Background

    2K
  • Wave

    Wave

    688
  • Stripe like gradient-shader

    Stripe like gradient-shader

    265
  • Black Hole

    Black Hole

    23
  • Waves shaders Homlu UI

    Waves shaders Homlu UI

    92