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.

mimo-v2.5 ocean UI screenshot
src/main.js src/styles.css package.json
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