Ducket Suites is a lightweight renderer for isometric rooms and animated furniture — inspired by classic hotel-style pixel worlds. Drop it on any page, no build step required.
Include the CDN script, create a container, and render your first room:
<!-- 1. add the script --> <script src="https://ducket-suites.pages.dev/ducket-suites.global.js"></script> <div id="room" style="width:800px;height:500px"></div> <script> (async function() { // 2. boot pixi var app = new DucketSuites.Application(); await app.init({ resizeTo: document.getElementById("room"), background: 0x0b1938, }); document.getElementById("room").appendChild(app.canvas); // 3. create a room var room = new DucketSuites.Room({ tilemap: "xxxxx\nx0000\n00000\nx0000\nx0000", wallColor: "#89B8CF", floorColor: "#FFD000", }); app.stage.addChild(room); // 4. place furniture var catalog = new DucketSuites.FurniCatalog(); await room.furnish([ { type: "throne", x: 2, y: 2, z: 0, dir: 4 }, ], catalog); })(); </script>
The main container. Parses a tilemap string and renders isometric walls, tiles, stairs, and furniture.
| field | type | description |
|---|---|---|
tilemap | string | Tilemap string. x=void, 0-9=floor height |
wallColor | string? | Hex wall colour, e.g. "#89B8CF" |
floorColor | string? | Hex floor colour |
| name | type | description |
|---|---|---|
wallHeight | number | Wall height px (default 116) |
tileHeight | number | Tile thickness px (default 8) |
hideWalls | boolean | Toggle wall visibility |
hideFloor | boolean | Toggle floor visibility |
hideTileCursor | boolean | Toggle hover cursor |
roomBounds | {minX,maxX,minY,maxY} | Bounds for centering |
| signature | description |
|---|---|
furnish(items, catalog?) | Place an array of furniture descriptors. Returns Promise<FloorFurniture[]> |
addFloorFurniture(f) | Add a single FloorFurniture |
removeFloorFurniture(f) | Remove a furniture piece |
getScreenPosition(x,y,z) | Convert room → screen pixel position |
destroy() | Clean up all resources |
A single piece of furniture — load from a .shroom URL or via the catalog.
| field | type | description |
|---|---|---|
roomX | number | Column |
roomY | number | Row |
roomZ | number | Floor height level |
direction | number | 0=N, 2=E, 4=S, 6=W |
animation | string? | Animation state id |
| signature | description |
|---|---|
load(url) | Load from a .shroom URL (returns a Promise) |
loadFromBundle(bundle) | Load from a pre-fetched ShroomAssetBundle |
All constructor options are also read/write properties — e.g. assigning f.roomX = 5 moves the furniture live.
Fetches furnidata.xml and resolves classnames ("throne") to download URLs.
| signature | returns | description |
|---|---|---|
new FurniCatalog(resourcePath?) | — | Defaults to https://ducket.net/resources |
resolveUrl(classname) | Promise<string> | Classname → .shroom URL |
search(query, limit?) | FurniInfo[] | Search by name or classname |
ready() | Promise<void> | Resolves when furnidata is loaded |
Tilemaps are multiline strings. Each character is a tile:
x — void (no tile)0–9 — floor at that height levelx is the door row// simple flat room with door var flat = [ "xxxxx", "x0000", "00000", // ← door row "x0000", "x0000", ].join("\n"); // raised platform — stairs auto-generated var raised = [ "xxxxxxxxx", "x00000000", "000000000", "x00111100", // height 1 platform "x00111100", "x00000000", ].join("\n");
Pass an array of descriptors to room.furnish() — bundles are deduped and fetched in parallel.
var catalog = new DucketSuites.FurniCatalog(); await room.furnish([ { type: "throne", x: 3, y: 3, z: 0, dir: 4 }, { type: "nft_h23_trippy_aloe", x: 1, y: 1, z: 0, dir: 2, anim: "0" }, { type: "hc23_11", x: 5, y: 2, z: 0, dir: 6, anim: "0" }, ], catalog);
var f = new DucketSuites.FloorFurniture({ roomX: 4, roomY: 3, roomZ: 0, direction: 2 }); await f.load("https://ducket.net/resources/hof_furni/12345/throne.shroom"); room.addFloorFurniture(f); // move it later — reactive setters f.roomX = 6; f.direction = 4;
| field | type | description |
|---|---|---|
type | string | Classname from furnidata (needs FurniCatalog) |
url | string | Direct .shroom URL (alt to type) |
x | number | Column |
y | number | Row |
z | number | Height level |
dir | number | Facing: 0 N, 2 E, 4 S, 6 W |
anim | string? | Animation state |
Assign callback properties directly on the room instance:
room.onTileClick = function(pos) { console.log("clicked", pos.roomX, pos.roomY, pos.roomZ); }; room.onTileOver = function(pos) { console.log("hover", pos.roomX, pos.roomY); }; room.onTileOut = function() { console.log("left tiles"); }; room.onActiveWallChange = function(info) { if (info) console.log(info.wall, info.roomX, info.roomY); };
| event | callback arg | description |
|---|---|---|
onTileClick | { roomX, roomY, roomZ } | User clicks a floor tile |
onTileOver | { roomX, roomY, roomZ } | Pointer enters a tile |
onTileOut | (none) | Pointer leaves all tiles |
onActiveWallChange | ActiveWallInfo | undefined | Pointer enters/leaves a wall |