← back to Model Arena
data/artifacts/127317180daf/qwen3-14b.html
524 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Rose City Rooftop Solstice</title>
<style>
html, body {
margin: 0;
padding: 0;
overflow: hidden;
background: #000;
font-family: 'Arial', sans-serif;
}
canvas {
display: block;
}
#controls {
position: absolute;
top: 10px;
left: 10px;
z-index: 10;
background: rgba(255,255,255,0.1);
padding: 10px;
border-radius: 10px;
color: #fff;
font-size: 14px;
}
#controls button, #controls select, #controls input {
margin: 5px 0;
padding: 6px 10px;
background: rgba(255,255,255,0.2);
border: 1px solid rgba(255,255,255,0.4);
color: #fff;
border-radius: 5px;
cursor: pointer;
transition: background 0.2s ease;
}
#controls button:hover, #controls select:hover, #controls input:hover {
background: rgba(255,255,255,0.3);
}
#controls label {
display: block;
margin: 5px 0 2px;
}
#info {
position: absolute;
bottom: 10px;
left: 10px;
z-index: 10;
color: #fff;
font-size: 12px;
text-align: left;
}
</style>
</head>
<body>
<canvas id="canvas"></canvas>
<div id="controls">
<label>Camera:</label>
<select id="camera">
<option value="skyline">Skyline</option>
<option value="rooftop">Rooftop</option>
<option value="birds-eye">Bird's-Eye</option>
</select>
<label>Scene:</label>
<select id="scene">
<option value="arrival">Arrival</option>
<option value="long-light">Long Light</option>
<option value="midnight-bloom">Midnight Bloom</option>
</select>
<label>Tempo:</label>
<input type="range" id="tempo" min="0.5" max="2" step="0.1" value="1">
<label>Density:</label>
<input type="range" id="density" min="0.3" max="1" step="0.1" value="0.7">
<label>Groups:</label>
<input type="checkbox" id="group1"> Central Circle
<input type="checkbox" id="group2"> Bridges
<input type="checkbox" id="group3"> Water Towers
<input type="checkbox" id="group4"> Fire Escapes
<label>Animals:</label>
<input type="checkbox" id="animalNames"> Show Names
<input type="checkbox" id="animalTrails"> Show Trails
<input type="checkbox" id="routeDiagrams"> Show Routes
<br>
<button id="pause">Pause</button>
<button id="restart">Restart</button>
<button id="reduceMotion">Reduce Motion</button>
</div>
<div id="info">
Visual rhythm is authored rather than listening to audio.
<br>
Keyboard controls:
<br>
Arrow keys: Move camera
<br>
W/S: Zoom
<br>
R: Reset
</div>
<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const width = canvas.width = window.innerWidth;
const height = canvas.height = window.innerHeight;
const controlElements = {
camera: document.getElementById('camera'),
scene: document.getElementById('scene'),
tempo: document.getElementById('tempo'),
density: document.getElementById('density'),
group1: document.getElementById('group1'),
group2: document.getElementById('group2'),
group3: document.getElementById('group3'),
group4: document.getElementById('group4'),
animalNames: document.getElementById('animalNames'),
animalTrails: document.getElementById('animalTrails'),
routeDiagrams: document.getElementById('routeDiagrams'),
pause: document.getElementById('pause'),
restart: document.getElementById('restart'),
reduceMotion: document.getElementById('reduceMotion'),
};
let state = {
scene: 'arrival',
camera: 'skyline',
tempo: 1,
density: 0.7,
groups: {1: true, 2: true, 3: true, 4: true},
showNames: false,
showTrails: false,
showRoutes: false,
isPaused: false,
reduceMotion: false,
time: 0,
frame: 0,
lastTime: 0,
};
const sceneColors = {
arrival: {bg: '#111', rose: '#ff6b6b', light: '#f0c14b', cloud: '#60a5fa'},
'long-light': {bg: '#0a0a0a', rose: '#ff4081', light: '#ffd700', cloud: '#3b82f6'},
'midnight-bloom': {bg: '#000', rose: '#e63946', light: '#e9c46a', cloud: '#2a2240'},
};
const entities = {
dancers: [],
animals: [],
buildings: [],
waterTowers: [],
fireEscapes: [],
};
const initEntities = () => {
const numDancers = Math.floor(100 * state.density);
const numAnimals = Math.floor(20 * state.density);
const numBuildings = Math.floor(50 * state.density);
for (let i = 0; i < numDancers; i++) {
entities.dancers.push({
type: 'dancer',
x: Math.random() * width,
y: Math.random() * height,
angle: Math.random() * Math.PI * 2,
speed: (Math.random() + 0.5) * 0.01 * state.tempo,
group: Math.floor(Math.random() * 4) + 1,
});
}
for (let i = 0; i < numAnimals; i++) {
const types = ['bear', 'cat', 'dog', 'moth', 'pigeon'];
const type = types[Math.floor(Math.random() * types.length)];
entities.animals.push({
type,
x: Math.random() * width,
y: Math.random() * height,
angle: Math.random() * Math.PI * 2,
speed: (Math.random() + 0.5) * 0.01 * state.tempo,
});
}
for (let i = 0; i < numBuildings; i++) {
entities.buildings.push({
x: Math.random() * width,
y: Math.random() * height,
scale: 0.2 + Math.random() * 0.3,
});
}
for (let i = 0; i < 10; i++) {
entities.waterTowers.push({
x: width * 0.2 + Math.random() * width * 0.6,
y: height * 0.2 + Math.random() * height * 0.6,
});
}
for (let i = 0; i < 5; i++) {
entities.fireEscapes.push({
x: width * 0.2 + Math.random() * width * 0.6,
y: height * 0.2 + Math.random() * height * 0.6,
});
}
};
const draw = (time) => {
if (state.isPaused) return;
state.time = time;
state.frame++;
ctx.clearRect(0, 0, width, height);
const color = sceneColors[state.scene];
ctx.fillStyle = color.bg;
ctx.fillRect(0, 0, width, height);
// Draw buildings with parallax
ctx.save();
ctx.translate(width / 2, height / 2);
ctx.scale(1, 1);
ctx.fillStyle = color.bg;
ctx.fillRect(-width / 2, -height / 2, width, height);
ctx.restore();
// Draw clouds
ctx.fillStyle = color.cloud;
for (let i = 0; i < 10; i++) {
const cx = Math.random() * width;
const cy = Math.random() * height * 0.3;
const size = 10 + Math.random() * 20;
ctx.beginPath();
ctx.arc(cx, cy, size, 0, Math.PI * 2);
ctx.fill();
}
// Draw water towers
ctx.fillStyle = color.light;
for (let tower of entities.waterTowers) {
const size = 15 + Math.random() * 10;
const x = tower.x;
const y = tower.y;
ctx.beginPath();
ctx.arc(x, y, size, 0, Math.PI * 2);
ctx.fill();
}
// Draw fire escapes
ctx.strokeStyle = color.light;
ctx.lineWidth = 2;
for (let escape of entities.fireEscapes) {
const size = 10 + Math.random() * 10;
const x = escape.x;
const y = escape.y;
ctx.beginPath();
ctx.moveTo(x - size, y);
ctx.lineTo(x + size, y);
ctx.stroke();
}
// Draw dancers
for (let d of entities.dancers) {
if (!state.groups[d.group]) continue;
let x = d.x;
let y = d.y;
let angle = d.angle;
if (d.group === 1) {
// Central Circle
const centerX = width / 2;
const centerY = height / 2;
const radius = 100 + Math.sin(state.time * d.speed) * 50;
x = centerX + Math.cos(angle) * radius;
y = centerY + Math.sin(angle) * radius;
angle += state.time * d.speed;
d.angle = angle;
} else if (d.group === 2) {
// Bridges
const start = {x: 0, y: height / 2};
const end = {x: width, y: height / 2};
const t = (Math.sin(state.time * d.speed) + 1) / 2;
x = start.x + t * (end.x - start.x);
y = start.y + t * (end.y - start.y);
angle = Math.atan2(end.y - start.y, end.x - start.x);
} else if (d.group === 3) {
// Water Towers
const size = 50 + Math.sin(state.time * d.speed) * 20;
x = d.x + Math.cos(angle) * size;
y = d.y + Math.sin(angle) * size;
angle += state.time * d.speed;
} else if (d.group === 4) {
// Fire Escapes
const speed = 0.005 * state.tempo;
d.y -= speed;
if (d.y < 0) {
d.y = height;
d.x = Math.random() * width;
}
}
d.x = x;
d.y = y;
d.angle = angle;
// Draw dancer
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle);
ctx.fillStyle = color.rose;
ctx.beginPath();
ctx.arc(0, 0, 4, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
// Draw animals
for (let a of entities.animals) {
let x = a.x;
let y = a.y;
let angle = a.angle;
if (a.type === 'bear') {
x += Math.cos(angle) * 5;
y += Math.sin(angle) * 5;
} else if (a.type === 'cat') {
x += Math.cos(angle) * 3;
y += Math.sin(angle) * 3;
} else if (a.type === 'dog') {
x += Math.cos(angle) * 4;
y += Math.sin(angle) * 4;
} else if (a.type === 'moth') {
x += Math.cos(angle) * 2;
y += Math.sin(angle) * 2;
angle += state.time * 0.01;
} else if (a.type === 'pigeon') {
x += Math.cos(angle) * 5;
y += Math.sin(angle) * 5;
angle += state.time * 0.005;
}
a.x = x;
a.y = y;
a.angle = angle;
if (state.showTrails) {
ctx.strokeStyle = color.light;
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(a.x, a.y);
ctx.lineTo(a.x + Math.cos(angle) * 5, a.y + Math.sin(angle) * 5);
ctx.stroke();
}
ctx.save();
ctx.translate(x, y);
ctx.rotate(angle);
ctx.fillStyle = color.light;
ctx.beginPath();
if (a.type === 'bear') {
ctx.fillRect(-4, -4, 8, 8);
} else if (a.type === 'cat') {
ctx.beginPath();
ctx.arc(0, 0, 4, 0, Math.PI * 2);
ctx.fill();
} else if (a.type === 'dog') {
ctx.beginPath();
ctx.arc(0, 0, 4, 0, Math.PI * 2);
ctx.fill();
ctx.fillRect(-2, -2, 4, 4);
} else if (a.type === 'moth') {
ctx.beginPath();
ctx.arc(0, 0, 3, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.moveTo(-3, 0);
ctx.lineTo(0, 4);
ctx.lineTo(3, 0);
ctx.fill();
} else if (a.type === 'pigeon') {
ctx.beginPath();
ctx.arc(0, 0, 5, 0, Math.PI * 2);
ctx.fill();
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, -5);
ctx.stroke();
}
ctx.restore();
if (state.showNames) {
ctx.fillStyle = color.light;
ctx.font = '10px Arial';
ctx.fillText(a.type, x + 6, y - 6);
}
}
// Draw central rose sculpture
ctx.fillStyle = color.rose;
ctx.beginPath();
ctx.moveTo(width / 2, height / 2);
for (let i = 0; i < 12; i++) {
const angle = (Math.PI * 2 / 12) * i;
const r = 40 + 20 * Math.sin(state.time * 0.01 * i);
const x = width / 2 + Math.cos(angle) * r;
const y = height / 2 + Math.sin(angle) * r;
ctx.lineTo(x, y);
}
ctx.closePath();
ctx.fill();
// Draw light trails
if (state.showTrails) {
ctx.strokeStyle = color.light;
ctx.lineWidth = 1;
for (let d of entities.dancers) {
ctx.beginPath();
ctx.moveTo(d.x, d.y);
ctx.lineTo(d.x + Math.cos(d.angle) * 5, d.y + Math.sin(d.angle) * 5);
ctx.stroke();
}
}
// Draw route diagrams
if (state.showRoutes) {
ctx.strokeStyle = color.light;
ctx.lineWidth = 1;
ctx.globalAlpha = 0.3;
for (let i = 0; i < 10; i++) {
ctx.beginPath();
ctx.moveTo(0, height / 2);
ctx.lineTo(width, height / 2);
ctx.stroke();
}
ctx.globalAlpha = 1;
}
requestAnimationFrame(draw);
};
const updateState = () => {
state.scene = controlElements.scene.value;
state.camera = controlElements.camera.value;
state.tempo = parseFloat(controlElements.tempo.value);
state.density = parseFloat(controlElements.density.value);
state.groups = {
1: controlElements.group1.checked,
2: controlElements.group2.checked,
3: controlElements.group3.checked,
4: controlElements.group4.checked,
};
state.showNames = controlElements.animalNames.checked;
state.showTrails = controlElements.animalTrails.checked;
state.showRoutes = controlElements.routeDiagrams.checked;
state.reduceMotion = controlElements.reduceMotion.checked;
};
const bindControls = () => {
controlElements.camera.addEventListener('change', updateState);
controlElements.scene.addEventListener('change', updateState);
controlElements.tempo.addEventListener('input', updateState);
controlElements.density.addEventListener('input', updateState);
controlElements.group1.addEventListener('change', updateState);
controlElements.group2.addEventListener('change', updateState);
controlElements.group3.addEventListener('change', updateState);
controlElements.group4.addEventListener('change', updateState);
controlElements.animalNames.addEventListener('change', updateState);
controlElements.animalTrails.addEventListener('change', updateState);
controlElements.routeDiagrams.addEventListener('change', updateState);
controlElements.pause.addEventListener('click', () => {
state.isPaused = !state.isPaused;
controlElements.pause.textContent = state.isPaused ? 'Resume' : 'Pause';
});
controlElements.restart.addEventListener('click', () => {
state.time = 0;
state.frame = 0;
initEntities();
});
controlElements.reduceMotion.addEventListener('click', () => {
state.reduceMotion = !state.reduceMotion;
controlElements.reduceMotion.textContent = state.reduceMotion ? 'Normal Motion' : 'Reduce Motion';
});
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowUp') {
e.preventDefault();
state.camera = 'skyline';
controlElements.camera.value = 'skyline';
} else if (e.key === 'ArrowDown') {
e.preventDefault();
state.camera = 'rooftop';
controlElements.camera.value = 'rooftop';
} else if (e.key === 'ArrowLeft') {
e.preventDefault();
state.camera = 'birds-eye';
controlElements.camera.value = 'birds-eye';
} else if (e.key === 'ArrowRight') {
e.preventDefault();
state.scene = 'arrival';
controlElements.scene.value = 'arrival';
} else if (e.key === 'w') {
e.preventDefault();
state.density = Math.min(state.density + 0.1, 1);
controlElements.density.value = state.density;
} else if (e.key === 's') {
e.preventDefault();
state.density = Math.max(state.density - 0.1, 0.3);
controlElements.density.value = state.density;
} else if (e.key === 'r') {
e.preventDefault();
state.time = 0;
state.frame = 0;
initEntities();
}
});
};
window.addEventListener('resize', () => {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
width = canvas.width;
height = canvas.height;
});
initEntities();
bindControls();
draw(0);
</script>
</body>
</html>