← Asian3D assetfogon/hanok
Hanok coreano
Drag to turn it// «Hanok coreano» · gpt-6-sol (medium)
// A traditional Korean hanok house: a low wooden house on a stone base, white plaster walls with dark wooden frames, lattice paper doors, and a gracefully curved dark grey tiled roof with upswept corners, plus a small stone wall and wooden gate in front.
const wood = "#503329", woodDark = "#382723", lacquer = "#873e32";
const gold = "#c89a55", plaster = "#eee8d9", paper = "#f8edce";
const stone = "#aaa9a0", stoneDark = "#777b79";
const tile = ["#384448", "#465357", "#526163", "#404d50"];
// Stone platform and steps.
box(8, 12, 0, 40, 36, 3, stoneDark);
box(9, 13, 3, 39, 35, 4, stone);
for (let x = 9; x <= 39; x += 4)
for (let y = 13; y <= 35; y += 4)
box(x, y, 4, Math.min(x + 2, 39), Math.min(y + 2, 35),
4, rand() < 0.5 ? "#b9b8ae" : "#999d99");
box(20, 10, 0, 28, 13, 1, "#989b97");
box(21, 11, 2, 27, 13, 2, "#c0beb2");
box(21, 13, 3, 27, 14, 4, "#c0beb2");
// White walls, framed in dark timber.
box(11, 16, 5, 37, 32, 21, plaster);
box(11, 14, 5, 37, 16, 21, "#e7dfcf");
box(11, 32, 5, 37, 34, 21, "#e7dfcf");
box(9, 16, 5, 11, 33, 21, plaster);
box(37, 16, 5, 39, 33, 21, plaster);
for (const x of [10, 20, 28, 38]) {
box(x, 13, 5, x + 1, 15, 23, woodDark);
box(x, 33, 5, x + 1, 35, 23, woodDark);
box(x, 15, 18, x + 1, 34, 19, wood);
box(x, 13, 20, x + 1, 35, 21, lacquer);
box(x, 13, 21, x + 1, 15, 21, gold);
}
for (const y of [16, 24, 33]) {
box(9, y, 5, 11, y + 1, 22, woodDark);
box(37, y, 5, 39, y + 1, 22, woodDark);
}
box(10, 13, 5, 38, 15, 6, woodDark);
box(10, 13, 19, 38, 15, 20, lacquer);
box(10, 33, 19, 38, 35, 20, lacquer);
box(9, 15, 6, 10, 34, 7, wood);
box(38, 15, 6, 39, 34, 7, wood);
// Three broad paper doors, with chunky, readable wooden lattice.
for (const [a, b] of [[12, 19], [21, 27], [29, 36]]) {
box(a, 12, 6, b, 13, 19, woodDark);
box(a + 1, 12, 7, b - 1, 12, 18, paper);
box(a, 12, 6, a, 12, 19, lacquer);
box(b, 12, 6, b, 12, 19, lacquer);
for (let x = a + 2; x < b; x += 2)
box(x, 11, 7, x, 11, 18, wood);
for (let z = 8; z <= 18; z += 3)
box(a + 1, 11, z, b - 1, 11, z, wood);
box(a, 11, 19, b, 12, 19, gold);
set(b - 2, 10, 11, gold);
}
// Latticed windows on both side walls.
for (const x of [8, 40]) {
const inner = x === 8 ? 9 : 39;
for (const [a, b] of [[18, 22], [27, 31]]) {
box(inner, a, 10, inner, b, 17, paper);
box(x, a, 9, x, b, 9, woodDark);
box(x, a, 18, x, b, 18, woodDark);
for (let y = a; y <= b; y += 2) box(x, y, 10, x, y, 17, wood);
for (let z = 11; z <= 17; z += 3) box(x, a, z, x, b, z, wood);
}
}
// Exposed brackets beneath the deep eaves.
for (let x = 11; x <= 37; x += 4) {
box(x, 11, 19, x + 1, 16, 20, woodDark);
box(x - 1, 11, 21, x + 2, 15, 21, lacquer);
set(x, 11, 20, gold);
}
for (let y = 16; y <= 33; y += 4) {
box(8, y, 19, 12, y + 1, 21, woodDark);
box(36, y, 19, 40, y + 1, 21, woodDark);
}
// Hipped roof: raised ridge, broad slopes, and corners that sweep upward.
function roofHeight(x, y) {
const dx = Math.max(0, Math.abs(x - 24) - 9) / 10;
const dy = Math.abs(y - 24) / 14;
const edge = Math.max(dx, dy);
const corner = Math.max(0, (Math.abs(x - 24) - 12) / 7)
* Math.max(0, (Math.abs(y - 24) - 9) / 5);
return Math.round(34 - 12 * edge + 5 * corner);
}
for (let x = 5; x <= 43; x++) {
for (let y = 10; y <= 38; y++) {
const z = roofHeight(x, y);
set(x, y, z - 2, woodDark);
set(x, y, z - 1, "#30383a");
const rib = x % 3 === 0;
set(x, y, z, rib ? "#627173" : tile[Math.floor(rand() * tile.length)]);
if ((y === 10 || y === 38 || x === 5 || x === 43))
set(x, y, z - 1, "#242e32");
}
}
// Glazed ridge caps and slightly lifted ornamental ridge ends.
box(14, 23, 34, 34, 25, 35, "#283439");
for (let x = 15; x <= 33; x += 2)
box(x, 23, 36, x, 25, 36, "#58676a");
for (const x of [13, 35]) {
box(x, 23, 34, x, 25, 37, "#303c40");
box(x - 1, 24, 37, x + 1, 24, 38, "#59686a");
}
for (const x of [5, 43])
for (const y of [10, 38])
set(x, y, roofHeight(x, y) + 1, "#657477");
// Low garden wall in front, leaving a wide opening for the gate.
for (const [a, b] of [[3, 17], [31, 44]]) {
box(a, 5, 0, b, 7, 2, stoneDark);
box(a, 5, 3, b, 6, 6, plaster);
box(a, 4, 7, b, 7, 7, woodDark);
box(a - 1, 4, 8, b + 1, 7, 8, "#495558");
for (let x = a; x <= b; x += 6) {
box(x, 4, 2, x + 1, 7, 7, stoneDark);
box(x, 4, 8, x + 1, 7, 8, "#627071");
}
}
for (const x of [3, 44]) {
box(x, 5, 0, x + 1, 12, 3, stoneDark);
box(x, 5, 4, x + 1, 12, 5, plaster);
}
// Wooden entry gate: open passage, red posts, and its own tiled canopy.
for (const x of [18, 29]) {
box(x, 3, 0, x + 1, 8, 2, stoneDark);
box(x, 4, 3, x + 1, 7, 11, lacquer);
box(x, 3, 10, x + 1, 8, 10, gold);
}
box(18, 4, 10, 30, 7, 11, woodDark);
box(20, 3, 9, 28, 3, 10, lacquer);
box(22, 2, 9, 26, 2, 9, gold);
for (let x = 16; x <= 32; x++)
for (let y = 2; y <= 9; y++) {
const rise = Math.max(0, Math.abs(x - 24) - 5)
+ Math.max(0, Math.abs(y - 5.5) - 2);
const z = Math.round(15 - 0.7 * rise
+ (Math.abs(x - 24) > 7 && (y === 2 || y === 9) ? 2 : 0));
set(x, y, z - 1, woodDark);
set(x, y, z, x % 3 === 0 ? "#667477" : "#3d4b4e");
}
box(21, 5, 15, 27, 6, 16, "#303b3e");import { draw } from "./assets/voxel";
import { hanok } from "./assets/hanok";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, hanok, 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 hanok
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["hanok"] })
# It lands in client/assets/hanok.ts
# https://fogon.page/object/hanok