[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-94734":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":15,"subscribersCount":15,"size":15,"stars1d":15,"stars7d":16,"stars30d":17,"stars90d":15,"forks30d":15,"starsTrendScore":15,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":10,"archived":19,"fork":19,"defaultBranch":20,"hasWiki":19,"hasPages":19,"topics":21,"createdAt":10,"pushedAt":10,"updatedAt":22,"readmeContent":23,"aiSummary":24,"trendingCount":15,"starSnapshotCount":15,"syncStatus":25,"lastSyncTime":26,"discoverSource":27},94734,"empire","thebuggeddev\u002Fempire","thebuggeddev","An interactive 3D empire explorer built using threejs with Kimi K3","https:\u002F\u002Fempireatlas.vercel.app",null,"TypeScript",110,30,101,0,3,6,43.57,false,"main",[],"2026-08-24 04:01:22","# Empire Atlas\n\n**Explore how civilizations lived.** An interactive 3D atlas of domestic architecture across eight\nhistorical empires. Turn each dwelling on its plinth, read the features pinned to its stonework, and\nfollow the household through its rooms, its objects and its geography.\n\n![Empire Atlas](.\u002Fpublic\u002Fog-cover.jpg)\n\n---\n\n## Contents\n\n- [What it is](#what-it-is)\n- [The dwellings](#the-dwellings)\n- [How it was made](#how-it-was-made)\n- [Running it](#running-it)\n- [How it is put together](#how-it-is-put-together)\n- [Notes on the 3D viewer](#notes-on-the-3d-viewer)\n- [Accessibility](#accessibility)\n- [Before you deploy](#before-you-deploy)\n\n---\n\n## What it is\n\nEight dwellings, one for each empire, each modelled in 3D and annotated with the architectural\nfeatures that made it work as a home. The viewer is the centre of the app: a turntable stage lit like\na museum vitrine, where a dwelling can be orbited, zoomed, sectioned and read.\n\n**What you can do**\n\n|                           |                                                                                                                         |\n| ------------------------- | ----------------------------------------------------------------------------------------------------------------------- |\n| **Turn the dwelling**     | Orbit, pan and zoom the model, or drive it from the keyboard (arrows, `+`\u002F`-`, `Home`)                                  |\n| **Read its architecture** | Four hotspot pins per dwelling, fixed to the geometry itself; hover one for its annotation, click to push the camera in |\n| **See through it**        | Wireframe and x-ray section layers, plus a turntable reference grid                                                     |\n| **Go deeper**             | Interior views, floor plans, household objects, daily life and the empire's geography                                   |\n| **Learn and test**        | A written lesson per empire, a timeline, and a quiz                                                                     |\n| **Search everything**     | `⌘K` finds empires, dwellings and individual architectural features                                                     |\n\n---\n\n## The dwellings\n\n| Empire           | Dwelling        | Period                    |\n| ---------------- | --------------- | ------------------------- |\n| Ancient Egypt    | Courtyard House | c. 1500 BCE (New Kingdom) |\n| Persian Empire   | Noble Residence | c. 500 BCE (Achaemenid)   |\n| Han China        | Siheyuan        | c. 100 CE (Eastern Han)   |\n| Roman Empire     | Roman Domus     | 1st century CE            |\n| Byzantine Empire | Urban House     | c. 10th century CE        |\n| Inca Empire      | Stone Dwelling  | c. 15th century CE        |\n| Ottoman Empire   | Courtyard Home  | c. 17th century CE        |\n| Mughal Empire    | Haveli          | c. 17th century CE        |\n\nAdding a ninth means adding a data file and its assets. The viewer and the UI are entirely\ndata-driven and need no changes. See [`src\u002Ftypes\u002Fempire.ts`](src\u002Ftypes\u002Fempire.ts) for the contract.\n\n---\n\n## How it was made\n\nThis project was produced end to end with generative tools, each doing the part it is best at.\n\n### The application — Kimi K3\n\nThe entire codebase was generated with **Kimi K3**: the React application, the three.js viewer, the\ndesign system and the empire content.\n\n### The 3D models — Tripo 3D\n\nAll eight dwellings were modelled with **[Tripo AI](https:\u002F\u002Fstudio.tripo3d.com\u002F?utm_source=brand&utm_medium=creator&utm_campaign=suj)**, exported as\nDraco-compressed glTF (`public\u002Fmodels\u002F*.glb`, ~2.1 MB each). They arrive as single-mesh models with\nbaked textures, which the viewer normalises into a consistent frame at load.\n\n### The imagery — GPT Image 2.0, run through Tripo\n\nThe 56 illustrations were generated with **GPT Image 2.0**: hero cutaways, interiors, floor plans,\nartefact studies, daily-life scenes and empire maps.\n\nWorth recording: these were generated through **[Tripo's GPT Image 2.0](https:\u002F\u002Fstudio.tripo3d.com\u002F?utm_source=brand&utm_medium=creator&utm_campaign=suj)** rather than going\ndirect. Tripo handles batch requests well, and in practice batching the image set through it came\nback noticeably faster than running the same batch against GPT Image 2 directly. That matters when a\nsingle empire needs seven consistent images and the set needs regenerating as the art direction\nsettles.\n\n---\n\n## Running it\n\nRequires Node 20 or newer.\n\n```bash\nnpm install\nnpm run dev        # dev server on :3000\nnpm run build      # typecheck (tsc -b) then production build to dist\u002F\nnpm run preview    # serve the production build\nnpm run lint\n```\n\n`npm run build` runs `tsc -b` first, so a type error fails the build rather than shipping.\n\n---\n\n## How it is put together\n\n```\nsrc\u002F\n├─ App.tsx                 app shell: layout, routing of modals, responsive behaviour\n├─ three\u002F\n│  └─ engine.ts            the entire 3D viewer — renderer, lighting, camera, transitions,\n│                          hotspot resolution, model residency\n├─ components\u002F\n│  ├─ Viewer.tsx           canvas host, tool rail, layer menu, request sequencing\n│  ├─ HotspotLayer.tsx     screen-space pins and their hover annotations\n│  ├─ EmpireLibrary.tsx    the empire rail (desktop) and drawer contents (mobile)\n│  ├─ InfoPanel.tsx        selected-dwelling detail, in a rail or in the page flow\n│  ├─ BottomCards.tsx      the five exploration cards\n│  ├─ Banner.tsx           dismissible attribution bar\n│  ├─ modals.tsx           lesson, quiz, artefacts, timeline, sections, ⌘K search\n│  └─ ui\u002F                  shadcn\u002Fui primitives\n├─ data\u002F\n│  └─ empires\u002F*.ts         one file per empire: copy, facts, hotspots, lesson, quiz, timeline\n└─ types\u002Fempire.ts         the data contract every empire satisfies\n```\n\n**Stack** — React 19 · TypeScript 5.9 · Vite 7 · Tailwind CSS 3.4 · three.js 0.185 (WebGPU renderer\nwith TSL node materials) · GSAP 3 · three-mesh-bvh · shadcn\u002Fui\n\n**Design language** — a warm parchment palette on Cormorant Garamond and Inter, defined once as CSS\ncustom properties in [`src\u002Findex.css`](src\u002Findex.css) and bridged into Tailwind and shadcn tokens.\n\n**Responsive behaviour** — the three-column desktop stage engages at 1280px. Below that the empire\nlibrary moves into a drawer behind a hamburger, the dwelling detail reads inline beneath the model,\nand the exploration cards step from five columns to three, two, then one.\n\n---\n\n## Notes on the 3D viewer\n\nA few decisions in [`src\u002Fthree\u002Fengine.ts`](src\u002Fthree\u002Fengine.ts) that are not obvious from the code:\n\n**Hotspots resolve against the geometry, not against coordinates.** Authoring a pin as a fixed point\nin the model's bounding box puts it in mid-air as often as on the building. Instead each hotspot\ndeclares _what kind of surface_ it belongs on (`roof`, `court` or `wall`), and the engine samples a\n20×20 top-surface height field over the footprint to find it, preferring candidates that are actually\nvisible from the resting camera. The authored anchor only breaks ties.\n\n**The stage backdrop is CSS, not scene geometry.** The canvas is transparent. A rendered parchment\ngradient would be run through ACES tone mapping and come out grey, so the backdrop is painted in CSS\nbehind the canvas and keeps the exact palette of the surrounding UI.\n\n**Switching dwellings is a turntable spin.** The dwelling on stage spins up about its own axis and,\nat the point where it is turning fastest, the next one takes over the same rotation and carries it to\nrest. Nothing leaves the ground, which is what avoids the floor plane slicing through a colonnade or\nan open courtyard, and lets the dwelling keep casting its shadow throughout.\n\n**Shadows are drawn on demand.** Orbiting moves the camera, not the building, so the shadow map is\nrefreshed only when the geometry actually changes rather than every frame.\n\n**Recently seen dwellings stay resident.** Six models are kept parsed in memory, and hovering an\nempire in the library begins fetching it, so the click that follows lands on a model that is already\ndownloaded, parsed, BVH-built and hotspot-resolved, instead of paying for all of that mid-animation.\n\n**Pins cost nothing per frame.** The projection loop holds element handles by ref, takes the stage\nsize from a `ResizeObserver` rather than reading layout, reuses its vectors, and writes a class only\nwhen it changes.\n\n---\n\n## Accessibility\n\n- Full keyboard control of the viewer, and hotspot pins are focusable buttons whose annotation opens\n  on focus as well as hover\n- `prefers-reduced-motion` is honoured and tracked live: transitions resolve instantly, and the pin\n  and loading animations stop\n- Semantic landmarks, labelled controls, `aria-pressed`\u002F`aria-expanded` on toggles, and live regions\n  on loading state\n- Focus rings are never removed, only restyled\n\n---\n\n## Before you deploy\n\n`og:image` and `og:url` in [`index.html`](index.html) are supposed to be absolute URLs. Most crawlers\nresolve a relative path against the page, but not all do. Once the site has a domain, swap\n`\u002Fog-cover.jpg` for the full URL and add an `og:url`. There is a comment marking the spot.\n","Empire Atlas 是一个基于 Three.js 构建的交互式三维历史住宅探索工具，可视化呈现古埃及、波斯、汉朝等八大帝国的典型民居建筑。项目支持模型自由旋转缩放、热点标注解读、线框\u002FX光剖切、室内漫游、平面图查看及关联历史地理信息，并集成每帝国的讲解文本、时间轴与知识测验。技术上采用 TypeScript 开发，数据驱动架构，UI 与 3D 视图完全解耦，便于扩展新文明案例。适用于历史教育、文化遗产数字化展示与人文学科交互教学场景。",2,"2026-08-15 02:30:05","CREATED_QUERY"]