← Piratas y marObjeto 3Dfogon/balsa
Balsa
Arrastrá para girarlo// «Balsa» · gpt-6-sol (medium)
// A castaway raft of eight round light-brown logs tied side by side with rope bands, a short mast made of a branch with a torn white cloth sail, a small barrel and a bunch of bananas on the deck.
const wood = ["#ad6d38", "#bb7a3d", "#c48645", "#b77439"];
const shadow = "#88502b";
const grain = "#d89a55";
const rope = "#e8c78a";
// Eight rounded logs, laid side by side.
for (let i = 0; i < 8; i++) {
const x = 8 + i * 4.5;
const base = wood[i % wood.length];
cylinder(x, 5, 3, 2.7, 38, base, "y");
// Dark undersides touch the floor at z = 0.
line(x, 6, 0, x, 41, 0, 0, shadow);
for (let y = 5; y <= 42; y++) {
for (let dx = -2; dx <= 2; dx++) {
if (get(x + dx, y, 1)) set(x + dx, y, 1, shadow);
}
}
// Long, irregular weathered grain.
for (let j = 0; j < 13; j++) {
const yy = 7 + Math.floor(rand() * 33);
const xx = x + (rand() < 0.5 ? -1 : 1);
line(xx, yy, 6, xx, Math.min(yy + 2 + Math.floor(rand() * 5), 41), 6, 0, grain);
}
// Bright cut ends with dark growth-ring marks.
for (const y of [5, 42]) {
for (let dx = -2; dx <= 2; dx++) {
for (let dz = -2; dz <= 2; dz++) {
if (dx * dx + dz * dz <= 5)
set(x + dx, y, 3 + dz, "#d99a55");
}
}
set(x, y, 3, "#a96b38");
set(x + 1, y, 3, "#b7793d");
}
}
// Two rope bands wrap across all the logs.
for (const y of [12, 36]) {
for (let dy = 0; dy <= 2; dy++) {
line(5, y + dy, 7, 42, y + dy, 7, 0, dy === 1 ? "#f3d99d" : "#c99b59");
}
for (const x of [5, 42]) {
line(x, y, 2, x, y, 7, 0, "#c99b59");
line(x, y + 2, 2, x, y + 2, 7, 0, rope);
}
}
sphere(39, 13, 8, 1.2, rope);
sphere(10, 37, 8, 1.2, rope);
// A stout, slightly crooked branch mast and its lashings.
cylinder(24, 25, 7, 1.6, 17, "#85502d");
line(24, 25, 23, 25, 25, 38, 1.1, "#a86d3b");
line(24, 25, 8, 25, 25, 39, 0, "#d29857");
for (const z of [9, 11, 21, 35]) {
cylinder(24, 25, z, 1.9, 1, rope);
}
// Small toy-like barrel on the deck.
cylinder(15, 22, 7, 3, 9, "#a96231");
cylinder(15, 22, 15, 2.7, 1, "#d18b45");
for (let z = 8; z <= 15; z++) {
for (let y = 19; y <= 25; y++) {
if (get(12, y, z)) set(12, y, z, "#794527");
}
}
for (const z of [9, 13]) {
for (let a = 0; a < Math.PI * 2; a += 0.12) {
set(15 + 3.15 * Math.cos(a), 22 + 3.15 * Math.sin(a), z, "#e6b659");
}
}
set(15, 22, 16, "#80502d");
set(16, 22, 16, "#edb66b");
// A clustered bunch of curved, sunny yellow bananas.
sphere(33, 18, 9, 1.2, "#80622c");
for (let i = 0; i < 5; i++) {
const side = i - 2;
const y = 18 + side * 0.8;
line(33, 18, 9, 34 + side * 0.75, y - 1, 10, 0.8, "#e8a824");
line(34 + side * 0.75, y - 1, 10,
36 + side * 0.9, y - 3, 9, 0.9, "#ffcf3e");
line(36 + side * 0.9, y - 3, 9,
37 + side * 0.8, y - 3.5, 10, 0.55, "#ffe16b");
set(37 + side * 0.8, y - 3.5, 10, "#79512c");
}
// The sail and its spars pivot together at the masthead.
part("sail", [25, 23, 37]);
line(25, 23, 36, 38, 21, 31, 0.65, "#a46c3a");
line(25, 23, 16, 41, 21, 18, 0.55, "#a46c3a");
for (let z = 16; z <= 35; z++) {
let right;
if (z >= 31) right = 25 + (36 - z) * 2.6;
else if (z <= 19) right = 26 + (z - 15) * 3.7;
else right = 41 - (z - 19) * 0.23;
for (let x = 26; x <= Math.floor(right); x++) {
// Ragged lower hem, a nick in the outer edge, and two small tears.
if (z <= 19 && ((x >= 31 && x <= 33 && z === 17) ||
(x >= 36 && x <= 38 && z === 18))) continue;
if (x > right - 2 && z >= 23 && z <= 25) continue;
if ((x === 33 && z === 26) || (x === 34 && z === 26) ||
(x === 37 && z === 22)) continue;
const y = 19 + Math.round(1.2 * Math.sin((x - 26) / 5) +
0.5 * Math.sin(z / 3));
const color = z > 28 ? "#fff9e8" :
z < 21 ? "#dfd5b9" :
(x + z) % 7 === 0 ? "#e7dec7" : "#f5efd9";
set(x, y, z, color);
if (x > 27 && x < right - 1) set(x, y - 1, z, color);
}
}
// Visible stitched reinforcement and a soft cloth seam.
line(27, 18, 33, 36, 19, 30, 0, "#d5cbb1");
line(27, 19, 18, 38, 19, 19, 0, "#cbbd9e");
for (const [x, z] of [[29, 32], [32, 30], [35, 29], [29, 19], [33, 19]]) {
set(x, 17, z, "#b7a98d");
}
animate("sail", { type: "swing", axis: "z", speed: 2, amplitude: 0.2 });import { draw } from "./assets/voxel";
import { balsa } from "./assets/balsa";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, balsa, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: lo que mide en px su lado más largo
// angle: giro sobre el piso, en radianes
// t: segundos; si se mueve, se anima solo con eso# En una terminal, en la carpeta del juego
fogon assets add balsa
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["balsa"] })
# Queda en client/assets/balsa.ts
# https://fogon.page/object/balsa