Snap a photo of your desk β get an editable 3D twin β record what's plugged into what β fix problems with Meta AI.
Quick start Β· How it works Β· Meta models Β· Architecture Β· νκ΅μ΄
Sample desk shown. Its devices and links are placeholders until you start your own desk.
One monitor goes black on a desk with a laptop, a dock, two screens and a pile of USB and Bluetooth gear. A photo shows what is there, but not what is plugged into what. A chatbot just guesses.
DeskTwin gives the AI a map of your actual setup and keeps facts and guesses apart:
| Comes from | Never treated as | |
|---|---|---|
| π· Photo interpretation | Muse Spark reading your desk photo | Proof that a device exists or is cabled |
| π Your report | You confirm a link or a device status | Proof that the link works |
| π» macOS observation | Optional, consented, local display/USB scan | Proof of cable routes or working parts |
Nothing the model suggests is saved until you confirm it. Saving a cable never marks a device as working.
Plus: βοΈ an Edit mode with collision-aware drag, surface placement and box-part shape editing Β· β©οΈ 20-step Undo/Redo Β· π» optional local macOS display/USB matching Β· π¦ JSON import/export with no photos, chat or keys inside.
| Model | Role in DeskTwin |
|---|---|
Muse Spark muse-spark-1.3 |
π· Reads the desk photo and proposes objects with kind, rough position, size, color and box parts. π¬ Answers questions about a selected device using your recorded setup. |
SAM 3.1 sam-3.1 (optional) |
βοΈ With two-stage analysis on, outlines each chosen object in the photo so you can see exactly what was found. |
| Muse Image | π¨ Generated the demo desk image used in the video. Generated images are not committed. |
Guardrails on every response:
- β A strict JSON schema and existing device IDs are required before anything is shown.
- π« Photo responses may describe visible objects only. Connection, status and executable fields are rejected.
- π The API key stays server-side in
.env(never inVITE_*). - π§ͺ No key? The same workflow runs as a clearly labeled local demo that never pretends to be a model.
Requires Node.js 22.12+
git clone https://github.com/junjunjunbong/DeskTwin.git
cd DeskTwin
npm ci
npm run devOpen http://127.0.0.1:5173. Without a key this is the offline local demo, and no external calls are made.
π Connect Meta models
cp .env.example .envMODEL_API_KEY=your_key_here
META_BASE_URL=https://api.meta.ai/v1
META_MODEL=muse-spark-1.3
# Optional: two-stage photo analysis + SAM 3.1 outlines
META_PHOTO_TWO_STAGE=false
META_SAM_ENABLED=false
META_SAM_MODEL=sam-3.1Restart the server, then open AI chat β Connect Meta API, review what will be sent, and enable it. Real calls may cost money. The local 20 requests/minute limit is not a spending cap.
π» macOS hardware matching (optional)
Requires macOS 12+ and Xcode Command Line Tools.
npm run hardware:build
MODEL_API_KEY='' npm run devOpen Hardware β Devices β Open Mac hardware details, agree to the local read, and press Start detection. You match each observation to a desk device yourself. Serial numbers become an installation-specific HMAC inside the native process and never leave the machine. Bluetooth live detection is not supported. See MACOS_HARDWARE.md.
π§ Custom ports
MODEL_API_KEY='' DESKTWIN_WEB_PORT=5187 PORT=4337 npm run devflowchart LR
photo["π· Desk photo"] -->|your consent| spark["Muse Spark<br/>structured output"]
spark -.optional.-> sam["SAM 3.1<br/>outlines"]
spark --> check{"Schema + ID<br/>validation"}
check --> review["π You review<br/>the 3D scene"]
review -->|Confirm and apply| ws[("Workspace<br/>source of truth")]
you["π You confirm<br/>connections"] --> ws
mac["π» macOS helper<br/>local only"] -.you match.-> ws
ws --> chat["π¬ AI chat<br/>Muse Spark"]
ws --> diag["π©Ί Monitor check"]
| Path | What lives there |
|---|---|
src/domain/workspace.ts |
Source of truth: schema, commands, validation |
src/components/ |
Three.js voxel scene, panels and dialogs |
server/ |
Local API, origin checks, Meta client (server/meta.ts) |
native/ |
macOS display/USB helper |
tests/ |
Playwright end-to-end tests with mocked Meta and hardware |
More in ARCHITECTURE.md.
- π· Photos stay in memory unless you explicitly send one for analysis. They are never written to storage or JSON.
- π¬ Chat sends the current message, up to 12 recent Meta-mode turns and the shareable device and link records. macOS observations and hardware identities are never sent.
- πΎ Your workspace lives in your browser. Details in PRIVACY.md.
npm run check # TypeScript + unit/API tests + production build
npx playwright install chromium
npm run test:e2e # Chromium UI tests (own servers, empty API key)
npm run test:production # production server + browser testEvery test mocks Meta requests, so no API credit is spent. Busy ports: DESKTWIN_TEST_PORT=5187 DESKTWIN_TEST_API_PORT=4337 npm run test:e2e.
π What was verified, and what was not
- Live Meta calls (2026-11-04): a conversation request succeeded in 14.3 s. On a Muse Image demo desk, two-stage photo analysis reached a scene that could be applied. On a real desk photo, analysis returned 17 objects, but 4β5 overlaps (monitor, riser, stand) still need manual fixes before applying. Photo limits are 120 s on the server and 125 s in the browser. See PHOTO_TWO_STAGE.md and PHOTO_EVALUATION.md.
- Not claimed: guided step-by-step checks exist for monitors only; other devices go to AI chat. Physical Mac re-verification of the hardware helper, Bluetooth live discovery, Windows/Linux helpers, multi-user hosting and cloud sync are out of scope.
- This is a single-user local MVP. Don't expose the server to the public internet.
π More docs (some in Korean)
Scene editor Β· Storage Β· Photo review Β· Photo reference fitting Β· Hackathon notes Β· Submission script Β· Contributing
This repository was started during the Meta AI Developer Hackathon, and every commit is from 2026-10-26 or later. The workspace, photo-to-3D flow, connection recording, troubleshooting, local Mac matching boundary and Meta structured-output integration were all built during the event.
MIT. Scene geometry and textures are generated by code, and no third-party 3D models or user photos are shipped. libheif-js (LGPL-3.0) is used for local HEIC conversion; see THIRD_PARTY_NOTICES.txt.


