{ "aspect_ratio": "3:4", "image_input": [], "output_format": "jpg", "prompt": "render this: /**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\n\n\nimport React, { useRef, useEffect } from 'react';\nimport { useAppContext } from '../context/AppContext';\n\n// A simple full-screen quad vertex shader\nconst VERTEX_SHADER = `#version 300 es\nin vec2 a_position;\nout vec2 v_uv;\nvoid main() {\n v_uv = a_position;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\nin vec2 v_uv;\nout vec4 outColor;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform mat4 u_shipRot;\nuniform float u_thrust;\nuniform float u_brake;\nuniform float u_yaw_velocity;\nuniform float u_pitch_velocity;\nuniform float u_thrust_ignition_time;\n\n// Ship DNA from sliders\nuniform float u_complexity;\nuniform float u_fold1;\nuniform float u_fold2;\nuniform float u_fold3;\nuniform float u_scale;\nuniform float u_stretch;\nuniform float u_taper;\nuniform float u_twist;\nuniform float u_asymmetryX;\nuniform float u_asymmetryY;\nuniform float u_asymmetryZ;\n\n// Parameter Biases\nuniform float u_twistAsymX;\nuniform float u_scaleAsymX;\nuniform float u_fold1AsymX;\nuniform float u_fold2AsymX;\n\nuniform float u_generalScale;\nuniform float u_chaseDistance;\nuniform float u_chaseVerticalOffset;\nuniform float u_translucency;\n\n#define MAX_STEPS 64\n#define MAX_DIST 15.0\n#define SURF_DIST 0.001\n\nmat2 rot(float a) { float s=sin(a), c=cos(a); return mat2(c, -s, s, c); }\n\n// KIFS Fractal for Ship Body\nfloat sdFractalShip(vec3 p) {\n // Store original position for asymmetry calculations\n vec3 pOrig = p;\n\n // Apply Asymmetry Distortion first (Spatial scaling based on sign)\n p.x *= 1.0 - sign(p.x) * u_asymmetryX * 0.5;\n p.y *= 1.0 - sign(p.y) * u_asymmetryY * 0.5;\n p.z *= 1.0 - sign(p.z) * u_asymmetryZ * 0.5;\n\n p /= u_generalScale;\n p.z /= u_stretch; // Longitudinal stretch\n \n // Tapering along Z axis (before rotation, Z is longitudinal)\n p.xy *= 1.0 + p.z * u_taper;\n\n // --- Asymmetric Twisting ---\n // Base twist + gradient based on original X position\n // If u_twistAsymX > 0, positive X (Right) twists more.\n float localTwist = u_twist + pOrig.x * u_twistAsymX;\n p.xy *= rot(p.z * localTwist * 2.0);\n\n // Initial orientation to make it face forward (-Z)\n p.yz *= rot(1.57); \n\n float s = 1.0;\n for(int i=0; i<int(u_complexity); i++) {\n // --- Asymmetric Folding ---\n // Base fold + gradient based on original X position\n // Note: pOrig.x is used to keep the bias fixed to the ship's original side\n float localFold1 = u_fold1 + pOrig.x * u_fold1AsymX;\n float localFold2 = u_fold2 + pOrig.x * u_fold2AsymX;\n\n // Folding space\n p = abs(p) - vec3(localFold1, localFold2, 0.3)/s;\n p.xz *= rot(u_fold3);\n \n // --- Asymmetric Scaling ---\n float localScale = u_scale + pOrig.x * u_scaleAsymX * 0.2;\n p *= localScale;\n s *= localScale;\n }\n // Base shape: a box that gets folded into the fractal\n float d = length(max(abs(p) - vec3(0.1, 0.8, 0.1), 0.0));\n return d/s * u_generalScale;\n}\n\n// Main SDF mapping the whole ship\nfloat map(vec3 p) {\n // Apply ship rotation (pitch/yaw/roll)\n p = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n\n // Main Body\n float dBody = sdFractalShip(p);\n \n // Engines (simple cylinders at the back)\n vec3 pEng = p;\n pEng.x = abs(pEng.x);\n pEng -= vec3(0.5, 0.0, 1.2); // Position at back\n float dEng = max(length(pEng.xy) - 0.2, abs(pEng.z) - 0.4);\n \n // Flaps (boxes at sides)\n vec3 pFlap = p;\n pFlap.x = abs(pFlap.x);\n pFlap -= vec3(1.1, 0.0, 0.2);\n // Rotate flaps when braking\n pFlap.yz *= rot(u_brake * 0.8);\n float dFlap = length(max(abs(pFlap) - vec3(0.4, 0.05, 0.3), 0.0));\n\n // Smooth blend body and dynamic parts\n float d = -log(exp(-dBody*12.0) + exp(-dEng*12.0) + exp(-dFlap*12.0)) / 12.0;\n return d;\n}\n\n// Calculate normal for lighting\nvec3 getNormal(vec3 p) {\n vec2 e = vec2(0.001, 0.0);\n return normalize(vec3(\n map(p + e.xyy) - map(p - e.xyy),\n map(p + e.yxy) - map(p - e.yxy),\n map(p + e.yyx) - map(p - e.yyx)\n ));\n}\n\nvoid main() {\n // Setup Ray from Chase Camera perspective\n vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / u_resolution.y;\n vec3 ro = vec3(0.0, u_chaseVerticalOffset, u_chaseDistance); // Fixed chase camera relative to ship center (0,0,0)\n vec3 rd = normalize(vec3(uv, -1.5)); // Looking forward (-Z)\n\n float d = 0.0, t = 0.0;\n for(int i = 0; i < MAX_STEPS; i++) {\n vec3 p = ro + rd * t;\n d = map(p);\n if(d < SURF_DIST || t > MAX_DIST) break;\n t += d;\n }\n\n if(t < MAX_DIST) {\n vec3 p = ro + rd * t;\n vec3 n = getNormal(p);\n vec3 l = normalize(vec3(1.0, 2.0, 3.0)); // Fixed light source\n\n // Basic lighting\n float diff = max(dot(n, l), 0.0);\n float amb = 0.1;\n vec3 col = vec3(0.2, 0.25, 0.3) * (diff + amb);\n \n // Rim lighting\n float rim = pow(1.0 - max(dot(-rd, n), 0.0), 4.0);\n col += vec3(0.1, 0.6, 1.0) * rim * 0.8;\n\n // Calculate local coordinates for emissive mapping\n vec3 localP = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n \n // --- Engine Glow ---\n // Wider mask to accommodate the ignition animation starting point\n float engineMask = smoothstep(0.4, 1.5, localP.z) * (1.0 - smoothstep(0.4, 1.0, abs(localP.x)));\n \n // Ignition Animation\n float timeSinceIgnition = u_time - u_thrust_ignition_time;\n float ignitionDuration = 0.3; // Animation duration in seconds\n\n // Ignition pulse travels from front (z=0.5) to back (z=1.5)\n float pulseProgress = clamp(timeSinceIgnition / ignitionDuration, 0.0, 1.0);\n float ignitionFrontZ = mix(0.5, 1.5, pulseProgress);\n\n // Moving pulse of light\n float pulseWidth = 0.15;\n float pulseShape = smoothstep(0.0, pulseWidth, localP.z - (ignitionFrontZ - pulseWidth)) * \n smoothstep(0.0, -pulseWidth, localP.z - (ignitionFrontZ + pulseWidth));\n float pulseGlow = pulseShape * 2.5 * (1.0 - pulseProgress); // Bright pulse that fades\n\n // Sustained Glow\n float wave1 = sin(localP.z * 8.0) * 0.5 + 0.5;\n float wave2 = sin(localP.z * 5.0) * 0.5 + 0.5;\n float sustainedIntensity = 0.2 + pow(wave1, 3.0) * 1.0 + pow(wave2, 5.0) * 0.8;\n\n // The sustained glow appears as the ignition pulse passes over it\n float sustainedVisibility = smoothstep(ignitionFrontZ - 0.2, ignitionFrontZ, localP.z);\n if (timeSinceIgnition > ignitionDuration) {\n sustainedVisibility = 1.0; // Fully visible after animation\n }\n float finalSustainedGlow = mix(0.1, sustainedIntensity, u_thrust * sustainedVisibility);\n\n // Combine glows\n float totalGlow = finalSustainedGlow + pulseGlow;\n col += vec3(1.0, 0.4, 0.05) * engineMask * totalGlow;\n\n // Flap Glow - asymmetric for turning\n float leftBrakeAmount = u_brake + max(0.0, u_yaw_velocity * 2.5); // Turn right, left brake lights up\n float rightBrakeAmount = u_brake + max(0.0, -u_yaw_velocity * 2.5); // Turn left, right brake lights up\n\n float flapMaskLeft = smoothstep(0.8, 1.6, localP.x) * (1.0 - smoothstep(0.0, 0.8, -localP.x));\n float flapMaskRight = smoothstep(0.8, 1.6, -localP.x) * (1.0 - smoothstep(0.0, 0.8, localP.x));\n\n col += vec3(1.0, 0.1, 0.1) * flapMaskLeft * leftBrakeAmount * 2.0;\n col += vec3(1.0, 0.1, 0.1) * flapMaskRight * rightBrakeAmount * 2.0;\n\n // Pitch maneuver lights\n // Pitching up (negative velocity) lights bottom. Pitching down (positive velocity) lights top.\n float pitchUpAmount = max(0.0, -u_pitch_velocity * 4.0);\n float pitchDownAmount = max(0.0, u_pitch_velocity * 4.0);\n\n // Define masks for top and bottom surfaces, concentrated on the main body/wings area\n float pitchLightAreaMask = smoothstep(0.8, 0.0, abs(localP.z));\n float topMask = smoothstep(0.2, 0.4, localP.y) * pitchLightAreaMask;\n float bottomMask = smoothstep(-0.2, -0.4, localP.y) * pitchLightAreaMask;\n\n col += vec3(1.0, 0.1, 0.1) * topMask * pitchDownAmount;\n col += vec3(1.0, 0.1, 0.1) * bottomMask * pitchUpAmount;\n\n // Add alpha for transparency around the ship\n outColor = vec4(col, u_translucency);\n } else {\n outColor = vec4(0.0); // Transparent background\n }\n}\n`;\n\nconst mat4 = {\n identity: (out: Float32Array) => { out.fill(0); out[0]=1; out[5]=1; out[10]=1; out[15]=1; },\n rotateX: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a10=a[4],a11=a[5],a12=a[6],a13=a[7], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[4]=a10*c+a20*s; out[5]=a11*c+a21*s; out[6]=a12*c+a22*s; out[7]=a13*c+a23*s;\n out[8]=a20*c-a10*s; out[9]=a21*c-a11*s; out[10]=a22*c-a12*s; out[11]=a23*c-a13*s;\n },\n rotateY: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[0]=a00*c-a20*s; out[1]=a01*c-a21*s; out[2]=a02*c-a22*s; out[3]=a03*c-a23*s;\n out[8]=a00*s+a20*c; out[9]=a01*s+a21*c; out[10]=a02*s+a22*c; out[11]=a03*s+a23*c;\n },\n rotateZ: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a10=a[4],a11=a[5],a12=a[6],a13=a[7];\n out.set(a);\n out[0]=a00*c+a10*s; out[1]=a01*c+a11*s; out[2]=a02*c+a13*s; out[3]=a03*c+a13*s;\n out[4]=a10*c-a00*s; out[5]=a11*c-a01*s; out[6]=a12*c-a02*s; out[7]=a13*c-a03*s;\n },\n};\n\nexport const ShipOverlay: React.FC = () => {\n const { viewMode, pressedKeys, controlConfig, effectiveShipConfigRef, cameraAngularVelocityRef, shipConfig } = useAppContext();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const shipState = useRef({ pitch: 0, yaw: 0, roll: 0 });\n\n const shipConfigRef = useRef(shipConfig);\n useEffect(() => { shipConfigRef.current = shipConfig; }, [shipConfig]);\n \n const pressedKeysRef = useRef(pressedKeys);\n useEffect(() => { pressedKeysRef.current = pressedKeys; }, [pressedKeys]);\n \n const controlConfigRef = useRef(controlConfig);\n useEffect(() => { controlConfigRef.current = controlConfig; }, [controlConfig]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || viewMode !== 'chase') return;\n const gl = canvas.getContext('webgl2', { alpha: true, depth: false, antialias: false }); // No depth needed for single quad\n if (!gl) return;\n\n // Enable blending for translucency\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n\n const compile = (type: number, src: string) => {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) console.error(gl.getShaderInfoLog(s));\n return s;\n };\n const p = gl.createProgram()!;\n gl.attachShader(p, compile(gl.VERTEX_SHADER, VERTEX_SHADER));\n gl.attachShader(p, compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER));\n gl.linkProgram(p);\n gl.useProgram(p);\n\n // Uniform locations\n const locs = {\n uRes: gl.getUniformLocation(p, 'u_resolution'),\n uTime: gl.getUniformLocation(p, 'u_time'),\n uShipRot: gl.getUniformLocation(p, 'u_shipRot'),\n uThrust: gl.getUniformLocation(p, 'u_thrust'),\n uThrustIgnitionTime: gl.getUniformLocation(p, 'u_thrust_ignition_time'),\n uBrake: gl.getUniformLocation(p, 'u_brake'),\n uYawVelocity: gl.getUniformLocation(p, 'u_yaw_velocity'),\n uPitchVelocity: gl.getUniformLocation(p, 'u_pitch_velocity'),\n // Ship DNA\n uComplexity: gl.getUniformLocation(p, 'u_complexity'),\n uFold1: gl.getUniformLocation(p, 'u_fold1'),\n uFold2: gl.getUniformLocation(p, 'u_fold2'),\n uFold3: gl.getUniformLocation(p, 'u_fold3'),\n uScale: gl.getUniformLocation(p, 'u_scale'),\n uStretch: gl.getUniformLocation(p, 'u_stretch'),\n uTaper: gl.getUniformLocation(p, 'u_taper'),\n uTwist: gl.getUniformLocation(p, 'u_twist'),\n uAsymmetryX: gl.getUniformLocation(p, 'u_asymmetryX'),\n uAsymmetryY: gl.getUniformLocation(p, 'u_asymmetryY'),\n uAsymmetryZ: gl.getUniformLocation(p, 'u_asymmetryZ'),\n \n // New Bias Uniforms\n uTwistAsymX: gl.getUniformLocation(p, 'u_twistAsymX'),\n uScaleAsymX: gl.getUniformLocation(p, 'u_scaleAsymX'),\n uFold1AsymX: gl.getUniformLocation(p, 'u_fold1AsymX'),\n uFold2AsymX: gl.getUniformLocation(p, 'u_fold2AsymX'),\n\n uGeneralScale: gl.getUniformLocation(p, 'u_generalScale'),\n uChaseDistance: gl.getUniformLocation(p, 'u_chaseDistance'),\n uChaseVerticalOffset: gl.getUniformLocation(p, 'u_chaseVerticalOffset'),\n uTranslucency: gl.getUniformLocation(p, 'u_translucency'),\n };\n\n // Fullscreen quad\n const vao = gl.createVertexArray()!;\n gl.bindVertexArray(vao);\n const vbo = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n const rotMat = new Float32Array(16);\n let lastTime = 0, animId = 0;\n\n // State for smooth thrust/brake animation, now with ignition tracking\n const thrustState = {\n level: 0.0,\n isThrusting: false,\n ignitionTime: -100.0, // Start far in the past to avoid animation on load\n };\n const brakeLevel = { current: 0.0 };\n\n const render = (t: number) => {\n const dt = Math.min((t - lastTime) / 1000, 0.1);\n const currentTimeSec = t * 0.001;\n lastTime = t;\n \n const dpr = window.devicePixelRatio || 1;\n const w = canvas.clientWidth * dpr, h = canvas.clientHeight * dpr;\n if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; gl.viewport(0, 0, w, h); }\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n const isThrustingNow = (pressedKeysRef.current.has('s') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('w') && controlConfigRef.current.invertForward);\n const isBraking = (pressedKeysRef.current.has('w') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('s') && controlConfigRef.current.invertForward);\n \n // Detect ignition start\n if (isThrustingNow && !thrustState.isThrusting) {\n thrustState.ignitionTime = currentTimeSec;\n }\n thrustState.isThrusting = isThrustingNow;\n \n // LERP for smooth animation\n const LERP_SPEED = 8.0;\n thrustState.level += ((isThrustingNow ? 1.0 : 0.0) - thrustState.level) * LERP_SPEED * dt;\n brakeLevel.current += ((isBraking ? 1.0 : 0.0) - brakeLevel.current) * LERP_SPEED * dt;\n \n // Use actual physics angular velocity for smoother, heavier animation\n // Negate yaw velocity because camera yaw is inverted relative to ship yaw visually\n const tYaw = -cameraAngularVelocityRef.current[1] * 1.2; \n const tPitch_velocity = cameraAngularVelocityRef.current[0];\n // Invert pitch velocity to match user preference (UP looks UP)\n const tPitch = -tPitch_velocity * 1.0 + (shipConfigRef.current.pitchOffset ?? 0.0);\n\n // Slower lerp for heavier feel (3.0 instead of 8.0)\n shipState.current.yaw += (tYaw - shipState.current.yaw) * 3.0 * dt;\n shipState.current.pitch += (tPitch - shipState.current.pitch) * 3.0 * dt;\n // Roll based on yaw for banking\n shipState.current.roll += (tYaw * 1.5 - shipState.current.roll) * 3.0 * dt;\n\n mat4.identity(rotMat);\n mat4.rotateY(rotMat, rotMat, shipState.current.yaw);\n mat4.rotateX(rotMat, rotMat, shipState.current.pitch);\n mat4.rotateZ(rotMat, rotMat, shipState.current.roll);\n\n gl.useProgram(p);\n gl.uniform2f(locs.uRes, w, h);\n gl.uniform1f(locs.uTime, currentTimeSec);\n gl.uniformMatrix4fv(locs.uShipRot, false, rotMat);\n gl.uniform1f(locs.uThrust, thrustState.level);\n gl.uniform1f(locs.uThrustIgnitionTime, thrustState.ignitionTime);\n gl.uniform1f(locs.uBrake, brakeLevel.current);\n gl.uniform1f(locs.uYawVelocity, tYaw);\n gl.uniform1f(locs.uPitchVelocity, tPitch_velocity);\n \n // Update DNA uniforms from EFFECTIVE config (includes modulations)\n const ec = effectiveShipConfigRef.current;\n gl.uniform1f(locs.uComplexity, ec.complexity);\n gl.uniform1f(locs.uFold1, ec.fold1);\n gl.uniform1f(locs.uFold2, ec.fold2);\n gl.uniform1f(locs.uFold3, ec.fold3);\n gl.uniform1f(locs.uScale, ec.scale);\n gl.uniform1f(locs.uStretch, ec.stretch);\n gl.uniform1f(locs.uTaper, ec.taper);\n gl.uniform1f(locs.uTwist, ec.twist);\n gl.uniform1f(locs.uAsymmetryX, ec.asymmetryX);\n gl.uniform1f(locs.uAsymmetryY, ec.asymmetryY);\n gl.uniform1f(locs.uAsymmetryZ, ec.asymmetryZ);\n\n // New Bias Uniforms\n gl.uniform1f(locs.uTwistAsymX, ec.twistAsymX);\n gl.uniform1f(locs.uScaleAsymX, ec.scaleAsymX);\n gl.uniform1f(locs.uFold1AsymX, ec.fold1AsymX);\n gl.uniform1f(locs.uFold2AsymX, ec.fold2AsymX);\n\n gl.uniform1f(locs.uGeneralScale, shipConfigRef.current.generalScale ?? 1.0);\n gl.uniform1f(locs.uChaseDistance, shipConfigRef.current.chaseDistance ?? 6.5);\n gl.uniform1f(locs.uChaseVerticalOffset, shipConfigRef.current.chaseVerticalOffset ?? 1.0);\n gl.uniform1f(locs.uTranslucency, shipConfigRef.current.translucency ?? 1.0);\n\n gl.bindVertexArray(vao);\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n animId = requestAnimationFrame(render);\n };\n render(performance.now());\n return () => { cancelAnimationFrame(animId); gl.deleteProgram(p); };\n }, [viewMode]);\n\n if (viewMode !== 'chase') return null;\n return <canvas ref={canvasRef} className=\"absolute top-0 left-0 w-full h-full pointer-events-none z-10\" />;\n};", "resolution": "2K", "safety_filter_level": "block_only_high" }
npm install replicate
REPLICATE_API_TOKEN
export REPLICATE_API_TOKEN=r8_FVs**********************************
This is your API token. Keep it to yourself.
import Replicate from "replicate"; import fs from "node:fs"; const replicate = new Replicate({ auth: process.env.REPLICATE_API_TOKEN, });
Run google/nano-banana-pro using Replicate’s API. Check out the model's schema for an overview of inputs and outputs.
const input = { aspect_ratio: "3:4", image_input: [], output_format: "jpg", prompt: "render this: /**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\n\n\nimport React, { useRef, useEffect } from 'react';\nimport { useAppContext } from '../context/AppContext';\n\n// A simple full-screen quad vertex shader\nconst VERTEX_SHADER = `#version 300 es\nin vec2 a_position;\nout vec2 v_uv;\nvoid main() {\n v_uv = a_position;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\nin vec2 v_uv;\nout vec4 outColor;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform mat4 u_shipRot;\nuniform float u_thrust;\nuniform float u_brake;\nuniform float u_yaw_velocity;\nuniform float u_pitch_velocity;\nuniform float u_thrust_ignition_time;\n\n// Ship DNA from sliders\nuniform float u_complexity;\nuniform float u_fold1;\nuniform float u_fold2;\nuniform float u_fold3;\nuniform float u_scale;\nuniform float u_stretch;\nuniform float u_taper;\nuniform float u_twist;\nuniform float u_asymmetryX;\nuniform float u_asymmetryY;\nuniform float u_asymmetryZ;\n\n// Parameter Biases\nuniform float u_twistAsymX;\nuniform float u_scaleAsymX;\nuniform float u_fold1AsymX;\nuniform float u_fold2AsymX;\n\nuniform float u_generalScale;\nuniform float u_chaseDistance;\nuniform float u_chaseVerticalOffset;\nuniform float u_translucency;\n\n#define MAX_STEPS 64\n#define MAX_DIST 15.0\n#define SURF_DIST 0.001\n\nmat2 rot(float a) { float s=sin(a), c=cos(a); return mat2(c, -s, s, c); }\n\n// KIFS Fractal for Ship Body\nfloat sdFractalShip(vec3 p) {\n // Store original position for asymmetry calculations\n vec3 pOrig = p;\n\n // Apply Asymmetry Distortion first (Spatial scaling based on sign)\n p.x *= 1.0 - sign(p.x) * u_asymmetryX * 0.5;\n p.y *= 1.0 - sign(p.y) * u_asymmetryY * 0.5;\n p.z *= 1.0 - sign(p.z) * u_asymmetryZ * 0.5;\n\n p /= u_generalScale;\n p.z /= u_stretch; // Longitudinal stretch\n \n // Tapering along Z axis (before rotation, Z is longitudinal)\n p.xy *= 1.0 + p.z * u_taper;\n\n // --- Asymmetric Twisting ---\n // Base twist + gradient based on original X position\n // If u_twistAsymX > 0, positive X (Right) twists more.\n float localTwist = u_twist + pOrig.x * u_twistAsymX;\n p.xy *= rot(p.z * localTwist * 2.0);\n\n // Initial orientation to make it face forward (-Z)\n p.yz *= rot(1.57); \n\n float s = 1.0;\n for(int i=0; i<int(u_complexity); i++) {\n // --- Asymmetric Folding ---\n // Base fold + gradient based on original X position\n // Note: pOrig.x is used to keep the bias fixed to the ship's original side\n float localFold1 = u_fold1 + pOrig.x * u_fold1AsymX;\n float localFold2 = u_fold2 + pOrig.x * u_fold2AsymX;\n\n // Folding space\n p = abs(p) - vec3(localFold1, localFold2, 0.3)/s;\n p.xz *= rot(u_fold3);\n \n // --- Asymmetric Scaling ---\n float localScale = u_scale + pOrig.x * u_scaleAsymX * 0.2;\n p *= localScale;\n s *= localScale;\n }\n // Base shape: a box that gets folded into the fractal\n float d = length(max(abs(p) - vec3(0.1, 0.8, 0.1), 0.0));\n return d/s * u_generalScale;\n}\n\n// Main SDF mapping the whole ship\nfloat map(vec3 p) {\n // Apply ship rotation (pitch/yaw/roll)\n p = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n\n // Main Body\n float dBody = sdFractalShip(p);\n \n // Engines (simple cylinders at the back)\n vec3 pEng = p;\n pEng.x = abs(pEng.x);\n pEng -= vec3(0.5, 0.0, 1.2); // Position at back\n float dEng = max(length(pEng.xy) - 0.2, abs(pEng.z) - 0.4);\n \n // Flaps (boxes at sides)\n vec3 pFlap = p;\n pFlap.x = abs(pFlap.x);\n pFlap -= vec3(1.1, 0.0, 0.2);\n // Rotate flaps when braking\n pFlap.yz *= rot(u_brake * 0.8);\n float dFlap = length(max(abs(pFlap) - vec3(0.4, 0.05, 0.3), 0.0));\n\n // Smooth blend body and dynamic parts\n float d = -log(exp(-dBody*12.0) + exp(-dEng*12.0) + exp(-dFlap*12.0)) / 12.0;\n return d;\n}\n\n// Calculate normal for lighting\nvec3 getNormal(vec3 p) {\n vec2 e = vec2(0.001, 0.0);\n return normalize(vec3(\n map(p + e.xyy) - map(p - e.xyy),\n map(p + e.yxy) - map(p - e.yxy),\n map(p + e.yyx) - map(p - e.yyx)\n ));\n}\n\nvoid main() {\n // Setup Ray from Chase Camera perspective\n vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / u_resolution.y;\n vec3 ro = vec3(0.0, u_chaseVerticalOffset, u_chaseDistance); // Fixed chase camera relative to ship center (0,0,0)\n vec3 rd = normalize(vec3(uv, -1.5)); // Looking forward (-Z)\n\n float d = 0.0, t = 0.0;\n for(int i = 0; i < MAX_STEPS; i++) {\n vec3 p = ro + rd * t;\n d = map(p);\n if(d < SURF_DIST || t > MAX_DIST) break;\n t += d;\n }\n\n if(t < MAX_DIST) {\n vec3 p = ro + rd * t;\n vec3 n = getNormal(p);\n vec3 l = normalize(vec3(1.0, 2.0, 3.0)); // Fixed light source\n\n // Basic lighting\n float diff = max(dot(n, l), 0.0);\n float amb = 0.1;\n vec3 col = vec3(0.2, 0.25, 0.3) * (diff + amb);\n \n // Rim lighting\n float rim = pow(1.0 - max(dot(-rd, n), 0.0), 4.0);\n col += vec3(0.1, 0.6, 1.0) * rim * 0.8;\n\n // Calculate local coordinates for emissive mapping\n vec3 localP = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n \n // --- Engine Glow ---\n // Wider mask to accommodate the ignition animation starting point\n float engineMask = smoothstep(0.4, 1.5, localP.z) * (1.0 - smoothstep(0.4, 1.0, abs(localP.x)));\n \n // Ignition Animation\n float timeSinceIgnition = u_time - u_thrust_ignition_time;\n float ignitionDuration = 0.3; // Animation duration in seconds\n\n // Ignition pulse travels from front (z=0.5) to back (z=1.5)\n float pulseProgress = clamp(timeSinceIgnition / ignitionDuration, 0.0, 1.0);\n float ignitionFrontZ = mix(0.5, 1.5, pulseProgress);\n\n // Moving pulse of light\n float pulseWidth = 0.15;\n float pulseShape = smoothstep(0.0, pulseWidth, localP.z - (ignitionFrontZ - pulseWidth)) * \n smoothstep(0.0, -pulseWidth, localP.z - (ignitionFrontZ + pulseWidth));\n float pulseGlow = pulseShape * 2.5 * (1.0 - pulseProgress); // Bright pulse that fades\n\n // Sustained Glow\n float wave1 = sin(localP.z * 8.0) * 0.5 + 0.5;\n float wave2 = sin(localP.z * 5.0) * 0.5 + 0.5;\n float sustainedIntensity = 0.2 + pow(wave1, 3.0) * 1.0 + pow(wave2, 5.0) * 0.8;\n\n // The sustained glow appears as the ignition pulse passes over it\n float sustainedVisibility = smoothstep(ignitionFrontZ - 0.2, ignitionFrontZ, localP.z);\n if (timeSinceIgnition > ignitionDuration) {\n sustainedVisibility = 1.0; // Fully visible after animation\n }\n float finalSustainedGlow = mix(0.1, sustainedIntensity, u_thrust * sustainedVisibility);\n\n // Combine glows\n float totalGlow = finalSustainedGlow + pulseGlow;\n col += vec3(1.0, 0.4, 0.05) * engineMask * totalGlow;\n\n // Flap Glow - asymmetric for turning\n float leftBrakeAmount = u_brake + max(0.0, u_yaw_velocity * 2.5); // Turn right, left brake lights up\n float rightBrakeAmount = u_brake + max(0.0, -u_yaw_velocity * 2.5); // Turn left, right brake lights up\n\n float flapMaskLeft = smoothstep(0.8, 1.6, localP.x) * (1.0 - smoothstep(0.0, 0.8, -localP.x));\n float flapMaskRight = smoothstep(0.8, 1.6, -localP.x) * (1.0 - smoothstep(0.0, 0.8, localP.x));\n\n col += vec3(1.0, 0.1, 0.1) * flapMaskLeft * leftBrakeAmount * 2.0;\n col += vec3(1.0, 0.1, 0.1) * flapMaskRight * rightBrakeAmount * 2.0;\n\n // Pitch maneuver lights\n // Pitching up (negative velocity) lights bottom. Pitching down (positive velocity) lights top.\n float pitchUpAmount = max(0.0, -u_pitch_velocity * 4.0);\n float pitchDownAmount = max(0.0, u_pitch_velocity * 4.0);\n\n // Define masks for top and bottom surfaces, concentrated on the main body/wings area\n float pitchLightAreaMask = smoothstep(0.8, 0.0, abs(localP.z));\n float topMask = smoothstep(0.2, 0.4, localP.y) * pitchLightAreaMask;\n float bottomMask = smoothstep(-0.2, -0.4, localP.y) * pitchLightAreaMask;\n\n col += vec3(1.0, 0.1, 0.1) * topMask * pitchDownAmount;\n col += vec3(1.0, 0.1, 0.1) * bottomMask * pitchUpAmount;\n\n // Add alpha for transparency around the ship\n outColor = vec4(col, u_translucency);\n } else {\n outColor = vec4(0.0); // Transparent background\n }\n}\n`;\n\nconst mat4 = {\n identity: (out: Float32Array) => { out.fill(0); out[0]=1; out[5]=1; out[10]=1; out[15]=1; },\n rotateX: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a10=a[4],a11=a[5],a12=a[6],a13=a[7], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[4]=a10*c+a20*s; out[5]=a11*c+a21*s; out[6]=a12*c+a22*s; out[7]=a13*c+a23*s;\n out[8]=a20*c-a10*s; out[9]=a21*c-a11*s; out[10]=a22*c-a12*s; out[11]=a23*c-a13*s;\n },\n rotateY: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[0]=a00*c-a20*s; out[1]=a01*c-a21*s; out[2]=a02*c-a22*s; out[3]=a03*c-a23*s;\n out[8]=a00*s+a20*c; out[9]=a01*s+a21*c; out[10]=a02*s+a22*c; out[11]=a03*s+a23*c;\n },\n rotateZ: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a10=a[4],a11=a[5],a12=a[6],a13=a[7];\n out.set(a);\n out[0]=a00*c+a10*s; out[1]=a01*c+a11*s; out[2]=a02*c+a13*s; out[3]=a03*c+a13*s;\n out[4]=a10*c-a00*s; out[5]=a11*c-a01*s; out[6]=a12*c-a02*s; out[7]=a13*c-a03*s;\n },\n};\n\nexport const ShipOverlay: React.FC = () => {\n const { viewMode, pressedKeys, controlConfig, effectiveShipConfigRef, cameraAngularVelocityRef, shipConfig } = useAppContext();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const shipState = useRef({ pitch: 0, yaw: 0, roll: 0 });\n\n const shipConfigRef = useRef(shipConfig);\n useEffect(() => { shipConfigRef.current = shipConfig; }, [shipConfig]);\n \n const pressedKeysRef = useRef(pressedKeys);\n useEffect(() => { pressedKeysRef.current = pressedKeys; }, [pressedKeys]);\n \n const controlConfigRef = useRef(controlConfig);\n useEffect(() => { controlConfigRef.current = controlConfig; }, [controlConfig]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || viewMode !== 'chase') return;\n const gl = canvas.getContext('webgl2', { alpha: true, depth: false, antialias: false }); // No depth needed for single quad\n if (!gl) return;\n\n // Enable blending for translucency\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n\n const compile = (type: number, src: string) => {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) console.error(gl.getShaderInfoLog(s));\n return s;\n };\n const p = gl.createProgram()!;\n gl.attachShader(p, compile(gl.VERTEX_SHADER, VERTEX_SHADER));\n gl.attachShader(p, compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER));\n gl.linkProgram(p);\n gl.useProgram(p);\n\n // Uniform locations\n const locs = {\n uRes: gl.getUniformLocation(p, 'u_resolution'),\n uTime: gl.getUniformLocation(p, 'u_time'),\n uShipRot: gl.getUniformLocation(p, 'u_shipRot'),\n uThrust: gl.getUniformLocation(p, 'u_thrust'),\n uThrustIgnitionTime: gl.getUniformLocation(p, 'u_thrust_ignition_time'),\n uBrake: gl.getUniformLocation(p, 'u_brake'),\n uYawVelocity: gl.getUniformLocation(p, 'u_yaw_velocity'),\n uPitchVelocity: gl.getUniformLocation(p, 'u_pitch_velocity'),\n // Ship DNA\n uComplexity: gl.getUniformLocation(p, 'u_complexity'),\n uFold1: gl.getUniformLocation(p, 'u_fold1'),\n uFold2: gl.getUniformLocation(p, 'u_fold2'),\n uFold3: gl.getUniformLocation(p, 'u_fold3'),\n uScale: gl.getUniformLocation(p, 'u_scale'),\n uStretch: gl.getUniformLocation(p, 'u_stretch'),\n uTaper: gl.getUniformLocation(p, 'u_taper'),\n uTwist: gl.getUniformLocation(p, 'u_twist'),\n uAsymmetryX: gl.getUniformLocation(p, 'u_asymmetryX'),\n uAsymmetryY: gl.getUniformLocation(p, 'u_asymmetryY'),\n uAsymmetryZ: gl.getUniformLocation(p, 'u_asymmetryZ'),\n \n // New Bias Uniforms\n uTwistAsymX: gl.getUniformLocation(p, 'u_twistAsymX'),\n uScaleAsymX: gl.getUniformLocation(p, 'u_scaleAsymX'),\n uFold1AsymX: gl.getUniformLocation(p, 'u_fold1AsymX'),\n uFold2AsymX: gl.getUniformLocation(p, 'u_fold2AsymX'),\n\n uGeneralScale: gl.getUniformLocation(p, 'u_generalScale'),\n uChaseDistance: gl.getUniformLocation(p, 'u_chaseDistance'),\n uChaseVerticalOffset: gl.getUniformLocation(p, 'u_chaseVerticalOffset'),\n uTranslucency: gl.getUniformLocation(p, 'u_translucency'),\n };\n\n // Fullscreen quad\n const vao = gl.createVertexArray()!;\n gl.bindVertexArray(vao);\n const vbo = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n const rotMat = new Float32Array(16);\n let lastTime = 0, animId = 0;\n\n // State for smooth thrust/brake animation, now with ignition tracking\n const thrustState = {\n level: 0.0,\n isThrusting: false,\n ignitionTime: -100.0, // Start far in the past to avoid animation on load\n };\n const brakeLevel = { current: 0.0 };\n\n const render = (t: number) => {\n const dt = Math.min((t - lastTime) / 1000, 0.1);\n const currentTimeSec = t * 0.001;\n lastTime = t;\n \n const dpr = window.devicePixelRatio || 1;\n const w = canvas.clientWidth * dpr, h = canvas.clientHeight * dpr;\n if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; gl.viewport(0, 0, w, h); }\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n const isThrustingNow = (pressedKeysRef.current.has('s') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('w') && controlConfigRef.current.invertForward);\n const isBraking = (pressedKeysRef.current.has('w') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('s') && controlConfigRef.current.invertForward);\n \n // Detect ignition start\n if (isThrustingNow && !thrustState.isThrusting) {\n thrustState.ignitionTime = currentTimeSec;\n }\n thrustState.isThrusting = isThrustingNow;\n \n // LERP for smooth animation\n const LERP_SPEED = 8.0;\n thrustState.level += ((isThrustingNow ? 1.0 : 0.0) - thrustState.level) * LERP_SPEED * dt;\n brakeLevel.current += ((isBraking ? 1.0 : 0.0) - brakeLevel.current) * LERP_SPEED * dt;\n \n // Use actual physics angular velocity for smoother, heavier animation\n // Negate yaw velocity because camera yaw is inverted relative to ship yaw visually\n const tYaw = -cameraAngularVelocityRef.current[1] * 1.2; \n const tPitch_velocity = cameraAngularVelocityRef.current[0];\n // Invert pitch velocity to match user preference (UP looks UP)\n const tPitch = -tPitch_velocity * 1.0 + (shipConfigRef.current.pitchOffset ?? 0.0);\n\n // Slower lerp for heavier feel (3.0 instead of 8.0)\n shipState.current.yaw += (tYaw - shipState.current.yaw) * 3.0 * dt;\n shipState.current.pitch += (tPitch - shipState.current.pitch) * 3.0 * dt;\n // Roll based on yaw for banking\n shipState.current.roll += (tYaw * 1.5 - shipState.current.roll) * 3.0 * dt;\n\n mat4.identity(rotMat);\n mat4.rotateY(rotMat, rotMat, shipState.current.yaw);\n mat4.rotateX(rotMat, rotMat, shipState.current.pitch);\n mat4.rotateZ(rotMat, rotMat, shipState.current.roll);\n\n gl.useProgram(p);\n gl.uniform2f(locs.uRes, w, h);\n gl.uniform1f(locs.uTime, currentTimeSec);\n gl.uniformMatrix4fv(locs.uShipRot, false, rotMat);\n gl.uniform1f(locs.uThrust, thrustState.level);\n gl.uniform1f(locs.uThrustIgnitionTime, thrustState.ignitionTime);\n gl.uniform1f(locs.uBrake, brakeLevel.current);\n gl.uniform1f(locs.uYawVelocity, tYaw);\n gl.uniform1f(locs.uPitchVelocity, tPitch_velocity);\n \n // Update DNA uniforms from EFFECTIVE config (includes modulations)\n const ec = effectiveShipConfigRef.current;\n gl.uniform1f(locs.uComplexity, ec.complexity);\n gl.uniform1f(locs.uFold1, ec.fold1);\n gl.uniform1f(locs.uFold2, ec.fold2);\n gl.uniform1f(locs.uFold3, ec.fold3);\n gl.uniform1f(locs.uScale, ec.scale);\n gl.uniform1f(locs.uStretch, ec.stretch);\n gl.uniform1f(locs.uTaper, ec.taper);\n gl.uniform1f(locs.uTwist, ec.twist);\n gl.uniform1f(locs.uAsymmetryX, ec.asymmetryX);\n gl.uniform1f(locs.uAsymmetryY, ec.asymmetryY);\n gl.uniform1f(locs.uAsymmetryZ, ec.asymmetryZ);\n\n // New Bias Uniforms\n gl.uniform1f(locs.uTwistAsymX, ec.twistAsymX);\n gl.uniform1f(locs.uScaleAsymX, ec.scaleAsymX);\n gl.uniform1f(locs.uFold1AsymX, ec.fold1AsymX);\n gl.uniform1f(locs.uFold2AsymX, ec.fold2AsymX);\n\n gl.uniform1f(locs.uGeneralScale, shipConfigRef.current.generalScale ?? 1.0);\n gl.uniform1f(locs.uChaseDistance, shipConfigRef.current.chaseDistance ?? 6.5);\n gl.uniform1f(locs.uChaseVerticalOffset, shipConfigRef.current.chaseVerticalOffset ?? 1.0);\n gl.uniform1f(locs.uTranslucency, shipConfigRef.current.translucency ?? 1.0);\n\n gl.bindVertexArray(vao);\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n animId = requestAnimationFrame(render);\n };\n render(performance.now());\n return () => { cancelAnimationFrame(animId); gl.deleteProgram(p); };\n }, [viewMode]);\n\n if (viewMode !== 'chase') return null;\n return <canvas ref={canvasRef} className=\"absolute top-0 left-0 w-full h-full pointer-events-none z-10\" />;\n};", resolution: "2K", safety_filter_level: "block_only_high" }; const output = await replicate.run("google/nano-banana-pro", { input }); // To access the file URL: console.log(output.url()); //=> "http://example.com" // To write the file to disk: fs.writeFile("my-image.png", output);
To learn more, take a look at the guide on getting started with Node.js.
pip install replicate
import replicate
output = replicate.run( "google/nano-banana-pro", input={ "aspect_ratio": "3:4", "image_input": [], "output_format": "jpg", "prompt": "render this: /**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\n\n\nimport React, { useRef, useEffect } from 'react';\nimport { useAppContext } from '../context/AppContext';\n\n// A simple full-screen quad vertex shader\nconst VERTEX_SHADER = `#version 300 es\nin vec2 a_position;\nout vec2 v_uv;\nvoid main() {\n v_uv = a_position;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\nin vec2 v_uv;\nout vec4 outColor;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform mat4 u_shipRot;\nuniform float u_thrust;\nuniform float u_brake;\nuniform float u_yaw_velocity;\nuniform float u_pitch_velocity;\nuniform float u_thrust_ignition_time;\n\n// Ship DNA from sliders\nuniform float u_complexity;\nuniform float u_fold1;\nuniform float u_fold2;\nuniform float u_fold3;\nuniform float u_scale;\nuniform float u_stretch;\nuniform float u_taper;\nuniform float u_twist;\nuniform float u_asymmetryX;\nuniform float u_asymmetryY;\nuniform float u_asymmetryZ;\n\n// Parameter Biases\nuniform float u_twistAsymX;\nuniform float u_scaleAsymX;\nuniform float u_fold1AsymX;\nuniform float u_fold2AsymX;\n\nuniform float u_generalScale;\nuniform float u_chaseDistance;\nuniform float u_chaseVerticalOffset;\nuniform float u_translucency;\n\n#define MAX_STEPS 64\n#define MAX_DIST 15.0\n#define SURF_DIST 0.001\n\nmat2 rot(float a) { float s=sin(a), c=cos(a); return mat2(c, -s, s, c); }\n\n// KIFS Fractal for Ship Body\nfloat sdFractalShip(vec3 p) {\n // Store original position for asymmetry calculations\n vec3 pOrig = p;\n\n // Apply Asymmetry Distortion first (Spatial scaling based on sign)\n p.x *= 1.0 - sign(p.x) * u_asymmetryX * 0.5;\n p.y *= 1.0 - sign(p.y) * u_asymmetryY * 0.5;\n p.z *= 1.0 - sign(p.z) * u_asymmetryZ * 0.5;\n\n p /= u_generalScale;\n p.z /= u_stretch; // Longitudinal stretch\n \n // Tapering along Z axis (before rotation, Z is longitudinal)\n p.xy *= 1.0 + p.z * u_taper;\n\n // --- Asymmetric Twisting ---\n // Base twist + gradient based on original X position\n // If u_twistAsymX > 0, positive X (Right) twists more.\n float localTwist = u_twist + pOrig.x * u_twistAsymX;\n p.xy *= rot(p.z * localTwist * 2.0);\n\n // Initial orientation to make it face forward (-Z)\n p.yz *= rot(1.57); \n\n float s = 1.0;\n for(int i=0; i<int(u_complexity); i++) {\n // --- Asymmetric Folding ---\n // Base fold + gradient based on original X position\n // Note: pOrig.x is used to keep the bias fixed to the ship's original side\n float localFold1 = u_fold1 + pOrig.x * u_fold1AsymX;\n float localFold2 = u_fold2 + pOrig.x * u_fold2AsymX;\n\n // Folding space\n p = abs(p) - vec3(localFold1, localFold2, 0.3)/s;\n p.xz *= rot(u_fold3);\n \n // --- Asymmetric Scaling ---\n float localScale = u_scale + pOrig.x * u_scaleAsymX * 0.2;\n p *= localScale;\n s *= localScale;\n }\n // Base shape: a box that gets folded into the fractal\n float d = length(max(abs(p) - vec3(0.1, 0.8, 0.1), 0.0));\n return d/s * u_generalScale;\n}\n\n// Main SDF mapping the whole ship\nfloat map(vec3 p) {\n // Apply ship rotation (pitch/yaw/roll)\n p = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n\n // Main Body\n float dBody = sdFractalShip(p);\n \n // Engines (simple cylinders at the back)\n vec3 pEng = p;\n pEng.x = abs(pEng.x);\n pEng -= vec3(0.5, 0.0, 1.2); // Position at back\n float dEng = max(length(pEng.xy) - 0.2, abs(pEng.z) - 0.4);\n \n // Flaps (boxes at sides)\n vec3 pFlap = p;\n pFlap.x = abs(pFlap.x);\n pFlap -= vec3(1.1, 0.0, 0.2);\n // Rotate flaps when braking\n pFlap.yz *= rot(u_brake * 0.8);\n float dFlap = length(max(abs(pFlap) - vec3(0.4, 0.05, 0.3), 0.0));\n\n // Smooth blend body and dynamic parts\n float d = -log(exp(-dBody*12.0) + exp(-dEng*12.0) + exp(-dFlap*12.0)) / 12.0;\n return d;\n}\n\n// Calculate normal for lighting\nvec3 getNormal(vec3 p) {\n vec2 e = vec2(0.001, 0.0);\n return normalize(vec3(\n map(p + e.xyy) - map(p - e.xyy),\n map(p + e.yxy) - map(p - e.yxy),\n map(p + e.yyx) - map(p - e.yyx)\n ));\n}\n\nvoid main() {\n // Setup Ray from Chase Camera perspective\n vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / u_resolution.y;\n vec3 ro = vec3(0.0, u_chaseVerticalOffset, u_chaseDistance); // Fixed chase camera relative to ship center (0,0,0)\n vec3 rd = normalize(vec3(uv, -1.5)); // Looking forward (-Z)\n\n float d = 0.0, t = 0.0;\n for(int i = 0; i < MAX_STEPS; i++) {\n vec3 p = ro + rd * t;\n d = map(p);\n if(d < SURF_DIST || t > MAX_DIST) break;\n t += d;\n }\n\n if(t < MAX_DIST) {\n vec3 p = ro + rd * t;\n vec3 n = getNormal(p);\n vec3 l = normalize(vec3(1.0, 2.0, 3.0)); // Fixed light source\n\n // Basic lighting\n float diff = max(dot(n, l), 0.0);\n float amb = 0.1;\n vec3 col = vec3(0.2, 0.25, 0.3) * (diff + amb);\n \n // Rim lighting\n float rim = pow(1.0 - max(dot(-rd, n), 0.0), 4.0);\n col += vec3(0.1, 0.6, 1.0) * rim * 0.8;\n\n // Calculate local coordinates for emissive mapping\n vec3 localP = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n \n // --- Engine Glow ---\n // Wider mask to accommodate the ignition animation starting point\n float engineMask = smoothstep(0.4, 1.5, localP.z) * (1.0 - smoothstep(0.4, 1.0, abs(localP.x)));\n \n // Ignition Animation\n float timeSinceIgnition = u_time - u_thrust_ignition_time;\n float ignitionDuration = 0.3; // Animation duration in seconds\n\n // Ignition pulse travels from front (z=0.5) to back (z=1.5)\n float pulseProgress = clamp(timeSinceIgnition / ignitionDuration, 0.0, 1.0);\n float ignitionFrontZ = mix(0.5, 1.5, pulseProgress);\n\n // Moving pulse of light\n float pulseWidth = 0.15;\n float pulseShape = smoothstep(0.0, pulseWidth, localP.z - (ignitionFrontZ - pulseWidth)) * \n smoothstep(0.0, -pulseWidth, localP.z - (ignitionFrontZ + pulseWidth));\n float pulseGlow = pulseShape * 2.5 * (1.0 - pulseProgress); // Bright pulse that fades\n\n // Sustained Glow\n float wave1 = sin(localP.z * 8.0) * 0.5 + 0.5;\n float wave2 = sin(localP.z * 5.0) * 0.5 + 0.5;\n float sustainedIntensity = 0.2 + pow(wave1, 3.0) * 1.0 + pow(wave2, 5.0) * 0.8;\n\n // The sustained glow appears as the ignition pulse passes over it\n float sustainedVisibility = smoothstep(ignitionFrontZ - 0.2, ignitionFrontZ, localP.z);\n if (timeSinceIgnition > ignitionDuration) {\n sustainedVisibility = 1.0; // Fully visible after animation\n }\n float finalSustainedGlow = mix(0.1, sustainedIntensity, u_thrust * sustainedVisibility);\n\n // Combine glows\n float totalGlow = finalSustainedGlow + pulseGlow;\n col += vec3(1.0, 0.4, 0.05) * engineMask * totalGlow;\n\n // Flap Glow - asymmetric for turning\n float leftBrakeAmount = u_brake + max(0.0, u_yaw_velocity * 2.5); // Turn right, left brake lights up\n float rightBrakeAmount = u_brake + max(0.0, -u_yaw_velocity * 2.5); // Turn left, right brake lights up\n\n float flapMaskLeft = smoothstep(0.8, 1.6, localP.x) * (1.0 - smoothstep(0.0, 0.8, -localP.x));\n float flapMaskRight = smoothstep(0.8, 1.6, -localP.x) * (1.0 - smoothstep(0.0, 0.8, localP.x));\n\n col += vec3(1.0, 0.1, 0.1) * flapMaskLeft * leftBrakeAmount * 2.0;\n col += vec3(1.0, 0.1, 0.1) * flapMaskRight * rightBrakeAmount * 2.0;\n\n // Pitch maneuver lights\n // Pitching up (negative velocity) lights bottom. Pitching down (positive velocity) lights top.\n float pitchUpAmount = max(0.0, -u_pitch_velocity * 4.0);\n float pitchDownAmount = max(0.0, u_pitch_velocity * 4.0);\n\n // Define masks for top and bottom surfaces, concentrated on the main body/wings area\n float pitchLightAreaMask = smoothstep(0.8, 0.0, abs(localP.z));\n float topMask = smoothstep(0.2, 0.4, localP.y) * pitchLightAreaMask;\n float bottomMask = smoothstep(-0.2, -0.4, localP.y) * pitchLightAreaMask;\n\n col += vec3(1.0, 0.1, 0.1) * topMask * pitchDownAmount;\n col += vec3(1.0, 0.1, 0.1) * bottomMask * pitchUpAmount;\n\n // Add alpha for transparency around the ship\n outColor = vec4(col, u_translucency);\n } else {\n outColor = vec4(0.0); // Transparent background\n }\n}\n`;\n\nconst mat4 = {\n identity: (out: Float32Array) => { out.fill(0); out[0]=1; out[5]=1; out[10]=1; out[15]=1; },\n rotateX: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a10=a[4],a11=a[5],a12=a[6],a13=a[7], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[4]=a10*c+a20*s; out[5]=a11*c+a21*s; out[6]=a12*c+a22*s; out[7]=a13*c+a23*s;\n out[8]=a20*c-a10*s; out[9]=a21*c-a11*s; out[10]=a22*c-a12*s; out[11]=a23*c-a13*s;\n },\n rotateY: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[0]=a00*c-a20*s; out[1]=a01*c-a21*s; out[2]=a02*c-a22*s; out[3]=a03*c-a23*s;\n out[8]=a00*s+a20*c; out[9]=a01*s+a21*c; out[10]=a02*s+a22*c; out[11]=a03*s+a23*c;\n },\n rotateZ: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a10=a[4],a11=a[5],a12=a[6],a13=a[7];\n out.set(a);\n out[0]=a00*c+a10*s; out[1]=a01*c+a11*s; out[2]=a02*c+a13*s; out[3]=a03*c+a13*s;\n out[4]=a10*c-a00*s; out[5]=a11*c-a01*s; out[6]=a12*c-a02*s; out[7]=a13*c-a03*s;\n },\n};\n\nexport const ShipOverlay: React.FC = () => {\n const { viewMode, pressedKeys, controlConfig, effectiveShipConfigRef, cameraAngularVelocityRef, shipConfig } = useAppContext();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const shipState = useRef({ pitch: 0, yaw: 0, roll: 0 });\n\n const shipConfigRef = useRef(shipConfig);\n useEffect(() => { shipConfigRef.current = shipConfig; }, [shipConfig]);\n \n const pressedKeysRef = useRef(pressedKeys);\n useEffect(() => { pressedKeysRef.current = pressedKeys; }, [pressedKeys]);\n \n const controlConfigRef = useRef(controlConfig);\n useEffect(() => { controlConfigRef.current = controlConfig; }, [controlConfig]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || viewMode !== 'chase') return;\n const gl = canvas.getContext('webgl2', { alpha: true, depth: false, antialias: false }); // No depth needed for single quad\n if (!gl) return;\n\n // Enable blending for translucency\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n\n const compile = (type: number, src: string) => {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) console.error(gl.getShaderInfoLog(s));\n return s;\n };\n const p = gl.createProgram()!;\n gl.attachShader(p, compile(gl.VERTEX_SHADER, VERTEX_SHADER));\n gl.attachShader(p, compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER));\n gl.linkProgram(p);\n gl.useProgram(p);\n\n // Uniform locations\n const locs = {\n uRes: gl.getUniformLocation(p, 'u_resolution'),\n uTime: gl.getUniformLocation(p, 'u_time'),\n uShipRot: gl.getUniformLocation(p, 'u_shipRot'),\n uThrust: gl.getUniformLocation(p, 'u_thrust'),\n uThrustIgnitionTime: gl.getUniformLocation(p, 'u_thrust_ignition_time'),\n uBrake: gl.getUniformLocation(p, 'u_brake'),\n uYawVelocity: gl.getUniformLocation(p, 'u_yaw_velocity'),\n uPitchVelocity: gl.getUniformLocation(p, 'u_pitch_velocity'),\n // Ship DNA\n uComplexity: gl.getUniformLocation(p, 'u_complexity'),\n uFold1: gl.getUniformLocation(p, 'u_fold1'),\n uFold2: gl.getUniformLocation(p, 'u_fold2'),\n uFold3: gl.getUniformLocation(p, 'u_fold3'),\n uScale: gl.getUniformLocation(p, 'u_scale'),\n uStretch: gl.getUniformLocation(p, 'u_stretch'),\n uTaper: gl.getUniformLocation(p, 'u_taper'),\n uTwist: gl.getUniformLocation(p, 'u_twist'),\n uAsymmetryX: gl.getUniformLocation(p, 'u_asymmetryX'),\n uAsymmetryY: gl.getUniformLocation(p, 'u_asymmetryY'),\n uAsymmetryZ: gl.getUniformLocation(p, 'u_asymmetryZ'),\n \n // New Bias Uniforms\n uTwistAsymX: gl.getUniformLocation(p, 'u_twistAsymX'),\n uScaleAsymX: gl.getUniformLocation(p, 'u_scaleAsymX'),\n uFold1AsymX: gl.getUniformLocation(p, 'u_fold1AsymX'),\n uFold2AsymX: gl.getUniformLocation(p, 'u_fold2AsymX'),\n\n uGeneralScale: gl.getUniformLocation(p, 'u_generalScale'),\n uChaseDistance: gl.getUniformLocation(p, 'u_chaseDistance'),\n uChaseVerticalOffset: gl.getUniformLocation(p, 'u_chaseVerticalOffset'),\n uTranslucency: gl.getUniformLocation(p, 'u_translucency'),\n };\n\n // Fullscreen quad\n const vao = gl.createVertexArray()!;\n gl.bindVertexArray(vao);\n const vbo = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n const rotMat = new Float32Array(16);\n let lastTime = 0, animId = 0;\n\n // State for smooth thrust/brake animation, now with ignition tracking\n const thrustState = {\n level: 0.0,\n isThrusting: false,\n ignitionTime: -100.0, // Start far in the past to avoid animation on load\n };\n const brakeLevel = { current: 0.0 };\n\n const render = (t: number) => {\n const dt = Math.min((t - lastTime) / 1000, 0.1);\n const currentTimeSec = t * 0.001;\n lastTime = t;\n \n const dpr = window.devicePixelRatio || 1;\n const w = canvas.clientWidth * dpr, h = canvas.clientHeight * dpr;\n if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; gl.viewport(0, 0, w, h); }\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n const isThrustingNow = (pressedKeysRef.current.has('s') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('w') && controlConfigRef.current.invertForward);\n const isBraking = (pressedKeysRef.current.has('w') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('s') && controlConfigRef.current.invertForward);\n \n // Detect ignition start\n if (isThrustingNow && !thrustState.isThrusting) {\n thrustState.ignitionTime = currentTimeSec;\n }\n thrustState.isThrusting = isThrustingNow;\n \n // LERP for smooth animation\n const LERP_SPEED = 8.0;\n thrustState.level += ((isThrustingNow ? 1.0 : 0.0) - thrustState.level) * LERP_SPEED * dt;\n brakeLevel.current += ((isBraking ? 1.0 : 0.0) - brakeLevel.current) * LERP_SPEED * dt;\n \n // Use actual physics angular velocity for smoother, heavier animation\n // Negate yaw velocity because camera yaw is inverted relative to ship yaw visually\n const tYaw = -cameraAngularVelocityRef.current[1] * 1.2; \n const tPitch_velocity = cameraAngularVelocityRef.current[0];\n // Invert pitch velocity to match user preference (UP looks UP)\n const tPitch = -tPitch_velocity * 1.0 + (shipConfigRef.current.pitchOffset ?? 0.0);\n\n // Slower lerp for heavier feel (3.0 instead of 8.0)\n shipState.current.yaw += (tYaw - shipState.current.yaw) * 3.0 * dt;\n shipState.current.pitch += (tPitch - shipState.current.pitch) * 3.0 * dt;\n // Roll based on yaw for banking\n shipState.current.roll += (tYaw * 1.5 - shipState.current.roll) * 3.0 * dt;\n\n mat4.identity(rotMat);\n mat4.rotateY(rotMat, rotMat, shipState.current.yaw);\n mat4.rotateX(rotMat, rotMat, shipState.current.pitch);\n mat4.rotateZ(rotMat, rotMat, shipState.current.roll);\n\n gl.useProgram(p);\n gl.uniform2f(locs.uRes, w, h);\n gl.uniform1f(locs.uTime, currentTimeSec);\n gl.uniformMatrix4fv(locs.uShipRot, false, rotMat);\n gl.uniform1f(locs.uThrust, thrustState.level);\n gl.uniform1f(locs.uThrustIgnitionTime, thrustState.ignitionTime);\n gl.uniform1f(locs.uBrake, brakeLevel.current);\n gl.uniform1f(locs.uYawVelocity, tYaw);\n gl.uniform1f(locs.uPitchVelocity, tPitch_velocity);\n \n // Update DNA uniforms from EFFECTIVE config (includes modulations)\n const ec = effectiveShipConfigRef.current;\n gl.uniform1f(locs.uComplexity, ec.complexity);\n gl.uniform1f(locs.uFold1, ec.fold1);\n gl.uniform1f(locs.uFold2, ec.fold2);\n gl.uniform1f(locs.uFold3, ec.fold3);\n gl.uniform1f(locs.uScale, ec.scale);\n gl.uniform1f(locs.uStretch, ec.stretch);\n gl.uniform1f(locs.uTaper, ec.taper);\n gl.uniform1f(locs.uTwist, ec.twist);\n gl.uniform1f(locs.uAsymmetryX, ec.asymmetryX);\n gl.uniform1f(locs.uAsymmetryY, ec.asymmetryY);\n gl.uniform1f(locs.uAsymmetryZ, ec.asymmetryZ);\n\n // New Bias Uniforms\n gl.uniform1f(locs.uTwistAsymX, ec.twistAsymX);\n gl.uniform1f(locs.uScaleAsymX, ec.scaleAsymX);\n gl.uniform1f(locs.uFold1AsymX, ec.fold1AsymX);\n gl.uniform1f(locs.uFold2AsymX, ec.fold2AsymX);\n\n gl.uniform1f(locs.uGeneralScale, shipConfigRef.current.generalScale ?? 1.0);\n gl.uniform1f(locs.uChaseDistance, shipConfigRef.current.chaseDistance ?? 6.5);\n gl.uniform1f(locs.uChaseVerticalOffset, shipConfigRef.current.chaseVerticalOffset ?? 1.0);\n gl.uniform1f(locs.uTranslucency, shipConfigRef.current.translucency ?? 1.0);\n\n gl.bindVertexArray(vao);\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n animId = requestAnimationFrame(render);\n };\n render(performance.now());\n return () => { cancelAnimationFrame(animId); gl.deleteProgram(p); };\n }, [viewMode]);\n\n if (viewMode !== 'chase') return null;\n return <canvas ref={canvasRef} className=\"absolute top-0 left-0 w-full h-full pointer-events-none z-10\" />;\n};", "resolution": "2K", "safety_filter_level": "block_only_high" } ) # To access the file URL: print(output.url()) #=> "http://example.com" # To write the file to disk: with open("my-image.png", "wb") as file: file.write(output.read())
To learn more, take a look at the guide on getting started with Python.
curl -s -X POST \ -H "Authorization: Bearer $REPLICATE_API_TOKEN" \ -H "Content-Type: application/json" \ -H "Prefer: wait" \ -d $'{ "input": { "aspect_ratio": "3:4", "image_input": [], "output_format": "jpg", "prompt": "render this: /**\\n * @license\\n * SPDX-License-Identifier: Apache-2.0\\n*/\\n\\n\\n\\nimport React, { useRef, useEffect } from \'react\';\\nimport { useAppContext } from \'../context/AppContext\';\\n\\n// A simple full-screen quad vertex shader\\nconst VERTEX_SHADER = `#version 300 es\\nin vec2 a_position;\\nout vec2 v_uv;\\nvoid main() {\\n v_uv = a_position;\\n gl_Position = vec4(a_position, 0.0, 1.0);\\n}\\n`;\\n\\nconst FRAGMENT_SHADER = `#version 300 es\\nprecision highp float;\\nin vec2 v_uv;\\nout vec4 outColor;\\n\\nuniform float u_time;\\nuniform vec2 u_resolution;\\nuniform mat4 u_shipRot;\\nuniform float u_thrust;\\nuniform float u_brake;\\nuniform float u_yaw_velocity;\\nuniform float u_pitch_velocity;\\nuniform float u_thrust_ignition_time;\\n\\n// Ship DNA from sliders\\nuniform float u_complexity;\\nuniform float u_fold1;\\nuniform float u_fold2;\\nuniform float u_fold3;\\nuniform float u_scale;\\nuniform float u_stretch;\\nuniform float u_taper;\\nuniform float u_twist;\\nuniform float u_asymmetryX;\\nuniform float u_asymmetryY;\\nuniform float u_asymmetryZ;\\n\\n// Parameter Biases\\nuniform float u_twistAsymX;\\nuniform float u_scaleAsymX;\\nuniform float u_fold1AsymX;\\nuniform float u_fold2AsymX;\\n\\nuniform float u_generalScale;\\nuniform float u_chaseDistance;\\nuniform float u_chaseVerticalOffset;\\nuniform float u_translucency;\\n\\n#define MAX_STEPS 64\\n#define MAX_DIST 15.0\\n#define SURF_DIST 0.001\\n\\nmat2 rot(float a) { float s=sin(a), c=cos(a); return mat2(c, -s, s, c); }\\n\\n// KIFS Fractal for Ship Body\\nfloat sdFractalShip(vec3 p) {\\n // Store original position for asymmetry calculations\\n vec3 pOrig = p;\\n\\n // Apply Asymmetry Distortion first (Spatial scaling based on sign)\\n p.x *= 1.0 - sign(p.x) * u_asymmetryX * 0.5;\\n p.y *= 1.0 - sign(p.y) * u_asymmetryY * 0.5;\\n p.z *= 1.0 - sign(p.z) * u_asymmetryZ * 0.5;\\n\\n p /= u_generalScale;\\n p.z /= u_stretch; // Longitudinal stretch\\n \\n // Tapering along Z axis (before rotation, Z is longitudinal)\\n p.xy *= 1.0 + p.z * u_taper;\\n\\n // --- Asymmetric Twisting ---\\n // Base twist + gradient based on original X position\\n // If u_twistAsymX > 0, positive X (Right) twists more.\\n float localTwist = u_twist + pOrig.x * u_twistAsymX;\\n p.xy *= rot(p.z * localTwist * 2.0);\\n\\n // Initial orientation to make it face forward (-Z)\\n p.yz *= rot(1.57); \\n\\n float s = 1.0;\\n for(int i=0; i<int(u_complexity); i++) {\\n // --- Asymmetric Folding ---\\n // Base fold + gradient based on original X position\\n // Note: pOrig.x is used to keep the bias fixed to the ship\'s original side\\n float localFold1 = u_fold1 + pOrig.x * u_fold1AsymX;\\n float localFold2 = u_fold2 + pOrig.x * u_fold2AsymX;\\n\\n // Folding space\\n p = abs(p) - vec3(localFold1, localFold2, 0.3)/s;\\n p.xz *= rot(u_fold3);\\n \\n // --- Asymmetric Scaling ---\\n float localScale = u_scale + pOrig.x * u_scaleAsymX * 0.2;\\n p *= localScale;\\n s *= localScale;\\n }\\n // Base shape: a box that gets folded into the fractal\\n float d = length(max(abs(p) - vec3(0.1, 0.8, 0.1), 0.0));\\n return d/s * u_generalScale;\\n}\\n\\n// Main SDF mapping the whole ship\\nfloat map(vec3 p) {\\n // Apply ship rotation (pitch/yaw/roll)\\n p = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\\n\\n // Main Body\\n float dBody = sdFractalShip(p);\\n \\n // Engines (simple cylinders at the back)\\n vec3 pEng = p;\\n pEng.x = abs(pEng.x);\\n pEng -= vec3(0.5, 0.0, 1.2); // Position at back\\n float dEng = max(length(pEng.xy) - 0.2, abs(pEng.z) - 0.4);\\n \\n // Flaps (boxes at sides)\\n vec3 pFlap = p;\\n pFlap.x = abs(pFlap.x);\\n pFlap -= vec3(1.1, 0.0, 0.2);\\n // Rotate flaps when braking\\n pFlap.yz *= rot(u_brake * 0.8);\\n float dFlap = length(max(abs(pFlap) - vec3(0.4, 0.05, 0.3), 0.0));\\n\\n // Smooth blend body and dynamic parts\\n float d = -log(exp(-dBody*12.0) + exp(-dEng*12.0) + exp(-dFlap*12.0)) / 12.0;\\n return d;\\n}\\n\\n// Calculate normal for lighting\\nvec3 getNormal(vec3 p) {\\n vec2 e = vec2(0.001, 0.0);\\n return normalize(vec3(\\n map(p + e.xyy) - map(p - e.xyy),\\n map(p + e.yxy) - map(p - e.yxy),\\n map(p + e.yyx) - map(p - e.yyx)\\n ));\\n}\\n\\nvoid main() {\\n // Setup Ray from Chase Camera perspective\\n vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / u_resolution.y;\\n vec3 ro = vec3(0.0, u_chaseVerticalOffset, u_chaseDistance); // Fixed chase camera relative to ship center (0,0,0)\\n vec3 rd = normalize(vec3(uv, -1.5)); // Looking forward (-Z)\\n\\n float d = 0.0, t = 0.0;\\n for(int i = 0; i < MAX_STEPS; i++) {\\n vec3 p = ro + rd * t;\\n d = map(p);\\n if(d < SURF_DIST || t > MAX_DIST) break;\\n t += d;\\n }\\n\\n if(t < MAX_DIST) {\\n vec3 p = ro + rd * t;\\n vec3 n = getNormal(p);\\n vec3 l = normalize(vec3(1.0, 2.0, 3.0)); // Fixed light source\\n\\n // Basic lighting\\n float diff = max(dot(n, l), 0.0);\\n float amb = 0.1;\\n vec3 col = vec3(0.2, 0.25, 0.3) * (diff + amb);\\n \\n // Rim lighting\\n float rim = pow(1.0 - max(dot(-rd, n), 0.0), 4.0);\\n col += vec3(0.1, 0.6, 1.0) * rim * 0.8;\\n\\n // Calculate local coordinates for emissive mapping\\n vec3 localP = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\\n \\n // --- Engine Glow ---\\n // Wider mask to accommodate the ignition animation starting point\\n float engineMask = smoothstep(0.4, 1.5, localP.z) * (1.0 - smoothstep(0.4, 1.0, abs(localP.x)));\\n \\n // Ignition Animation\\n float timeSinceIgnition = u_time - u_thrust_ignition_time;\\n float ignitionDuration = 0.3; // Animation duration in seconds\\n\\n // Ignition pulse travels from front (z=0.5) to back (z=1.5)\\n float pulseProgress = clamp(timeSinceIgnition / ignitionDuration, 0.0, 1.0);\\n float ignitionFrontZ = mix(0.5, 1.5, pulseProgress);\\n\\n // Moving pulse of light\\n float pulseWidth = 0.15;\\n float pulseShape = smoothstep(0.0, pulseWidth, localP.z - (ignitionFrontZ - pulseWidth)) * \\n smoothstep(0.0, -pulseWidth, localP.z - (ignitionFrontZ + pulseWidth));\\n float pulseGlow = pulseShape * 2.5 * (1.0 - pulseProgress); // Bright pulse that fades\\n\\n // Sustained Glow\\n float wave1 = sin(localP.z * 8.0) * 0.5 + 0.5;\\n float wave2 = sin(localP.z * 5.0) * 0.5 + 0.5;\\n float sustainedIntensity = 0.2 + pow(wave1, 3.0) * 1.0 + pow(wave2, 5.0) * 0.8;\\n\\n // The sustained glow appears as the ignition pulse passes over it\\n float sustainedVisibility = smoothstep(ignitionFrontZ - 0.2, ignitionFrontZ, localP.z);\\n if (timeSinceIgnition > ignitionDuration) {\\n sustainedVisibility = 1.0; // Fully visible after animation\\n }\\n float finalSustainedGlow = mix(0.1, sustainedIntensity, u_thrust * sustainedVisibility);\\n\\n // Combine glows\\n float totalGlow = finalSustainedGlow + pulseGlow;\\n col += vec3(1.0, 0.4, 0.05) * engineMask * totalGlow;\\n\\n // Flap Glow - asymmetric for turning\\n float leftBrakeAmount = u_brake + max(0.0, u_yaw_velocity * 2.5); // Turn right, left brake lights up\\n float rightBrakeAmount = u_brake + max(0.0, -u_yaw_velocity * 2.5); // Turn left, right brake lights up\\n\\n float flapMaskLeft = smoothstep(0.8, 1.6, localP.x) * (1.0 - smoothstep(0.0, 0.8, -localP.x));\\n float flapMaskRight = smoothstep(0.8, 1.6, -localP.x) * (1.0 - smoothstep(0.0, 0.8, localP.x));\\n\\n col += vec3(1.0, 0.1, 0.1) * flapMaskLeft * leftBrakeAmount * 2.0;\\n col += vec3(1.0, 0.1, 0.1) * flapMaskRight * rightBrakeAmount * 2.0;\\n\\n // Pitch maneuver lights\\n // Pitching up (negative velocity) lights bottom. Pitching down (positive velocity) lights top.\\n float pitchUpAmount = max(0.0, -u_pitch_velocity * 4.0);\\n float pitchDownAmount = max(0.0, u_pitch_velocity * 4.0);\\n\\n // Define masks for top and bottom surfaces, concentrated on the main body/wings area\\n float pitchLightAreaMask = smoothstep(0.8, 0.0, abs(localP.z));\\n float topMask = smoothstep(0.2, 0.4, localP.y) * pitchLightAreaMask;\\n float bottomMask = smoothstep(-0.2, -0.4, localP.y) * pitchLightAreaMask;\\n\\n col += vec3(1.0, 0.1, 0.1) * topMask * pitchDownAmount;\\n col += vec3(1.0, 0.1, 0.1) * bottomMask * pitchUpAmount;\\n\\n // Add alpha for transparency around the ship\\n outColor = vec4(col, u_translucency);\\n } else {\\n outColor = vec4(0.0); // Transparent background\\n }\\n}\\n`;\\n\\nconst mat4 = {\\n identity: (out: Float32Array) => { out.fill(0); out[0]=1; out[5]=1; out[10]=1; out[15]=1; },\\n rotateX: (out: Float32Array, a: Float32Array, rad: number) => {\\n let s=Math.sin(rad), c=Math.cos(rad), a10=a[4],a11=a[5],a12=a[6],a13=a[7], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\\n out.set(a);\\n out[4]=a10*c+a20*s; out[5]=a11*c+a21*s; out[6]=a12*c+a22*s; out[7]=a13*c+a23*s;\\n out[8]=a20*c-a10*s; out[9]=a21*c-a11*s; out[10]=a22*c-a12*s; out[11]=a23*c-a13*s;\\n },\\n rotateY: (out: Float32Array, a: Float32Array, rad: number) => {\\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\\n out.set(a);\\n out[0]=a00*c-a20*s; out[1]=a01*c-a21*s; out[2]=a02*c-a22*s; out[3]=a03*c-a23*s;\\n out[8]=a00*s+a20*c; out[9]=a01*s+a21*c; out[10]=a02*s+a22*c; out[11]=a03*s+a23*c;\\n },\\n rotateZ: (out: Float32Array, a: Float32Array, rad: number) => {\\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a10=a[4],a11=a[5],a12=a[6],a13=a[7];\\n out.set(a);\\n out[0]=a00*c+a10*s; out[1]=a01*c+a11*s; out[2]=a02*c+a13*s; out[3]=a03*c+a13*s;\\n out[4]=a10*c-a00*s; out[5]=a11*c-a01*s; out[6]=a12*c-a02*s; out[7]=a13*c-a03*s;\\n },\\n};\\n\\nexport const ShipOverlay: React.FC = () => {\\n const { viewMode, pressedKeys, controlConfig, effectiveShipConfigRef, cameraAngularVelocityRef, shipConfig } = useAppContext();\\n const canvasRef = useRef<HTMLCanvasElement>(null);\\n const shipState = useRef({ pitch: 0, yaw: 0, roll: 0 });\\n\\n const shipConfigRef = useRef(shipConfig);\\n useEffect(() => { shipConfigRef.current = shipConfig; }, [shipConfig]);\\n \\n const pressedKeysRef = useRef(pressedKeys);\\n useEffect(() => { pressedKeysRef.current = pressedKeys; }, [pressedKeys]);\\n \\n const controlConfigRef = useRef(controlConfig);\\n useEffect(() => { controlConfigRef.current = controlConfig; }, [controlConfig]);\\n\\n useEffect(() => {\\n const canvas = canvasRef.current;\\n if (!canvas || viewMode !== \'chase\') return;\\n const gl = canvas.getContext(\'webgl2\', { alpha: true, depth: false, antialias: false }); // No depth needed for single quad\\n if (!gl) return;\\n\\n // Enable blending for translucency\\n gl.enable(gl.BLEND);\\n gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\\n\\n const compile = (type: number, src: string) => {\\n const s = gl.createShader(type)!;\\n gl.shaderSource(s, src);\\n gl.compileShader(s);\\n if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) console.error(gl.getShaderInfoLog(s));\\n return s;\\n };\\n const p = gl.createProgram()!;\\n gl.attachShader(p, compile(gl.VERTEX_SHADER, VERTEX_SHADER));\\n gl.attachShader(p, compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER));\\n gl.linkProgram(p);\\n gl.useProgram(p);\\n\\n // Uniform locations\\n const locs = {\\n uRes: gl.getUniformLocation(p, \'u_resolution\'),\\n uTime: gl.getUniformLocation(p, \'u_time\'),\\n uShipRot: gl.getUniformLocation(p, \'u_shipRot\'),\\n uThrust: gl.getUniformLocation(p, \'u_thrust\'),\\n uThrustIgnitionTime: gl.getUniformLocation(p, \'u_thrust_ignition_time\'),\\n uBrake: gl.getUniformLocation(p, \'u_brake\'),\\n uYawVelocity: gl.getUniformLocation(p, \'u_yaw_velocity\'),\\n uPitchVelocity: gl.getUniformLocation(p, \'u_pitch_velocity\'),\\n // Ship DNA\\n uComplexity: gl.getUniformLocation(p, \'u_complexity\'),\\n uFold1: gl.getUniformLocation(p, \'u_fold1\'),\\n uFold2: gl.getUniformLocation(p, \'u_fold2\'),\\n uFold3: gl.getUniformLocation(p, \'u_fold3\'),\\n uScale: gl.getUniformLocation(p, \'u_scale\'),\\n uStretch: gl.getUniformLocation(p, \'u_stretch\'),\\n uTaper: gl.getUniformLocation(p, \'u_taper\'),\\n uTwist: gl.getUniformLocation(p, \'u_twist\'),\\n uAsymmetryX: gl.getUniformLocation(p, \'u_asymmetryX\'),\\n uAsymmetryY: gl.getUniformLocation(p, \'u_asymmetryY\'),\\n uAsymmetryZ: gl.getUniformLocation(p, \'u_asymmetryZ\'),\\n \\n // New Bias Uniforms\\n uTwistAsymX: gl.getUniformLocation(p, \'u_twistAsymX\'),\\n uScaleAsymX: gl.getUniformLocation(p, \'u_scaleAsymX\'),\\n uFold1AsymX: gl.getUniformLocation(p, \'u_fold1AsymX\'),\\n uFold2AsymX: gl.getUniformLocation(p, \'u_fold2AsymX\'),\\n\\n uGeneralScale: gl.getUniformLocation(p, \'u_generalScale\'),\\n uChaseDistance: gl.getUniformLocation(p, \'u_chaseDistance\'),\\n uChaseVerticalOffset: gl.getUniformLocation(p, \'u_chaseVerticalOffset\'),\\n uTranslucency: gl.getUniformLocation(p, \'u_translucency\'),\\n };\\n\\n // Fullscreen quad\\n const vao = gl.createVertexArray()!;\\n gl.bindVertexArray(vao);\\n const vbo = gl.createBuffer()!;\\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);\\n gl.enableVertexAttribArray(0);\\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\\n\\n const rotMat = new Float32Array(16);\\n let lastTime = 0, animId = 0;\\n\\n // State for smooth thrust/brake animation, now with ignition tracking\\n const thrustState = {\\n level: 0.0,\\n isThrusting: false,\\n ignitionTime: -100.0, // Start far in the past to avoid animation on load\\n };\\n const brakeLevel = { current: 0.0 };\\n\\n const render = (t: number) => {\\n const dt = Math.min((t - lastTime) / 1000, 0.1);\\n const currentTimeSec = t * 0.001;\\n lastTime = t;\\n \\n const dpr = window.devicePixelRatio || 1;\\n const w = canvas.clientWidth * dpr, h = canvas.clientHeight * dpr;\\n if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; gl.viewport(0, 0, w, h); }\\n gl.clearColor(0, 0, 0, 0);\\n gl.clear(gl.COLOR_BUFFER_BIT);\\n\\n const isThrustingNow = (pressedKeysRef.current.has(\'s\') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has(\'w\') && controlConfigRef.current.invertForward);\\n const isBraking = (pressedKeysRef.current.has(\'w\') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has(\'s\') && controlConfigRef.current.invertForward);\\n \\n // Detect ignition start\\n if (isThrustingNow && !thrustState.isThrusting) {\\n thrustState.ignitionTime = currentTimeSec;\\n }\\n thrustState.isThrusting = isThrustingNow;\\n \\n // LERP for smooth animation\\n const LERP_SPEED = 8.0;\\n thrustState.level += ((isThrustingNow ? 1.0 : 0.0) - thrustState.level) * LERP_SPEED * dt;\\n brakeLevel.current += ((isBraking ? 1.0 : 0.0) - brakeLevel.current) * LERP_SPEED * dt;\\n \\n // Use actual physics angular velocity for smoother, heavier animation\\n // Negate yaw velocity because camera yaw is inverted relative to ship yaw visually\\n const tYaw = -cameraAngularVelocityRef.current[1] * 1.2; \\n const tPitch_velocity = cameraAngularVelocityRef.current[0];\\n // Invert pitch velocity to match user preference (UP looks UP)\\n const tPitch = -tPitch_velocity * 1.0 + (shipConfigRef.current.pitchOffset ?? 0.0);\\n\\n // Slower lerp for heavier feel (3.0 instead of 8.0)\\n shipState.current.yaw += (tYaw - shipState.current.yaw) * 3.0 * dt;\\n shipState.current.pitch += (tPitch - shipState.current.pitch) * 3.0 * dt;\\n // Roll based on yaw for banking\\n shipState.current.roll += (tYaw * 1.5 - shipState.current.roll) * 3.0 * dt;\\n\\n mat4.identity(rotMat);\\n mat4.rotateY(rotMat, rotMat, shipState.current.yaw);\\n mat4.rotateX(rotMat, rotMat, shipState.current.pitch);\\n mat4.rotateZ(rotMat, rotMat, shipState.current.roll);\\n\\n gl.useProgram(p);\\n gl.uniform2f(locs.uRes, w, h);\\n gl.uniform1f(locs.uTime, currentTimeSec);\\n gl.uniformMatrix4fv(locs.uShipRot, false, rotMat);\\n gl.uniform1f(locs.uThrust, thrustState.level);\\n gl.uniform1f(locs.uThrustIgnitionTime, thrustState.ignitionTime);\\n gl.uniform1f(locs.uBrake, brakeLevel.current);\\n gl.uniform1f(locs.uYawVelocity, tYaw);\\n gl.uniform1f(locs.uPitchVelocity, tPitch_velocity);\\n \\n // Update DNA uniforms from EFFECTIVE config (includes modulations)\\n const ec = effectiveShipConfigRef.current;\\n gl.uniform1f(locs.uComplexity, ec.complexity);\\n gl.uniform1f(locs.uFold1, ec.fold1);\\n gl.uniform1f(locs.uFold2, ec.fold2);\\n gl.uniform1f(locs.uFold3, ec.fold3);\\n gl.uniform1f(locs.uScale, ec.scale);\\n gl.uniform1f(locs.uStretch, ec.stretch);\\n gl.uniform1f(locs.uTaper, ec.taper);\\n gl.uniform1f(locs.uTwist, ec.twist);\\n gl.uniform1f(locs.uAsymmetryX, ec.asymmetryX);\\n gl.uniform1f(locs.uAsymmetryY, ec.asymmetryY);\\n gl.uniform1f(locs.uAsymmetryZ, ec.asymmetryZ);\\n\\n // New Bias Uniforms\\n gl.uniform1f(locs.uTwistAsymX, ec.twistAsymX);\\n gl.uniform1f(locs.uScaleAsymX, ec.scaleAsymX);\\n gl.uniform1f(locs.uFold1AsymX, ec.fold1AsymX);\\n gl.uniform1f(locs.uFold2AsymX, ec.fold2AsymX);\\n\\n gl.uniform1f(locs.uGeneralScale, shipConfigRef.current.generalScale ?? 1.0);\\n gl.uniform1f(locs.uChaseDistance, shipConfigRef.current.chaseDistance ?? 6.5);\\n gl.uniform1f(locs.uChaseVerticalOffset, shipConfigRef.current.chaseVerticalOffset ?? 1.0);\\n gl.uniform1f(locs.uTranslucency, shipConfigRef.current.translucency ?? 1.0);\\n\\n gl.bindVertexArray(vao);\\n gl.drawArrays(gl.TRIANGLES, 0, 6);\\n\\n animId = requestAnimationFrame(render);\\n };\\n render(performance.now());\\n return () => { cancelAnimationFrame(animId); gl.deleteProgram(p); };\\n }, [viewMode]);\\n\\n if (viewMode !== \'chase\') return null;\\n return <canvas ref={canvasRef} className=\\"absolute top-0 left-0 w-full h-full pointer-events-none z-10\\" />;\\n};", "resolution": "2K", "safety_filter_level": "block_only_high" } }' \ https://api.replicate.com/v1/models/google/nano-banana-pro/predictions
To learn more, take a look at Replicate’s HTTP API reference docs.
{ "id": "b8r4pc351srma0ctmwd8dr5kfr", "model": "google/nano-banana-pro", "version": "hidden", "input": { "aspect_ratio": "3:4", "image_input": [], "output_format": "jpg", "prompt": "render this: /**\n * @license\n * SPDX-License-Identifier: Apache-2.0\n*/\n\n\n\nimport React, { useRef, useEffect } from 'react';\nimport { useAppContext } from '../context/AppContext';\n\n// A simple full-screen quad vertex shader\nconst VERTEX_SHADER = `#version 300 es\nin vec2 a_position;\nout vec2 v_uv;\nvoid main() {\n v_uv = a_position;\n gl_Position = vec4(a_position, 0.0, 1.0);\n}\n`;\n\nconst FRAGMENT_SHADER = `#version 300 es\nprecision highp float;\nin vec2 v_uv;\nout vec4 outColor;\n\nuniform float u_time;\nuniform vec2 u_resolution;\nuniform mat4 u_shipRot;\nuniform float u_thrust;\nuniform float u_brake;\nuniform float u_yaw_velocity;\nuniform float u_pitch_velocity;\nuniform float u_thrust_ignition_time;\n\n// Ship DNA from sliders\nuniform float u_complexity;\nuniform float u_fold1;\nuniform float u_fold2;\nuniform float u_fold3;\nuniform float u_scale;\nuniform float u_stretch;\nuniform float u_taper;\nuniform float u_twist;\nuniform float u_asymmetryX;\nuniform float u_asymmetryY;\nuniform float u_asymmetryZ;\n\n// Parameter Biases\nuniform float u_twistAsymX;\nuniform float u_scaleAsymX;\nuniform float u_fold1AsymX;\nuniform float u_fold2AsymX;\n\nuniform float u_generalScale;\nuniform float u_chaseDistance;\nuniform float u_chaseVerticalOffset;\nuniform float u_translucency;\n\n#define MAX_STEPS 64\n#define MAX_DIST 15.0\n#define SURF_DIST 0.001\n\nmat2 rot(float a) { float s=sin(a), c=cos(a); return mat2(c, -s, s, c); }\n\n// KIFS Fractal for Ship Body\nfloat sdFractalShip(vec3 p) {\n // Store original position for asymmetry calculations\n vec3 pOrig = p;\n\n // Apply Asymmetry Distortion first (Spatial scaling based on sign)\n p.x *= 1.0 - sign(p.x) * u_asymmetryX * 0.5;\n p.y *= 1.0 - sign(p.y) * u_asymmetryY * 0.5;\n p.z *= 1.0 - sign(p.z) * u_asymmetryZ * 0.5;\n\n p /= u_generalScale;\n p.z /= u_stretch; // Longitudinal stretch\n \n // Tapering along Z axis (before rotation, Z is longitudinal)\n p.xy *= 1.0 + p.z * u_taper;\n\n // --- Asymmetric Twisting ---\n // Base twist + gradient based on original X position\n // If u_twistAsymX > 0, positive X (Right) twists more.\n float localTwist = u_twist + pOrig.x * u_twistAsymX;\n p.xy *= rot(p.z * localTwist * 2.0);\n\n // Initial orientation to make it face forward (-Z)\n p.yz *= rot(1.57); \n\n float s = 1.0;\n for(int i=0; i<int(u_complexity); i++) {\n // --- Asymmetric Folding ---\n // Base fold + gradient based on original X position\n // Note: pOrig.x is used to keep the bias fixed to the ship's original side\n float localFold1 = u_fold1 + pOrig.x * u_fold1AsymX;\n float localFold2 = u_fold2 + pOrig.x * u_fold2AsymX;\n\n // Folding space\n p = abs(p) - vec3(localFold1, localFold2, 0.3)/s;\n p.xz *= rot(u_fold3);\n \n // --- Asymmetric Scaling ---\n float localScale = u_scale + pOrig.x * u_scaleAsymX * 0.2;\n p *= localScale;\n s *= localScale;\n }\n // Base shape: a box that gets folded into the fractal\n float d = length(max(abs(p) - vec3(0.1, 0.8, 0.1), 0.0));\n return d/s * u_generalScale;\n}\n\n// Main SDF mapping the whole ship\nfloat map(vec3 p) {\n // Apply ship rotation (pitch/yaw/roll)\n p = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n\n // Main Body\n float dBody = sdFractalShip(p);\n \n // Engines (simple cylinders at the back)\n vec3 pEng = p;\n pEng.x = abs(pEng.x);\n pEng -= vec3(0.5, 0.0, 1.2); // Position at back\n float dEng = max(length(pEng.xy) - 0.2, abs(pEng.z) - 0.4);\n \n // Flaps (boxes at sides)\n vec3 pFlap = p;\n pFlap.x = abs(pFlap.x);\n pFlap -= vec3(1.1, 0.0, 0.2);\n // Rotate flaps when braking\n pFlap.yz *= rot(u_brake * 0.8);\n float dFlap = length(max(abs(pFlap) - vec3(0.4, 0.05, 0.3), 0.0));\n\n // Smooth blend body and dynamic parts\n float d = -log(exp(-dBody*12.0) + exp(-dEng*12.0) + exp(-dFlap*12.0)) / 12.0;\n return d;\n}\n\n// Calculate normal for lighting\nvec3 getNormal(vec3 p) {\n vec2 e = vec2(0.001, 0.0);\n return normalize(vec3(\n map(p + e.xyy) - map(p - e.xyy),\n map(p + e.yxy) - map(p - e.yxy),\n map(p + e.yyx) - map(p - e.yyx)\n ));\n}\n\nvoid main() {\n // Setup Ray from Chase Camera perspective\n vec2 uv = (gl_FragCoord.xy * 2.0 - u_resolution.xy) / u_resolution.y;\n vec3 ro = vec3(0.0, u_chaseVerticalOffset, u_chaseDistance); // Fixed chase camera relative to ship center (0,0,0)\n vec3 rd = normalize(vec3(uv, -1.5)); // Looking forward (-Z)\n\n float d = 0.0, t = 0.0;\n for(int i = 0; i < MAX_STEPS; i++) {\n vec3 p = ro + rd * t;\n d = map(p);\n if(d < SURF_DIST || t > MAX_DIST) break;\n t += d;\n }\n\n if(t < MAX_DIST) {\n vec3 p = ro + rd * t;\n vec3 n = getNormal(p);\n vec3 l = normalize(vec3(1.0, 2.0, 3.0)); // Fixed light source\n\n // Basic lighting\n float diff = max(dot(n, l), 0.0);\n float amb = 0.1;\n vec3 col = vec3(0.2, 0.25, 0.3) * (diff + amb);\n \n // Rim lighting\n float rim = pow(1.0 - max(dot(-rd, n), 0.0), 4.0);\n col += vec3(0.1, 0.6, 1.0) * rim * 0.8;\n\n // Calculate local coordinates for emissive mapping\n vec3 localP = (inverse(u_shipRot) * vec4(p, 1.0)).xyz;\n \n // --- Engine Glow ---\n // Wider mask to accommodate the ignition animation starting point\n float engineMask = smoothstep(0.4, 1.5, localP.z) * (1.0 - smoothstep(0.4, 1.0, abs(localP.x)));\n \n // Ignition Animation\n float timeSinceIgnition = u_time - u_thrust_ignition_time;\n float ignitionDuration = 0.3; // Animation duration in seconds\n\n // Ignition pulse travels from front (z=0.5) to back (z=1.5)\n float pulseProgress = clamp(timeSinceIgnition / ignitionDuration, 0.0, 1.0);\n float ignitionFrontZ = mix(0.5, 1.5, pulseProgress);\n\n // Moving pulse of light\n float pulseWidth = 0.15;\n float pulseShape = smoothstep(0.0, pulseWidth, localP.z - (ignitionFrontZ - pulseWidth)) * \n smoothstep(0.0, -pulseWidth, localP.z - (ignitionFrontZ + pulseWidth));\n float pulseGlow = pulseShape * 2.5 * (1.0 - pulseProgress); // Bright pulse that fades\n\n // Sustained Glow\n float wave1 = sin(localP.z * 8.0) * 0.5 + 0.5;\n float wave2 = sin(localP.z * 5.0) * 0.5 + 0.5;\n float sustainedIntensity = 0.2 + pow(wave1, 3.0) * 1.0 + pow(wave2, 5.0) * 0.8;\n\n // The sustained glow appears as the ignition pulse passes over it\n float sustainedVisibility = smoothstep(ignitionFrontZ - 0.2, ignitionFrontZ, localP.z);\n if (timeSinceIgnition > ignitionDuration) {\n sustainedVisibility = 1.0; // Fully visible after animation\n }\n float finalSustainedGlow = mix(0.1, sustainedIntensity, u_thrust * sustainedVisibility);\n\n // Combine glows\n float totalGlow = finalSustainedGlow + pulseGlow;\n col += vec3(1.0, 0.4, 0.05) * engineMask * totalGlow;\n\n // Flap Glow - asymmetric for turning\n float leftBrakeAmount = u_brake + max(0.0, u_yaw_velocity * 2.5); // Turn right, left brake lights up\n float rightBrakeAmount = u_brake + max(0.0, -u_yaw_velocity * 2.5); // Turn left, right brake lights up\n\n float flapMaskLeft = smoothstep(0.8, 1.6, localP.x) * (1.0 - smoothstep(0.0, 0.8, -localP.x));\n float flapMaskRight = smoothstep(0.8, 1.6, -localP.x) * (1.0 - smoothstep(0.0, 0.8, localP.x));\n\n col += vec3(1.0, 0.1, 0.1) * flapMaskLeft * leftBrakeAmount * 2.0;\n col += vec3(1.0, 0.1, 0.1) * flapMaskRight * rightBrakeAmount * 2.0;\n\n // Pitch maneuver lights\n // Pitching up (negative velocity) lights bottom. Pitching down (positive velocity) lights top.\n float pitchUpAmount = max(0.0, -u_pitch_velocity * 4.0);\n float pitchDownAmount = max(0.0, u_pitch_velocity * 4.0);\n\n // Define masks for top and bottom surfaces, concentrated on the main body/wings area\n float pitchLightAreaMask = smoothstep(0.8, 0.0, abs(localP.z));\n float topMask = smoothstep(0.2, 0.4, localP.y) * pitchLightAreaMask;\n float bottomMask = smoothstep(-0.2, -0.4, localP.y) * pitchLightAreaMask;\n\n col += vec3(1.0, 0.1, 0.1) * topMask * pitchDownAmount;\n col += vec3(1.0, 0.1, 0.1) * bottomMask * pitchUpAmount;\n\n // Add alpha for transparency around the ship\n outColor = vec4(col, u_translucency);\n } else {\n outColor = vec4(0.0); // Transparent background\n }\n}\n`;\n\nconst mat4 = {\n identity: (out: Float32Array) => { out.fill(0); out[0]=1; out[5]=1; out[10]=1; out[15]=1; },\n rotateX: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a10=a[4],a11=a[5],a12=a[6],a13=a[7], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[4]=a10*c+a20*s; out[5]=a11*c+a21*s; out[6]=a12*c+a22*s; out[7]=a13*c+a23*s;\n out[8]=a20*c-a10*s; out[9]=a21*c-a11*s; out[10]=a22*c-a12*s; out[11]=a23*c-a13*s;\n },\n rotateY: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a20=a[8],a21=a[9],a22=a[10],a23=a[11];\n out.set(a);\n out[0]=a00*c-a20*s; out[1]=a01*c-a21*s; out[2]=a02*c-a22*s; out[3]=a03*c-a23*s;\n out[8]=a00*s+a20*c; out[9]=a01*s+a21*c; out[10]=a02*s+a22*c; out[11]=a03*s+a23*c;\n },\n rotateZ: (out: Float32Array, a: Float32Array, rad: number) => {\n let s=Math.sin(rad), c=Math.cos(rad), a00=a[0],a01=a[1],a02=a[2],a03=a[3], a10=a[4],a11=a[5],a12=a[6],a13=a[7];\n out.set(a);\n out[0]=a00*c+a10*s; out[1]=a01*c+a11*s; out[2]=a02*c+a13*s; out[3]=a03*c+a13*s;\n out[4]=a10*c-a00*s; out[5]=a11*c-a01*s; out[6]=a12*c-a02*s; out[7]=a13*c-a03*s;\n },\n};\n\nexport const ShipOverlay: React.FC = () => {\n const { viewMode, pressedKeys, controlConfig, effectiveShipConfigRef, cameraAngularVelocityRef, shipConfig } = useAppContext();\n const canvasRef = useRef<HTMLCanvasElement>(null);\n const shipState = useRef({ pitch: 0, yaw: 0, roll: 0 });\n\n const shipConfigRef = useRef(shipConfig);\n useEffect(() => { shipConfigRef.current = shipConfig; }, [shipConfig]);\n \n const pressedKeysRef = useRef(pressedKeys);\n useEffect(() => { pressedKeysRef.current = pressedKeys; }, [pressedKeys]);\n \n const controlConfigRef = useRef(controlConfig);\n useEffect(() => { controlConfigRef.current = controlConfig; }, [controlConfig]);\n\n useEffect(() => {\n const canvas = canvasRef.current;\n if (!canvas || viewMode !== 'chase') return;\n const gl = canvas.getContext('webgl2', { alpha: true, depth: false, antialias: false }); // No depth needed for single quad\n if (!gl) return;\n\n // Enable blending for translucency\n gl.enable(gl.BLEND);\n gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);\n\n const compile = (type: number, src: string) => {\n const s = gl.createShader(type)!;\n gl.shaderSource(s, src);\n gl.compileShader(s);\n if (!gl.getShaderParameter(s, gl.COMPILE_STATUS)) console.error(gl.getShaderInfoLog(s));\n return s;\n };\n const p = gl.createProgram()!;\n gl.attachShader(p, compile(gl.VERTEX_SHADER, VERTEX_SHADER));\n gl.attachShader(p, compile(gl.FRAGMENT_SHADER, FRAGMENT_SHADER));\n gl.linkProgram(p);\n gl.useProgram(p);\n\n // Uniform locations\n const locs = {\n uRes: gl.getUniformLocation(p, 'u_resolution'),\n uTime: gl.getUniformLocation(p, 'u_time'),\n uShipRot: gl.getUniformLocation(p, 'u_shipRot'),\n uThrust: gl.getUniformLocation(p, 'u_thrust'),\n uThrustIgnitionTime: gl.getUniformLocation(p, 'u_thrust_ignition_time'),\n uBrake: gl.getUniformLocation(p, 'u_brake'),\n uYawVelocity: gl.getUniformLocation(p, 'u_yaw_velocity'),\n uPitchVelocity: gl.getUniformLocation(p, 'u_pitch_velocity'),\n // Ship DNA\n uComplexity: gl.getUniformLocation(p, 'u_complexity'),\n uFold1: gl.getUniformLocation(p, 'u_fold1'),\n uFold2: gl.getUniformLocation(p, 'u_fold2'),\n uFold3: gl.getUniformLocation(p, 'u_fold3'),\n uScale: gl.getUniformLocation(p, 'u_scale'),\n uStretch: gl.getUniformLocation(p, 'u_stretch'),\n uTaper: gl.getUniformLocation(p, 'u_taper'),\n uTwist: gl.getUniformLocation(p, 'u_twist'),\n uAsymmetryX: gl.getUniformLocation(p, 'u_asymmetryX'),\n uAsymmetryY: gl.getUniformLocation(p, 'u_asymmetryY'),\n uAsymmetryZ: gl.getUniformLocation(p, 'u_asymmetryZ'),\n \n // New Bias Uniforms\n uTwistAsymX: gl.getUniformLocation(p, 'u_twistAsymX'),\n uScaleAsymX: gl.getUniformLocation(p, 'u_scaleAsymX'),\n uFold1AsymX: gl.getUniformLocation(p, 'u_fold1AsymX'),\n uFold2AsymX: gl.getUniformLocation(p, 'u_fold2AsymX'),\n\n uGeneralScale: gl.getUniformLocation(p, 'u_generalScale'),\n uChaseDistance: gl.getUniformLocation(p, 'u_chaseDistance'),\n uChaseVerticalOffset: gl.getUniformLocation(p, 'u_chaseVerticalOffset'),\n uTranslucency: gl.getUniformLocation(p, 'u_translucency'),\n };\n\n // Fullscreen quad\n const vao = gl.createVertexArray()!;\n gl.bindVertexArray(vao);\n const vbo = gl.createBuffer()!;\n gl.bindBuffer(gl.ARRAY_BUFFER, vbo);\n gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1]), gl.STATIC_DRAW);\n gl.enableVertexAttribArray(0);\n gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);\n\n const rotMat = new Float32Array(16);\n let lastTime = 0, animId = 0;\n\n // State for smooth thrust/brake animation, now with ignition tracking\n const thrustState = {\n level: 0.0,\n isThrusting: false,\n ignitionTime: -100.0, // Start far in the past to avoid animation on load\n };\n const brakeLevel = { current: 0.0 };\n\n const render = (t: number) => {\n const dt = Math.min((t - lastTime) / 1000, 0.1);\n const currentTimeSec = t * 0.001;\n lastTime = t;\n \n const dpr = window.devicePixelRatio || 1;\n const w = canvas.clientWidth * dpr, h = canvas.clientHeight * dpr;\n if (canvas.width !== w || canvas.height !== h) { canvas.width = w; canvas.height = h; gl.viewport(0, 0, w, h); }\n gl.clearColor(0, 0, 0, 0);\n gl.clear(gl.COLOR_BUFFER_BIT);\n\n const isThrustingNow = (pressedKeysRef.current.has('s') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('w') && controlConfigRef.current.invertForward);\n const isBraking = (pressedKeysRef.current.has('w') && !controlConfigRef.current.invertForward) || (pressedKeysRef.current.has('s') && controlConfigRef.current.invertForward);\n \n // Detect ignition start\n if (isThrustingNow && !thrustState.isThrusting) {\n thrustState.ignitionTime = currentTimeSec;\n }\n thrustState.isThrusting = isThrustingNow;\n \n // LERP for smooth animation\n const LERP_SPEED = 8.0;\n thrustState.level += ((isThrustingNow ? 1.0 : 0.0) - thrustState.level) * LERP_SPEED * dt;\n brakeLevel.current += ((isBraking ? 1.0 : 0.0) - brakeLevel.current) * LERP_SPEED * dt;\n \n // Use actual physics angular velocity for smoother, heavier animation\n // Negate yaw velocity because camera yaw is inverted relative to ship yaw visually\n const tYaw = -cameraAngularVelocityRef.current[1] * 1.2; \n const tPitch_velocity = cameraAngularVelocityRef.current[0];\n // Invert pitch velocity to match user preference (UP looks UP)\n const tPitch = -tPitch_velocity * 1.0 + (shipConfigRef.current.pitchOffset ?? 0.0);\n\n // Slower lerp for heavier feel (3.0 instead of 8.0)\n shipState.current.yaw += (tYaw - shipState.current.yaw) * 3.0 * dt;\n shipState.current.pitch += (tPitch - shipState.current.pitch) * 3.0 * dt;\n // Roll based on yaw for banking\n shipState.current.roll += (tYaw * 1.5 - shipState.current.roll) * 3.0 * dt;\n\n mat4.identity(rotMat);\n mat4.rotateY(rotMat, rotMat, shipState.current.yaw);\n mat4.rotateX(rotMat, rotMat, shipState.current.pitch);\n mat4.rotateZ(rotMat, rotMat, shipState.current.roll);\n\n gl.useProgram(p);\n gl.uniform2f(locs.uRes, w, h);\n gl.uniform1f(locs.uTime, currentTimeSec);\n gl.uniformMatrix4fv(locs.uShipRot, false, rotMat);\n gl.uniform1f(locs.uThrust, thrustState.level);\n gl.uniform1f(locs.uThrustIgnitionTime, thrustState.ignitionTime);\n gl.uniform1f(locs.uBrake, brakeLevel.current);\n gl.uniform1f(locs.uYawVelocity, tYaw);\n gl.uniform1f(locs.uPitchVelocity, tPitch_velocity);\n \n // Update DNA uniforms from EFFECTIVE config (includes modulations)\n const ec = effectiveShipConfigRef.current;\n gl.uniform1f(locs.uComplexity, ec.complexity);\n gl.uniform1f(locs.uFold1, ec.fold1);\n gl.uniform1f(locs.uFold2, ec.fold2);\n gl.uniform1f(locs.uFold3, ec.fold3);\n gl.uniform1f(locs.uScale, ec.scale);\n gl.uniform1f(locs.uStretch, ec.stretch);\n gl.uniform1f(locs.uTaper, ec.taper);\n gl.uniform1f(locs.uTwist, ec.twist);\n gl.uniform1f(locs.uAsymmetryX, ec.asymmetryX);\n gl.uniform1f(locs.uAsymmetryY, ec.asymmetryY);\n gl.uniform1f(locs.uAsymmetryZ, ec.asymmetryZ);\n\n // New Bias Uniforms\n gl.uniform1f(locs.uTwistAsymX, ec.twistAsymX);\n gl.uniform1f(locs.uScaleAsymX, ec.scaleAsymX);\n gl.uniform1f(locs.uFold1AsymX, ec.fold1AsymX);\n gl.uniform1f(locs.uFold2AsymX, ec.fold2AsymX);\n\n gl.uniform1f(locs.uGeneralScale, shipConfigRef.current.generalScale ?? 1.0);\n gl.uniform1f(locs.uChaseDistance, shipConfigRef.current.chaseDistance ?? 6.5);\n gl.uniform1f(locs.uChaseVerticalOffset, shipConfigRef.current.chaseVerticalOffset ?? 1.0);\n gl.uniform1f(locs.uTranslucency, shipConfigRef.current.translucency ?? 1.0);\n\n gl.bindVertexArray(vao);\n gl.drawArrays(gl.TRIANGLES, 0, 6);\n\n animId = requestAnimationFrame(render);\n };\n render(performance.now());\n return () => { cancelAnimationFrame(animId); gl.deleteProgram(p); };\n }, [viewMode]);\n\n if (viewMode !== 'chase') return null;\n return <canvas ref={canvasRef} className=\"absolute top-0 left-0 w-full h-full pointer-events-none z-10\" />;\n};", "resolution": "2K", "safety_filter_level": "block_only_high" }, "logs": "Generating image...\nGenerated image in 64.93 seconds", "output": "https://replicate.delivery/xezq/0P5gHVWjTtLSEdd8KHla8eqWe9AD3VLQztpEVLY8GGWVwjrVA/tmpld7wvp79.jpeg", "data_removed": false, "error": null, "source": "web", "status": "succeeded", "created_at": "2025-11-21T15:48:36.238Z", "started_at": "2025-11-21T15:48:36.242448Z", "completed_at": "2025-11-21T15:49:41.647814Z", "urls": { "cancel": "https://api.replicate.com/v1/predictions/b8r4pc351srma0ctmwd8dr5kfr/cancel", "get": "https://api.replicate.com/v1/predictions/b8r4pc351srma0ctmwd8dr5kfr", "stream": "https://stream.replicate.com/v1/files/bcwr-xkywghwdeuiu6inrdca6w3bk3x63imjl4vyau3zfhc3gexwr6olq", "web": "https://replicate.com/p/b8r4pc351srma0ctmwd8dr5kfr" }, "metrics": { "predict_time": 65.405365558, "total_time": 65.4098142 } }