← Medieval3D assetfogon/barril-de-cerveza
Barril de cerveza
Drag to turn it// «Barril de cerveza» · gpt-6-sol (medium)
// A big wooden beer barrel lying on its side on a wooden cradle stand: curved brown staves with three black iron hoops, a brass tap on the front end with a few drops, and a wooden mug with white foam on the stand next to the tap.
const wood = ["#704222", "#85502a", "#986036", "#aa7040"];
const darkWood = "#4a2b1b";
const iron = "#202328";
const ironLight = "#42464a";
const brass = "#c7973f";
const brassLight = "#efd079";
// The stand: two long skids, crosspieces, and stout cradle supports.
box(7, 5, 0, 12, 42, 2, "#56341f");
box(36, 5, 0, 41, 42, 2, "#56341f");
box(7, 5, 2, 12, 42, 3, "#80502d");
box(36, 5, 2, 41, 42, 3, "#80502d");
for (const y of [6, 38]) {
box(8, y, 1, 40, y + 3, 3, "#694024");
box(9, y, 3, 39, y, 3, "#a06a3d");
}
for (const y of [14, 35]) {
for (let x = 9; x <= 39; x++) {
const top = Math.round(8 + 0.036 * (x - 24) ** 2);
box(x, y, 4, x, y + 2, top, x % 6 === 0 ? "#684022" : "#80502d");
set(x, y, top, "#a47345");
}
box(9, y, 4, 11, y + 2, 17, "#654026");
box(37, y, 4, 39, y + 2, 17, "#654026");
box(9, y, 16, 11, y + 2, 17, "#a47345");
box(37, y, 16, 39, y + 2, 17, "#a47345");
for (const x of [11, 37]) {
set(x, y - 1, 7, "#c39255");
set(x, y - 1, 13, "#c39255");
}
}
// Solid, gently swollen barrel. Narrow radial seams separate the long staves.
const radiusAt = y => 13.15 + 2.25 * Math.sin(Math.PI * (y - 10) / 29);
const staveCount = 18;
for (let y = 10; y <= 39; y++) {
const r = radiusAt(y);
for (let x = 8; x <= 40; x++) {
for (let z = 8; z <= 40; z++) {
const dx = x - 24, dz = z - 24;
const distance = Math.hypot(dx, dz);
if (distance > r) continue;
let color = "#704426";
if (distance >= r - 2.7) {
const angle = (Math.atan2(dz, dx) + Math.PI * 2) % (Math.PI * 2);
const stave = angle * staveCount / (Math.PI * 2);
const seam = Math.min(stave % 1, 1 - stave % 1);
const lit = dz > 5 ? 1 : dz < -5 ? -1 : 0;
const shade = Math.max(0, Math.min(3,
1 + lit + (Math.floor(stave) % 4 === 0 ? 1 : 0)
+ (rand() < 0.065 ? 1 : 0)));
color = seam < 0.065 ? darkWood : wood[shade];
if (distance < r - 1.2) color = "#754626";
}
set(x, y, z, color);
}
}
}
// Front head: individual vertical planks, a dark circular rim and wood grain.
for (let y = 8; y <= 9; y++) {
for (let x = 10; x <= 38; x++) {
for (let z = 10; z <= 38; z++) {
const d = Math.hypot(x - 24, z - 24);
if (d > (y === 8 ? 12.15 : 12.85)) continue;
const seam = [15, 21, 27, 33].some(s => Math.abs(x - s) < 0.48);
let c = ["#966038", "#a66c3d", "#b77b47"][Math.floor((x + 2) / 6) % 3];
if (z < 19) c = "#87532f";
if (seam) c = "#56351f";
if (d > 11.65) c = d > 12.3 ? "#342b24" : "#694126";
if (!seam && d < 11.5 && rand() < 0.035) c = "#c08a51";
set(x, y, z, c);
}
}
}
for (let x = 10; x <= 38; x++) {
for (let z = 10; z <= 38; z++) {
const d = Math.hypot(x - 24, z - 24);
if (d > 11.7 && d < 13.5) set(x, 10, z, "#362c25");
}
}
// Three heavy iron hoops wrap completely around the barrel.
for (const [a, b] of [[12, 14], [24, 26], [36, 38]]) {
for (let y = a; y <= b; y++) {
const r = radiusAt(y);
for (let x = 7; x <= 41; x++) {
for (let z = 7; z <= 41; z++) {
const d = Math.hypot(x - 24, z - 24);
if (d >= r - 1.15 && d <= r + 0.65) {
set(x, y, z, z > 27 && y === a ? ironLight : iron);
}
}
}
}
for (let i = 0; i < 12; i++) {
const t = i * Math.PI / 6;
const r = radiusAt(a + 1);
set(24 + Math.cos(t) * r, a, 24 + Math.sin(t) * r,
i % 2 ? "#73716b" : "#9a9587");
}
}
// Small hammered fasteners on the front iron rim.
for (let i = 0; i < 12; i++) {
const t = i * Math.PI / 6;
set(24 + 12.1 * Math.cos(t), 8, 24 + 12.1 * Math.sin(t), "#a49b7c");
}
// Brass tap, set low on the front barrel head.
box(22, 7, 18, 26, 8, 22, "#70491f");
box(23, 6, 19, 25, 8, 21, brass);
box(23, 2, 19, 25, 6, 20, "#aa762e");
box(23, 3, 20, 25, 6, 20, brassLight);
box(23, 2, 16, 25, 3, 19, brass);
box(22, 2, 16, 26, 3, 17, brassLight);
box(23, 4, 20, 25, 5, 23, brass);
box(21, 4, 23, 27, 5, 24, brassLight);
box(20, 4, 23, 21, 5, 24, "#a26b28");
box(27, 4, 23, 28, 5, 24, "#a26b28");
set(24, 2, 15, "#f4d777");
// A few golden drops falling from the spout.
set(24, 2, 13, "#edbd55");
set(24, 2, 12, "#b97a2b");
set(23, 2, 9, "#efc966");
set(24, 2, 6, "#d89c3d");
// Wooden mug beside the tap, resting on the front crosspiece.
const mx = 39, my = 7;
for (let z = 4; z <= 13; z++) {
for (let x = 34; x <= 44; x++) {
for (let y = 2; y <= 12; y++) {
const d = Math.hypot(x - mx, y - my);
if (d > 3.9) continue;
if (z >= 10 && d < 2.7) continue;
let c = x < mx ? "#9b6135" : "#754525";
if (d > 3.25 && (x === 37 || x === 41)) c = "#51321e";
if (z === 4 || z === 13) c = d > 2.9 ? "#443126" : "#a87543";
set(x, y, z, c);
}
}
}
for (let z of [5, 12]) {
for (let x = 35; x <= 43; x++)
for (let y = 3; y <= 11; y++)
if (Math.abs(Math.hypot(x - mx, y - my) - 3.6) < 0.7)
set(x, y, z, "#303035");
}
for (let x = 43; x <= 46; x++)
for (let z = 6; z <= 12; z++)
if (x === 43 || x === 46 || z === 6 || z === 12)
box(x, 6, z, x, 8, z, x === 46 ? "#9a6338" : "#704324");
// Thick, overflowing cream foam and a few rounded bubbles.
for (let x = 35; x <= 43; x++)
for (let y = 3; y <= 11; y++)
if (Math.hypot(x - mx, y - my) <= 3.25)
set(x, y, 13, "#f5edcf");
ellipsoid(39, 7, 14, 3.2, 3, 1.5, "#fff7dd");
sphere(37, 5, 15, 1.2, "#fffdf0");
sphere(41, 8, 15, 1.2, "#fffdf0");
box(36, 3, 11, 37, 3, 13, "#faf5de");
set(37, 3, 10, "#f4e9cb");
// Visible hand-cut grain and a few lighter worn edges on the stand.
for (const x of [8, 10, 37, 39]) {
for (const y of [19, 23, 29, 33]) {
line(x, y, 3, x, y + 2, 3, 0, "#a06d3c");
}
}import { draw } from "./assets/voxel";
import { barrilDeCerveza } from "./assets/barril-de-cerveza";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, barrilDeCerveza, 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 barril-de-cerveza
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["barril-de-cerveza"] })
# It lands in client/assets/barril-de-cerveza.ts
# https://fogon.page/object/barril-de-cerveza