← NaturalezaObjeto 3Dfogon/roca-con-musgo
Piedra con musgo
Arrastrá para girarlo// «Piedra con musgo» · gpt-6-sol (medium)
// A tall rounded standing stone heavily covered in bright green moss on top and one side, with grey rock showing below.
// A rounded standing stone with a thick, sunlit moss cap and a mossy left side.
const rock = ["#899196", "#9ba3a5", "#aeb6b5", "#c3c9c4"];
const moss = ["#308e43", "#43ad48", "#61c958", "#89dc69"];
function radii(z) {
let rx;
if (z < 5) rx = 9.2 + z * 0.18;
else if (z < 17) rx = 10.1;
else if (z < 30) rx = 10.1 - (z - 17) * 0.1;
else if (z < 34) rx = 8.8;
else rx = 8.8 * Math.sqrt(Math.max(0, 1 - ((z - 34) / 6) ** 2));
return [rx, rx * 0.88];
}
// Solid, gently leaning stone with an uneven but rounded outline.
for (let z = 0; z <= 39; z++) {
const [rx, ry] = radii(z);
const cx = 24 + Math.sin(z * 0.12) * 0.75;
const cy = 24 + Math.sin(z * 0.16 + 1) * 0.45;
for (let x = 12; x <= 36; x++) {
for (let y = 12; y <= 36; y++) {
const angle = Math.atan2(y - cy, x - cx);
const uneven = 1 + 0.035 * Math.sin(angle * 5 + z * 0.19)
+ 0.025 * Math.sin(angle * 9 - z * 0.31);
const d = ((x - cx) / rx) ** 2 + ((y - cy) / ry) ** 2;
if (d <= uneven * uneven) {
const shade = rand();
const color = shade < 0.12 ? rock[0] : shade < 0.72 ? rock[1] : rock[2];
set(x, y, z, color);
}
}
}
}
function frontStone(x, z, color) {
for (let y = 12; y <= 29; y++) {
if (get(x, y, z)) {
set(x, y, z, color);
return;
}
}
}
// A few short, irregular cracks in the exposed lower face.
[
[25, 5], [25, 6], [26, 7], [26, 8], [27, 9],
[26, 12], [27, 13], [27, 14], [28, 15],
[22, 17], [22, 18], [21, 19], [21, 20]
].forEach(([x, z]) => frontStone(x, z, "#707c80"));
// Recolor only the outside: stone stays visible across the lower front.
const surface = [];
forEach((x, y, z) => {
const exposed = !get(x + 1, y, z) || !get(x - 1, y, z) ||
!get(x, y + 1, z) || !get(x, y - 1, z) ||
!get(x, y, z + 1);
if (exposed) surface.push([x, y, z]);
});
for (const [x, y, z] of surface) {
const edge = 11 + 2 * Math.sin(y * 0.57 + z * 0.25);
const leftMoss = x <= 18 && z >= edge;
const spreadingMoss = x <= 22 && z >= 19 + 2 * Math.sin(x * 0.72 + y * 0.4);
const frontMoss = y <= 21 && z >= 27 + 2 * Math.sin(x * 0.66);
const capMoss = z >= 31 + 1.5 * Math.sin(x * 0.43 + y * 0.38);
if (leftMoss || spreadingMoss || frontMoss || capMoss) {
const lit = z > 32 || !get(x, y, z + 1);
const t = rand();
const color = lit
? (t < 0.16 ? moss[1] : t < 0.77 ? moss[2] : moss[3])
: (t < 0.19 ? moss[0] : t < 0.78 ? moss[1] : moss[2]);
set(x, y, z, color);
// Occasional raised tufts give the moss a soft, chunky silhouette.
if (rand() < 0.13 && z > 8) {
if (!get(x, y, z + 1) && z < 40) set(x, y, z + 1, moss[2]);
else if (y < 24 && !get(x, y - 1, z)) set(x, y - 1, z, moss[1]);
else if (x < 23 && !get(x - 1, y, z)) set(x - 1, y, z, moss[1]);
}
} else if (rand() < 0.17) {
set(x, y, z, z > 18 ? rock[3] : rock[0]);
}
}
// Small patches of moss trailing down the otherwise bare stone.
for (const [x, z] of [[18, 7], [19, 8], [17, 10], [20, 14], [21, 15]]) {
for (let y = 12; y <= 29; y++) {
if (get(x, y, z)) {
set(x, y, z, moss[1]);
break;
}
}
}import { draw } from "./assets/voxel";
import { rocaConMusgo } from "./assets/roca-con-musgo";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, rocaConMusgo, 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 roca-con-musgo
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["roca-con-musgo"] })
# Queda en client/assets/roca-con-musgo.ts
# https://fogon.page/object/roca-con-musgo