glm-5.1 Code

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

glm-5.1 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 = 'glm-5-1';5 6const app = document.querySelector('#app');7 8const renderer = new THREE.WebGLRenderer({ antialias: true });9renderer.setPixelRatio(window.devicePixelRatio);10renderer.setSize(window.innerWidth, window.innerHeight);11renderer.toneMapping = THREE.ACESFilmicToneMapping;12renderer.toneMappingExposure = 0.9;13app.appendChild(renderer.domElement);14 15const scene = new THREE.Scene();16scene.background = new THREE.Color('#1a2a44');17scene.fog = new THREE.FogExp2('#1a2a44', 0.0012);18 19const camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 2000);20camera.position.set(0, 25, 80);21camera.lookAt(0, 0, 0);22 23const vertexShader = `24  uniform float uTime;25  uniform float uWaveHeight;26  uniform float uWaveSpeed;27 28  varying vec3 vWorldPos;29  varying vec3 vNormalCalc;30  varying float vElevation;31 32  void main() {33    vec3 pos = position;34    float t = uTime * uWaveSpeed;35 36    float w1 = sin(pos.x * 0.02 + t * 0.8) * uWaveHeight;37    float w2 = sin(pos.z * 0.03 + t * 0.6) * uWaveHeight * 0.7;38    float w3 = sin((pos.x + pos.z) * 0.015 + t * 1.1) * uWaveHeight * 0.5;39    float w4 = sin(pos.x * 0.05 + pos.z * 0.04 + t * 1.4) * uWaveHeight * 0.3;40    float w5 = sin(pos.x * 0.08 - t * 0.9) * uWaveHeight * 0.15;41 42    pos.y += w1 + w2 + w3 + w4 + w5;43 44    float dx = cos(pos.x * 0.02 + t * 0.8) * 0.02 * uWaveHeight45             + cos((pos.x + pos.z) * 0.015 + t * 1.1) * 0.015 * uWaveHeight46             + cos(pos.x * 0.05 + pos.z * 0.04 + t * 1.4) * 0.05 * uWaveHeight47             + cos(pos.x * 0.08 - t * 0.9) * 0.08 * uWaveHeight;48 49    float dz = cos(pos.z * 0.03 + t * 0.6) * 0.03 * uWaveHeight * 0.750             + cos((pos.x + pos.z) * 0.015 + t * 1.1) * 0.015 * uWaveHeight51             + cos(pos.x * 0.05 + pos.z * 0.04 + t * 1.4) * 0.04 * uWaveHeight;52 53    vec3 n = normalize(vec3(-dx, 1.0, -dz));54 55    vWorldPos = pos;56    vNormalCalc = n;57    vElevation = pos.y;58 59    gl_Position = projectionMatrix * modelViewMatrix * vec4(pos, 1.0);60  }61`;62 63const fragmentShader = `64  uniform float uTime;65  uniform vec3 uDeepColor;66  uniform vec3 uShallowColor;67  uniform vec3 uFoamColor;68 69  varying vec3 vWorldPos;70  varying vec3 vNormalCalc;71  varying float vElevation;72 73  void main() {74    vec3 lightDir = normalize(vec3(0.5, 0.8, 0.3));75    vec3 viewDir = normalize(cameraPosition - vWorldPos);76    vec3 halfDir = normalize(lightDir + viewDir);77 78    float diff = max(dot(vNormalCalc, lightDir), 0.0);79    float spec = pow(max(dot(vNormalCalc, halfDir), 0.0), 64.0);80 81    float depthFactor = smoothstep(-8.0, 15.0, vElevation);82    vec3 waterColor = mix(uDeepColor, uShallowColor, depthFactor);83 84    float foamThreshold = 7.0;85    float foam = smoothstep(foamThreshold - 1.5, foamThreshold + 1.5, vElevation);86    waterColor = mix(waterColor, uFoamColor, foam * 0.6);87 88    float edgeFoam = smoothstep(foamThreshold + 1.5, foamThreshold - 1.5, vElevation);89    float sparkle = sin(vWorldPos.x * 2.0 + uTime * 1.5) * sin(vWorldPos.z * 2.3 + uTime * 1.2);90    sparkle = smoothstep(0.85, 1.0, sparkle) * edgeFoam;91    waterColor += uFoamColor * sparkle * 0.15;92 93    vec3 color = waterColor * (0.35 + diff * 0.45) + vec3(1.0) * spec * 0.5;94 95    float fogDist = length(vWorldPos - cameraPosition);96    float fogFactor = 1.0 - exp(-0.0012 * fogDist * fogDist * 0.0004);97    color = mix(color, vec3(0.102, 0.165, 0.267), fogFactor);98 99    gl_FragColor = vec4(color, 1.0);100  }101`;102 103const oceanUniforms = {104  uTime: { value: 0 },105  uWaveHeight: { value: 8.0 },106  uWaveSpeed: { value: 1.0 },107  uDeepColor: { value: new THREE.Color('#041830') },108  uShallowColor: { value: new THREE.Color('#0b4f8a') },109  uFoamColor: { value: new THREE.Color('#b8dbe8') },110};111 112const oceanMaterial = new THREE.ShaderMaterial({113  vertexShader,114  fragmentShader,115  uniforms: oceanUniforms,116  side: THREE.DoubleSide,117});118 119const oceanGeometry = new THREE.PlaneGeometry(600, 600, 200, 200);120oceanGeometry.rotateX(-Math.PI / 2);121 122const ocean = new THREE.Mesh(oceanGeometry, oceanMaterial);123scene.add(ocean);124 125const ambientLight = new THREE.AmbientLight('#3a5a8a', 0.4);126scene.add(ambientLight);127 128const dirLight = new THREE.DirectionalLight('#ffffff', 1.2);129dirLight.position.set(50, 80, 30);130scene.add(dirLight);131 132const controls = document.createElement('div');133controls.id = 'controls';134controls.innerHTML = `135  <div class="control-row">136    <label>Wave Height137      <div class="control-row">138        <input type="range" id="wave-height" min="1" max="20" step="0.5" value="8" />139        <span class="value-display" id="wave-height-val">8.0</span>140      </div>141    </label>142  </div>143  <div class="control-row">144    <label>Wave Speed145      <div class="control-row">146        <input type="range" id="wave-speed" min="0.1" max="3.0" step="0.1" value="1.0" />147        <span class="value-display" id="wave-speed-val">1.0</span>148      </div>149    </label>150  </div>151  <button id="pause-btn">Pause</button>152`;153app.appendChild(controls);154 155const pauseBtn = document.getElementById('pause-btn');156const waveHeightInput = document.getElementById('wave-height');157const waveHeightVal = document.getElementById('wave-height-val');158const waveSpeedInput = document.getElementById('wave-speed');159const waveSpeedVal = document.getElementById('wave-speed-val');160 161let paused = false;162 163pauseBtn.addEventListener('click', () => {164  paused = !paused;165  pauseBtn.textContent = paused ? 'Resume' : 'Pause';166});167 168waveHeightInput.addEventListener('input', (e) => {169  const v = parseFloat(e.target.value);170  oceanUniforms.uWaveHeight.value = v;171  waveHeightVal.textContent = v.toFixed(1);172});173 174waveSpeedInput.addEventListener('input', (e) => {175  const v = parseFloat(e.target.value);176  oceanUniforms.uWaveSpeed.value = v;177  waveSpeedVal.textContent = v.toFixed(1);178});179 180const modelLabel = document.createElement('div');181modelLabel.id = 'model-label';182modelLabel.textContent = MODEL_NAME;183app.appendChild(modelLabel);184 185const fpsCounter = document.createElement('div');186fpsCounter.id = 'fps-counter';187app.appendChild(fpsCounter);188 189let elapsedTime = 0;190const clock = new THREE.Clock();191let frameCount = 0;192let fpsTime = 0;193 194function animate() {195  requestAnimationFrame(animate);196 197  const delta = clock.getDelta();198 199  if (!paused) {200    elapsedTime += delta;201    oceanUniforms.uTime.value = elapsedTime;202  }203 204  const camRadius = 120;205  const camSpeed = 0.05;206  camera.position.x = Math.sin(elapsedTime * camSpeed) * camRadius;207  camera.position.z = Math.cos(elapsedTime * camSpeed) * camRadius;208  camera.position.y = 20 + Math.sin(elapsedTime * camSpeed * 0.5) * 8;209  camera.lookAt(0, 0, 0);210 211  frameCount++;212  fpsTime += delta;213  if (fpsTime >= 1) {214    fpsCounter.textContent = `${Math.round(frameCount / fpsTime)} fps`;215    frameCount = 0;216    fpsTime = 0;217  }218 219  renderer.render(scene, camera);220}221 222animate();223 224window.addEventListener('resize', () => {225  camera.aspect = window.innerWidth / window.innerHeight;226  camera.updateProjectionMatrix();227  renderer.setSize(window.innerWidth, window.innerHeight);228});
CSS

src/styles.css

1* {2  box-sizing: border-box;3}4 5html,6body,7#app {8  width: 100%;9  height: 100%;10  margin: 0;11}12 13body {14  font-family: system-ui, -apple-system, sans-serif;15  overflow: hidden;16  background: #0a0e1a;17}18 19#app {20  position: relative;21}22 23canvas {24  display: block;25  width: 100%;26  height: 100%;27}28 29#controls {30  position: absolute;31  bottom: 20px;32  left: 20px;33  background: rgba(0, 0, 0, 0.55);34  backdrop-filter: blur(8px);35  border-radius: 10px;36  padding: 14px 18px;37  color: #e0ecff;38  display: flex;39  flex-direction: column;40  gap: 10px;41  min-width: 220px;42  max-width: 280px;43  border: 1px solid rgba(100, 160, 255, 0.2);44}45 46#controls label {47  font-size: 12px;48  text-transform: uppercase;49  letter-spacing: 0.06em;50  opacity: 0.7;51  display: flex;52  flex-direction: column;53  gap: 4px;54}55 56#controls .control-row {57  display: flex;58  align-items: center;59  gap: 10px;60}61 62#controls input[type="range"] {63  flex: 1;64  accent-color: #4a90d9;65  height: 4px;66}67 68#controls .value-display {69  min-width: 32px;70  text-align: right;71  font-size: 13px;72  font-variant-numeric: tabular-nums;73}74 75#pause-btn {76  background: rgba(74, 144, 217, 0.25);77  border: 1px solid rgba(74, 144, 217, 0.4);78  color: #e0ecff;79  border-radius: 6px;80  padding: 8px 16px;81  cursor: pointer;82  font-size: 13px;83  font-family: inherit;84  transition: background 0.2s;85  letter-spacing: 0.04em;86}87 88#pause-btn:hover {89  background: rgba(74, 144, 217, 0.45);90}91 92#model-label {93  position: absolute;94  top: 14px;95  right: 14px;96  background: rgba(0, 0, 0, 0.45);97  backdrop-filter: blur(6px);98  border-radius: 6px;99  padding: 6px 12px;100  color: rgba(200, 220, 255, 0.7);101  font-size: 11px;102  letter-spacing: 0.04em;103  border: 1px solid rgba(100, 160, 255, 0.15);104}105 106#fps-counter {107  position: absolute;108  top: 14px;109  left: 14px;110  color: rgba(200, 220, 255, 0.45);111  font-size: 11px;112  font-variant-numeric: tabular-nums;113}114 115@media (max-width: 600px) {116  #controls {117    bottom: 10px;118    left: 10px;119    right: 10px;120    max-width: none;121    min-width: 0;122    padding: 10px 14px;123    gap: 8px;124  }125 126  #model-label {127    top: 10px;128    right: 10px;129    font-size: 10px;130  }131 132  #fps-counter {133    top: 10px;134    left: 10px;135    font-size: 10px;136  }137}
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