PolyCity v1.0 — full-featured 3D city-builder (Three.js + Vite)

- Procedural island maps, RCI zoning, demand-driven growth
- City-wide power grid with brownouts; wind coastal bonus
- Land value, upgrades, services, pollution, fires & fire spread
- Budget/taxes, happiness, milestones, quest onboarding
- Traffic agents, day/night cycle, adaptive render scale
- Saves: autosave + 3 slots + JSON export/import
- PWA (offline), GitHub Pages/Netlify deploy configs
- Tests: 40-assertion engine suite + headless E2E
This commit is contained in:
PolyCity
2026-08-22 19:17:10 +00:00
commit 56bf3fa2a2
37 changed files with 4996 additions and 0 deletions
+25
View File
@@ -0,0 +1,25 @@
/** Inline stroke-style SVG icon set (24×24). */
const S = 'fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"';
function svg(inner) {
return `<svg viewBox="0 0 24 24" ${S}>${inner}</svg>`;
}
export const ICONS = {
query: svg('<circle cx="10" cy="10" r="6"/><path d="M14.5 14.5L20 20"/>'),
bulldoze: svg('<rect x="3" y="12" width="8" height="6" rx="1"/><path d="M11 13h4l4 4v1h-8"/><circle cx="7" cy="19.5" r="1.8"/><circle cx="16.5" cy="19.5" r="1.5"/><path d="M5 12V9h4v3"/>'),
road: svg('<path d="M9 3L5 21"/><path d="M15 3l4 18"/><path d="M12 4v3"/><path d="M12 11v3"/><path d="M12 18v3"/>'),
res: svg('<path d="M4 11l8-7 8 7"/><path d="M6 10v10h12V10"/><path d="M10 20v-5h4v5"/>'),
com: svg('<rect x="4" y="8" width="16" height="12" rx="1"/><path d="M4 8l2-4h12l2 4"/><path d="M9 20v-6h6v6"/><path d="M4 12h16"/>'),
ind: svg('<path d="M4 20V10l5 3v-3l5 3v-3l6 3v7z"/><rect x="16.5" y="4" width="3" height="6"/>'),
coal: svg('<circle cx="12" cy="12" r="9"/><path d="M13 6l-5 7h4l-1 5 5-7h-4z"/>'),
solar: svg('<path d="M4 14h16l-2 6H6z"/><path d="M8 14l1.5 6"/><path d="M16 14l-1.5 6"/><path d="M5.5 17h13"/><circle cx="18" cy="5" r="2.4"/>'),
wind: svg('<path d="M12 21v-8"/><path d="M12 13V4"/><path d="M12 13l7.8 4.5"/><path d="M12 13L4.2 17.5"/><circle cx="12" cy="13" r="1.6"/>'),
police: svg('<path d="M12 3l7 3v6c0 4.5-3 7.5-7 9-4-1.5-7-4.5-7-9V6z"/><path d="M9 12l2 2 4-4"/>'),
fire: svg('<path d="M12 3c1 3 4.5 4.5 4.5 8.5a4.5 4.5 0 01-9 0c0-2 .9-3.2 1.8-4.3C10.2 9 12 6.5 12 3z"/><path d="M12 21a3 3 0 003-3c0-1.5-1.5-2.5-3-4-1.5 1.5-3 2.5-3 4a3 3 0 003 3z"/>'),
hospital: svg('<rect x="4" y="4" width="16" height="16" rx="2"/><path d="M12 8v8"/><path d="M8 12h8"/>'),
school: svg('<path d="M3 9l9-4 9 4-9 4z"/><path d="M7 11.5v3.5c0 1.6 2.2 3 5 3s5-1.4 5-3v-3.5"/><path d="M21 9v5"/>'),
park: svg('<path d="M12 3l5 7h-3l4 6H6l4-6H7z"/><path d="M12 16v5"/>'),
plaza: svg('<path d="M12 4v4"/><path d="M12 8c-2 0-3.2 1-3.2 3h6.4c0-2-1.2-3-3.2-3z"/><path d="M5 14h14l-1.5 6h-11z"/><path d="M8.5 11.5h7"/>'),
stadium: svg('<ellipse cx="12" cy="13" rx="8.5" ry="5.5"/><ellipse cx="12" cy="13" rx="4" ry="2.2"/><path d="M3.8 10.5L2 7.5M20.2 10.5L22 7.5"/>')
};