← Asian3D assetfogon/dojo
Dojo
Drag to turn it// «Dojo» · gpt-6-sol (medium)
// A Japanese martial arts dojo: a wooden hall on a low stone base with sliding white paper shoji walls framed in dark wood, an open entrance with a wooden step, a dark grey tiled roof with upturned eaves, and a vertical wooden sign with black kanji-like strokes next to the door.
const stone = ["#c7c4b8", "#b9b8ae", "#d8d5c8"];
const red = "#a4312b";
const redLight = "#bb4335";
const redDark = "#752621";
const wood = "#57372d";
const paper = "#f3eddb";
// Low stone foundation and broad entrance steps.
box(6, 10, 0, 41, 40, 3, stone[1]);
box(6, 10, 3, 41, 40, 3, stone[0]);
for (let x = 6; x <= 41; x++) {
for (let y = 10; y <= 40; y++) {
if (rand() < 0.13) set(x, y, 3, stone[rand() < 0.5 ? 0 : 2]);
}
}
for (let z = 0; z <= 2; z++) {
box(17 + z, 5 + z, z, 30 - z, 10, z,
z === 2 ? "#d8d3c1" : stone[1]);
}
box(20, 8, 3, 27, 11, 4, "#80513a");
box(20, 8, 4, 27, 9, 4, "#ad7248");
// Wooden floor, with a glimpse of tatami through the open doorway.
box(9, 11, 4, 38, 38, 4, "#79492f");
for (let x = 11; x <= 36; x += 7) {
for (let y = 13; y <= 34; y += 8) {
box(x, y, 5, x + 5, y + 6, 5, "#bca574");
box(x, y, 5, x + 5, y, 5, "#665a3c");
}
}
// Rear wall and the dark interior, set well behind the open entrance.
box(9, 37, 5, 38, 38, 21, wood);
box(10, 36, 8, 37, 36, 19, "#392b27");
box(21, 35, 11, 26, 35, 17, "#875532");
box(22, 34, 12, 25, 34, 16, "#b99950");
box(23, 33, 13, 24, 33, 15, "#343328");
// Lower wooden walls.
box(9, 10, 5, 38, 11, 7, redDark);
box(9, 11, 5, 10, 38, 8, red);
box(37, 11, 5, 38, 38, 8, red);
box(9, 11, 19, 10, 38, 21, redDark);
box(37, 11, 19, 38, 38, 21, redDark);
// Shoji panels on both long sides.
for (const x of [9, 38]) {
for (let y = 12; y <= 36; y++) {
for (let z = 9; z <= 18; z++) {
const frame = (y - 12) % 5 === 0 || z === 13 || z === 18;
set(x, y, z, frame ? wood : paper);
}
}
}
// Front shoji, leaving the central entrance genuinely open.
for (const [a, b] of [[10, 18], [29, 37]]) {
for (let x = a; x <= b; x++) {
for (let z = 8; z <= 19; z++) {
const frame = x === a || x === b || (x - a) % 4 === 0 ||
z === 8 || z === 12 || z === 16 || z === 19;
set(x, 10, z, frame ? wood : paper);
}
}
}
box(9, 10, 20, 38, 12, 21, redDark);
box(20, 10, 19, 27, 11, 21, "#c4994c");
// Lacquered structural posts and warm gold collars.
for (const x of [9, 19, 28, 38]) {
box(x, 9, 4, x + 1, 12, 21, red);
box(x, 9, 5, x + 1, 9, 5, "#d5a55b");
box(x, 9, 19, x + 1, 9, 19, "#d5a55b");
line(x, 9, 7, x, 9, 17, 0, redLight);
}
for (const y of [18, 27, 37]) {
for (const x of [9, 38]) {
box(x, y, 5, x + 1, y + 1, 21, redDark);
box(x, y, 19, x + 1, y + 1, 19, "#ad7845");
}
}
box(8, 9, 20, 39, 11, 21, red);
box(8, 9, 20, 39, 9, 20, "#c79748");
// Front gable: a triangular red wooden face beneath the roof.
function roofHeight(x, y) {
const slope = 32 - Math.abs(x - 23.5) * 0.48;
const sideCurl = Math.max(0, 8 - Math.min(x, 47 - x)) * 0.35;
const endCurl = Math.max(0, 9 - Math.min(y, 48 - y)) * 0.35;
return Math.round(slope + sideCurl + endCurl);
}
for (let x = 8; x <= 39; x++) {
const top = roofHeight(x, 8) - 2;
for (let z = 22; z <= top; z++) {
set(x, 8, z, (x % 5 === 0) ? redLight : redDark);
set(x, 9, z, redDark);
}
}
for (let x = 11; x <= 36; x += 5) {
const top = roofHeight(x, 8) - 3;
line(x, 7, 22, x, 7, top, 0, "#a46d3f");
}
box(21, 7, 24, 26, 7, 27, "#c6994e");
box(22, 6, 25, 25, 6, 26, redDark);
set(23, 5, 26, "#e2bb6b");
set(24, 5, 26, "#e2bb6b");
// Deep grey glazed roof, with raised courses of tiles.
for (let x = 4; x <= 43; x++) {
for (let y = 5; y <= 43; y++) {
const z = roofHeight(x, y);
set(x, y, z - 2, "#493932");
set(x, y, z - 1, "#383b3c");
let tile = y % 4 === 0 ? "#61686a" :
y % 4 === 1 ? "#4e5759" : "#414a4d";
if (rand() < 0.07) tile = "#697174";
set(x, y, z, tile);
if (y % 4 === 0 && x > 5 && x < 42)
set(x, y, z + 1, rand() < 0.13 ? "#777e7e" : "#555e60");
}
}
// Strong front fascia and gently upturned roof corners.
for (let x = 4; x <= 43; x++) {
const z = roofHeight(x, 5);
set(x, 5, z - 2, redDark);
if (x % 4 !== 0) set(x, 4, z - 1, "#b48649");
}
for (const x of [4, 43]) {
for (const y of [5, 43]) {
const z = roofHeight(x, y);
line(x, y, z, x, y, z + 3, 0, "#626a69");
set(x, y, z + 3, "#b48c50");
}
}
box(23, 6, 33, 24, 42, 34, "#333b3e");
for (let y = 7; y <= 41; y += 4) {
box(22, y, 33, 25, y, 34, "#687073");
}
box(22, 5, 33, 25, 7, 34, "#8b724d");
// Vertical wooden dojo sign beside the doorway.
box(14, 7, 9, 18, 8, 19, "#80502f");
box(15, 6, 10, 17, 6, 18, "#c59553");
for (let z = 10; z <= 18; z++) {
set(14, 6, z, "#e3bd77");
set(18, 6, z, "#e3bd77");
}
box(14, 6, 19, 18, 6, 19, "#e3bd77");
box(14, 6, 9, 18, 6, 9, "#e3bd77");
// Two bold, kanji-like brush characters on the face of the plaque.
const glyphs = [
["111", "010", "111", "101"],
["111", "101", "111", "010"]
];
for (let g = 0; g < 2; g++) {
for (let row = 0; row < 4; row++) {
for (let col = 0; col < 3; col++) {
if (glyphs[g][row][col] === "1")
set(15 + col, 5, 17 - g * 5 - row, "#262523");
}
}
}import { draw } from "./assets/voxel";
import { dojo } from "./assets/dojo";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, dojo, 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 dojo
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["dojo"] })
# It lands in client/assets/dojo.ts
# https://fogon.page/object/dojo