← Monsters and enemies3D assetfogon/caballero-oscuro
Caballero oscuro
Drag to turn it// «Caballero oscuro» · gpt-6-sol (medium)
// A menacing cartoon dark knight facing -y: heavy black plate armor with dark purple trim and spikes on the shoulders, a closed helmet with a narrow visor slit glowing red, a tattered dark red cape, a big black sword in the right hand and a spiked shield in the left.
const black = "#11121d";
const shadow = "#090a12";
const iron = "#252638";
const lightIron = "#39394e";
const purple = "#51234f";
const brightPurple = "#763468";
const cape = "#621d32";
const capeDark = "#391323";
const red = "#ff343e";
// Tattered cape, hanging behind the armor.
box(15, 30, 16, 34, 33, 31, capeDark);
box(12, 33, 19, 37, 35, 30, cape);
box(13, 35, 14, 8, 37, 25, capeDark);
box(16, 35, 19, 6, 38, 25, cape);
box(21, 35, 25, 10, 38, 25, capeDark);
box(28, 35, 31, 5, 38, 25, cape);
box(34, 35, 36, 9, 37, 25, capeDark);
for (let x = 13; x <= 36; x++) {
const bottom = 7 + (x * 7 % 5);
for (let z = bottom; z < 15; z++) {
if (get(x, 36, z) && rand() < 0.25) set(x, 36, z, null);
}
}
box(13, 32, 28, 36, 34, 31, brightPurple);
// Broad breastplate and narrow waist.
box(17, 20, 18, 32, 31, 30, black);
box(16, 19, 23, 33, 30, 31, iron);
box(18, 17, 24, 31, 19, 30, black);
box(19, 16, 25, 30, 16, 29, iron);
box(20, 16, 29, 29, 17, 30, lightIron);
box(18, 19, 18, 31, 29, 22, shadow);
box(19, 17, 19, 30, 18, 22, purple);
box(20, 16, 20, 29, 16, 21, brightPurple);
// Angled chest plates and a little sinister crest.
box(18, 17, 24, 23, 17, 29, iron);
box(26, 17, 24, 31, 17, 29, iron);
line(18, 16, 29, 23, 16, 24, 0, lightIron);
line(31, 16, 29, 26, 16, 24, 0, lightIron);
box(23, 15, 27, 26, 16, 28, purple);
box(24, 14, 25, 25, 15, 27, red);
box(17, 17, 18, 32, 30, 19, iron);
box(18, 16, 18, 31, 19, 19, brightPurple);
box(20, 15, 18, 29, 16, 18, shadow);
box(22, 15, 18, 27, 15, 18, lightIron);
// Left arm, held forward behind its shield.
box(11, 20, 24, 18, 29, 31, black);
box(12, 18, 25, 18, 27, 31, iron);
box(12, 17, 25, 17, 18, 29, purple);
box(12, 17, 21, 17, 24, 25, black);
box(11, 16, 18, 16, 20, 22, iron);
box(11, 14, 17, 16, 18, 19, lightIron);
box(12, 13, 17, 16, 15, 19, shadow);
// Left pauldron: thick rim and a tall triangular spike.
box(11, 18, 29, 19, 31, 33, shadow);
box(12, 17, 31, 19, 29, 34, iron);
box(12, 17, 32, 17, 18, 33, brightPurple);
for (let z = 34; z <= 40; z++) {
const inset = Math.floor((z - 34) / 2);
box(12 + inset, 22, z, 16 - inset, 26, z, z < 37 ? iron : lightIron);
}
// Spiked shield, with a strongly outlined pointed bottom.
box(7, 11, 18, 17, 14, 27, shadow);
box(5, 11, 18, 19, 13, 24, shadow);
box(8, 11, 14, 16, 13, 27, shadow);
box(10, 11, 12, 14, 13, 27, shadow);
box(12, 11, 10, 13, 13, 27, shadow);
box(7, 10, 19, 17, 10, 26, purple);
box(6, 10, 19, 18, 10, 23, purple);
box(9, 10, 15, 15, 10, 26, purple);
box(11, 10, 13, 13, 10, 26, purple);
box(12, 10, 11, 13, 10, 26, purple);
box(8, 9, 19, 16, 9, 24, iron);
box(10, 9, 16, 14, 9, 26, iron);
box(11, 9, 13, 13, 9, 26, iron);
box(12, 9, 11, 13, 9, 26, iron);
line(12, 8, 13, 12, 8, 25, 0, brightPurple);
box(10, 8, 20, 14, 8, 22, lightIron);
box(11, 7, 20, 13, 7, 22, purple);
box(12, 5, 21, 12, 6, 21, lightIron);
for (const [x, z] of [[7, 19], [17, 19], [9, 25], [15, 25]]) {
box(x, 8, z, x, 9, z + 1, lightIron);
set(x, 7, z, brightPurple);
}
// Chunky closed helmet, oversized for a cartoon silhouette.
box(18, 18, 31, 31, 29, 39, shadow);
box(17, 17, 34, 32, 29, 39, iron);
box(19, 18, 39, 30, 28, 41, iron);
box(21, 19, 42, 28, 27, 42, lightIron);
box(23, 20, 43, 26, 26, 43, iron);
box(17, 16, 33, 32, 19, 37, shadow);
box(18, 15, 34, 31, 16, 38, iron);
box(19, 15, 39, 30, 17, 40, lightIron);
box(18, 15, 33, 31, 17, 34, purple);
// Visor is one narrow, dark horizontal slit with two blazing eyes.
box(19, 14, 36, 30, 14, 37, shadow);
box(20, 13, 36, 29, 13, 36, "#570d25");
box(20, 12, 36, 22, 12, 36, red);
box(27, 12, 36, 29, 12, 36, red);
set(21, 11, 36, "#ff8b68");
set(28, 11, 36, "#ff8b68");
box(18, 14, 35, 31, 14, 35, lightIron);
box(22, 14, 32, 27, 15, 34, iron);
box(23, 13, 32, 26, 14, 33, shadow);
box(24, 12, 33, 25, 13, 34, purple);
// Side flanges and short swept-back helmet horns.
box(16, 18, 35, 18, 27, 39, shadow);
box(31, 18, 35, 33, 27, 39, shadow);
line(17, 25, 39, 14, 28, 43, 1, iron);
line(32, 25, 39, 35, 28, 43, 1, iron);
set(14, 28, 44, lightIron);
set(35, 28, 44, lightIron);
// Subtle worn variation on large armor and cape surfaces.
forEach((x, y, z, color) => {
if (color === iron && rand() < 0.035) set(x, y, z, lightIron);
if (color === cape && rand() < 0.045) set(x, y, z, capeDark);
});
// Each leg has its own hip pivot.
part("leftLeg", [21, 25, 19]);
box(17, 21, 12, 23, 29, 19, iron);
box(18, 19, 10, 22, 24, 15, black);
box(17, 19, 10, 23, 21, 12, purple);
box(18, 22, 4, 23, 28, 11, iron);
box(17, 17, 0, 24, 29, 5, shadow);
box(17, 16, 2, 24, 19, 5, iron);
box(18, 15, 1, 23, 16, 3, lightIron);
box(18, 18, 5, 23, 19, 5, brightPurple);
animate("leftLeg", {type:"swing", axis:"x", speed:4, amplitude:0.3});
part("rightLeg", [28, 25, 19]);
box(26, 21, 12, 32, 29, 19, iron);
box(27, 19, 10, 31, 24, 15, black);
box(26, 19, 10, 32, 21, 12, purple);
box(26, 22, 4, 31, 28, 11, iron);
box(25, 17, 0, 32, 29, 5, shadow);
box(25, 16, 2, 32, 19, 5, iron);
box(26, 15, 1, 31, 16, 3, lightIron);
box(26, 18, 5, 31, 19, 5, brightPurple);
animate("rightLeg", {type:"swing", axis:"x", speed:-4, amplitude:0.3});
// Sword arm and weapon move together from the shoulder.
part("swordArm", [34, 25, 30]);
box(32, 19, 26, 39, 29, 32, shadow);
box(33, 18, 27, 39, 28, 33, iron);
box(33, 17, 30, 39, 19, 32, brightPurple);
for (let z = 33; z <= 39; z++) {
const inset = Math.floor((z - 33) / 2);
box(34 + inset, 22, z, 38 - inset, 26, z, z < 36 ? iron : lightIron);
}
box(35, 18, 21, 40, 25, 28, black);
box(36, 17, 22, 40, 19, 27, iron);
box(37, 15, 18, 42, 21, 23, shadow);
box(38, 14, 20, 42, 16, 22, lightIron);
box(39, 13, 19, 42, 15, 21, purple);
// Wrapped grip, wide crossguard, and broad black blade.
box(40, 12, 21, 42, 15, 28, shadow);
for (let z = 22; z <= 26; z += 2)
box(40, 11, z, 42, 12, z, brightPurple);
box(37, 12, 27, 45, 15, 29, shadow);
box(36, 12, 28, 46, 14, 28, purple);
box(37, 11, 29, 38, 13, 30, lightIron);
box(44, 11, 29, 45, 13, 30, lightIron);
box(39, 12, 30, 44, 16, 40, shadow);
box(40, 11, 30, 43, 12, 41, iron);
box(40, 11, 32, 40, 11, 39, purple);
box(44, 13, 31, 44, 15, 39, lightIron);
box(40, 12, 41, 43, 15, 42, shadow);
box(41, 12, 43, 42, 14, 44, iron);
set(41, 13, 45, lightIron);
animate("swordArm", {type:"swing", axis:"x", speed:3, amplitude:0.5});
part("body", [24, 24, 20]);import { draw } from "./assets/voxel";
import { caballeroOscuro } from "./assets/caballero-oscuro";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, caballeroOscuro, 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 caballero-oscuro
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["caballero-oscuro"] })
# It lands in client/assets/caballero-oscuro.ts
# https://fogon.page/object/caballero-oscuro