← BibliotecaKitmormon/starter-city-builder
Clonar
fogon pieces add starter-city-buildergit clone https://git.fogon.gg/mormon/starter-city-builder.gitfogon new starter-city-builder --from starter-city-builderKit de inicio: constructor de ciudad
El Starter Kit City Builder de Kenney, que está hecho para Godot, portado a three.js y TypeScript para Fogón: la misma mecánica, los mismos números y la misma escena, con sus modelos y sonidos originales. Una grilla de casillas de un metro, un selector que sigue al puntero y quince estructuras para colocar, girar y demoler; cada una cuesta plata, la cámara se desplaza, gira y hace zoom, y el mapa se guarda y se carga.

En la demo: clic construye lo que está elegido, clic derecho (o R) lo gira, Supr (o X) demuele lo que hay bajo el selector y Q / E cambian de estructura. La cámara se mueve con W A S D, vuelve al centro con F, gira con el botón del medio apretado (o con ← →) y se acerca con la rueda. F1 guarda el mapa, F2 lo carga y F3 trae el mapa de muestra del kit; los mismos botones están arriba, junto con «Exportar / importar» (el mapa como texto) y «Vaciar». En el teléfono: un toque construye, arrastrar mueve la cámara, dos dedos hacen zoom, y los botones de la derecha giran la estructura y pasan de construir a demoler.
Es solo la página. No hay sala ni red: todo pasa en el navegador de quien juega. Es una base para empezar un juego propio, no un juego terminado.
Qué trae
client/city-builder es lo que se lleva.
| Archivo | Qué hace |
|---|---|
builder.ts | Builder: la grilla y el selector. aim / aimAt apuntan, build, demolish, rotate, toggle y choose son las acciones, save y load pasan el mapa a datos y de vuelta. Es el builder.gd del kit. |
map.ts | CityMap: la ciudad como datos (la plata y qué hay en cada casilla), sin motor. toJSON() y CityMap.from(datos). |
structures.ts | STRUCTURES: las quince estructuras, cada una con su modelo, su nombre y su precio. |
sample.ts | SAMPLE_MAP: el mapa de muestra del kit (122 casillas), decodificado de su map.res. |
view.ts | View: la cámara en un brazo que mira un punto del suelo. Se mueve, gira y hace zoom suavizado (el view.gd del kit). |
environment.ts | Environment: el fondo, la luz de ambiente, el sol con sombras y la misma curva de color que usa Godot («Filmic»). |
audio.ts | Sounds: los efectos (uno al azar entre varios, con el tono apenas distinto cada vez, como el kit) y el ambiente en bucle. |
assets.ts | De dónde salen los archivos: loadModel, loadTexture, url y setBase. |
Lo demás es la demo y sirve de ejemplo: client/main.ts tiene el mouse, el teclado, los toques, los botones, guardar en el navegador y lo que se escribe en pantalla.
Cómo se usa en un juego
fogon pieces add starter-city-builder
Eso trae client/city-builder/ (solo código) y agrega three.js al package.json. Los modelos, las imágenes y los sonidos no viajan con el juego: se cargan desde la demo publicada de esta pieza (https://play.fogon.page/starter-city-builder/city/).
import * as THREE from "three";
import { Builder } from "./city-builder/builder";
import { Environment } from "./city-builder/environment";
import { Sounds } from "./city-builder/audio";
import { View } from "./city-builder/view";
const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
const scene = new THREE.Scene();
const environment = new Environment(scene, renderer); // fondo, luces, sombras y curva de color
const view = new View();
const sounds = new Sounds();
const builder = await Builder.create({
sounds,
onCash: (cash) => (cashLabel.textContent = "$" + cash),
});
scene.add(view.object, builder.object);
// El puntero: el selector va a la casilla que tiene debajo, y un clic construye.
const raycaster = new THREE.Raycaster();
canvas.addEventListener("pointermove", (e) => {
raycaster.setFromCamera(new THREE.Vector2((e.clientX / innerWidth) * 2 - 1, -(e.clientY / innerHeight) * 2 + 1), view.camera);
builder.aim(raycaster.ray);
});
canvas.addEventListener("pointerdown", () => {
sounds.unlock(); // el navegador solo deja sonar después de un toque o una tecla
builder.build();
});
renderer.setAnimationLoop(() => {
const dt = 1 / 60;
view.update(dt, 0, 0); // (derecha, atrás): hacia dónde mover la cámara, de −1 a 1
builder.update(dt);
environment.follow(view.object.position, view.zoom * 0.6 + 6); // las sombras, donde mira la cámara
renderer.render(scene, view.camera);
});
// Guardar y cargar: el mapa es un objeto chico, sirve para localStorage o para mandarlo a una sala.
const data = builder.save(); // { cash: 9905, structures: [[x, z, estructura, giros], …] }
builder.load(data);
Agregar estructuras
Una estructura es un modelo que ocupa una casilla (de −0,5 a 0,5, apoyado en y = 0) y un precio. La lista se le pasa al constructor; un mapa nombra cada estructura por su lugar en la lista, así que conviene agregar al final.
import { STRUCTURES } from "./city-builder/structures";
const builder = await Builder.create({
structures: [...STRUCTURES, { model: "building-garage", label: "Otro garaje", price: 120 }],
});
model es el nombre de un .glb de la carpeta models/ de donde se cargan los archivos. Para usar modelos propios, servilos vos (el punto que sigue) y sumalos a esa carpeta.
Usar los archivos sin depender de la demo
Para tenerlos dentro de tu juego (sin conexión, o servidos por vos), bajalos a public/city/ y decíselo al cargador una vez, antes de cargar nada:
mkdir -p public/city/models/Textures public/city/sprites public/city/sounds && cd public/city
B=https://play.fogon.page/starter-city-builder/city
for m in road-straight road-straight-lightposts road-corner road-split road-intersection pavement pavement-fountain \
building-small-a building-small-b building-small-c building-small-d building-garage grass grass-trees grass-trees-tall; do
curl -fo models/$m.glb $B/models/$m.glb
done
curl -fo models/Textures/colormap.png $B/models/Textures/colormap.png
for s in selector coin; do curl -fo sprites/$s.png $B/sprites/$s.png; done
for s in ambience placement-a placement-b placement-c placement-d removal-a removal-b removal-c removal-d rotate toggle; do
curl -fo sounds/$s.ogg $B/sounds/$s.ogg
done
import { setBase } from "./city-builder/assets";
setBase("./city/");
Son 1,7 MB: quince modelos (models/*.glb y su paleta, models/Textures/colormap.png), dos imágenes (sprites/selector.png, sprites/coin.png) y once sonidos (sounds/*.ogg; el ambiente pesa 1,2 MB él solo).
Para hacerlo entre varios
El mapa ya es datos (CityMap): en server/room.ts guardá uno por sala, que el cliente mande «construí esto acá» y que la sala lo valide (¿alcanza la plata?), lo aplique y lo reparta. Builder dibuja lo que diga el mapa.
Qué quedó distinto del original
- El mapa se guarda como JSON (en el kit es un recurso binario de Godot). El giro de cada casilla va de 0 a 3 cuartos de vuelta; el kit guarda el índice de orientación de Godot (0, 16, 10, 22).
- Demoler también sale con X o con retroceso, girar con R y la cámara gira con las flechas: no todos los teclados tienen Supr ni todos los mouse botón del medio. Los controles táctiles, los botones, «Exportar / importar» y «Vaciar» son agregados.
- La cámara se mueve a 15 m por segundo en cualquier pantalla (el kit avanza un cuarto de metro por cuadro: lo mismo a 60 cuadros por segundo).
- El kit prende oclusión ambiental (SSAO); acá no está.
- Como en el kit: la plata puede quedar en negativo, demoler no devuelve nada y volver a poner lo mismo en una casilla (para girarlo) es gratis.
Créditos y licencia
El kit original, sus modelos, imágenes y sonidos son de Kenney (kenney.nl): el código bajo licencia MIT (va copiada en LICENSE-kenney.md) y los modelos, imágenes y sonidos en dominio público (CC0). El port a three.js es nuestro, también MIT. No hace falta dar crédito a Kenney, pero se agradece.
Elegí un archivo.
| Versión | Cuándo | Peso | Commit |
|---|---|---|---|
| v1 en la demo | 12 de nov de 2026 | 2.6 MB | 05919b8 |
Todavía nadie publicó una versión hecha a partir de esta pieza.
Hacé tu versión de
Copiá este pedido y pegáselo a tu IA (Claude, ChatGPT…): arma tu versión con el código de este juego y la publica como un juego tuyo.