← Pirates and sea3D assetfogon/roca-con-algas
Roca con algas
Drag to turn it// «Roca con algas» · gpt-6-sol (medium)
// A rounded dark grey sea rock with green seaweed hanging down its sides, a few barnacles and a small puddle of turquoise water at its foot.
// Shallow turquoise puddle and sandy edge.
for (let x = 2; x <= 45; x++) {
for (let y = 6; y <= 43; y++) {
const dx = (x - 24) / 21;
const dy = (y - 25) / 17;
const ripple = 0.055 * Math.sin(x * 0.63) + 0.04 * Math.cos(y * 0.81);
const d = dx * dx + dy * dy + ripple;
if (d < 1.15) set(x, y, 0, "#e9cf91");
if (d < 1.0) {
set(x, y, 0, d > 0.83 ? "#79dfd5" : "#20b8bc");
if (d < 0.88) set(x, y, 1, d > 0.69 ? "#55d6cf" : "#28c8c8");
}
}
}
// Rounded, slightly lopsided sea rock.
ellipsoid(24, 25, 14, 17, 15, 14, "#51565a");
ellipsoid(19, 25, 14, 11, 13, 14, "#51565a");
ellipsoid(30, 27, 11, 10, 11, 10, "#51565a");
ellipsoid(13, 26, 7, 6, 9, 6, "#51565a");
ellipsoid(36, 25, 7, 5, 8, 6, "#51565a");
const rockColors = new Set(["#51565a", "#41494c", "#626b6c", "#737c79"]);
forEach((x, y, z, color) => {
if (!rockColors.has(color)) return;
let shade = z > 20 ? "#626b6c" : z < 8 ? "#41494c" : "#51565a";
if (rand() < 0.13) shade = z > 15 ? "#737c79" : "#41494c";
set(x, y, z, shade);
});
// Look up the exposed front or side of the rock, so the seaweed hugs its shape.
function frontY(x, z) {
for (let y = 7; y < 43; y++) {
if (rockColors.has(get(x, y, z))) return y;
}
return null;
}
function sideX(y, z) {
for (let x = 43; x >= 5; x--) {
if (rockColors.has(get(x, y, z))) return x;
}
return null;
}
// Long, chunky ribbons of seaweed dangling over the front.
for (const [base, top, bottom, phase] of [
[14, 24, 9, 0.3],
[20, 27, 6, 1.7],
[27, 27, 10, 3.2],
[34, 24, 7, 4.6]
]) {
for (let z = top; z >= bottom; z--) {
const x = Math.round(base + 1.3 * Math.sin(z * 0.38 + phase));
const y = frontY(x, z);
if (y === null) continue;
const green = z % 5 < 2 ? "#398b46" : "#28763e";
box(x - 1, y - 2, z, x + 1, y - 1, z, green);
set(x - 1, y - 3, z, "#4cac52");
if (z % 4 === 0) {
set(x + 2, y - 1, z, "#398b46");
set(x + 2, y - 1, z - 1, "#28763e");
}
if (z % 5 === 2) {
set(x - 2, y - 1, z, "#4cac52");
set(x - 2, y - 1, z - 1, "#28763e");
}
}
}
// More seaweed spilling down the rock's right-hand side.
for (const [baseY, top, bottom, phase] of [
[21, 24, 8, 0.4],
[29, 24, 10, 2.2]
]) {
for (let z = top; z >= bottom; z--) {
const y = Math.round(baseY + Math.sin(z * 0.4 + phase));
const x = sideX(y, z);
if (x === null) continue;
box(x + 1, y - 1, z, x + 2, y + 1, z, "#28763e");
set(x + 3, y - 1, z, "#4cac52");
if (z % 4 === 1) set(x + 1, y + 2, z, "#398b46");
}
}
// Small ivory barnacles, each with a dark opening facing the viewer.
for (const [x, z, r] of [
[16, 15, 2], [31, 14, 2], [36, 10, 2],
[11, 9, 1], [25, 8, 1], [30, 7, 1]
]) {
const surface = frontY(x, z);
if (surface === null) continue;
const y = surface - 2;
sphere(x, y, z, r, "#f2e7be");
set(x, y - r, z, "#977e68");
set(x, y - r, z + 1, "#fff5d5");
}
// Bright glints and little foam flecks in exposed water.
for (let x = 5; x <= 43; x++) {
for (let y = 9; y <= 41; y++) {
if (get(x, y, 1) !== "#28c8c8" && get(x, y, 1) !== "#55d6cf") continue;
if (get(x, y, 2)) continue;
if ((x * 7 + y * 11) % 47 === 0) set(x, y, 2, "#b6f5dc");
else if ((x * 13 + y * 3) % 61 === 0) set(x, y, 2, "#72e5d6");
}
}import { draw } from "./assets/voxel";
import { rocaConAlgas } from "./assets/roca-con-algas";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, rocaConAlgas, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: its longest side, in px
// angle: turn on the floor, in radians
// t: seconds; if it moves, that animates it# In a terminal, in the game's folder
fogon assets add roca-con-algas
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["roca-con-algas"] })
# It lands in client/assets/roca-con-algas.ts
# https://fogon.page/object/roca-con-algas