← NaturalezaObjeto 3Dfogon/palmera
Palmera
Arrastrá para girarlo// «Palmera» · gpt-6-sol (medium)
// A tropical palm tree: a tall gently curved trunk made of stacked ring segments in tan and light brown, topped by 6-7 long arching bright green fronds drooping outward in a star, with 3 brown coconuts clustered under the fronds.
const bark = ["#a96b39", "#bd8046", "#ce9253", "#dda365"];
const groove = "#88542f";
const leafDark = "#279640";
const leafMid = "#38b84b";
const leafBright = "#59d65a";
const leafSun = "#83e673";
// A gently bending trunk built from short, rounded bark rings.
function trunkCenter(z) {
const t = z / 35;
return [23 + 4 * t * t, 25 - 2 * t + 0.25 * Math.sin(t * 7)];
}
for (let z = 0; z <= 35; z++) {
const [cx, cy] = trunkCenter(z);
const radius = z < 4 ? 3.0 - z * 0.18 : 2.35;
for (let x = Math.floor(cx - radius); x <= Math.ceil(cx + radius); x++) {
for (let y = Math.floor(cy - radius); y <= Math.ceil(cy + radius); y++) {
const d = Math.hypot(x - cx, y - cy);
if (d > radius) continue;
const ring = z % 4 === 0 && d > radius - 1.15;
const shade = y < cy - 0.5 ? 2 : (x < cx ? 1 : 0);
let color = ring ? groove : bark[Math.min(3, shade + (rand() < 0.12 ? 1 : 0))];
if (z % 4 === 1 && d > radius - 0.7 && y < cy) color = bark[3];
set(x, y, z, color);
}
}
}
// Short, splayed roots anchor the tree to the ground.
for (const a of [0.25, 2.25, 3.65, 5.15]) {
const dx = Math.cos(a), dy = Math.sin(a);
line(23, 25, 2, 23 + dx * 4, 25 + dy * 4, 0, 1, "#a96b39");
set(23 + dx * 4, 25 + dy * 4, 0, "#ce9253");
}
part("crown", [27, 23, 35]);
// Seven broad, feather-edged fronds arc up, then droop at their tips.
const cx = 27, cy = 23;
function leafHeight(r) {
return 35 + 0.76 * r - 0.061 * r * r;
}
for (let i = 0; i < 7; i++) {
const a = i * Math.PI * 2 / 7;
const dx = Math.cos(a), dy = Math.sin(a);
const sx = -dy, sy = dx;
for (let r = 1; r <= 19.5; r += 0.65) {
const width = Math.max(0.45, 3.25 * Math.sin(Math.PI * r / 20));
const z = Math.round(leafHeight(r));
for (let side = -width; side <= width; side += 0.8) {
const x = Math.round(cx + dx * r + sx * side);
const y = Math.round(cy + dy * r + sy * side);
const edge = Math.abs(side) / width;
set(x, y, z - 1, leafDark);
set(x, y, z,
edge < 0.23 ? leafSun :
edge < 0.72 ? (rand() < 0.22 ? leafSun : leafBright) :
leafMid
);
}
}
// Alternating pointed leaflets give each frond its palm-leaf outline.
for (let r = 5; r < 18; r += 2.2) {
const width = 3.25 * Math.sin(Math.PI * r / 20);
for (const side of [-1, 1]) {
const startX = cx + dx * r + sx * side * (width - 0.4);
const startY = cy + dy * r + sy * side * (width - 0.4);
const endX = cx + dx * (r + 1.1) + sx * side * (width + 2.0);
const endY = cy + dy * (r + 1.1) + sy * side * (width + 2.0);
line(startX, startY, leafHeight(r),
endX, endY, leafHeight(r + 1.1) - 0.7, 0, leafBright);
}
}
}
ellipsoid(27, 23, 35, 2.7, 2.7, 1.7, "#39ad45");
set(27, 23, 37, leafSun);
// Three coconuts hang visibly beneath the canopy.
for (const [x, y, z] of [[25, 21, 33], [29, 22, 33], [27, 25, 32]]) {
ellipsoid(x, y, z, 1.65, 1.65, 1.55, "#754626");
set(x, y - 1, z, "#a46a37");
set(x - 1, y, z + 1, "#bd8046");
set(x, y, z + 1, "#ca9050");
set(x, y - 1, z - 1, "#593820");
}
animate("crown", { type: "swing", axis: "y", speed: 1.5, amplitude: 0.12 });import { draw } from "./assets/voxel";
import { palmera } from "./assets/palmera";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, palmera, 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 palmera
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["palmera"] })
# Queda en client/assets/palmera.ts
# https://fogon.page/object/palmera