Interactive 3D aquariumOne-line
Gemma 4 31B
by Googlereasoning default1 console error
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 22.3 s
- Cost
- $0.0009
- Output tokens
- 2,456
- Spent thinking
- 0 tokens
- Speed
- 112.3 tok/s
- Console errors
- 1
- First token after
- 448 ms
- First visible text after
- 448 ms
- Prompt tokens
- 466
- Code size
- 8.5 KB
- Finish reason
- stop
- Served by
- CoreWeave
- Model id
google/gemma-4-31b-it- Reasoning sent
model default- Max output
- 16,384 tokens
- Generated
- Nov 13, 2026
Console errors
Caught in the first 3 seconds after load, in a sandboxed iframe like the one above.
THREE.TriangleGeometry is not a constructor
What it was asked
The prompt
“a 3D aquarium with Three.js where the fish swim away when I move the mouse near them (Load Three.js only through this import map: <script type="importmap">{"imports":{"three":"https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js","three/addons/":"https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"}}</script>)”
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task. Output rules: - Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block. - Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task. - Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw. - The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar. - Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction. - Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session. - Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing. - The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message. - The code must run with zero errors in the console of the latest Chrome.
Code run-1.html · 236 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>3D Interactive Aquarium</title>
<style>
body {
margin: 0;
overflow: hidden;
background-color: #001b3d;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
#ui {
position: absolute;
top: 20px;
left: 20px;
color: white;
pointer-events: none;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
.instruction {
font-size: 1.2rem;
opacity: 0.8;
}
canvas {
display: block;
}
</style>
</head>
<body>
<div id="ui">
<h1>Digital Aquarium</h1>
<p class="instruction">Move your mouse to scare the fish!</p>
</div>
<script type="importmap">
{
"imports": {
"three": "https://cdn.jsdelivr.net/npm/three@0.170.0/build/three.module.js",
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.170.0/examples/jsm/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
// --- Configuration ---
const FISH_COUNT = 40;
const AQUARIUM_SIZE = 20;
const REPEL_DISTANCE = 4;
const REPEL_STRENGTH = 0.15;
const RETURN_SPEED = 0.02;
let scene, camera, renderer, clock;
let fishArray = [];
let mouse = new THREE.Vector2(-1000, -1000);
let raycaster = new THREE.Raycaster();
init();
animate();
function init() {
// Scene & Camera
scene = new THREE.Scene();
scene.background = new THREE.Color(0x001b3d);
scene.fog = new THREE.Fog(0x001b3d, 10, 50);
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 25);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
document.body.appendChild(renderer.domElement);
clock = new THREE.Clock();
// Lights
const ambientLight = new THREE.AmbientLight(0x404040, 2);
scene.add(ambientLight);
const pointLight = new THREE.PointLight(0xffffff, 100);
pointLight.position.set(0, 10, 0);
scene.add(pointLight);
const blueLight = new THREE.PointLight(0x00ffff, 50);
blueLight.position.set(-10, -5, 5);
scene.add(blueLight);
// Aquarium Box (Glass effect)
const boxGeo = new THREE.BoxGeometry(AQUARIUM_SIZE, AQUARIUM_SIZE, AQUARIUM_SIZE);
const boxMat = new THREE.MeshPhongMaterial({
color: 0xaaaaff,
transparent: true,
opacity: 0.1,
side: THREE.BackSide
});
const aquarium = new THREE.Mesh(boxGeo, boxMat);
scene.add(aquarium);
// Sand/Floor
const floorGeo = new THREE.PlaneGeometry(AQUARIUM_SIZE, AQUARIUM_SIZE);
const floorMat = new THREE.MeshPhongMaterial({ color: 0xc2b280 });
const floor = new THREE.Mesh(floorGeo, floorMat);
floor.rotation.x = -Math.PI / 2;
floor.position.y = -AQUARIUM_SIZE / 2;
scene.add(floor);
// Create Fish
const colors = [0xff6600, 0xffff00, 0x00ffcc, 0xff00ff, 0xffaa00];
for (let i = 0; i < FISH_COUNT; i++) {
createFish(colors[Math.floor(Math.random() * colors.length)]);
}
window.addEventListener('resize', onWindowResize);
window.addEventListener('mousemove', onMouseMove);
}
function createFish(color) {
const group = new THREE.Group();
// Body - Simple elongated sphere/cone
const bodyGeo = new THREE.ConeGeometry(0.3, 1, 8);
bodyGeo.rotateX(Math.PI / 2);
const bodyMat = new THREE.MeshPhongMaterial({ color: color });
const body = new THREE.Mesh(bodyGeo, bodyMat);
group.add(body);
// Tail
const tailGeo = new THREE.TriangleGeometry(); // Mocked by scaled plane
const tailMesh = new THREE.Mesh(
new THREE.PlaneGeometry(0.4, 0.4),
bodyMat
);
tailMesh.position.z = -0.6;
tailMesh.rotation.y = Math.PI;
group.add(tailMesh);
// Random starting position
group.position.set(
(Math.random() - 0.5) * (AQUARIUM_SIZE * 0.8),
(Math.random() - 0.5) * (AQUARIUM_SIZE * 0.8),
(Math.random() - 0.5) * (AQUARIUM_SIZE * 0.8)
);
// Fish Logic
const fish = {
mesh: group,
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1
),
targetPos: new THREE.Vector3(
(Math.random() - 0.5) * AQUARIUM_SIZE,
(Math.random() - 0.5) * AQUARIUM_SIZE,
(Math.random() - 0.5) * AQUARIUM_SIZE
),
phase: Math.random() * Math.PI * 2
};
scene.add(group);
fishArray.push(fish);
}
function onMouseMove(event) {
// Normalized device coordinates
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
const time = clock.getElapsedTime();
// Map mouse to 3D space via raycaster
raycaster.setFromCamera(mouse, camera);
const plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0);
const mouseWorldPos = new THREE.Vector3();
raycaster.ray.intersectPlane(plane, mouseWorldPos);
fishArray.forEach(fish => {
// 1. Natural movement towards target
const toTarget = new THREE.Vector3().subVectors(fish.targetPos, fish.mesh.position).normalize();
fish.velocity.addScaledVector(toTarget, 0.001);
// 2. Repel from mouse
const distToMouse = fish.mesh.position.distanceTo(mouseWorldPos);
if (distToMouse < REPEL_DISTANCE) {
const repelDir = new THREE.Vector3().subVectors(fish.mesh.position, mouseWorldPos).normalize();
const force = (REPEL_DISTANCE - distToMouse) / REPEL_DISTANCE;
fish.velocity.addScaledVector(repelDir, force * REPEL_STRENGTH);
}
// 3. Boundary check (keep inside aquarium)
const pos = fish.mesh.position;
const limit = AQUARIUM_SIZE / 2;
if (Math.abs(pos.x) > limit) fish.velocity.x *= -1;
if (Math.abs(pos.y) > limit) fish.velocity.y *= -1;
if (Math.abs(pos.z) > limit) fish.velocity.z *= -1;
// 4. Apply physics
fish.velocity.multiplyScalar(0.98); // friction
fish.mesh.position.add(fish.velocity);
// 5. Update rotation to look where it's swimming
const lookTarget = new THREE.Vector3().addVectors(fish.mesh.position, fish.velocity);
fish.mesh.lookAt(lookTarget);
// 6. Tail animation (wobble)
fish.mesh.children[1].rotation.y = Math.sin(time * 10 + fish.phase) * 0.5;
// 7. Change target occasionally
if (Math.random() < 0.01) {
fish.targetPos.set(
(Math.random() - 0.5) * AQUARIUM_SIZE,
(Math.random() - 0.5) * AQUARIUM_SIZE,
(Math.random() - 0.5) * AQUARIUM_SIZE
);
}
});
renderer.render(scene, camera);
}
</script>
</body>
</html>