← Medieval3D assetfogon/herreria-con-yunque
Herrería con yunque
Drag to turn it// «Herrería con yunque» · gpt-6-sol (medium)
// A blacksmith's anvil on a stump, big and filling most of the grid: a thick round brown tree-stump block (about 14 wide, 10 tall) with ring lines on top, and on it a big dark iron anvil (about 26 long): a wide flat rectangular top face with light grey edge highlights, a long pointed cone horn sticking out to one side, a stepped narrower waist and a wider flared foot. A hammer with a wooden handle lies across the anvil top and a glowing orange horseshoe sits next to it. A small wooden bucket stands against the stump. Everything is touching and solid: no loose floating bits, no scattered debris on the ground.
// A bark-covered stump, with its cut rings showing around the anvil's foot.
const cx = 24, cy = 24;
for (let z = 0; z <= 12; z++) {
for (let x = 15; x <= 33; x++) {
for (let y = 15; y <= 33; y++) {
const angle = Math.atan2(y - cy, x - cx);
const radius = Math.hypot(x - cx, y - cy);
const edge = 8.1 + 0.35 * Math.sin(angle * 7) + 0.25 * Math.sin(angle * 13);
if (radius > edge) continue;
if (z === 12) {
const ring = Math.min(
Math.abs(radius - 2.5),
Math.abs(radius - 4.6),
Math.abs(radius - 6.6)
);
set(x, y, z, ring < 0.42 ? "#684528" :
radius > 7.3 ? "#563820" : rand() < 0.16 ? "#a77b48" : "#91673b");
} else {
const bark = radius > edge - 1.35;
const groove = (x * 3 + y * 5 + Math.floor(z / 4)) % 9 === 0;
set(x, y, z, bark
? groove ? "#49301f" : rand() < 0.19 ? "#785235" : "#604029"
: rand() < 0.12 ? "#735032" : "#805a35");
}
}
}
}
// A few long, readable fissures in the front bark.
for (const x of [19, 23, 28, 31]) {
for (let z = 1; z <= 10; z++) {
for (let y = 15; y <= 23; y++) {
if (get(x, y, z) && !get(x, y - 1, z)) {
set(x, y, z, z % 5 === 0 ? "#49301f" : "#513521");
break;
}
}
}
}
// Broad foot, stepped shoulders, and a pinched waist.
box(15, 19, 13, 34, 29, 15, "#34393c");
box(16, 18, 15, 33, 30, 17, "#41474a");
box(17, 19, 18, 32, 29, 19, "#343a3d");
box(19, 21, 20, 30, 28, 24, "#383e41");
box(17, 19, 24, 32, 29, 26, "#42484b");
box(14, 18, 26, 33, 30, 28, "#383e42");
// The massive flat working face and its projecting square heel.
box(11, 18, 27, 17, 29, 29, "#41474a");
box(13, 17, 28, 33, 31, 29, "#4b5153");
box(12, 17, 30, 33, 31, 30, "#656b6a");
for (let x = 13; x <= 32; x++) {
for (let y = 18; y <= 30; y++) {
if (rand() < 0.075) set(x, y, 30, "#747a77");
}
}
box(12, 17, 30, 33, 17, 30, "#929694");
box(12, 17, 29, 33, 17, 29, "#737a79");
box(12, 31, 30, 32, 31, 30, "#858a87");
box(11, 18, 30, 13, 29, 30, "#888d89");
box(11, 18, 27, 11, 29, 29, "#34393d");
// One continuous tapered horn, forged out of the right side of the face.
for (let x = 32; x <= 43; x++) {
const t = (x - 32) / 11;
const ry = 6.3 * (1 - t) + 0.35;
const rz = 3.2 * (1 - t) + 0.35;
const midZ = 27 + t * 1.5;
for (let y = 17; y <= 31; y++) {
for (let z = 24; z <= 31; z++) {
const d = ((y - 24) / ry) ** 2 + ((z - midZ) / rz) ** 2;
if (d <= 1) {
set(x, y, z, z > midZ + 0.6 ? "#727977" :
y < 24 ? "#555c5d" : "#383e42");
}
}
}
}
// Forged trim and big iron rivets on the front of the foot.
box(17, 18, 16, 32, 18, 16, "#5f6666");
box(18, 19, 13, 31, 19, 13, "#515757");
for (const x of [19, 24, 30]) {
set(x, 17, 16, "#878986");
set(x, 18, 14, "#777a78");
}
box(20, 20, 21, 29, 20, 22, "#51585a");
// A wooden bucket tucked tightly against the front-left side of the stump.
const bx = 15, by = 17;
for (let z = 0; z <= 8; z++) {
for (let x = 11; x <= 19; x++) {
for (let y = 13; y <= 21; y++) {
const r = Math.hypot(x - bx, y - by);
if (r > (z < 2 ? 3.5 : 4.05)) continue;
const stave = ((Math.round(Math.atan2(y - by, x - bx) * 5) + 50) % 4 === 0);
set(x, y, z, stave ? "#674329" : rand() < 0.13 ? "#ae7843" : "#895b32");
if (r > 3.1 && (z === 2 || z === 6)) set(x, y, z, "#303335");
}
}
}
for (let x = 11; x <= 19; x++) {
for (let y = 13; y <= 21; y++) {
const r = Math.hypot(x - bx, y - by);
if (r <= 2.8) set(x, y, 9, "#342c24");
else if (r <= 4.2) set(x, y, 9, "#aa7541");
}
}
for (const x of [12, 18]) set(x, 13, 6, "#8e918a");
// A hammer laid diagonally across the working face.
line(20, 20, 32, 29, 23, 32, 1, "#80512e");
line(23, 21, 33, 28, 23, 33, 0, "#ac7540");
box(17, 18, 32, 22, 22, 35, "#404547");
box(17, 18, 35, 22, 22, 35, "#727775");
box(17, 18, 33, 17, 22, 34, "#8c9089");
box(22, 18, 33, 22, 22, 34, "#303638");
box(18, 18, 32, 21, 18, 32, "#646b69");
// A thick, glowing horseshoe: its open ends face the viewer.
const glow = "#ef7924", hot = "#ffad40", edge = "#a8461c";
for (let x = 19; x <= 27; x++) {
for (let y = 25; y <= 30; y++) {
const outer = ((x - 23) / 4.5) ** 2 + ((y - 26) / 4.4) ** 2;
const inner = ((x - 23) / 2.25) ** 2 + ((y - 26) / 2.2) ** 2;
if (outer <= 1 && inner >= 1 && !(y < 27 && x > 21 && x < 25)) {
set(x, y, 31, edge);
set(x, y, 32, x <= 20 || x >= 26 || y >= 29 ? hot : glow);
}
}
}
for (const x of [20, 26]) {
set(x, 25, 32, "#ffc16a");
set(x, 26, 33, "#ffbd54");
}import { draw } from "./assets/voxel";
import { herreriaConYunque } from "./assets/herreria-con-yunque";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, herreriaConYunque, 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 herreria-con-yunque
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["herreria-con-yunque"] })
# It lands in client/assets/herreria-con-yunque.ts
# https://fogon.page/object/herreria-con-yunque