WallpaperMachine
The wallpapers you love. A new home on your Mac.
Plan a Snow Peak IGT setup in 3D — and know it will go together.
Translation pending
LifestyleJavaScript · PythonGitHub @iqisOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Plan a Snow Peak IGT (Iron Grill Table) setup in 3D, to the millimetre — with open rules your own AI agent can drive.
Loading the full README. The saved excerpt is shown below.
igt.iqis.app — plan a Snow Peak Iron Grill Table (IGT) setup
in 3D, to the millimetre, and know it will actually go together.
Frames, hook-on boards, corners, slide-in extensions, burners, trays, the Jikaro fire ring,
chairs, tarps: drop them in and the planner works out where each one really ends up —
from the measured hooks and brackets, not from bounding boxes — and tells you what doesn't
fit, what the manuals forbid, and what the whole kit weighs. Nothing to install, no account;
designs live in your browser and travel as links.Read the full README ↗igt.iqis.app — plan a Snow Peak Iron Grill Table (IGT) setup in 3D, to the millimetre, and know it will actually go together.
Frames, hook-on boards, corners, slide-in extensions, burners, trays, the Jikaro fire ring, chairs, tarps: drop them in and the planner works out where each one really ends up — from the measured hooks and brackets, not from bounding boxes — and tells you what doesn't fit, what the manuals forbid, and what the whole kit weighs. Nothing to install, no account; designs live in your browser and travel as links.
Using it with your own AI — under development. The rules engine (web/core.js) has no
DOM and no three.js, so an agent can already write a layout and have the planner's own rules
check it — from a terminal (node scripts/igt.mjs evaluate) or from code. The rest is not
finished: the in-app AI entry is hidden on the public site while it is reworked, and the
chat-window route (docs/AI.md, also served as
igt.iqis.app/llms.txt) is experimental and may change.
git clone https://github.com/iqis/igt-planner && cd igt-planner
py serve.py --port 8795 # -> http://localhost:8795/web/ (any static server works)
node scripts/igt.mjs example # the rules from a terminal, no browser
Vanilla JavaScript and vendored three.js: no build step, no runtime dependencies. MIT licensed. An independent project, not affiliated with Snow Peak; product names are used only to say what each part is.
Development process: making wishes to Claude.
Everything here is open: the app, the parts catalog (catalog/igt-catalog.json), and the
rules that decide what fits (web/core.js, plus the evidence in catalog/overrides.json).
Use the data in your own tools, fork the planner, and send pull requests — a part that is
missing or mismeasured, a combination the manuals allow that the planner refuses (or the
other way round), a better outline for a tarp, a translation, or something new altogether.
Run npm run smoke before you push; where a number comes from a photo or a manual, say which.
Not sure where to start? Open an issue.
What follows is how it was built — where the numbers come from, and why they can be trusted.
IGT looks like a 3D packing problem and isn't. A frame is a linear run of unit slots, and every module claims a whole number of half-slots. Slot assignment is 1D interval packing; everything else is a layer stacked on top (legs, rail clamps, hangers).
The unit pitch is never published. derive_grid.py recovers it by differencing frames of
known unit count, and refuses to emit a constant the frame family does not corroborate:
[collapsible] W(n) = 250.0n + 96.0 zero residual, 3 frames
[standard] W(n) = 250.0n + 96.0 zero residual, 2 frames
unit = 250mm, half-unit = 125mm. See SCHEMA.md for the model — including why span comes from the unit label and never from millimetres.
No storefront has everything, so the catalog is a join on SKU (CK-149), which every
region carries. What each one is actually good for, measured rather than assumed:
| region | good for | not good for |
|---|---|---|
US snowpeak.com | SKU, JAN, USD price, stock, images, collections, and descriptions (which state unit counts the product names omit, and link set components) | weight is shipping weight — 74–1200g heavier than the part |
JP ec.snowpeak.co.jp | the only source of geometry: mm dimensions, 収納サイズ (packed size), true weight, material, set contents, and the manual PDF | — |
UK snowpeak.co.uk | GBP price (Shopify, so the SKU join is clean) | publishes no dimensions at all, and its variant weights are duplicated: CK-149 and CK-150 are both listed at 4900g, though the 4-unit frame is 700g heavier |
| TW / KR | — | SPA storefronts whose scraped rows carry no SKU; nothing to join on, so they are left out rather than guessed at |
Neither the US nor the JP catalog is a superset. The US has 83 IGT products (the Renewed/TR lines, US-only sets); the JP category has 70, of which 20 exist nowhere in the US. The universe is the union.
And neither storefront's taxonomy is clean, in both directions: the US files Takibi grill
plates under cookers and 24 buckets and coolers under storage; the JP files the TUGUCA
wooden shelving line under IGT&キッチン. None of them can enter a unit slot, so membership
is gated on rules rather than on either vendor's own tree.
Two facts make the rest work:
py scripts/fetch_us.py # the 6 IGT collections -> data/us_products_latest.json
py scripts/sync_jp_specs.py # JP specs, from the snapshot -> data/jp_specs_latest.json
py scripts/fetch_regions.py # JP + UK prices, from snaps -> data/regions_latest.json
py scripts/derive_grid.py # recover the unit pitch -> catalog/grid.json
py scripts/build_catalog.py # join + classify -> catalog/igt-catalog.json
A separate price tracker (snowpeak-sale-watch, not part of this repo) already fetches all ~2,100 JP product
pages, plus the US and UK catalogs, every day — and was throwing the JP spec table
away. It now keeps it, so this project parses the dimensional data instead of re-crawling
for it:
/products.json does not carry collection membership and the whole role taxonomy hangs
off it. Six requests.fetch_jp_specs.py remains as the bootstrap crawler. Its --reparse re-derives dimensions
from the stored size_raw offline, so a parser bug costs a second rather than another pass
over 2,100 pages — which is how four of them were found and fixed.
Vanilla three.js, vendored — no build step, no CDN, works offline. It reads
catalog/igt-catalog.json directly, so a scraper fix shows up on reload.
Modules are drawn at their own width, centred in the slots they claim, never stretched to fill them. That is the whole point of carrying real millimetres: a tray built 5mm narrower than its unit shows a genuine gap, and the Flat Burner's 20mm-wider rim really does sit on the rails. Stretching parts to their allocation would hide the one thing worth seeing.
scripts/ the five build steps above, plus smoke.mjs (below)
catalog/ committed output: grid.json, igt-catalog.json, overrides.json
web/ the planner: core.js (the rules, no DOM) + app.js (the 3D app, vendored three.js)
docs/AI.md driving it from your own agent -- under development (also served as /llms.txt)
data/ raw fetches and timestamped archives (gitignored)
npm install # once -- puppeteer-core only, drives the Chrome already installed
npm run smoke # ~15s: boot, place, hook, undo, share round-trip, bench dispatch,
# zero console errors, and the on-demand renderer actually idling
The app itself still has no build step and no runtime dependencies; package.json exists
solely for this. A pre-push hook runs it and blocks a red push — on a fresh clone,
cp scripts/hooks/pre-push .git/hooks/ — and it skips politely when node_modules is
absent.