← Whole house3D assetfogon/notebook
Notebook
Drag to turn it// «Notebook» · gpt-6-sol (medium)
// An open laptop: a thin silver base with a dark keyboard and trackpad, and the screen tilted back showing a colorful game on it (green, blue and yellow pixels). A small sticker on the back of the lid.
// Soft rubber feet and a thin, rounded silver base.
for (const x of [8, 36]) {
for (const y of [11, 31]) box(x, y, 0, x + 3, y + 3, 0, "#69777c");
}
for (let z = 1; z <= 4; z++) {
for (let x = 4; x <= 43; x++) {
for (let y = 6; y <= 36; y++) {
const corner = (x < 6 || x > 41) && (y < 8 || y > 34);
if (corner || (z === 4 && (x === 4 || x === 43 || y === 6 || y === 36))) continue;
const shade = z === 1 ? "#909da3"
: z === 2 ? "#c2cdd0"
: z === 3 ? "#e0e7e5"
: rand() < 0.08 ? "#d9e3e1" : "#edf1ed";
set(x, y, z, shade);
}
}
}
box(7, 7, 3, 40, 7, 3, "#f8f8f1");
for (const x of [35, 38]) set(x, 7, 3, x === 35 ? "#94d7af" : "#f7d887");
// Keyboard well, with individually raised toy-like keys.
box(9, 20, 5, 39, 31, 5, "#56646a");
box(10, 21, 5, 38, 30, 5, "#394950");
for (const y of [22, 25, 28]) {
for (let x = 11; x <= 36; x += 3) {
const color = rand() < 0.12 ? "#8ba5a8" : "#71858b";
box(x, y, 6, x + 1, y + 1, 6, color);
set(x, y, 7, "#afbdba");
}
}
box(20, 22, 6, 29, 23, 6, "#84989b");
box(21, 22, 7, 27, 22, 7, "#b5c5c1");
// Trackpad and a tiny pastel palm-rest badge.
box(17, 10, 5, 30, 18, 5, "#a6b4b8");
box(18, 11, 5, 29, 17, 5, "#d5dddd");
box(19, 12, 6, 28, 12, 6, "#e8edeb");
box(10, 11, 5, 14, 15, 5, "#f2cfb8");
box(11, 12, 6, 13, 12, 6, "#fff5df");
set(12, 13, 6, "#fff5df");
// Rounded hinge behind the keys.
box(8, 33, 5, 40, 35, 6, "#9ba9ad");
box(10, 33, 7, 38, 34, 7, "#dce4e2");
// The lid leans away from the viewer as it rises.
const lidY = z => 31 + Math.round((z - 4) * 0.30);
const face = (x, z, color) => set(x, lidY(z) - 1, z, color);
for (let z = 4; z <= 36; z++) {
const y = lidY(z);
for (let x = 5; x <= 43; x++) {
if ((z === 4 || z === 36) && (x === 5 || x === 43)) continue;
box(x, y, z, x, y + 2, z, "#b5c3c5");
set(x, y + 3, z, rand() < 0.06 ? "#c5d2d0" : "#dce6e2");
face(x, z, x === 5 || z === 36 ? "#f3f5ed" : "#c5d1d1");
}
}
// Dark bezel and the glowing pixel-game display.
for (let z = 7; z <= 34; z++) {
for (let x = 7; x <= 41; x++) face(x, z, "#34474f");
}
for (let z = 9; z <= 32; z++) {
for (let x = 9; x <= 39; x++) {
let color = z >= 18 ? "#85cfe2" : "#81bc75";
if (z >= 14 && z < 18) color = "#aad98a";
if (z < 12) color = (x + z) % 5 === 0 ? "#59a864" : "#65b570";
face(x, z, color);
}
}
// Blocky clouds, sun, hills, platforms and coins.
for (const [x, z] of [[12, 28], [13, 28], [14, 28], [13, 29],
[27, 26], [28, 26], [29, 26], [28, 27]]) {
face(x, z, "#f5f5df");
}
box(0, 0, 0, 0, 0, 0, null); // No geometry; keep all picture details on the tilted face.
for (let x = 33; x <= 36; x++) {
for (let z = 27; z <= 30; z++) {
if ((x === 33 || x === 36) && (z === 27 || z === 30)) continue;
face(x, z, "#ffdc78");
}
}
for (let x = 9; x <= 39; x++) {
const hill = x < 21 ? 17 + Math.floor((x - 9) / 5)
: 19 - Math.floor((x - 21) / 6);
for (let z = 14; z <= hill; z++) face(x, z, z === hill ? "#c4e38d" : "#73be79");
}
for (let x = 10; x <= 19; x++) face(x, 13, "#a97952");
for (let x = 29; x <= 38; x++) face(x, 15, "#a97952");
for (const x of [15, 32, 35]) {
face(x, 20, "#fff0a1");
face(x, 21, "#ffd458");
face(x + 1, 20, "#eab94c");
}
// A tiny adventurer on the grass.
for (const x of [23, 25]) {
face(x, 11, "#484c70");
face(x, 12, "#484c70");
}
for (let x = 22; x <= 26; x++) {
for (let z = 13; z <= 16; z++) face(x, z, "#ee917c");
}
for (let x = 23; x <= 25; x++) {
for (let z = 17; z <= 19; z++) face(x, z, "#f7c695");
}
for (let x = 22; x <= 26; x++) face(x, 20, "#5a5a70");
face(24, 18, "#423f4d");
face(22, 15, "#ffd178");
// Screen glints and a little silver webcam.
for (let x = 10; x <= 19; x++) face(x, 31, "#b5e3e8");
face(24, 35, "#586970");
face(25, 35, "#e5eeea");
// A cheerful flower sticker on the OUTSIDE of the lid.
const back = (x, z, color) => set(x, lidY(z) + 4, z, color);
for (let x = 32; x <= 39; x++) {
for (let z = 22; z <= 30; z++) {
if ((x < 34 || x > 37) && (z < 24 || z > 28)) continue;
back(x, z, "#f5f1da");
}
}
for (const [x, z] of [[35, 24], [36, 24], [34, 26], [37, 26],
[35, 28], [36, 28]]) back(x, z, "#f6cf65");
back(35, 26, "#ef9b85");
back(36, 26, "#ef9b85");import { draw } from "./assets/voxel";
import { notebook } from "./assets/notebook";
// Every frame: standing on (x, y), the centre of its base.
draw(ctx, notebook, 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 notebook
# With Fogón's tools (connector)
add_assets({ slug: "<your-game>", ids: ["notebook"] })
# It lands in client/assets/notebook.ts
# https://fogon.page/object/notebook