mimo-v2.5 Code
Model-specific source generated from the shared prompt shown on the gallery page. The prompt itself is intentionally not duplicated here.

JavaScript
src/main.js
1import './styles.css';2import * as THREE from 'three';3 4const MODEL_NAME = 'mimo-v2-5';5 6const state = {7 paused: false,8 time: 0,9 waveHeight: 1.0,10 waveSpeed: 1.0,11};12 13const vertexShader = `14 uniform float uTime;15 uniform float uWaveHeight;16 varying vec2 vUv;17 varying float vElevation;18 19 void main() {20 vUv = uv;21 vec3 pos = position;22 23 float wave1 = sin(pos.x * 0.8 + uTime * 1.2) * 0.5;24 float wave2 = sin(pos.z * 1.1 + uTime * 0.9) * 0.35;25 float wave3 = cos(pos.x * 0.5 + pos.z * 0.6 + uTime * 1.5) * 0.25;26 float wave4 = sin(pos.x * 2.0 + pos.z * 1.5 + uTime * 2.0) * 0.1;27 28 float elevation = (wave1 + wave2 + wave3 + wave4) * uWaveHeight;29 pos.y += elevation;30 vElevation = elevation;31 32 gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);33 }34`;35 36const fragmentShader = `37 varying vec2 vUv;38 varying float vElevation;39 40 void main() {41 vec3 deepColor = vec3(0.01, 0.06, 0.18);42 vec3 midColor = vec3(0.03, 0.22, 0.42);43 vec3 peakColor = vec3(0.15, 0.55, 0.65);44 vec3 foamColor = vec3(0.85, 0.92, 0.97);45 46 float t = smoothstep(-1.0, 1.5, vElevation);47 vec3 color = mix(deepColor, midColor, smoothstep(0.0, 0.3, t));48 color = mix(color, peakColor, smoothstep(0.3, 0.7, t));49 color = mix(color, foamColor, smoothstep(0.7, 1.2, t));50 51 float fresnel = pow(1.0 - max(dot(normalize(vec3(vUv.x - 0.5, 0.5, vUv.y - 0.5)), vec3(0.0, 1.0, 0.0)), 0.0), 3.0);52 color += vec3(0.1, 0.15, 0.2) * fresnel * 0.3;53 54 gl_FragColor = vec4(color, 0.95);55 }56`;57 58const app = document.querySelector('#app');59app.innerHTML = '';60 61const canvas = document.createElement('canvas');62app.appendChild(canvas);63 64const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });65renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));66renderer.setSize(window.innerWidth, window.innerHeight);67renderer.toneMapping = THREE.ACESFilmicToneMapping;68renderer.toneMappingExposure = 1.2;69 70const scene = new THREE.Scene();71scene.background = new THREE.Color(0x87CEEB);72scene.fog = new THREE.FogExp2(0x87CEEB, 0.015);73 74const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);75camera.position.set(0, 8, 20);76camera.lookAt(0, 0, 0);77 78const sunLight = new THREE.DirectionalLight(0xfff4e0, 2.5);79sunLight.position.set(10, 20, 10);80scene.add(sunLight);81 82const ambientLight = new THREE.AmbientLight(0x4488cc, 0.6);83scene.add(ambientLight);84 85const fillLight = new THREE.DirectionalLight(0x88aaff, 0.4);86fillLight.position.set(-10, 5, -10);87scene.add(fillLight);88 89const oceanGeometry = new THREE.PlaneGeometry(100, 100, 200, 200);90oceanGeometry.rotateX(-Math.PI / 2);91 92const oceanMaterial = new THREE.ShaderMaterial({93 vertexShader,94 fragmentShader,95 uniforms: {96 uTime: { value: 0 },97 uWaveHeight: { value: state.waveHeight },98 },99 transparent: true,100 side: THREE.DoubleSide,101});102 103const ocean = new THREE.Mesh(oceanGeometry, oceanMaterial);104scene.add(ocean);105 106const skyGeo = new THREE.SphereGeometry(200, 32, 15);107const skyMat = new THREE.ShaderMaterial({108 side: THREE.BackSide,109 uniforms: {},110 vertexShader: `111 varying vec3 vWorldPos;112 void main() {113 vWorldPos = (modelMatrix * vec4(position, 1.0)).xyz;114 gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);115 }116 `,117 fragmentShader: `118 varying vec3 vWorldPos;119 void main() {120 float h = normalize(vWorldPos).y;121 vec3 skyTop = vec3(0.2, 0.5, 0.9);122 vec3 skyMid = vec3(0.55, 0.75, 0.95);123 vec3 skyHorizon = vec3(0.85, 0.88, 0.93);124 vec3 color = mix(skyHorizon, skyMid, smoothstep(0.0, 0.3, h));125 color = mix(color, skyTop, smoothstep(0.3, 0.8, h));126 float sun = pow(max(dot(normalize(vWorldPos), normalize(vec3(10.0, 20.0, 10.0))), 0.0), 64.0);127 color += vec3(1.0, 0.95, 0.8) * sun * 0.8;128 gl_FragColor = vec4(color, 1.0);129 }130 `,131});132const sky = new THREE.Mesh(skyGeo, skyMat);133scene.add(sky);134 135const uiOverlay = document.createElement('div');136uiOverlay.id = 'ui-overlay';137app.appendChild(uiOverlay);138 139const modelLabel = document.createElement('div');140modelLabel.id = 'model-label';141modelLabel.textContent = MODEL_NAME;142uiOverlay.appendChild(modelLabel);143 144const controlsPanel = document.createElement('div');145controlsPanel.id = 'controls-panel';146uiOverlay.appendChild(controlsPanel);147 148const pauseBtn = document.createElement('button');149pauseBtn.id = 'pause-btn';150pauseBtn.textContent = 'Pause';151pauseBtn.addEventListener('click', () => {152 state.paused = !state.paused;153 pauseBtn.textContent = state.paused ? 'Resume' : 'Pause';154});155controlsPanel.appendChild(pauseBtn);156 157function makeSlider(labelText, min, max, step, value, onChange) {158 const wrap = document.createElement('div');159 wrap.className = 'slider-group';160 const label = document.createElement('label');161 label.textContent = labelText;162 const input = document.createElement('input');163 input.type = 'range';164 input.min = min;165 input.max = max;166 input.step = step;167 input.value = value;168 const valSpan = document.createElement('span');169 valSpan.className = 'slider-val';170 valSpan.textContent = value;171 input.addEventListener('input', () => {172 const v = parseFloat(input.value);173 valSpan.textContent = v.toFixed(1);174 onChange(v);175 });176 label.appendChild(valSpan);177 wrap.appendChild(label);178 wrap.appendChild(input);179 return wrap;180}181 182controlsPanel.appendChild(makeSlider('Wave Height', 0, 3, 0.1, state.waveHeight, (v) => {183 state.waveHeight = v;184 oceanMaterial.uniforms.uWaveHeight.value = v;185}));186 187controlsPanel.appendChild(makeSlider('Speed', 0.1, 3, 0.1, state.waveSpeed, (v) => {188 state.waveSpeed = v;189}));190 191let cameraAngle = 0;192const cameraRadius = 22;193const cameraHeight = 10;194 195function animate() {196 requestAnimationFrame(animate);197 if (!state.paused) {198 state.time += 0.016 * state.waveSpeed;199 oceanMaterial.uniforms.uTime.value = state.time;200 cameraAngle += 0.001 * state.waveSpeed;201 camera.position.x = Math.sin(cameraAngle) * cameraRadius;202 camera.position.z = Math.cos(cameraAngle) * cameraRadius;203 camera.position.y = cameraHeight + Math.sin(cameraAngle * 0.5) * 2;204 camera.lookAt(0, -1, 0);205 }206 renderer.render(scene, camera);207}208 209function onResize() {210 const w = window.innerWidth;211 const h = window.innerHeight;212 camera.aspect = w / h;213 camera.updateProjectionMatrix();214 renderer.setSize(w, h);215}216window.addEventListener('resize', onResize);217 218animate();219
CSS
src/styles.css
1* {2 box-sizing: border-box;3 margin: 0;4 padding: 0;5}6 7html,8body,9#app {10 width: 100%;11 height: 100%;12 overflow: hidden;13}14 15body {16 font-family: system-ui, -apple-system, sans-serif;17}18 19canvas {20 display: block;21 width: 100%;22 height: 100%;23}24 25#ui-overlay {26 position: fixed;27 inset: 0;28 pointer-events: none;29 z-index: 10;30}31 32#model-label {33 position: absolute;34 top: 16px;35 left: 16px;36 background: rgba(0, 0, 0, 0.55);37 color: #cde;38 padding: 6px 14px;39 border-radius: 6px;40 font-size: 13px;41 font-weight: 500;42 letter-spacing: 0.3px;43 backdrop-filter: blur(6px);44 -webkit-backdrop-filter: blur(6px);45 user-select: none;46}47 48#controls-panel {49 position: absolute;50 bottom: 20px;51 left: 50%;52 transform: translateX(-50%);53 display: flex;54 align-items: center;55 gap: 18px;56 background: rgba(0, 0, 0, 0.5);57 backdrop-filter: blur(10px);58 -webkit-backdrop-filter: blur(10px);59 padding: 10px 22px;60 border-radius: 12px;61 pointer-events: auto;62 flex-wrap: wrap;63 justify-content: center;64 max-width: 92vw;65}66 67#pause-btn {68 background: rgba(255, 255, 255, 0.15);69 border: 1px solid rgba(255, 255, 255, 0.25);70 color: #eef;71 padding: 7px 18px;72 border-radius: 8px;73 font-size: 14px;74 cursor: pointer;75 transition: background 0.15s;76 white-space: nowrap;77}78 79#pause-btn:hover {80 background: rgba(255, 255, 255, 0.25);81}82 83.slider-group {84 display: flex;85 flex-direction: column;86 gap: 3px;87}88 89.slider-group label {90 color: #cde;91 font-size: 12px;92 font-weight: 500;93}94 95.slider-val {96 margin-left: 6px;97 opacity: 0.7;98 font-variant-numeric: tabular-nums;99}100 101.slider-group input[type='range'] {102 width: 120px;103 accent-color: #4af;104 cursor: pointer;105}106 107@media (max-width: 600px) {108 #controls-panel {109 bottom: 12px;110 padding: 8px 14px;111 gap: 12px;112 }113 114 .slider-group input[type='range'] {115 width: 90px;116 }117 118 #model-label {119 font-size: 11px;120 top: 12px;121 left: 12px;122 padding: 5px 10px;123 }124}125
Package
package.json
1{2 "name": "ocean-ui-model-run",3 "version": "0.1.0",4 "private": true,5 "type": "module",6 "scripts": {7 "dev": "vite --host 127.0.0.1",8 "build": "vite build",9 "preview": "vite preview --host 127.0.0.1"10 },11 "dependencies": {12 "three": "^0.171.0",13 "vite": "^6.0.7"14 },15 "devDependencies": {}16}17