← MedievalObjeto 3Dfogon/cepo
Cepo
Arrastrá para girarlo// «Cepo» · gpt-6-sol (medium)
// Medieval stocks: two thick wooden posts in the ground holding a horizontal plank board split in two halves with three round holes (a bigger one in the middle for the head, two smaller for the hands), black iron hinges and a padlock, on a small wooden platform.
const stone = ["#857e72", "#958d7f", "#aaa293", "#706b62"];
const wood = ["#765032", "#835b39", "#946a42", "#68452d"];
const darkWood = "#4b3124";
const iron = "#292b2c";
const ironLight = "#555759";
function holes(x, z, extra = 0) {
return (
Math.hypot(x - 15, z - 26) <= 2.55 + extra ||
Math.hypot(x - 24, z - 26) <= 4.45 + extra ||
Math.hypot(x - 33, z - 26) <= 2.55 + extra
);
}
// Low stone footing, with a broad wooden deck and a step at the front.
box(4, 11, 0, 43, 38, 1, stone[0]);
for (let x = 4; x <= 43; x++) {
for (let y = 11; y <= 38; y++) {
if (rand() < 0.16) set(x, y, 1, stone[1 + Math.floor(rand() * 3)]);
}
}
box(9, 8, 0, 38, 12, 1, stone[1]);
box(9, 9, 2, 38, 13, 2, "#725034");
box(6, 13, 2, 41, 36, 3, darkWood);
for (let y = 13; y <= 36; y += 4) {
box(6, y, 4, 41, Math.min(y + 3, 36), 4, "#926941");
line(6, y, 4, 41, y, 4, 0, "#b18855");
for (let x = 8; x <= 39; x++) {
if (rand() < 0.09) set(x, y + 2, 4, wood[Math.floor(rand() * wood.length)]);
}
}
box(6, 13, 3, 41, 13, 4, "#b18a56");
box(6, 36, 3, 41, 36, 4, "#624329");
for (let x of [8, 19, 30, 40]) {
set(x, 13, 4, "#493728");
set(x, 36, 4, "#493728");
}
// Two massive upright posts. Their projecting feet brace them to the deck.
for (let [a, b] of [[8, 11], [37, 40]]) {
box(a, 19, 4, b, 28, 35, "#684429");
box(a - 1, 17, 4, b + 1, 30, 6, "#604028");
box(a, 18, 6, b, 29, 8, "#795131");
box(a - 1, 19, 35, b + 1, 28, 37, "#91683e");
box(a - 1, 18, 36, b + 1, 18, 37, "#ad8150");
box(a, 18, 9, a, 18, 34, "#a17444");
box(b, 18, 9, b, 18, 34, "#513422");
for (let z = 10; z <= 34; z++) {
if (rand() < 0.27) set(a + 2, 18, z, "#805735");
if (rand() < 0.13) set(a + 1, 18, z, "#4f3526");
}
for (let z of [12, 32]) {
box(a, 17, z, b, 18, z + 1, iron);
box(a + 1, 17, z + 1, b - 1, 17, z + 1, ironLight);
set(a + 1, 16, z, "#9d9a88");
set(b - 1, 16, z, "#9d9a88");
}
}
// The two heavy halves of the stocks meet along the centers of the openings.
for (let x = 11; x <= 37; x++) {
for (let y = 20; y <= 28; y++) {
for (let z = 18; z <= 34; z++) {
if (holes(x, z)) continue;
let c = z >= 26 ? "#91673e" : "#805632";
if (z === 34 || z === 26) c = "#ad7c48";
if (z === 18 || z === 25) c = "#67432b";
if (rand() < 0.075) c = wood[Math.floor(rand() * wood.length)];
set(x, y, z, c);
}
}
}
// Dark, readable joint between the lifting upper half and fixed lower half.
for (let x = 12; x <= 36; x++) {
if (!holes(x, 25)) set(x, 19, 25, "#3e2b22");
if (!holes(x, 26)) set(x, 19, 26, "#ba8951");
}
// Rounded shadows at the cut edges of all three through-holes.
for (let x = 12; x <= 36; x++) {
for (let z = 20; z <= 32; z++) {
if (!holes(x, z) && holes(x, z, 1.05)) {
set(x, 19, z, "#513425");
if (z >= 27 && !holes(x, z)) set(x, 18, z, "#af7e49");
}
}
}
// Long grain, pegged ends, and a slight overhang on each plank.
for (let x = 12; x <= 36; x++) {
if (!holes(x, 20) && x % 5 !== 0) set(x, 19, 20, "#966a40");
if (!holes(x, 33) && x % 6 !== 0) set(x, 19, 33, "#b2844c");
}
for (let x of [12, 19, 29, 36]) {
for (let z of [21, 30]) {
if (!holes(x, z)) {
set(x, 18, z, "#493322");
set(x, 17, z, "#a78658");
}
}
}
// Black wrought-iron hinges on the left, with bright hammered rivets.
for (let z of [21, 29]) {
box(10, 16, z, 13, 18, z + 2, iron);
box(12, 15, z + 1, 14, 16, z + 1, ironLight);
box(10, 15, z + 1, 11, 15, z + 1, "#77756b");
set(13, 14, z + 1, "#aaa797");
}
box(10, 15, 24, 11, 17, 29, iron);
box(10, 14, 26, 11, 14, 27, ironLight);
// Iron hasp and substantial hanging padlock at the opposite end.
box(36, 16, 25, 40, 18, 27, iron);
box(37, 15, 27, 39, 16, 27, ironLight);
for (let x of [37, 40]) set(x, 15, 26, "#99978a");
box(37, 14, 21, 40, 16, 24, "#303233");
box(37, 13, 23, 40, 13, 24, ironLight);
box(38, 14, 25, 39, 15, 26, "#666866");
box(38, 13, 22, 39, 13, 23, "#444648");
set(38, 12, 22, "#bba46a");
set(38, 12, 21, "#bba46a");
// A few soft mossy flecks caught between stones, away from the timber.
for (let i = 0; i < 28; i++) {
let x = 4 + Math.floor(rand() * 40);
let y = 11 + Math.floor(rand() * 28);
if (x < 7 || x > 40 || y < 14 || y > 35) {
set(x, y, 1, rand() < 0.5 ? "#6b7959" : "#788362");
}
}import { draw } from "./assets/voxel";
import { cepo } from "./assets/cepo";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, cepo, 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 cepo
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["cepo"] })
# Queda en client/assets/cepo.ts
# https://fogon.page/object/cepo