Interactive 3D aquariumOne-line
Ministral 3 14B 2512
by Mistralreasoning defaultClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 20.8 s
- Cost
- $0.0006
- Output tokens
- 2,650
- Spent thinking
- 0 tokens
- Speed
- 129.4 tok/s
- Console errors
- 0
- First token after
- 309 ms
- First visible text after
- 309 ms
- Prompt tokens
- 437
- Code size
- 11.0 KB
- Finish reason
- stop
- Served by
- Mistral
- Model id
mistralai/ministral-14b-2512- Reasoning sent
model default- Max output
- 209,715 tokens
- Generated
- Nov 13, 2026
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 · 311 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
<title>3D Aquarium with Fish</title>
<style>
body {
margin: 0;
overflow: hidden;
background: linear-gradient(to bottom, #1a6fc9, #0d2b45);
font-family: Arial, sans-serif;
color: white;
text-align: center;
padding: 20px;
height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
#container {
position: relative;
width: 100%;
max-width: 100%;
height: 80vh;
max-height: 80vh;
}
#instruction {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.7);
padding: 15px 25px;
border-radius: 10px;
font-size: 16px;
pointer-events: none;
z-index: 100;
display: none;
}
#canvas {
display: block;
width: 100%;
height: 100%;
}
@media (max-width: 768px) {
#container {
height: 70vh;
}
}
</style>
</head>
<body>
<div id="container">
<canvas id="canvas"></canvas>
<div id="instruction">Click or press a key to start</div>
</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';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
// Scene setup
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1a6fc9);
const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 3, 8);
const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('canvas'), antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
// Lighting
const ambientLight = new THREE.AmbientLight(0x404040, 0.5);
scene.add(ambientLight);
const directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
directionalLight.position.set(1, 1, 1);
directionalLight.castShadow = true;
scene.add(directionalLight);
// Water effect
const waterGeometry = new THREE.PlaneGeometry(20, 20);
const water = new THREE.Mesh(
waterGeometry,
new THREE.MeshStandardMaterial({
color: 0x1e90ff,
roughness: 0.1,
metalness: 0.1,
side: THREE.DoubleSide
})
);
water.rotation.x = -Math.PI / 2;
water.position.y = -2;
water.receiveShadow = true;
scene.add(water);
// Fish data
const fishData = [
{ position: [0, 0, 0], speed: 0.02, direction: 1, size: 0.5, color: 0xff7e8c },
{ position: [2, 0, -2], speed: 0.015, direction: -1, size: 0.4, color: 0xffcc99 },
{ position: [-2, 0, 1], speed: 0.025, direction: 1, size: 0.6, color: 0x66ccff },
{ position: [1, 0, -3], speed: 0.01, direction: -1, size: 0.3, color: 0x99ff99 },
{ position: [-1, 0, 2], speed: 0.03, direction: 1, size: 0.7, color: 0xff99cc }
];
// Create fish
const fishGroup = new THREE.Group();
scene.add(fishGroup);
fishData.forEach((fish, index) => {
const geometry = new THREE.SphereGeometry(fish.size, 16, 16);
const material = new THREE.MeshStandardMaterial({
color: fish.color,
roughness: 0.3,
metalness: 0.1
});
const fishMesh = new THREE.Mesh(geometry, material);
fishMesh.position.set(fish.position[0], fish.position[1], fish.position[2]);
fishMesh.castShadow = true;
fishMesh.receiveShadow = true;
// Add eye
const eyeGeometry = new THREE.SphereGeometry(0.05, 8, 8);
const eyeMaterial = new THREE.MeshStandardMaterial({ color: 0x000000 });
const eye = new THREE.Mesh(eyeGeometry, eyeMaterial);
eye.position.set(fish.size * 0.8, 0, fish.size * 0.3);
fishMesh.add(eye);
fishGroup.add(fishMesh);
// Store fish data
fishMesh.userData = {
speed: fish.speed,
direction: fish.direction,
originalPosition: [...fish.position],
originalSpeed: fish.speed,
originalDirection: fish.direction,
size: fish.size,
color: fish.color,
mesh: fishMesh
};
});
// Bubbles
const bubbleCount = 50;
const bubbles = [];
for (let i = 0; i < bubbleCount; i++) {
const bubbleGeometry = new THREE.SphereGeometry(0.05, 8, 8);
const bubbleMaterial = new THREE.MeshStandardMaterial({
color: 0xffffff,
transparent: true,
opacity: 0.5
});
const bubble = new THREE.Mesh(bubbleGeometry, bubbleMaterial);
bubble.position.set(
(Math.random() - 0.5) * 10,
-2,
(Math.random() - 0.5) * 10
);
bubble.userData = {
speed: 0.01 + Math.random() * 0.02,
targetY: -2 + Math.random() * 2
};
scene.add(bubble);
bubbles.push(bubble);
}
// Controls
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
controls.screenSpacePanning = false;
controls.minDistance = 5;
controls.maxDistance = 15;
// Mouse interaction
let mouseX = 0;
let mouseY = 0;
let windowHalfX = window.innerWidth / 2;
let windowHalfY = window.innerHeight / 2;
document.addEventListener('mousemove', (event) => {
mouseX = (event.clientX - windowHalfX) / 200;
mouseY = (event.clientY - windowHalfY) / 200;
});
// Animation
let animationId;
let isPlaying = false;
function startAnimation() {
if (isPlaying) return;
isPlaying = true;
document.getElementById('instruction').style.display = 'none';
function animate() {
requestAnimationFrame(animate);
// Update fish based on mouse position
fishData.forEach((fish, index) => {
const fishMesh = fishGroup.children[index];
const fishData = fishMesh.userData;
// Calculate distance to mouse (projected in 3D space)
const mouse3D = new THREE.Vector3(
mouseX * 2,
-mouseY * 2,
0
).unproject(camera);
const fishPos = fishMesh.position;
const directionToMouse = mouse3D.clone().sub(fishPos).normalize();
const distanceToMouse = fishPos.distanceTo(mouse3D);
// If mouse is near, make fish swim away
if (distanceToMouse < 5) {
// Calculate flee direction (away from mouse)
const fleeDirection = directionToMouse.clone().multiplyScalar(-1);
// Update fish position and rotation
fishPos.add(fleeDirection.multiplyScalar(fishData.speed * 2));
// Limit movement to keep fish in aquarium
fishPos.x = Math.max(-5, Math.min(5, fishPos.x));
fishPos.z = Math.max(-5, Math.min(5, fishPos.z));
// Change speed based on distance
fishData.speed = 0.01 + (5 - distanceToMouse) * 0.005;
fishData.speed = Math.min(fishData.speed, 0.05);
// Rotate fish to face direction of movement
const lookAtPos = fishPos.clone().add(fleeDirection);
fishMesh.lookAt(lookAtPos);
} else {
// Return to original behavior when mouse is far
fishData.speed = fishData.originalSpeed;
fishData.direction = fishData.originalDirection;
// Simple swimming pattern
fishPos.x += fishData.direction * fishData.speed;
if (Math.abs(fishPos.x) > 4) {
fishData.direction *= -1;
}
// Rotate fish to face direction of movement
const lookAtPos = fishPos.clone().add(new THREE.Vector3(fishData.direction, 0, 0));
fishMesh.lookAt(lookAtPos);
}
});
// Update bubbles
bubbles.forEach(bubble => {
bubble.position.y += bubble.userData.speed;
if (bubble.position.y > bubble.userData.targetY) {
bubble.position.y = -2;
bubble.position.x = (Math.random() - 0.5) * 10;
bubble.position.z = (Math.random() - 0.5) * 10;
}
});
controls.update();
renderer.render(scene, camera);
}
animationId = requestAnimationFrame(animate);
}
// Handle window resize
window.addEventListener('resize', () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
windowHalfX = window.innerWidth / 2;
windowHalfY = window.innerHeight / 2;
});
// Start animation when user interacts
document.getElementById('container').addEventListener('click', startAnimation);
document.addEventListener('keydown', startAnimation);
// Start immediately for demo purposes
window.setTimeout(startAnimation, 1000);
// Cleanup on unload
window.addEventListener('beforeunload', () => {
if (animationId) {
cancelAnimationFrame(animationId);
}
});
</script>
</body>
</html>