← Monsters and enemies3D assetfogon/troll
Troll
Drag to turn it// «Troll» · gpt-6-sol (medium)
// A big lumpy cartoon cave troll facing -y: grey-blue stony skin with mossy green patches, a small head on huge shoulders, a big round nose, tiny eyes and an underbite with two teeth, very long arms that reach the ground with huge fists, short thick legs and a fur loincloth.
const dark = "#354b5d";
const mid = "#547185";
const light = "#7897a7";
const highlight = "#a1b9bd";
const moss = "#587c48";
const mossLight = "#91ad61";
const furDark = "#493d3b";
const fur = "#785c4b";
const furLight = "#a3825f";
function skinBlob(x, y, z, rx, ry, rz) {
ellipsoid(x, y, z, rx, ry, rz, dark);
ellipsoid(x, y, z + 1, rx - 0.7, ry - 0.7, rz - 1, mid);
ellipsoid(x - 0.5, y - 0.5, z + 2, rx - 1.8, ry - 1.8, rz - 2.5, light);
}
function mossClump(x, y, z) {
ellipsoid(x, y, z, 2.4, 1.2, 1.3, moss);
sphere(x - 1, y - 0.5, z + 1, 0.8, mossLight);
sphere(x + 1, y, z + 0.5, 0.7, mossLight);
}
// Short, heavy legs.
for (const leg of [
{ name: "leftLeg", x: 17, speed: 2 },
{ name: "rightLeg", x: 31, speed: -2 }
]) {
part(leg.name, [leg.x, 24, 14]);
skinBlob(leg.x, 25, 9, 5.7, 5.6, 8);
ellipsoid(leg.x, 20, 3, 6.2, 8, 3.2, dark);
ellipsoid(leg.x, 19, 4, 5.7, 7.2, 2.5, mid);
ellipsoid(leg.x, 17, 3, 4.6, 4.3, 1.7, light);
for (let dx = -3; dx <= 3; dx += 3) {
ellipsoid(leg.x + dx, 13, 2, 1.2, 2, 0.8, highlight);
}
animate(leg.name, {
type: "swing",
axis: "x",
speed: leg.speed,
amplitude: 0.3
});
}
part("body");
// Huge shoulders and a forward-projecting belly.
skinBlob(24, 25, 22, 14, 10, 13);
skinBlob(24, 24, 30, 17, 10, 7);
skinBlob(24, 19, 19, 11.5, 9, 9);
ellipsoid(24, 17, 16, 9, 4, 3, mid);
// Uneven rocky lumps around the silhouette.
const bumps = [
[10, 23, 31, 2.5], [38, 25, 30, 2.8],
[11, 29, 23, 2], [36, 31, 24, 2.3],
[15, 31, 30, 2], [32, 31, 29, 2]
];
for (const b of bumps) {
sphere(b[0], b[1], b[2], b[3], mid);
sphere(b[0] - 0.5, b[1] - 0.5, b[2] + 0.8, b[3] * 0.55, light);
}
// Small stone flecks across the belly.
for (let i = 0; i < 55; i++) {
const x = 14 + rand() * 20;
const z = 15 + rand() * 15;
const q = ((x - 24) / 12) ** 2 + ((z - 22) / 12) ** 2;
if (q < 0.83) {
const y = 24 - 10 * Math.sqrt(1 - q);
set(x, y - 0.5, z, rand() < 0.6 ? light : dark);
}
}
const shoulderMoss = [
[13, 17, 34], [16, 19, 36], [35, 18, 35],
[38, 22, 33], [12, 29, 33], [34, 31, 33]
];
for (const p of shoulderMoss) {
mossClump(p[0], p[1], p[2]);
}
// Ragged fur belt and loincloth.
ellipsoid(24, 18, 14, 11, 5, 2.6, furDark);
box(15, 13, 14, 33, 14, 16, fur);
for (let x = 15; x <= 33; x += 3) {
box(x, 12, 16, x + 1, 12, 16, furLight);
}
ellipsoid(24, 13, 11, 8, 2.5, 5.3, furDark);
ellipsoid(24, 12, 11, 7, 1.5, 4.6, fur);
for (let x = 18; x <= 30; x += 3) {
const tipX = x + (x < 24 ? -1 : 1);
const tipZ = 6 + Math.floor(rand() * 3);
line(x, 11, 11, tipX, 11, tipZ, 0.8, furLight);
}
for (const x of [17, 31]) {
line(x, 15, 13, x, 17, 6, 1.1, furDark);
sphere(x, 17, 6, 1.1, furLight);
}
// Small head, ears, brow, and glowing eyes.
skinBlob(24, 19, 37, 6.7, 6, 5.6);
for (const x of [17, 31]) {
ellipsoid(x, 20, 36, 3, 2.4, 2.5, dark);
sphere(x + (x < 24 ? -1 : 1), 19, 37, 1.4, mid);
}
ellipsoid(24, 15, 40, 4.5, 2.8, 1.5, light);
for (const x of [21, 27]) {
ellipsoid(x, 13, 38, 1.8, 0.8, 1.6, "#263941");
sphere(x, 12, 38, 0.9, "#edee66");
set(x, 11, 38, "#fff9ad");
box(x - 2, 12, 40, x + 1, 13, 40, dark);
}
// Round nose and protruding underbite with two blunt teeth.
ellipsoid(24, 10, 35, 3.4, 3.6, 2.8, mid);
ellipsoid(23, 8, 36, 2, 1.7, 1.4, light);
set(22, 7, 34, "#263941");
set(26, 7, 34, "#263941");
ellipsoid(24, 12, 31, 5.2, 3.1, 2.1, dark);
ellipsoid(24, 10, 30, 5, 2.2, 1.5, mid);
box(21, 8, 32, 27, 9, 32, "#283842");
for (const x of [21, 27]) {
box(x, 7, 32, x + 1, 8, 33, "#f3e8bc");
set(x, 7, 34, "#f3e8bc");
}
mossClump(29, 17, 41);
// Long arms with enormous ground-reaching fists.
for (const arm of [
{ name: "leftArm", side: -1, speed: 2 },
{ name: "rightArm", side: 1, speed: -2 }
]) {
const shoulder = 24 + arm.side * 14;
const hand = 24 + arm.side * 17;
part(arm.name, [shoulder, 23, 31]);
skinBlob(shoulder, 23, 29, 5.5, 5.2, 6);
skinBlob(hand, 22, 23, 4.5, 4.6, 8);
sphere(hand, 21, 18, 4.4, mid);
skinBlob(hand, 19, 13, 4.3, 4.2, 8);
ellipsoid(hand, 17, 5, 5, 5.3, 5, dark);
ellipsoid(hand, 16, 6, 4.6, 4.8, 4, mid);
ellipsoid(hand, 14, 7, 3.8, 2.6, 2.3, light);
ellipsoid(hand - arm.side * 4, 17, 6, 2.2, 2.4, 2.8, mid);
for (let i = -2; i <= 2; i += 2) {
sphere(hand + i, 13, 4, 1.25, mid);
set(hand + i, 12, 4, highlight);
}
mossClump(shoulder + arm.side, 19, 33);
mossClump(hand, 18, 16);
animate(arm.name, {
type: "swing",
axis: "x",
speed: arm.speed,
amplitude: 0.3
});
}
part("body");import { draw } from "./assets/voxel";
import { troll } from "./assets/troll";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, troll, 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 troll
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["troll"] })
# It lands in client/assets/troll.ts
# https://fogon.page/object/troll