Boat game, built by Flint
NVFP4via DaBenchllama.cpp
114tok/s
First token included
19.6Ktokens
2m 53s
Show the code the model wroteHide the code
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Ultra Realistic Water - Boat</title>
<style>
html, body { margin: 0; padding: 0; overflow: hidden; background: #001122; }
canvas { display: block; width: 100vw; height: 100vh; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
let W = canvas.width = innerWidth;
let H = canvas.height = innerHeight;
window.addEventListener('resize', () => { W = canvas.width = innerWidth; H = canvas.height = innerHeight; });
// Input
const keys = { w: false, s: false, a: false, d: false, arrowup: false, arrowdown: false, arrowleft: false, arrowright: false };
let mouseX = W / 2, mouseY = H / 2;
canvas.addEventListener('mousemove', e => { mouseX = e.clientX; mouseY = e.clientY; });
canvas.addEventListener('mousedown', e => { if (e.button === 0) firing = true; });
canvas.addEventListener('mouseup', e => { if (e.button === 0) firing = false; });
let firing = false;
// Water
const water = {
gridRes: 50,
worldSize: 50,
amp1: 0.8, freq1: 0.08, amp2: 0.6, freq2: 0.06, amp3: 0.4, freq3: 0.05,
getHeight(x, z, t) {
return Math.sin(x * this.freq1 + t) * this.amp1 + Math.cos(z * this.freq2 - t) * this.amp2 + Math.sin((x + z) * this.freq3 + t) * this.amp3;
}
};
// Boat
const boat = {
pos: { x: 0, z: 0 },
vel: { x: 0, z: 0 },
yaw: 0,
pitch: 0,
roll: 0,
health: 100,
throttle: 0,
turn: 0,
angularVel: 0,
width: 3,
length: 6,
mass: 100,
};
// Enemies
let enemies = [];
let projectiles = [];
let enemyTimer = 0;
let gameOver = false;
let time = 0;
let shake = 0;
// Camera & scale
const scale = Math.min(W, H) / 60;
let camX = 0, camZ = 0;
function updateCamera() {
camX = boat.pos.x;
camZ = boat.pos.z;
}
// Physics update
function update(dt) {
if (gameOver) return;
let throttle = (keys.w ? 1 : 0) - (keys.s ? 1 : 0);
let turn = (keys.d ? 1 : 0) - (keys.a ? 1 : 0);
boat.throttle = throttle;
boat.turn = turn;
const thrustForce = throttle * 30;
boat.vel.x += Math.cos(boat.yaw) * thrustForce * dt;
boat.vel.z += Math.sin(boat.yaw) * thrustForce * dt;
boat.vel.x *= Math.max(0, 1 - 0.5 * dt);
boat.vel.z *= Math.max(0, 1 - 0.5 * dt);
boat.angularVel = turn * 2;
boat.yaw += boat.angularVel * dt;
boat.pos.x += boat.vel.x * dt;
boat.pos.z += boat.vel.z * dt;
boat.pos.x = Math.max(-20, Math.min(20, boat.pos.x));
boat.pos.z = Math.max(-20, Math.min(20, boat.pos.z));
const h = water.getHeight(boat.pos.x, boat.pos.z, time);
const slopeF = (water.getHeight(boat.pos.x + 0.1, boat.pos.z, time) - water.getHeight(boat.pos.x - 0.1, boat.pos.z, time)) / 0.2 * Math.cos(boat.yaw);
const slopeR = (water.getHeight(boat.pos.x, boat.pos.z + 0.1, time) - water.getHeight(boat.pos.x, boat.pos.z - 0.1, time)) / 0.2 * Math.sin(boat.yaw);
boat.pitch += (slopeF * 2 - boat.pitch) * 0.1;
boat.roll += (slopeR * 2 - boat.roll) * 0.1;
}
// Enemy logic
function spawnEnemy() {
const angle = Math.random() * Math.PI * 2;
const dist = 15 + Math.random() * 10;
enemies.push({
x: boat.pos.x + Math.cos(angle) * dist,
z: boat.pos.z + Math.sin(angle) * dist,
health: 30,
fireTimer: 0,
});
}
function updateEnemies(dt) {
enemyTimer -= dt;
if (enemyTimer <= 0 && enemies.length < 5) {
spawnEnemy();
enemyTimer = 2 + Math.random() * 3;
}
for (let i = enemies.length - 1; i >= 0; i--) {
const e = enemies[i];
const dx = boat.pos.x - e.x;
const dz = boat.pos.z - e.z;
const dist = Math.hypot(dx, dz);
if (dist < 5) {
// shoot
e.fireTimer -= dt;
if (e.fireTimer <= 0) {
projectiles.push({
x: e.x, z: e.z, vx: dx * 2, vz: dz * 2, life: 2,
});
e.fireTimer = 1;
}
} else {
e.x += (dx / dist) * 2 * dt;
e.z += (dz / dist) * 2 * dt;
}
}
// update projectiles
for (let i = projectiles.length - 1; i >= 0; i--) {
const p = projectiles[i];
p.life -= dt;
p.x += p.vx * dt;
p.z += p.vz * dt;
const dx = boat.pos.x - p.x;
const dz = boat.pos.z - p.z;
const dist = Math.hypot(dx, dz);
if (dist < 2) {
boat.health -= 10;
projectiles.splice(i, 1);
if (boat.health <= 0) gameOver = true;
}
if (p.life <= 0) projectiles.splice(i, 1);
}
}
// Render water
function renderWater(t) {
const cell = water.worldSize / (water.gridRes - 1);
for (let i = 0; i < water.gridRes; i++) {
for (let j = 0; j < water.gridRes; j++) {
const x = -water.worldSize / 2 + i * cell;
const z = -water.worldSize / 2 + j * cell;
const h00 = water.getHeight(x, z, t);
const h10 = water.getHeight(x + cell, z, t);
const h01 = water.getHeight(x, z + cell, t);
const h11 = water.getHeight(x + cell, z + cell, t);
const h0 = h00 + (h10 - h00) * 0.5;
const h1 = h01 + (h11 - h01) * 0.5;
const h = h0 + (h1 - h0) * 0.5;
const sx0 = W / 2 + (x - camX) * scale;
const sy0 = H / 2 - (z - camZ) * scale;
const sx1 = W / 2 + (x + cell - camX) * scale;
const sy1 = H / 2 - (z - camZ) * scale;
const sx2 = W / 2 + (x - camX) * scale;
const sy2 = H / 2 - (z + cell - camZ) * scale;
const sx3 = W / 2 + (x + cell - camX) * scale;
const sy3 = H / 2 - (z + cell - camZ) * scale;
ctx.beginPath();
ctx.moveTo(sx0, sy0);
ctx.lineTo(sx1, sy1);
ctx.lineTo(sx3, sy3);
ctx.lineTo(sx2, sy2);
ctx.closePath();
const col = h > 0.4 ? '#2a7a9a' : h > 0.2 ? '#1a5a7a' : '#0a2a4a';
ctx.fillStyle = col;
ctx.fill();
}
}
}
// Render boat
function renderBoat() {
const sx = W / 2 + (boat.pos.x - camX) * scale;
const sy = H / 2 - (boat.pos.z - camZ) * scale;
ctx.save();
ctx.translate(sx, sy);
ctx.rotate(boat.yaw);
// hull
ctx.fillStyle = '#1a3a5a';
ctx.beginPath();
ctx.ellipse(0, 0, boat.length / 2, boat.width / 2, 0, 0, Math.PI * 2);
ctx.fill();
// deck
ctx.fillStyle = '#2a5a7a';
ctx.beginPath();
ctx.ellipse(0, 0, boat.length / 2 - 1, boat.width / 2 - 1, 0, 0, Math.PI * 2);
ctx.fill();
// mast
ctx.strokeStyle = '#5a3a2a';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(0, -boat.length / 2);
ctx.lineTo(0, boat.length / 2);
ctx.stroke();
// turret
ctx.fillStyle = '#888';
ctx.beginPath();
ctx.arc(0, -boat.length / 2 + 2, 2, 0, Math.PI * 2);
ctx.fill();
// health bar
ctx.fillStyle = '#0f0';
ctx.fillRect(-boat.length / 2, -boat.width / 2 - 5, boat.length * boat.health / 100, 3);
ctx.restore();
}
// Render enemies
function renderEnemies() {
for (const e of enemies) {
const sx = W / 2 + (e.x - camX) * scale;
const sy = H / 2 - (e.z - camZ) * scale;
ctx.save();
ctx.translate(sx, sy);
ctx.fillStyle = '#a00';
ctx.beginPath();
ctx.arc(0, 0, 4, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
}
// Render projectiles
function renderProjectiles() {
for (const p of projectiles) {
const sx = W / 2 + (p.x - camX) * scale;
const sy = H / 2 - (p.z - camZ) * scale;
ctx.fillStyle = '#ff0';
ctx.fillRect(sx - 1, sy - 1, 2, 2);
}
}
// Main loop
function loop() {
let dt = 1 / 60;
time += dt;
update(dt);
updateCamera();
updateEnemies(dt);
renderWater(time);
renderBoat();
renderEnemies();
renderProjectiles();
if (gameOver) {
ctx.fillStyle = '#fff';
ctx.font = '30px Arial';
ctx.fillText('GAME OVER', W / 2 - 100, H / 2);
}
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script>
</body>
</html>Same prompt, other models
One email when a new model lands on the board or in the showcase. Unsubscribe anytime.