← Basics3D assetfogon/llave-fija
Llave fija
Drag to turn it// «Llave fija» · gpt-6-sol (medium)
// Open wrench («Llave fija»).
// Open wrench, lying flat with its jaws facing +y.
const steel = "#aebfc6";
const light = "#d7e2e5";
const highlight = "#e9eff0";
const mid = "#91a7b2";
const shade = "#617985";
const dark = "#455f6e";
const occupied = new Set();
const key = (x, y) => `${x},${y}`;
function metal(x, y) {
// Rounded ring at the end of the handle.
if (y >= 6 && y <= 13) {
const half = [3, 5, 6, 6, 6, 6, 5, 4][y - 6];
if (Math.abs(x - 24) <= half) {
if (y >= 8 && y <= 11 && x >= 22 && x <= 25) return false;
return true;
}
}
// Straight, slightly tapered shaft.
if (y >= 14 && y <= 29) {
const half = y < 18 ? 4 : y < 25 ? 3 : 4;
if (Math.abs(x - 24) <= half) return true;
}
// Broad shoulder and the two spreading jaws.
const rows = {
30: [19, 29], 31: [17, 31], 32: [15, 33],
33: [13, 35], 34: [12, 36], 35: [11, 37],
36: [10, 38], 37: [10, 38], 38: [10, 38],
39: [10, 38], 40: [10, 38], 41: [11, 37],
42: [11, 37], 43: [12, 36], 44: [13, 35]
};
const row = rows[y];
if (!row || x < row[0] || x > row[1]) return false;
const mouth = {
35: [23, 25], 36: [21, 27], 37: [20, 28],
38: [19, 29], 39: [18, 30], 40: [17, 31],
41: [16, 32], 42: [16, 32], 43: [16, 32],
44: [16, 32]
}[y];
return !mouth || x < mouth[0] || x > mouth[1];
}
for (let y = 6; y <= 44; y++)
for (let x = 9; x <= 39; x++)
if (metal(x, y)) occupied.add(key(x, y));
function has(x, y) { return occupied.has(key(x, y)); }
for (let y = 6; y <= 44; y++) {
for (let x = 9; x <= 39; x++) {
if (!has(x, y)) continue;
const left = !has(x - 1, y);
const right = !has(x + 1, y);
const front = !has(x, y - 1);
const back = !has(x, y + 1);
const edge = left || right || front || back;
for (let z = 0; z <= 3; z++) {
let color = z === 0 ? dark : z === 1 ? shade : steel;
if (z >= 2 && (left || front)) color = mid;
if (z === 3 && (right || back)) color = light;
set(x, y, z, color);
}
// A narrow stepped bevel catches the light around the silhouette.
set(x, y, 4, edge ? (left || front ? mid : light) :
rand() < 0.09 ? steel : light);
if (!edge) set(x, y, 5, rand() < 0.10 ? steel : light);
}
}
// Bright, continuous raised ridge down the handle.
for (let y = 14; y <= 32; y++) {
for (let x = 23; x <= 25; x++) {
if (has(x, y) && has(x - 1, y) && has(x + 1, y))
set(x, y, 5, x === 23 ? light : highlight);
}
}
// Small cool-blue stamped notches along both sides of the shaft.
for (let y = 17; y <= 28; y += 3) {
for (const x of [21, 27]) {
if (has(x, y)) set(x, y, 5, shade);
if (has(x, y + 1)) set(x, y + 1, 5, mid);
}
}
// Reinforced shoulders and faceted highlights around the jaw roots.
for (let y = 31; y <= 35; y++) {
for (const x of [17, 18, 30, 31]) {
if (has(x, y) && has(x - 1, y) && has(x + 1, y))
set(x, y, 5, y % 2 ? steel : highlight);
}
}
for (let y = 34; y <= 42; y++) {
for (const x of [12, 13, 35, 36]) {
if (has(x, y) && has(x - 1, y) && has(x + 1, y))
set(x, y, 5, rand() < 0.3 ? mid : highlight);
}
}
// Sharply defined gripping faces on the inside of each open jaw.
for (let y = 38; y <= 43; y++) {
const innerLeft = [19, 18, 17, 16, 16, 16][y - 38] - 1;
const innerRight = [29, 30, 31, 32, 32, 32][y - 38] + 1;
for (const x of [innerLeft, innerRight]) {
if (!has(x, y)) continue;
set(x, y, 4, y % 2 ? steel : highlight);
if (has(x, y - 1) && has(x, y + 1))
set(x, y, 5, y % 2 ? mid : light);
}
}
// Pale raised rim and dark inner wall of the hole in the handle end.
for (let y = 7; y <= 12; y++) {
for (let x = 20; x <= 27; x++) {
if (!has(x, y)) continue;
const besideHole =
!has(x - 1, y) || !has(x + 1, y) ||
!has(x, y - 1) || !has(x, y + 1);
if (besideHole) set(x, y, 4, (x === 21 || y === 8) ? shade : highlight);
}
}import { draw } from "./assets/voxel";
import { llaveFija } from "./assets/llave-fija";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, llaveFija, 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 llave-fija
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["llave-fija"] })
# It lands in client/assets/llave-fija.ts
# https://fogon.page/object/llave-fija