← MedievalObjeto 3Dfogon/pozo-con-balde
Pozo con balde
Arrastrá para girarlo// «Pozo con balde» · gpt-6-sol (medium)
// A medieval village well: a round low wall of grey stones with a dark water opening, two wooden posts holding a small pointed roof of red tiles, a horizontal wooden crank axle between the posts with a handle on one side, a rope wound on it going down to a wooden bucket with an iron band hanging over the opening.
const cx = 24, cy = 24;
const stone = ["#827e77", "#938f86", "#aaa59a", "#716e69"];
const wood = "#4d3023";
const iron = "#292d30";
const rope = "#cfb681";
// Round, hollow stone well.
for (let z = 0; z <= 10; z++) {
for (let x = 9; x <= 39; x++) {
for (let y = 9; y <= 39; y++) {
const dx = x - cx, dy = y - cy;
const d = Math.hypot(dx, dy);
if (d < 9.5 || d > 13.5) continue;
const angle = Math.atan2(dy, dx);
const joint = ((angle * 11 + (Math.floor(z / 3) % 2) * 0.55 + 50) % 1);
let c = stone[Math.floor(rand() * stone.length)];
if (joint < 0.075 || z % 3 === 0) c = "#66635f";
else if (z >= 8 && rand() < 0.35) c = "#aaa59a";
if (z < 5 && rand() < 0.045) c = "#687359";
set(x, y, z, c);
}
}
}
// Heavy, pale coping around the opening.
for (let x = 9; x <= 39; x++) {
for (let y = 9; y <= 39; y++) {
const d = Math.hypot(x - cx, y - cy);
if (d >= 9.3 && d <= 14.1) {
set(x, y, 11, rand() < 0.16 ? "#87857f" : "#b4afa3");
if (d > 12.7 && rand() < 0.65)
set(x, y, 10, "#77736c");
}
}
}
// Dark water, with small blue-grey glints.
for (let x = 14; x <= 34; x++) {
for (let y = 14; y <= 34; y++) {
if (Math.hypot(x - cx, y - cy) < 9.3)
set(x, y, 5, rand() < 0.14 ? "#536c73" : "#253f4a");
}
}
for (let x = 18; x <= 29; x++) {
if (Math.abs(x - 24) > 2) set(x, 20, 6, "#71858a");
}
// Two stout timber uprights.
for (const x of [12, 36]) {
box(x - 1, 20, 11, x + 1, 23, 31, wood);
box(x - 1, 19, 14, x + 1, 19, 16, "#60402b");
box(x - 1, 19, 25, x + 1, 19, 27, "#60402b");
box(x - 2, 19, 29, x + 2, 24, 31, "#68452d");
box(x - 1, 19, 11, x + 1, 19, 13, iron);
set(x, 18, 12, "#a6a49b");
}
// Braces beneath the roof.
line(13, 21, 25, 19, 21, 32, 1, "#593a29");
line(35, 21, 25, 29, 21, 32, 1, "#593a29");
box(9, 21, 29, 39, 23, 30, "#533522");
// Pointed red-tile roof, with staggered courses.
for (let x = 6; x <= 42; x++) {
const slope = Math.abs(x - cx);
const roofZ = Math.round(41 - slope * 0.69);
for (let y = 11; y <= 37; y++) {
set(x, y, roofZ - 1, "#653c32");
const course = Math.floor(slope / 3);
const stagger = (course % 2) * 2;
const seam = (y + stagger) % 5 === 0;
const palette = ["#9e4438", "#ad4e3b", "#bd6046", "#87392f"];
let tile = palette[Math.floor(rand() * palette.length)];
if (seam) tile = "#72372f";
if (slope % 3 === 2) tile = "#824036";
set(x, y, roofZ, tile);
}
}
// Projecting eaves and dark wooden gable edges.
for (const y of [10, 38]) {
for (let x = 6; x <= 42; x++) {
const z = Math.round(41 - Math.abs(x - cx) * 0.69);
set(x, y, z - 1, "#4c3025");
set(x, y, z, "#8d3f33");
}
}
box(23, 10, 41, 25, 38, 42, "#6e342c");
for (let y = 11; y <= 37; y += 5)
box(23, y, 43, 25, Math.min(y + 1, 37), 43, "#b25a43");
// Iron-pinned horizontal crank axle.
cylinder(13, 21, 23, 1.5, 28, "#654027", "x");
for (const x of [14, 16, 32, 35, 38]) {
box(x, 19, 22, x, 23, 24, iron);
set(x, 19, 23, "#81817a");
}
// Wound rope around the middle of the axle.
for (let x = 21; x <= 27; x++) {
set(x, 19, 23, rope);
set(x, 20, 25, "#e0c795");
set(x, 23, 23, "#ab9068");
}
line(24, 20, 22, 24, 20, 17, 0, "#dfc796");
line(25, 20, 22, 25, 20, 17, 0, "#9e845f");
// Hand crank extending from the right end.
box(40, 20, 22, 42, 22, 24, iron);
line(42, 21, 23, 42, 16, 23, 1, "#383634");
box(41, 14, 21, 43, 17, 25, "#795033");
box(42, 14, 22, 42, 14, 24, "#a47547");
// Hanging wooden bucket: tapered sides, dark interior, iron hoops.
for (let z = 12; z <= 17; z++) {
const r = z < 14 ? 2.5 : 3.3;
for (let x = 20; x <= 28; x++) {
for (let y = 16; y <= 24; y++) {
const d = Math.hypot(x - 24, y - 20);
if (d <= r && (z === 12 || d >= r - 1.15)) {
const plank = (x + Math.floor(y / 2)) % 3 === 0;
set(x, y, z, plank ? "#815534" : "#9a6940");
}
}
}
}
for (const z of [13, 16]) {
for (let x = 20; x <= 28; x++) {
for (let y = 16; y <= 24; y++) {
const d = Math.hypot(x - 24, y - 20);
const r = z === 13 ? 2.5 : 3.3;
if (d >= r - 0.8 && d <= r + 0.1) set(x, y, z, iron);
}
}
}
for (let x = 22; x <= 26; x++)
for (let y = 18; y <= 22; y++)
if (Math.hypot(x - 24, y - 20) < 2.2)
set(x, y, 16, "#283a3d");
// Bucket handle and bright iron rivets.
line(21, 20, 17, 22, 20, 19, 0, iron);
line(22, 20, 19, 24, 20, 20, 0, iron);
line(24, 20, 20, 26, 20, 19, 0, iron);
line(26, 20, 19, 27, 20, 17, 0, iron);
set(21, 19, 16, "#9d9b8f");
set(27, 19, 16, "#9d9b8f");
// Small heraldic badge on the front of the left upright.
box(10, 18, 19, 14, 18, 22, "#d1ad63");
box(11, 17, 19, 13, 17, 21, "#882f35");
set(12, 16, 20, "#d9ba70");
set(12, 18, 18, "#d1ad63");import { draw } from "./assets/voxel";
import { pozoConBalde } from "./assets/pozo-con-balde";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, pozoConBalde, 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 pozo-con-balde
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["pozo-con-balde"] })
# Queda en client/assets/pozo-con-balde.ts
# https://fogon.page/object/pozo-con-balde