← Nature3D assetfogon/bloque-de-hielo
Hielo
Drag to turn it// «Hielo» · gpt-6-sol (medium)
// A chunky block of ice: a cracked light blue translucent-looking cube with white frost on the edges and top, slightly irregular.
const hash = (a, b, c = 0) => {
const n = Math.sin(a * 127.1 + b * 311.7 + c * 74.7) * 43758.5453;
return n - Math.floor(n);
};
const lo = 8, hi = 40;
// A solid ice block with clipped corners and an uneven, gently beveled top.
for (let x = lo; x <= hi; x++) {
for (let y = lo; y <= hi; y++) {
const dx = Math.min(x - lo, hi - x);
const dy = Math.min(y - lo, hi - y);
if (dx + dy < 3) continue;
const edge = Math.min(dx, dy);
const patch = hash(Math.floor(x / 6), Math.floor(y / 6));
const top = 33 - (edge < 2 ? 2 : edge < 4 ? 1 : 0)
- (patch > 0.86 ? 1 : 0);
for (let z = 0; z <= top; z++) {
let color = "#8edced";
if (y <= 10) color = "#a9eaf4";
if (x >= 38) color = "#78cee8";
if (z < 5) color = x >= 37 ? "#65b9dc" : "#83cee5";
// Broad, faint shapes suggest light passing through cloudy ice.
const cloud = hash(Math.floor(x / 7), Math.floor(y / 7), Math.floor(z / 6));
if (cloud > 0.68) color = y <= 10 ? "#b8f0f7" : "#9be3f0";
else if (cloud < 0.16) color = y <= 10 ? "#91dbe9" : "#79cce5";
if (z === top) color = patch > 0.5 ? "#dcfaff" : "#c9f4fb";
set(x, y, z, color);
}
}
}
// Find the actual face of the irregular block, so details hug its surface.
function front(x, z, color) {
x = Math.round(x); z = Math.round(z);
for (let y = lo; y <= hi; y++) {
if (get(x, y, z)) { set(x, y, z, color); return; }
}
}
function right(y, z, color) {
y = Math.round(y); z = Math.round(z);
for (let x = hi; x >= lo; x--) {
if (get(x, y, z)) { set(x, y, z, color); return; }
}
}
function stroke(points, paint, color) {
for (let i = 0; i < points.length - 1; i++) {
const [a, b] = points[i], [c, d] = points[i + 1];
const steps = Math.max(Math.abs(c - a), Math.abs(d - b)) * 2;
for (let j = 0; j <= steps; j++) {
const t = j / steps;
paint(a + (c - a) * t, b + (d - b) * t, color);
}
}
}
// Large angular glints on the front and side.
for (let z = 5; z <= 27; z++) {
for (let x = 11; x <= 38; x++) {
if (x > 11 + Math.floor(z * 0.42) &&
x < 20 + Math.floor(z * 0.40) &&
z > 8 && z < 27) {
front(x, z, "#bceff7");
}
}
}
for (let z = 9; z <= 29; z++) {
for (let y = 13; y <= 37; y++) {
if (y > 30 - Math.floor(z * 0.25) &&
y < 37 - Math.floor(z * 0.10)) {
right(y, z, "#a1e5f2");
}
}
}
// Sharp blue cracks, edged with tiny white refractions.
stroke([[24,32],[23,28],[26,25],[24,21],[28,17],[27,13],[31,9],[30,5]],
front, "#59b9d6");
stroke([[25,32],[24,28],[27,25],[25,21],[29,17],[28,13]],
front, "#e3fbff");
stroke([[26,25],[31,27],[34,25],[37,26]], front, "#67c4dc");
stroke([[27,26],[31,28],[34,26]], front, "#e8fcff");
stroke([[9,15],[14,18],[18,16],[20,12],[25,11]], front, "#69c3db");
stroke([[10,16],[14,19],[18,17]], front, "#e4faff");
stroke([[18,31],[20,26],[18,23],[23,19],[22,15],[27,12]],
right, "#55b7d5");
stroke([[19,31],[21,26],[19,23],[24,19]], right, "#def9ff");
stroke([[22,15],[29,18],[33,16]], right, "#69c4dd");
// White, uneven frost clings to the rim, corners, and upper sides.
for (let x = lo; x <= hi; x++) {
for (let y = lo; y <= hi; y++) {
for (let z = 0; z <= 33; z++) {
if (!get(x, y, z)) continue;
const exposedTop = !get(x, y, z + 1);
const exposedSide =
!get(x - 1, y, z) || !get(x + 1, y, z) ||
!get(x, y - 1, z) || !get(x, y + 1, z);
if (!exposedTop && !exposedSide) continue;
const edge = Math.min(x - lo, hi - x, y - lo, hi - y);
const fleck = hash(x, y, z);
if (exposedTop && (edge < 5 || fleck > 0.80)) {
set(x, y, z, fleck > 0.42 ? "#f3feff" : "#dcfaff");
} else if (exposedSide && z >= 27 &&
(edge < 5 || fleck > 0.84)) {
if (fleck > 0.30) set(x, y, z, "#e9fcff");
} else if (exposedSide && edge < 2 && fleck > 0.68) {
set(x, y, z, "#d7f8fc");
}
}
}
}import { draw } from "./assets/voxel";
import { bloqueDeHielo } from "./assets/bloque-de-hielo";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, bloqueDeHielo, 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 bloque-de-hielo
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["bloque-de-hielo"] })
# It lands in client/assets/bloque-de-hielo.ts
# https://fogon.page/object/bloque-de-hielo