Agent skill

Room From Photos

by SkylarKitchen in SkylarKitchen/skills

Builds a 3D model of a real room from a few phone photos, with movable furniture layouts, as one Three.js HTML page you can open in a browser.

MITAuto-check passedGame Development

Install Room From Photos

skills CLI
$ npx skills add SkylarKitchen/skills --skill room-from-photos -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install SkylarKitchen/skills room-from-photos --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/SkylarKitchen/skills.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/design/room-from-photos .claude/skills/room-from-photos && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
room-from-photos
GitHub stars
117
Token cost
~6k tokens
SKILL.md length
3,952 words
Files
19
Skills in repo
3
Repo updated
First seen
Licence
MIT

At a glance

Builds a 3D model of a real room from a few phone photos, with movable furniture layouts, as one Three.js HTML page you can open in a browser.

  • Works in 9 steps: Ask only for what blocks you. You need… → Read each photo by perspective before… → Scale from known objects and list each… → …
  • Checking whether a new bed or sofa fits in a room you only have photos of
  • SKILL.md covers Process, CONFIG reference, Common mistakes and Gotchas
  • Runs Python and JavaScript scripts from its folder; calls python3

What it does

Send a handful of phone photos of a room you already have and the agent builds a single HTML page around a 3D model of it, using Three.js. No floor plan is needed. The page shows a drawn plan, a dollhouse view that cuts away the nearest walls, and tabs for alternative furniture layouts, and you can drag and turn each piece in either view.

The agent copies `starter.html` and changes just the CONFIG block inside it, so the page engine itself stays untouched. Live fit checks flag whether a piece fits, and each photo can be shown with the model drawn over it to confirm the match. The model opens in the room's own finishes, such as paint, floorboards, paneling, trim and each piece's colors, and a toggle switches to a plain white architectural model for judging the layout alone. Helper scripts (`build.py`, `snapsink.py`, `test.py`) and a texture set ship alongside it.

When your agent uses it

  • Checking whether a new bed or sofa fits in a room you only have photos of
  • Comparing several furniture arrangements before moving anything heavy
  • Turning phone photos into a shareable 3D room page when no floor plan exists

Example prompts

  • “Here are four photos of my bedroom. Will the new queen bed fit under the window?”
  • “Make a 3D model of this living room and let me try three different sofa layouts.”
  • “Where should the desk go in my home office? I only have these photos.”

Requirements

  • Phone photos of the room

Workflow steps

9 steps, taken from the first numbered list in SKILL.md.

  1. Ask only for what blocks you. You need the photos, ideally one from the doorway and one from the opposite corner, and the new thing's size…
  2. Read each photo by perspective before drawing anything. Work out which wall faces the camera, which floor lines recede, and what each…
  3. Scale from known objects and list each estimate in ROOM.verify. Don't wait for a tape measure.
  4. Fill CONFIG. Pick any wall as the top of the plan (the one facing you from the doorway reads well); every yaw and rot is measured from it…
  5. Colour it from the photos. Sample the wall paint, flooring, trim and every piece you keep from a lit patch of the photo, away from corners…
  6. Match every photo. Give each photo a PHOTOS entry: {src: 'photos/door.jpg', label: 'From the door', at: [x, y], h: 60, yaw: 0, pitch: 0…
  7. Verify. Serve the page over localhost (python3 -m http.server). Judge the look on a real GPU, not headless: open the page with #debug, run…
  8. Deliver one .html file with the photos beside it in photos/ and the finishes in textures/ (build.py copies them in; an Artifact publishes…
  9. Iterate. The user drags things or says "try the bed under the window", adds pieces from the library, takes pieces out, and tries paint and…

What it can do on your machine

Read from SKILL.md and the folder at commit fb53232. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Ships script files (Python and JavaScript, from the files we listed), which the agent can run.

    Shell commands in SKILL.md call:

    • python3

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Room From Photos loads about 6k tokens when it runs. Until then it costs about 100 tokens; SKILL.md has 3,952 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~100
When it runs · the whole SKILL.md, loaded when a task matches
~6k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from SkylarKitchen/skills at commit fb53232, republished under its MIT licence (© SkylarKitchen). 3,952 words, ~5,953 tokens.

Download SKILL.mdSave it as .claude/skills/room-from-photos/SKILL.md (or your agent's skills folder). This skill also uses 18 other files; get the full folder from GitHub.
name
room-from-photos
description
Turn a few phone photos of an existing room into a near-photoreal 3D model and plan with furniture layouts to compare and drag around, as a single Three.js HTML file. Use when the user sends photos of a room, with no floor plan, and wants to see it in 3D or work out where furniture goes: "will the new bed fit in this room", "where should the desk go", "can we try a few layouts".

Room from photos

Photos in, a 3D room out, then layouts the user moves around. Copy starter.html and edit only its CONFIG block. The engine draws the plan (the working drawing), a dollhouse model that cuts away the near walls, live fit checks, option tabs, drag and turn in either view, and each photo with the model drawn over it. The model opens in the room's real finishes (paint, floorboards, paneling, trim, each piece's colours), and a toggle switches to a white architectural model for reading the layout alone. It works like a configurator.

The model renders close to photoreal: three.js 0.162 loaded as ES modules from jsDelivr, physically based finishes from CC0 photo scans in textures/ (ambientCG wood cut board by board into a strip floor and plank by plank into the paneling, a linen weave, brick and carpet pile, each tiled at its real size; greyscale, so every swatch still tints them; drawn stand-ins when the scans can't load), soft sun shadows, ambient occlusion at half resolution, and a view through each window. The dollhouse is the working view, so it stays bright and clean under a studio light: every swatch reads as itself (a lit wall or floor lands within a few ΔE of its hex), each window is a soft area light, lamp shades glow with a warm bulb inside, and every piece stands in its own contact shadow. Through a photo's camera the room lights itself the way the photos show it instead: the environment is captured from the room's own centre (six small cube faces, blurred, two bounces from a studio light, so it comes out the same after every edit), so the floor's gloss streaks with the windows, the ceiling is a lit warm grey rather than a painted white, and the paneling's bounce warms the corners; exposure, a cooler sun, the view outside blown to white and a phone lens's vignette are graded to match, measured against a real room's five photos. The white model keeps its own studio light and sun, unchanged. It redraws only on change, and a slow GPU drops the occlusion pass while things move; the room-light capture and the shadow redraw run only once a change settles, never per frame. Select a piece in the model and a gizmo appears: arrows slide it and a ring turns it in 15° steps. One-click looks recolour the room, swatch chips set each surface, and a selected piece offers its style variants (a longer sofa, a bigger rug) and its colours. "Add a piece" opens a library: a catalogue of common pieces in real sizes (sofas, tables, storage, beds, rugs, lamps, plants, a TV, art) plus the room's own entries, each shown as the engine's own render of it; a piece added from it lands in the clearest spot, selected, and drags, turns, takes variants and colours and is checked like the rest. Every choice belongs to the current option. The sample room renders on its own.

Process

  1. Ask only for what blocks you. You need the photos, ideally one from the doorway and one from the opposite corner, and the new thing's size (a product link or W × D × H). Estimate everything else.

  2. Read each photo by perspective before drawing anything. Work out which wall faces the camera, which floor lines recede, and what each doorway looks through to. Write the room out wall by wall (top wall left to right, then clockwise), with every door, window, closet, radiator and vent, and check that text against every photo. Skipping this is the most common way to get the room wrong.

  3. Scale from known objects and list each estimate in ROOM.verify. Don't wait for a tape measure.

    ObjectSize
    Interior door80″ high; 28–32″ wide (bedrooms often 30)
    Outlet / switchcentre 12–16″ / 48″ off the floor; cover plate 4.5″ tall
    Ceiling96″ unless the photo says otherwise
    Mattresstwin 38 × 75, full 54 × 75, queen 60 × 80
    Window sill24–36″; head usually lines up with the door head
  4. Fill CONFIG. Pick any wall as the top of the plan (the one facing you from the doorway reads well); every yaw and rot is measured from it. The outline traces the inner wall faces clockwise from the top-left corner, in inches. Place each opening by its centre point on the wall. Existing furniture goes in as items, built-ins go in fixed, and the thing being placed gets new: true. Write 2–3 layouts that are different ideas (corner, centred, along a wall), each with a one-sentence trade-off. When the room is furnished, make the first option the room as it is.

  5. Colour it from the photos. Sample the wall paint, flooring, trim and every piece you keep from a lit patch of the photo, away from corners and window glare. A swatch is the finish itself, not the pixel: the engine lights it again, so a sample taken in shade renders about twice as dark. Take the brightest unglared patch and lift it toward the material's own colour (one white wall can read anywhere from #625a47 to #f6edcf in a single photo). Metals go in paint. Name each one in PALETTE ("Pale sage", "Walnut") so the pickers show names, not hex. Set ROOM.walls, floor, trim and boards, and each item's color and color2. Colours for things not yet bought (the new bed's bedding, a rug) come from the user's inspiration, or else sit quietly with the room's colours. Group the swatches as paint, wood, fabric and clay so each surface offers the right ones. Add LOOKS for the room's big palette levers (paint the paneling, a darker wall) and variants for any piece whose size or kind is in question. When the palette is part of the question, give an option its own colors so the options differ as a design choice, and say so in its note. Otherwise keep one palette and let the layouts differ.

  6. Match every photo. Give each photo a PHOTOS entry: {src: 'photos/door.jpg', label: 'From the door', at: [x, y], h: 60, yaw: 0, pitch: 0, roll: 0, fov: 67}. The camera stands at plan at with its lens h inches up; yaw 0 looks at the top wall and 90 at the right one; pitch is up-positive, roll clockwise-positive, and fov is the vertical angle. On a phone's 1× lens that's about 67° for a portrait shot and 53° for landscape; the 0.5× ultra-wide is about 106° and 90°. Read the lens from EXIF when it's there (a 35 mm-equivalent focal length near 13 mm is the 0.5×, 24–26 mm the 1×); when it's stripped, judge it by how much of the room one frame holds. Fix fov from the lens: left free, a solve slides along fov and distance at almost the same error. With three or more photos, solve them jointly (a background agent works well for this): click corners, jambs, sills and board lines in every photo, then least-squares the room's size, the openings and all the cameras together. A five-photo living room came back within 1–4 px per photo and corrected an eyeballed reading by 9″ in length and 3″ in height. The absolute scale rests on known objects (an 80″ door, 2¼″ floor strips). Photos that share no feature can't fix the distance between them: two shots facing opposite ends of a room give its width but not its length. Take that from a known object or a symmetry (a centred fireplace), and list it in verify. A second pass with the solved cameras measures each piece's footprint by back-projecting its feet onto the floor. Open the photo in the page and tune the fields until the model's corners, jambs and sill land on the photo's. If no camera lines them all up, the room is wrong: fix the outline, not the camera. "Copy camera" hands the numbers back.

  7. Verify. Serve the page over localhost (python3 -m http.server). Judge the look on a real GPU, not headless: open the page with #debug, run python3 snapsink.py <dir> in another terminal, and call ROOM.snap(name, w, h, zoom, [x, y, z]) in the console for views (the current view's camera; zoom 2 is twice as close, and [x, y, z] is the point it looks at, as plan x, height, plan y) or ROOM.snapPhoto(i, name, true) for a photo's camera at full quality (i counts from 0, unlike #photo=N); the images land in <dir>, and both sides use port 8794. Put each snapPhoto beside its photo: that comparison is the realism test, and score it rather than eyeball it: mean luminance of the ceiling, wall and floor bands and the mean difference of a 20 × 15 grid of block luminances (the living room's photo 1 went from 22 to 11 on that scale when the room lit itself; the ceiling band from 0.91 to 0.63 against the photo's 0.60). Aim a few percent brighter than the photo, never darker. Headless, #debug&photo=N&bare gives the same render at the window's size (--window-size=1000,750 fills a 4:3 photo exactly). Score the dollhouse the other way: the mean colour of a lit patch of each wall and of the open floor, converted to Lab, should sit within about 8 ΔE of its swatch hex (the sample room's walls sit at 2–4 and its floor at 8, most of that the floor's own grain); a dollhouse that drifts past that has taken grading that belongs in the photo view. Run localStorage.clear() and reload first, or your own test drags show up. Then take headless captures and look at each one: 1440 × 900 with an item selected, the same at #look=white, 390 × 844 through an iframe harness (headless Chrome won't go narrower than about 500 px, so capture a page holding <iframe src="index.html" width="390" height="844" style="border:0"> at a 500 × 900 window), and one per photo at #photo=N. Captures need the network: three.js and the fonts load from CDNs.

  8. Deliver one .html file with the photos beside it in photos/ and the finishes in textures/ (build.py copies them in; an Artifact publishes both folders as files). Three.js loads from a CDN and everything else is inline, so it opens from any static host. Opened straight from disk (file://), a browser won't let the page read its textures, so it falls back to the drawn finishes: serve it. Until you have a capture from the browser the user will open, call the render unverified.

  9. Iterate. The user drags things or says "try the bed under the window", adds pieces from the library, takes pieces out, and tries paint and finishes in the colour pickers. "Copy layout for Claude" gives {option, name, place, colors, variants, added}; paste place, colors and variants into that option in LAYOUTS, and each entry of added into ITEMS under its key: the spec is complete (name, type, size, colours, new: true, and lib, the catalogue entry it came from), so the piece becomes part of the room and the option's place already carries where it stands. A configured piece the user took out is simply missing from place. For a real room, keep CONFIG in its own config.js in a project folder and run python3 build.py <project-dir> to splice it into the engine, so engine fixes carry over. Add an option rather than overwriting one the user liked.

Show full SKILL.md (2,064 more words)Show less

CONFIG reference

  • rot is the wall an item's back faces: 0 top, 90 right, 180 bottom, 270 left. The front is the side you use (the bed's foot, the drawers, the desk's chair side).
  • rot takes any angle, not just the four walls. A piece given only w is round or square: d defaults to w.
  • Door hinge is 'left' or 'right' as seen standing in the room facing that wall; swing is 'in' or 'out'. type: 'opening' is a closet or cased opening; clear sets the depth kept free in front of it (default 24″). An opening's label is a short noun ("Hall", "Closet"), because the checks use it in sentences: "Desk blocks the closet".
  • Types: bed, crib, dresser, nightstand, desk (with chair), bookshelf, wardrobe, sofa, armchair, lounge (a bentwood cantilever chair; throw: true adds a sheepskin), chair (a side chair sized to its w, d and h), table (glass: true for a framed glass top, shelf: true for a lower shelf, round: true for a round top on splayed legs), rug, box, ottoman, petbed, stands (plant stands with pots), floorlamp (a tripod lamp; arc: 22 makes an arc lamp that hangs its shade 22″ out in front, so aim it with rot, and the checks flag a shade that reaches through a wall; shade = radius; an arc lamp's h is the arc's crown, and its shade hangs about a third of the reach below it), floorplant (w is the canopy's spread and h its top, and the pot scales from w; heads for a leafy tree, upright: true for spears, pole: true for a climber on a moss pole), art (a framed picture: mount = its bottom edge's height, print: 'landscape' | 'poster' | 'abstract' | 'mirror'), media (a console; tv = the screen's diagonal in inches; mount: 58 hangs just the TV on the wall at that height, with no floor footprint, drawn dashed in the plan), fireplace (a built-in: h is the mantel, face and faceH the firebox face, front the hearth kept clear, fw its width).
  • Wall-mounted items (mount) have no floor footprint and hide while their wall is cut away in the dollhouse view.
  • Windows take panes (the number of sashes; the default is one per 26″). Openings also take type: 'niche': shelves recessed into the wall between sill and head. ROOM.paneling: {walls: [edge indexes], name, color, plank: [min, max]} panels whole walls with random-width planks; edge i runs from outline[i] to outline[i+1], so a rectangle traced from the top-left is 0 top, 1 right, 2 bottom, 3 left. A built-in in fixed takes an id, which is the key its colours use in colors; its c is its centre and its rot works as for items.
  • LIBRARY (optional) adds this room's own entries to the "Add a piece" catalogue: [{id: 'toys', name: 'Toy chest', type: 'box', w: 36, d: 18, h: 20}], each an item spec with an id and a name (variants work as on ITEMS, so "the new bed in three sizes" is one entry). group files it under seating, tables, storage, beds, lighting, plants, rugs or walls; without one it is listed first as "For this room". {base: false, entries: [...]} offers only these. The built-in catalogue covers each type in common sizes: a three-seat sofa and loveseat, armchair, lounge and dining chairs, an ottoman, coffee tables (rectangular, round, glass) and a side table, a media console, bookshelf, dresser, nightstand, wardrobe and desk, twin to king beds and a crib, tripod and arc lamps, a tree, a snake plant and a climber, 5 × 8 to 9 × 12 rugs, a pet bed, a wall TV and art. An added piece takes the palette's quietest swatches for its finishes, lands in the biggest clear square (a wall piece on the nearest wall, clear of its openings), is selected with the gizmo on it, and persists per option with its place, colours and variants under storageKey beside the older edits. Pieces taken out of an option wait in the library under "In this room". Thumbnails are the engine's own renders, made when the library opens and cached.
  • variants: [{label: 'Yours'}, {label: 'Longer', w: 96}] on an item; an option picks one with variants: {sofa: 'Longer'}. LOOKS: [{name, colors}] replace the option's colours in one click; {} is the room as configured. Default clearances: dresser and wardrobe 36″ in front, desk 30″, bookshelf 24″, sofa 14″ (the usual reach to a coffee table); a bed needs one side with 20″ free. Override per item with front or side.
  • Checks: things that run into a wall, overlap, or sit in a door swing; a blocked front, closet or bed side; tall things in front of a window; an arc lamp's shade through a wall or hanging into what's under it; open floor and the biggest clear square.
  • python3 test.py <project-dir> audits the model against those checks and fails on any finding: every part stays over its footprint or a zone a check sees (an arc lamp's reach, a desk chair's front clearance, a hearth), stands on the floor (or its wall) joined to the rest, stays under its height, and every rod or tube ends on another part without passing through one. It also fails when the photo finishes don't load, when the page's load event waits for a photo or scan, when the photo view's light shifts as the room is re-captured, or when a piece loses its turn in the model after the ring, a nudge and the turn buttons. An expect.json beside a fixture's config.js pins what the panel says. Run it after any builder or finish change; tests/every-piece holds every type and flag.
  • Colour: ROOM.walls, floor, trim, boards (board width in inches, 0 = none) and boardsDir ('x' or 'y'). On items, color is the body and color2 the second finish: bedding (bed), mattress (crib), legs (desk, table), cushions (sofa, armchair), cushion over a wood frame (lounge), shade over the stand (floorlamp), the pot (floorplant), the print (art), border (rug). Mattress and pillows stay soft white, and shelf books get muted colours of their own. LAYOUTS[i].colors overrides any of these for one option, as walls: 0x… or bed: [body, second]. look: 'white' opens on the white model.
  • Finishes: TEXTURES names the folder of photo scans (default 'textures/'; false keeps the drawn finishes). textures/SOURCES.md lists each scan, its ambientCG source and the size one tile covers; swap in any greyscale scan under the same file name and set its size in SCANS in the engine. #debug&drawn shows the drawn finishes, for a before-and-after.
  • Light: every lamp glows by default (a warm bulb inside any part a builder tags kind: 'shade'); ROOM.lamps: 0 turns them all off and 2 doubles them, and an item's glow: 0.5 scales its own. Every solid piece stands in a soft contact shadow; contact: 0 on an item removes it, 1 darkens it. Everything that dims or grades applies only through a photo's camera, never in the dollhouse: there, floors and paneling render a little less saturated than their swatch (15 % and 12 % toward grey), painted walls and trim take 70 % of the room's own bounce, and the capture itself sees the wood half as saturated, because wood under that warm bounce goes redder than a photo of it and an off-white wall beside it would tan where the photos show it white-grey; the view outside a window is lit 1.7× and hazed toward white, the way a camera exposed for the room sees it. A room with no window has no daylight in colour: give it a window, or its lamps carry the room.
  • URL hash: #layout=2&view=sw|top&sel=bed&pane=plan&photo=1&look=white (layout and photo count from 1); add debug for the ROOM handle, and debug&frame=<id>&el=20 for a close-up of one piece or built-in (the visual sweep of tests/every-piece uses it). With debug, photo=N&bare draws that photo's camera alone, filling the window with no photo or UI, for a capture beside the photo; bench=8 writes frame costs into <pre id="bench"> (ROOM.bench(n) returns them: still, moving with the shadow map redrawn, env for the room-light capture, and draw calls); and exp, sun, win (window light), sky (the view's brightness), lamp, vig, wenv (how much of the captured room paint takes) and grey (how far the wood is greyed for the capture) override the photo view's light levels for tuning against photos (the defaults live in LIGHT in the engine; win and lamp also reach the dollhouse); lib opens the library, libadd=sofa3,art adds those catalogue entries, and libtest adds two, takes one out, and writes the stored state and the copy output to pre#libtest for a --dump-dom check.

Common mistakes

MistakeInstead
Placing walls by eye from the photosWrite the wall-by-wall text, then prove it with the overlay
Asking for measurements before drawingEstimate from known objects, mark them verify
Bending the photo camera to hide a wrong roomFix the outline; the overlay is the test
Three nudges of one layoutDifferent ideas, each with its trade-off
Inventing a paletteSample the room's colours from the photos and name them
Shadowed or glary samplesSample a lit patch of wall, away from corners and glass
Adding a person for scaleNone: the furniture gives scale, and a figure standing in someone's own room looks odd
Editing the engine for one roomChange starter.html itself and re-capture the sample
Judging realism from the dollhouse viewsnapPhoto beside each photo: floor tone, wall brightness, lamps and plants show up there first
Guessing where the furniture standsBack-project each piece from the solved cameras. One living room's guesses were off by up to 30″ (a dog bed), 9″ (a coffee table's length) and 6″ (a sofa's depth)
Fixing every flag on the "as it is" optionNudge only within the cameras' 3–5″ tolerance (a table top over a chair arm is not an overlap). Real pinch points stay as findings, and the note names them
A third option that nudges the other twoA different idea (move the sofa under the window, put the TV over the mantel)

Gotchas

  • Headless Chrome renders in software: slow, and fine for layout and the phone check but not for judging light. Use a visible browser on a real GPU for that; a hidden or background tab pauses its frame loop, and the loop is what applies a photo view's grading and captures the room's light. ROOM.snapPhoto applies both itself; for any other capture from a hidden tab, call ROOM.ev('applyLight(); captureEnv(); render3d()') first, or you'll compare studio light against the photo.
  • Headless captures: "<Chrome>" --headless=new --user-data-dir=<scratch>/st-N --disable-gpu --use-angle=swiftshader --enable-unsafe-swiftshader --window-size=1440,900 --virtual-time-budget=5000 --screenshot=<png> <url>, one at a time with a timeout (e.g. perl -e 'alarm 45; exec @ARGV' …), then pkill -f "[u]ser-data-dir=<scratch>/st-N". The brackets stop pkill from matching and killing your own shell. file:// URLs work (add --allow-file-access-from-files or the textures fall back to drawn ones); give the phone harness's iframe an absolute file:// URL (a relative one came back ERR_FILE_NOT_FOUND). A capture with the library open takes a minute or more: its thumbnails render in software, so allow alarm 200. At phone width, headless SwiftShader never delivers a screenshot of the open library beside the model canvas (it does at desktop size), so capture the phone library over the plan (#debug&lib&pane=plan) or with nothumb, which skips the thumbnails. Chrome lingers after writing the file, so poll for it and kill rather than wait for exit; on a loaded machine the screenshot sometimes lands before the first frame as a 4 KB white page, so check the size and retry with a bigger budget. Software rendering is slow (a photo view with all passes takes 20–50 s) but its light is the same maths as a GPU's, so luminance measurements from it are valid; only the look needs a real GPU.
  • Hosts that wrap the page in their own skeleton (claude.ai Artifacts do) want a copy without doctype, <html> and <body>: build.py --artifact writes one. Such hosts often pass only a bare #anchor, so make the defaults (view, the first option) the right opening state.
  • claude.ai keeps an Artifact blank until the page's load event, and that event waits for every image started before it: a five-photo room's thumbnails and scans held one blank for 20–40 s. The engine starts its scans and thumbnails through afterLoad; start any new image the same way.
  • Once a layout is chosen and something has to be built, the step-by-step build guide is the 3d-assembly-manual skill.

© SkylarKitchen, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 18 other files in skills/design/room-from-photos of SkylarKitchen/skills.

  • SKILL.md
  • agents/openai.yaml
  • build.py
  • snapsink.py
  • starter.html
  • test.py
  • tests/arc-lamp/config.js
  • tests/arc-lamp/expect.json
  • tests/every-piece/config.js
  • tests/every-piece/expect.json
  • tests/every-piece/photos/corner.jpg
  • textures/SOURCES.md
  • textures/brick-n.jpg
  • textures/brick.jpg
  • textures/carpet-n.jpg
  • … and 4 more

Open the folder on GitHubat commit fb53232

Compare with similar skills

Room From Photos next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Room From Photos compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Room From Photos this skillSkylarKitchen/skills117—~6kAutomated safety check: PassMIT
Threejs Image Generatorvalkor-ai/loom1.2k1 repos~1.4kAutomated safety check: PassApache-2.0
3D Image Rendererhassancs91/claude-image-generation102—~1.4kAutomated safety check: PassMIT
Frontendnotque/vexjoy-agent441—~5kAutomated safety check: NotesMIT
Motion DesignWrongStack/WrongStack371—~852Automated safety check: PassMIT
Image to Three.js Modelimg2threejs/img2threejs18k1 repos~8.2kAutomated safety check: PassApache-2.0

Similar skills

  • Generate and edit 2D image assets for Three.js games with Google's Gemini image API: concept sheets, image-to-3D inputs, texture and material references, sky and background plates, decals, logos…

    1.2k GitHub starsUsed in 1 repo~1.4k tokens
    Game DevelopmentAuto-check passed
  • 3D Image Renderer

    hassancs91/claude-image-generation

    Generate PNG images by building a real Three.js 3D scene and capturing one frame headlessly — no image model involved.

    102 GitHub stars~1.4k tokensUpdated 1 mo ago
    Game DevelopmentAuto-check passed
  • Frontend

    notque/vexjoy-agent

    Frontend: UI design, distinctive visual styles, HTML artifacts, Three.js 3D.

    441 GitHub stars~5k tokensUpdated yesterday
    Frontend & DesignAuto-check: notes
  • Motion Design

    WrongStack/WrongStack

    Implement web and React animation, gesture feedback, layout transitions and scroll sequences.

    371 GitHub stars~852 tokensUpdated yesterday
    Game DevelopmentAuto-check passed
  • Image to Three.js Model

    img2threejs/img2threejs

    Rebuilds the object in a reference image as a procedural, animation-ready Three.js model written entirely in code, using staged sculpting with quality checks.

    18k GitHub starsUsed in 1 repo~8.2k tokens
    Game DevelopmentAuto-check passed
  • Threejs World Generation

    calesthio/OpenMontage

    Build deterministic, editable, free-viewpoint Three.js worlds from text or structured briefs.

    66k GitHub stars~2k tokensUpdated 7 days ago
    Game DevelopmentAuto-check passed

More from SkylarKitchen/skills

  • 3D Assembly Manual

    SkylarKitchen/skills

    Builds a phone-first interactive 3D step-by-step build guide as one self-contained Three.js HTML file, starting from a bundled starter template.

    117 GitHub stars~1.6k tokensUpdated 13 days ago
    Auto-check passed
  • Launch Film

    SkylarKitchen/skills

    Make a short, frame-exact product film for X or a portfolio from the real thing (a web app, a site, a Three.js scene, project photos), authored as a plan and rendered on a canvas engine rather than…

    117 GitHub stars~1.9k tokensUpdated 13 days ago
    Auto-check passed

Works with

Questions about Room From Photos

What does Room From Photos do?

Builds a 3D model of a real room from a few phone photos, with movable furniture layouts, as one Three.js HTML page you can open in a browser. js. No floor plan is needed.

When should I use Room From Photos?

Room From Photos fits situations like: checking whether a new bed or sofa fits in a room you only have photos of; comparing several furniture arrangements before moving anything heavy; turning phone photos into a shareable 3D room page when no floor plan exists.

How do I install Room From Photos in Claude Code?

Run `npx skills add SkylarKitchen/skills --skill room-from-photos -a claude-code`. Or copy the skill folder (skills/design/room-from-photos in SkylarKitchen/skills) into .claude/skills/room-from-photos in your project. Claude Code loads it when a task matches its description.

How do I install Room From Photos in Codex?

Run `npx skills add SkylarKitchen/skills --skill room-from-photos -a codex`. Or copy the skill folder (skills/design/room-from-photos in SkylarKitchen/skills) into .agents/skills/room-from-photos in your project. Codex loads it when a task matches its description.

Can I use Room From Photos in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add SkylarKitchen/skills --skill room-from-photos -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/room-from-photos, .gemini/skills/room-from-photos, .github/skills/room-from-photos and .opencode/skills/room-from-photos in your project.

What does Room From Photos need to run?

Going by SKILL.md and its folder, Room From Photos needs Python and JavaScript for the scripts in its folder and the command-line tools its instructions call (python3). Our summary lists: Phone photos of the room.

Does Room From Photos access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Room From Photos safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Room From Photos use?

Room From Photos is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Room From Photos use?

About 6k tokens (SKILL.md is roughly 24k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Room From Photos?

Skills that share tags, products or a category with Room From Photos: Threejs Image Generator (valkor-ai/loom, 1.2k stars), 3D Image Renderer (hassancs91/claude-image-generation, 102 stars), Frontend (notque/vexjoy-agent, 441 stars) and Motion Design (WrongStack/WrongStack, 371 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Room From Photos?

SkylarKitchen (a GitHub user) maintains it in SkylarKitchen/skills, which has 117 GitHub stars. The repository holds 3 skills in this directory. The repository was last updated on September 28, 2026.

Source: SkylarKitchen/skills on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.