← FantasíaObjeto 3Dfogon/portal-de-hielo
Portal de hielo
Arrastrá para girarlo// «Portal de hielo» · gpt-6-sol (medium)
// A magic ice portal: a tall arch made of jagged pale blue ice crystals and frosty white snow at its base, with a swirling glowing light-blue magic surface filling the inside of the arch, facing front (-y).
// The portal faces -y. Its magic surface is kept separate for animation.
const cx = 24;
function innerLeft(z) {
if (z <= 29) return 16;
return Math.min(24, 16 + Math.round((z - 29) * 1.35));
}
function innerRight(z) {
return 48 - innerLeft(z);
}
function outerLeft(z) {
if (z <= 29) return 9;
const t = Math.min(1, (z - 29) / 13);
return Math.round(cx - 15 * Math.sqrt(1 - t * t));
}
// Low, chunky stone threshold.
box(9, 19, 0, 39, 29, 2, "#617b83");
box(13, 17, 0, 35, 22, 2, "#8caab0");
box(14, 18, 2, 34, 21, 3, "#c8edf0");
for (let x = 12; x <= 36; x += 3) {
box(x, 18, 1, x + 1, 18, 1, "#a9c8ce");
}
// Solid ice arch, with darker depth and bright, uneven front facets.
for (let z = 4; z <= 42; z++) {
const ol = outerLeft(z);
const or = 48 - ol;
const il = innerLeft(z);
const ir = innerRight(z);
const open = z <= 35;
for (let x = ol; x <= or; x++) {
if (open && x >= il && x <= ir) continue;
for (let y = 20; y <= 29; y++) {
let color = y >= 26 ? "#5299aa" : y >= 23 ? "#79cbd8" : "#a9e8eb";
if (x <= ol + 1 || x >= or - 1) color = "#86d6e3";
if (y === 20 || z >= 39) color = "#c6f2f1";
if (rand() < 0.11) color = y < 24 ? "#e2f9f5" : "#66bdcd";
set(x, y, z, color);
}
}
}
// Big angular facets climbing each pillar.
for (const side of [-1, 1]) {
for (let z = 7; z <= 29; z++) {
const edge = side < 0 ? innerLeft(z) - 1 : innerRight(z) + 1;
set(edge, 19, z, z % 7 < 4 ? "#d9faf6" : "#8ddde5");
set(edge - side, 19, z, "#a6e9e9");
if (z % 9 < 5) set(edge - side * 2, 20, z, "#e4faf5");
}
line(cx + side * 12, 19, 7, cx + side * 14, 18, 23, 1, "#d5f8f5");
line(cx + side * 13, 20, 16, cx + side * 17, 18, 27, 1, "#87d4e3");
}
// Crystal teeth break up the silhouette.
function crystal(x, y, bottom, height, lean) {
for (let dz = 0; dz < height; dz++) {
const px = Math.round(x + lean * dz / height);
const r = Math.max(0, Math.floor((height - dz) / 5));
box(px - r, y - r, bottom + dz, px + r, y + r, bottom + dz,
dz > height - 4 ? "#e6fbf8" : dz % 4 === 0 ? "#87d9e5" : "#b5eff0");
set(px, y - r - 1, bottom + dz, "#e4fbf7");
}
}
crystal(11, 19, 8, 15, -5);
crystal(37, 19, 9, 16, 5);
crystal(13, 22, 25, 13, -3);
crystal(35, 22, 25, 13, 3);
crystal(19, 22, 37, 8, -2);
crystal(29, 22, 37, 8, 2);
crystal(24, 24, 40, 5, 0);
// Frosty snowdrifts piled against the feet, leaving the doorway clear.
for (const s of [-1, 1]) {
const x = cx + s * 16;
ellipsoid(x, 23, 2, 6, 7, 3, "#d8f4f2");
ellipsoid(x - s * 2, 19, 3, 4, 3, 2, "#f4fcf7");
ellipsoid(x + s * 2, 27, 2, 4, 3, 2, "#b9e4e8");
crystal(x + s * 3, 17, 2, 8, s * 2);
crystal(x - s * 3, 18, 3, 6, -s);
}
for (let i = 0; i < 65; i++) {
const x = 7 + Math.floor(rand() * 35);
const y = 17 + Math.floor(rand() * 14);
const z = 1 + Math.floor(rand() * 2);
if (get(x, y, z)) set(x, y, z, rand() < 0.5 ? "#effbf7" : "#a9dce3");
}
// A luminous, gently swirling membrane inside the arch.
part("magic surface", [24, 23, 19]);
for (let z = 4; z <= 35; z++) {
const left = innerLeft(z);
const right = innerRight(z);
for (let x = left; x <= right; x++) {
for (let y = 22; y <= 24; y++) {
const wave = Math.sin(x * 0.65 + z * 0.38);
set(x, y, z, wave > 0.48 ? "#d9ffff" :
wave < -0.45 ? "#54dbea" : "#94f3fa");
}
}
}
// Pale curling ribbons and a bright heart give the portal depth.
for (let i = 0; i < 140; i++) {
const t = i / 139;
const angle = t * Math.PI * 4.2;
const radius = 1 + t * 8;
const x = Math.round(24 + Math.cos(angle) * radius);
const z = Math.round(19 + Math.sin(angle) * radius * 1.45);
if (z >= 5 && z <= 35 && x > innerLeft(z) && x < innerRight(z)) {
set(x, 21, z, i % 5 === 0 ? "#ffffff" : "#c7ffff");
}
}
ellipsoid(24, 21, 19, 2, 0, 3, "#e8ffff");
for (const [x, z] of [[20, 26], [29, 24], [18, 14], [28, 11], [25, 31]]) {
set(x, 20, z, "#ffffff");
set(x - 1, 21, z, "#d6ffff");
set(x + 1, 21, z, "#d6ffff");
set(x, 21, z + 1, "#d6ffff");
set(x, 21, z - 1, "#d6ffff");
}
animate("magic surface", {
type: "colors",
palette: ["#a9efff", "#43e3f5", "#efffff", "#79d6ff"],
pattern: "wave",
glow: 0.9
});import { draw } from "./assets/voxel";
import { portalDeHielo } from "./assets/portal-de-hielo";
// En cada cuadro: parado sobre (x, y), el centro de su base.
draw(ctx, portalDeHielo, x, y, { size: 64, angle: 0, t: performance.now() / 1000 });
// size: lo que mide en px su lado más largo
// angle: giro sobre el piso, en radianes
// t: segundos; si se mueve, se anima solo con eso# En una terminal, en la carpeta del juego
fogon assets add portal-de-hielo
# Con las herramientas de Fogón (conector)
add_assets({ slug: "<tu-juego>", ids: ["portal-de-hielo"] })
# Queda en client/assets/portal-de-hielo.ts
# https://fogon.page/object/portal-de-hielo