# Internet Paradise — full reference for AI agents > Everything an agent needs to build in Internet Paradise, as plain text. Generated from the site's code (docs updated 23 October 2026; SDK 0.3.0). Human pages: https://internetparadise.xyz/docs/. Short version: https://internetparadise.xyz/llms.txt. ## What the site is Internet Paradise is a walkable 3D town for Tezos art that runs in the browser. The mainland is an old-European coastal village with 67 artist plots (31 of 16 m, 27 of 32 m, 4 of 48 m, 5 of 80 m), the Palazzo delle Arti and public squares. Tenants build galleries on their rented plots and hang NFTs from their wallets; visitors walk in, chat and collect on objkt. Up to 50 people share the mainland at once. ## Publishing rules (read first) - Agents never publish. No tool publishes, signs, spends tez, uploads model files or hangs NFTs. - Preview, then decide. After each round, show the owner the `preview` image. Before they decide: `validate`, `review_changes` (objects and groups added, removed and changed against the published plot, cell by cell, and the plot weight), and `preview_link` (a link where the signed-in owner walks the draft in place on their plot; nothing is saved or published there, and "Back to my draft" leaves everything as it was). `restore_published` puts the published plot back into the draft (undo returns); `discard_draft` deletes a draft. Call these, and `deploy`, only when the owner asks. - `deploy` validates the draft and returns a link. The owner opens it in their plot editor (Share › AI agents › Preview or Open in the editor; from a preview, Use this draft) and publishes from Share › Publish your whole plot with their wallet's signature (no tez is spent). - Never ask for a seed phrase, private key or password. Never claim something is published. - Only build with art and models the owner has the right to show. Token metadata is not proof of authorship. ## Connecting Remote MCP: https://internetparadise.xyz/mcp (Streamable HTTP, stateless; protocol revisions 2024-11-05 to 2026-07-28). - OAuth 2.1, the site is the authorization server. Metadata: /.well-known/oauth-protected-resource/mcp and /.well-known/oauth-authorization-server. Dynamic client registration or client ID metadata documents; PKCE S256 required; `resource` parameter; public clients, no secrets. - The owner signs in with their Tezos wallet on /connect and presses Allow. Only invited wallets or plot holders, with a claimed plot. The draft is always of that wallet's plot. - Access token 1 h; rotating refresh token 30 days; a connection ends after 90 days. Personal bearer tokens (7, 30, 90 days) from account › Connected agents, sent as `Authorization: Bearer `. - Limits: 60 tool calls a minute and 1,500 a day per wallet; 4 drafts per wallet, 1 MB each, 5 undo steps. - ChatGPT: chatgpt.com/plugins › + › Add custom MCP server, OAuth, client ID empty. Claude: Settings › Connectors › Add custom connector. Claude Code: `claude mcp add --transport http internet-paradise https://internetparadise.xyz/mcp` then `/mcp`. Codex: `codex mcp add internet-paradise --url https://internetparadise.xyz/mcp` then `codex mcp login internet-paradise`. Local MCP (stdio): download https://internetparadise.xyz/sdk/third-life-mcp.mjs (Node.js 20+), then claude mcp add internet-paradise -- node "$PWD/third-life-mcp.mjs" --scene "$PWD/my-world.json" codex mcp add internet-paradise -- node "$PWD/third-life-mcp.mjs" --scene "$PWD/scene.json" Options: --scene , --assets (repeatable), --offline. Plot folder: `node third-life-pack.mjs init --plot ` writes plot.json (cells, entrance, neighbours, limits), scene.json, base.json (where the folder started; never edit it) and agent setups (.mcp.json for Claude Code, .codex/config.toml for Codex, .cursor, .vscode, mcp/claude-desktop.json, mcp/codex.toml). Validate: `node third-life-pack.mjs scene.json --check` (also after editing scene.json by hand; there positions are per cell, 0 to 16, not plot coordinates). Diff: `node third-life-pack.mjs diff`. Walk it: `node third-life-pack.mjs preview` (writes preview.png and opens the owner's plot showing the folder, served from 127.0.0.1 for 30 minutes). The owner deploys: `node third-life-pack.mjs deploy` (opens the deploy page; the wallet signs). The same as tools: review_changes, preview_link, restore_published (when the folder came from the published plot), deploy. Codex config (~/.codex/config.toml or a trusted folder's .codex/config.toml): [mcp_servers.internet-paradise] command = "node" args = ["/full/path/third-life-mcp.mjs", "--scene", "/full/path/scene.json"] or remote: [mcp_servers.internet-paradise] url = "https://internetparadise.xyz/mcp" then `codex mcp login internet-paradise`. The local server adds new_scene, open_scene, save_scene, inspect_model (a .glb measured against the budgets, unchanged), optimize_model (a lighter copy written beside it with the site's own import preparation), add_model (places a .glb with automatic collision) and export_zip (the ZIP a plot editor imports, into a cell of the plot). ## Coordinates - Metres, y up. A cell is 16 x 16 m, 16 m tall. A plot is 16, 32, 48 and 80 m square: 1, 4, 9 or 25 cells, numbered row by row from the north-west. - Positions are the centre of an object's bounding box from the north-west corner (of the cell, or of the plot in a plot scene). On the ground, y = height / 2. - North -z, south +z, east +x, west -x. In a plot, the street entrance is the front. - Tools take degrees; the scene file stores radians. Solid objects turn only around y. - Boxes crossing a cell border are cut per cell; anything else must lie inside one cell. ## describe_rules (the text the tools return, one-cell scene) Internet Paradise scene rules (SDK 0.3.0) UNITS AND AXES - Metres. y is up. A scene is one build cell of 16 x 16 m, 16 m tall. - Positions are relative to the cell's north-west corner: x and z run 0 to 16, y = 0 is the ground. - Compass words used by the helpers: north = -z, south = +z, east = +x, west = -x. Visitors arrive 2 m outside the south edge, at [8, 0, 18], looking north (-z): the south side is the front. - Angles are DEGREES. yaw turns around the vertical axis, counter-clockwise seen from above: yaw 90 turns an object's +x side to face north (-z) and swaps its x and z extents. OBJECTS (add_objects) - position is the CENTRE of the object's bounding box. Something of height h standing on the ground has y = h / 2; on a floor whose top is at y = f it has y = f + h / 2. - size is the full extent [x, y, z] before yaw, each above 0 and at most 16. It defaults per shape. - Shapes: box: Rectangular block filling its size box: walls, floors, slabs, steps, plinths, tables. Default size 2 × 2 × 2 m. cylinder: Upright cylinder: size x and z are its diameters, size y its height. Columns, posts, round tables. Default 1 × 3 × 1 m. sphere: Sphere or ellipsoid filling its size box. Domes (sink the lower half into a roof), lamps, shrubs. Default 2 × 2 × 2 m. torus: Ring standing upright in the x–y plane, its hole facing ±z (turn it with yaw). Outer diameter = size x and y; the tube is about a quarter of size z thick. Default 2 × 2 × 2 m. vault: Hollow half-round arch shell: spans size x, rises to size y at its crown, runs along size z and is open at both z ends and underneath. Barrel-vault roofs, arcades, tunnels. Default 4 × 2 × 4 m. foliage: Leafy fern or shrub filling its size box. Not solid by default. Default 1.5 × 1.5 × 1.5 m. frame: Empty picture frame the creator later fills with a Tezos NFT from the builder’s Art tab: a thin box whose picture faces +z (south) at yaw 0, +x (east) at yaw 90, −x (west) at yaw −90 and −z (north) at yaw 180. So on the inside of a north wall use yaw 0, south wall 180, west wall 90, east wall −90. Never solid. Default 2 × 1.6 × 0.08 m; hang it 0.05 m in front of the wall face, its centre about 1.6 m up. add_frames hangs a row of them on a wall for you. - color is "#rrggbb"; it defaults to the material's colour. material: stone, metal, glass, plaster, copper, plywood, painted, concrete, brick, fabric. - label names an object; group puts objects in one building group the creator moves as one. Use groups. - Every object lies wholly inside the cell: x and z within 0..16, bottom at least -0.3, top at most 16. Within 1 mm of an edge it is nudged inside; further out it is refused with the distance to move it. WALKING AND COLLISION - The visitor is 0.6 m wide and 1.72 m tall, and walks up any ledge of at most 0.28 m. Anything taller is a wall; stairs need risers of at most 0.28 m (the helpers use 0.18 m). - collider: true makes an object solid: visitors cannot walk through it and can stand on it. It defaults to true for box, cylinder and vault. A solid object collides as its bounding box (a vault as its arch) and may only turn with yaw; tilted pieces (roof slopes, rafters) must be collider: false. - collisionOnly: true makes an invisible solid box, to give decoration or a model walls and floors. - A model keeps its proportions: size is the box it fits inside, and the box snaps to the model as drawn. stretch: true (models only) fills the size side by side instead, as a wall module stretched to any length. - Doorways need at least 0.8 m of width and 1.82 m of height (helpers use 1.2 x 2.3 m). - Over a stair keep 2.1 m of headroom: leave the hole add_stairs returns open in the floor above (add_floor or a room ceiling with that hole). HELPERS (fastest way to rough out) - add_room: four walls with a door and windows, a floor and optionally a ceiling, as one group. x, z are the room's north-west corner; y is the floor level it stands on. The next storey of a room of height h with a ceiling slab t starts at y + h + t (add_room says so). - add_wall: one straight wall from [x, z] to [x, z], cut for a door and windows. add_floor: a slab with holes. - add_stairs: a straight flight a visitor walks up; it returns the hole to leave in the floor above. - list_prefabs / add_prefab: ready old-town pieces (walls with cornices, doorways, arcades, stairs, roofs, a fountain, benches, cypresses, three small buildings) placed as one group. Prefabs keep their real height above the level you give. - add_objects items take repeat: { count, offset } for rows of posts, slats, columns or steps. - Prefer helpers and prefabs for structure, add_objects for details, update_objects for adjustments, undo to step back. CHECKING YOUR WORK - describe_scene: what is where, per group, what a visitor can reach (a real walk test with the game's own movement), and what ground is still free. - preview: a picture of the scene: plans and elevations. Look at it after each round. - validate: the site’s own checks, and whether every model file can be found. LIMITS PER SCENE - 500 objects. 32 different local files (models and pictures together), 128 model instances. - GLB files up to 20 MB each, 150 MB in total; 200,000 triangles per model, 500,000 per scene; textures embedded as PNG, JPEG or WebP, up to 16.8 megapixels per model. Draco and KTX2 are refused. - 8,192 model collision surfaces per scene. WORKFLOW - Every change is saved to the scene file at once. undo steps back (up to 30 steps). - add_model places your own .glb files (static models get the site's automatic collision). - export_zip writes the ZIP the plot editor imports (My space, Share, Import): the cell lands in the creator's plot on the mainland. Building happens only on mainland plots; there are no standalone worlds. For a whole plot, use new_plot and deploy. - Tezos NFTs are hung after import, from the plot editor, into the frames you placed. ## describe_rules addition for a whole plot (example: plot 12, 32 m) THIS SCENE IS A WHOLE PLOT - Artist plot 12: 32 x 32 m, 4 cells of 16 m (2 x 2), numbered row by row from the north-west: cell 1 is x 0–16, z 0–16. - Every tool takes metres from the PLOT's north-west corner: x and z run 0 to 32, y 0 to 16. This replaces the single-cell numbers below. - The street reaches the plot at [16, 32], on its south side: that is the front. describe_scene walks it from the street. - The site stores the plot cell by cell. A box (wall, floor, slab, step) that crosses a cell border is cut into one piece per cell: it looks and collides as one, keeps its id, and counts once in each cell. Anything else (cylinder, sphere, torus, foliage, a vault across its arch, a frame, a model, a prefab's columns and roof) must lie inside one cell; the tools say where it fits. - LIMITS PER SCENE below are per cell here: each cell holds 500 objects, 128 models from 32 files, 500,000 triangles. - WEIGHT: this plot publishes at most 100 MB of its own files (models, images) and 800 files: 50 MB and 200 files a cell, never more than 200 MB and 800 files without paid extra storage. This, not the 150 MB scene figure below, is what blocks publishing. Tezos NFTs hung in frames are token references and do not count. - plot.json beside the scene names the neighbouring plots, buildings and streets, in the same coordinates. - When it is ready, run validate. The creator deploys it with `node third-life-pack.mjs deploy` and approves it with their wallet; deploy only when they ask. ## Tools (remote server, in working order) ### describe_rules Read this first. The cell (16 x 16 x 16 m, metres, y up, positions are object CENTRES from the north-west corner), angles in degrees, where visitors arrive, the avatar and what it can climb, shapes, materials, collision, helpers, prefabs and every limit. Changes nothing. (no arguments) ### list_drafts The drafts this wallet keeps for agents: id, plot, name, objects, when and by whom each was last saved, and which one is open. Changes nothing. (no arguments) ### new_plot Start an empty draft of the creator's own plot of the mainland and work on it from now on: every cell of the plot, coordinates in metres from its north-west corner, the street entrance and the neighbours as describe_rules tells them. plot is only for the island host, who may name any plot by number; anyone else builds on the plot their wallet owns. Returns the link the owner opens it with. - name: Draft name. - description: A sentence about the scene. - plot: Host only: the plot number, e.g. "5". Default: the wallet’s own plot. ### open_draft Work on another of this wallet’s drafts, by id or exact name (list_drafts). The owner may have changed it from the plot editor since; describe_scene shows what is there now. - draft (required): Draft id or name. ### describe_scene What is built now, in one screen of text: each group with its bounds, a walk test from the arrival point with the game’s own movement (which floors a visitor reaches and which they cannot), the ground still free, and things resting on nothing or frames hanging on nothing. Call it after each round of changes. Changes nothing. (no arguments) ### preview A picture of the scene to check your work: by default a ground-floor plan, an upper-floor plan (or the roof), and the south and east elevations, with a 1 m grid. Plans are cut 1.4 m above their level like an architect’s plan (walls cut dark, what is above left out); green marks where a visitor can stand, red floors they cannot reach. Changes nothing. - views: Panels, up to four: top (everything from above), plan (cut at each of levels), south, north, east, west (elevations). - levels: Floor levels for plan panels, e.g. [0, 3.71]. Default: the levels found. - highlight: Ids to draw strongly, with everything else faded. - format: png (default, an image) or svg (text). ### list_objects The objects in the cell: id, label, shape, position (centre), size, yaw in degrees (or rotation when tilted), color, material, collider (solid), group, and locked for scenery the creator has locked. Filter by group or shape. Changes nothing. - group: Only objects of this group name. - shape: Only objects of this shape. ### add_room The fastest way to rough out a building: four solid walls whose OUTER faces sit on the footprint x..x+width, z..z+depth (x, z = north-west corner), standing on level y, with a door (default on the south side, 1.2 x 2.3 m), windows, a floor slab (default) and optionally a ceiling with holes for stairs. One group. Returns the inside faces of the walls (for add_frames), the door and where the next storey starts (y + height + ceiling thickness). - x (required): West edge of the footprint (minimum x), metres. - z (required): North edge of the footprint (minimum z), metres. - width (required): Size along x, metres. - depth (required): Size along z, metres. - height (required): Wall height above the floor, metres. - y: Floor level the room stands on, default 0. For an upper storey use the nextStorey a lower room returned. - thickness: Wall thickness, default 0.25 m. - doorSide: Wall with the door: south (default, facing arriving visitors), north, east, west or none. - door: Door size and place; at is measured from the wall’s west or north end. Default centred, 1.2 x 2.3 m. - windows: Windows per wall, spread evenly. - windowSides: Walls that get windows; default every wall but the door wall. - window: Size of counted windows (default 1 m wide, 1.2 m tall, sill at 0.9 m). - floor: Floor slab under the room, its top at y. Default true. - ceiling: Ceiling slab on top of the walls, default false. Give it a hole over a stair. - color: Hex colour such as "#b9ab92". Defaults to the material’s colour (warm stone). - material: Surface finish; color still tints it. glass is see-through. - label: Name shown in the Objects list, e.g. "North wall". - group: Group name. A group is selected and moved as one in the editor; an existing group with this name is joined. ### add_wall One straight solid wall along its centreline from [x, z] to [x, z], standing on level y, cut for an optional door and windows (sills and lintels are added). One group. - from (required): Start of the centreline [x, z]. - to (required): End of the centreline [x, z]. - height (required): Wall height, metres. - thickness: Wall thickness, default 0.25 m. - y: Floor level the wall stands on, default 0. - door: true for a centred 1.2 x 2.3 m door, or { at, width, height }. - windows: A count spread evenly, or a list of { at, width, height, sill }. - window: Size of counted windows (default 1 m wide, 1.2 m tall, sill at 0.9 m). - color: Hex colour such as "#b9ab92". Defaults to the material’s colour (warm stone). - material: Surface finish; color still tints it. glass is see-through. - label: Name shown in the Objects list, e.g. "North wall". - group: Group name. A group is selected and moved as one in the editor; an existing group with this name is joined. ### add_floor A solid slab whose TOP is the walking surface at y, over x..x+width, z..z+depth, with holes left open (for stairs). One group. - x (required): West edge (minimum x). - z (required): North edge (minimum z). - width (required): Size along x. - depth (required): Size along z. - y: Height of the walking surface, default 0. - thickness: Slab thickness, default 0.2 m. - hole: A hole to leave open, usually the hole add_stairs returned. - holes: Several holes. - color: Hex colour such as "#b9ab92". Defaults to the material’s colour (warm stone). - material: Surface finish; color still tints it. glass is see-through. - label: Name shown in the Objects list, e.g. "North wall". - group: Group name. A group is selected and moved as one in the editor; an existing group with this name is joined. ### add_stairs A straight solid flight a visitor walks up, climbing rise metres toward direction from 'from' (the middle of its bottom edge). Risers stay at or under 0.18 m by default (a visitor climbs up to 0.28 m). Returns the footprint: leave it open in the floor or ceiling above (hole) for headroom, and the point where a visitor steps off at the top. - from (required): Middle of the bottom edge of the first step [x, z]. - direction (required): The way up: north, south, east or west. - rise (required): Height to climb, usually the next floor level minus y. - y: Level the stair starts from, default 0. - width: Width, default 1.2 m. - tread: Tread depth, default 0.3 m. - maxRiser: Largest riser, default 0.18 m, at most 0.28. - color: Hex colour such as "#b9ab92". Defaults to the material’s colour (warm stone). - material: Surface finish; color still tints it. glass is see-through. - label: Name shown in the Objects list, e.g. "North wall". - group: Group name. A group is selected and moved as one in the editor; an existing group with this name is joined. ### add_frames Hang count empty picture frames evenly along a wall face, for the creator to fill with Tezos NFTs from the Art tab after import. from and to are two points ON THE WALL’S FACE (the insideFaces add_room returns, or a wall’s face line) and must run along x or along z; facing is the way the pictures look (into the room). Frames are not solid and join the group "Frames" unless you name another. - from (required): One end of the wall face [x, z]. - to (required): The other end of the wall face [x, z]. - facing (required): The way the pictures face: north, south, east or west. - count (required): How many frames, spread evenly. - width: Frame width, default 2 m. - height: Frame height, default 1.6 m. - centreHeight: Height of the frames’ centres above the floor level, default 1.6 m. - y: Floor level of the room, default 0. - label: Name shown in the Objects list, e.g. "North wall". - group: Group name. A group is selected and moved as one in the editor; an existing group with this name is joined. ### list_prefabs Ready old-town pieces to place with add_prefab: three small buildings (studio, loggia, gallery room), walls with plinths and cornices, doorways, windows, floors, stairs and a landing, columns, an arcade bay, a portico, roofs, a balustrade, a bench, a cypress planter, a lemon tree, a lamp post and a fountain. Each with its id, size [x, y, z] in metres at yaw 0 (front facing south), the height its lowest part sits above the level it is placed on, and its piece count. Changes nothing. - category: Only this category. ### add_prefab Place one prefab from list_prefabs as one new group. at is the centre of its footprint [x, z]; y is the floor level it stands on (default 0), and its parts keep their real height above it, so a roof lands on 3.5 m walls built at the same level. yaw turns it in degrees (default 0: its front faces south, toward arriving visitors; 90 east, 180 north, -90 west). scale (default 1) resizes it uniformly. Returns its bounds, doorways and stair ends in cell coordinates. - prefab (required): Prefab id from list_prefabs, e.g. "loggia". - at: Centre of the footprint [x, z]. Default the middle of the cell, [8, 8], or in a plot scene of its middle cell. - y: Floor level it stands on, default 0. - yaw: Turn in degrees; 0 faces south (+z). Quarter turns keep it on the grid. - scale: Uniform scale, default 1. - group: Group name; default the prefab’s name, numbered if taken. - models: Use the prefab’s model files where it has them (roof tiles), as the Prefabs shelf does. Default true; false places plain primitives only. ### add_objects Add a batch of primitives in one step: box, cylinder, sphere, torus, vault, foliage or frame (an empty picture frame for an NFT). Each needs shape and position; size, yaw, color, material, collider, collisionOnly, label, group and id are optional. position is the CENTRE in metres from the cell’s north-west corner: x and z 0–16, y is height, so a box of height h on the ground has y = h / 2. size is [x width, y height, z depth] before yaw; yaw is degrees (90 turns the +x side to face north). The whole object must stay inside the cell. Solid objects (default for box, cylinder, vault) block walking and can be stood on. Example, a 10 x 8 m stone floor and its back wall: {shape:"box", position:[8,0.1,8], size:[10,0.2,8], material:"stone", group:"Room"}, {shape:"box", position:[8,1.7,4.1], size:[10,3,0.2], group:"Room"}. repeat makes rows (posts, slats, columns) in one item. All or nothing: if any object is wrong nothing is added and the reply lists every problem. One Undo step. In a plot scene (new_plot) coordinates run across the whole plot from its north-west corner; a box that crosses a 16 m cell border is cut into one piece per cell, and anything else must lie inside one cell. - objects (required): The objects to add, each { shape, position, ... }. ### update_objects Change existing objects by id in one step. Give each id with only the fields to change: position (new centre), offset (added to the centre, e.g. [2,0,0] moves 2 m east), size, yaw or rotation (degrees), color, material (null clears it), collider, collisionOnly, label, group (a name to join or create, null to leave the group) or shape (between box, cylinder, sphere, torus, vault and foliage). Same coordinates and limits as add_objects. All or nothing, one Undo step. Locked scenery cannot be changed. - changes (required): One { id, ...fields to change } per object. ### move_group Move or turn a whole group as one, the way the editor does: offset adds [dx, dy, dz] (e.g. [0, 0.15, 0] lifts it onto a 15 cm slab), to puts the middle of its footprint at [x, z], and yaw turns it in degrees about the vertical axis through that middle. One Undo step; locked scenery cannot move. - group (required): The group’s name, from describe_scene or list_objects. - offset: Metres to move it [dx, dy, dz]. - to: New centre of its footprint [x, z], instead of offset. - yaw: Turn in degrees, counter-clockwise seen from above, about its middle. ### remove_objects Delete objects by id, every member of a group by its name, or both, in one step (one Undo step). Locked scenery cannot be removed. - ids: Objects to delete, from list_objects. - group: Delete every object of this group. ### describe_game_api The API for a plot's own game (teztopia-plot-game/1): events, commands, limits, house rules (no money of any kind), the plot's daily multiplayer allowance, and whether this plot has a game. Read it before set_game. Changes nothing. (no arguments) ### get_game The plot game's code as it is saved in this draft, its size and any problem that would stop it publishing. Changes nothing. (no arguments) ### set_game Save a game in this plot: your own JavaScript (source) or an example ('starter', 'lantern-collect'). It is checked (version and size) and replaces any game the plot had; a portal to the game is added near the entrance unless portal is false or one exists. The code never runs on the server: the owner tests it with preview_link (walk through the portal, choose Play) and publishes it with the plot, signed by their wallet. One Undo step. - source: The game, written against `game` (describe_game_api). - example: "string" - portal: Add a portal to the game. Default true. - portal_at: Where the portal stands, [x, z] in the scene. Default: near the entrance. ### remove_game Remove the plot's game and its portal from this draft. One Undo step. (no arguments) ### undo Undo the last change (up to 30 steps). A whole add, update, remove, helper or prefab call is one step. (no arguments) ### restore_published Replace the open draft with the plot exactly as it is published now (a draft of the owner's plot is started if none is open): to change what is live, or to throw away the changes made since. One step: undo returns to the draft before. The published plot itself is not touched. (no arguments) ### validate Check the open draft the way the site will: the plot and each cell’s limits, whether the wallet still owns the plot, and which model files the owner’s browser must hold. describe_scene tells what a visitor can reach. Changes nothing. (no arguments) ### review_changes Before the owner decides: what the open draft changes against the published plot (objects and groups added, removed and changed, cell by cell, model files, NFT frames), its weight against the plot allowance, and anything that would block publishing. Tell the owner the result in plain words. Changes nothing. (no arguments) ### preview_link A link for the owner to walk the open draft in place on their plot, in their browser, before deciding. Only the signed-in owner of the plot can open it; nothing is saved or published there and their own browser draft is untouched. Give it to the owner with the preview images. Changes nothing. (no arguments) ### deploy Only when the owner says to publish: check the draft the way the site will and give the owner the link that opens it in their plot editor, where they publish it with their wallet's signature. Nothing is published without that signature; this server never holds a key or publishes. Call review_changes and preview_link first, so they decide knowing what changes. Changes nothing here. (no arguments) ### discard_draft Only when the owner says they do not want it: delete a draft for good (the open one unless draft names another) with its undo steps. The published plot is not touched. Cannot be undone. - draft: Draft id or exact name. Default: the open draft. ## Example call {"jsonrpc":"2.0","id":7,"method":"tools/call","params":{"name":"add_room","arguments":{"x":4,"z":4,"width":8,"depth":6,"height":3.5,"doorSide":"south","windows":2,"label":"Gallery room"}}} Invalid arguments return a tool error listing every problem with its path, so fix the whole call at once. ## Scene format JSON Schema: https://internetparadise.xyz/sdk/world.schema.json. "spec": "tezworlds-dev/1", "parcelSize": 16, parcels (cells) with nodes. Shapes: box, cylinder, sphere, torus, vault, foliage, model; a box with galleryFrame: true is an empty NFT frame. Materials: stone, brick, plaster, metal, glass, copper, plywood, painted, concrete, fabric. Prefer the tools to writing the file. ## Limits Per cell: 500 objects; 128 model instances; 32 different model files; 24 live NFT displays; 8 artworks carrying their own file; 16 portals; 500,000 model triangles. Per GLB model: 20 MB; 200,000 triangles; 64 materials; 256 draw primitives; 1,000 nodes; 64 images / 128 textures; one image up to 8 MB and 4096 px a side; 16.8 MP of textures in total; 1,000,000 vertices per accessor; 4 animation clips, 512 channels for a building on a plot (64 for other scenery), LINEAR/STEP, translation/rotation/scale only; no skins, morph targets, lights, sparse accessors or external files. Accepted GLB extensions: EXT_meshopt_compression, KHR_mesh_quantization, EXT_texture_webp, KHR_materials_emissive_strength, KHR_materials_unlit, KHR_materials_specular, KHR_materials_ior, KHR_texture_transform. Draco is decoded only by the plot editor's own import; the SDK and published files refuse it. KTX2, EXT_mesh_gpu_instancing and KHR_meshopt_compression are refused. Builder preparation targets: 180,000 triangles, 24 materials, textures 2,048 px, about 3 MB per model; distant copy 30,000 triangles. The SDK uses files as given and warns above these. Per plot (publish weight): 50 MB and 200 files per cell, ceiling 200 MB and 800 files; signed description 72 KB per cell (min 1 MB, max 1.8 MB). Paid storage: 25 MB add-ons, up to 150 MB (16 m) or 300 MB (larger). NFTs are token references and do not count; their display copies have a quota of 40 MB per cell up to 120 MB. Seats and beds: a node may carry "interaction": { "kind": "sit" | "lie" | "none", "anchors": [{ "at": [x, y, z] (each -0.5..0.5 of the node's size: where the pelvis rests), "yaw": radians (the sitter faces (-sin yaw, -cos yaw) in the node's frame; π faces its front, +z), "drop"?: metres from seat to feet (default: to the box's bottom) }] }. Up to 8 anchors per node and 64 per cell; seat height 0.05 m–1.3 m; the node must be upright. GLB empties named tz_sit, tz_sit_1… or tz_lie become anchors in the builder. Textures: WebP at quality 0.85–0.92, at most 2048 px on the long side (1024/512 for small things), powers of two recommended. ## Optimizing models for the town (read before adding any GLB) Human page with the same content and the whole Blender script: https://internetparadise.xyz/docs/optimize Why: every visitor's browser, often a phone with fifty people in the square, downloads and draws the plot. A render model (a million triangles, 8K textures, dozens of materials) must be brought down before it is placed. Draw calls (one per material per mesh part, doubled for shadows) matter as much as triangles. A visitor's device keeps only so much in detail at once: a phone 600,000 model triangles and 160 draws, a roomy desktop 1,600,000 and 360. Budgets (hard limit / aim for): - One GLB: 20 MB / about 3 MB for a whole building; 200,000 / 180,000 triangles; 64 / 24 materials; 256 / 240 draw primitives; textures 4096 px and 16.8 MP / 2,048 px and 12.6 megapixels, as WebP. - One 16 m cell: 500,000 model triangles in all, 128 model instances from 32 files, 500 objects. A file placed ten times is downloaded once and drawn ten times. - One plot: 50 MB and 200 files per cell, at most 200 MB and 800 files. Targets by object type (recommendations): - Small prop (chair, lamp, vase): 500-3,000 triangles, 1 material, one 512-1024 px texture, under 200 KB. - Large prop (table and chairs, fountain, tree): 3,000-15,000 triangles, 1-2 materials, one 1024 px atlas, under 600 KB. - Sculpture of the creator's own (scenery, not an NFT): 10,000-50,000 triangles, 1-2 materials, one 2048 px texture, under 1.5 MB. - Room interior or small pavilion: 20,000-60,000 triangles, up to 4 materials, one 2048 px atlas, under 1.5 MB. - Whole gallery building: 50,000-150,000 triangles (at most 180,000), up to 8 materials, one or two 2048 px atlases, at most 3 MB. - Everything in one cell: about 250,000 triangles (at most 500,000). NFTs hung from a wallet are not models the agent places; the site makes their display copies. Guiding a non-technical creator, step by step: 1. Ask what they bring: their own model (which program, how heavy), a downloaded one (check they may use it), or nothing (model it with Blender's Python). 2. Install: Node.js 20+ from nodejs.org; the SDK (`curl -O https://internetparadise.xyz/sdk/third-life-mcp.mjs`, `curl -O https://internetparadise.xyz/sdk/third-life-pack.mjs`, `curl -O https://internetparadise.xyz/sdk/teztopia_optimize.py`); `npm install sharp` in that folder for textures in optimize_model (and `npm install draco3dgltf` for Draco sources); Blender 4.1+ from blender.org when there is modelling, baking or a non-GLB file. Blender runs headless: `blender -b --python script.py` (Windows: "C:\Program Files\Blender Foundation\Blender 4.5\blender.exe"; macOS: /Applications/Blender.app/Contents/MacOS/Blender). 3. inspect_model on every GLB: size, triangles, draw primitives, materials, textures, nodes against target and hard limit, share of a cell, reasons it would be refused. 4. Far over (millions of triangles, many materials, 4K-8K textures, modifiers, or .blend/.fbx/.obj): `blender -b --python teztopia_optimize.py -- in.blend out.glb --triangles 100000 --texture 2048`, with `--bake` to bake every material's colour into one atlas and one material. The script removes lights and cameras, applies modifiers, merges duplicate vertices, decimates every mesh by one ratio to the triangle target, joins meshes that share materials, shrinks textures, and exports GLB with WebP textures and no Draco. Tested on Blender 4.1, 4.5 and 5.2. 5. optimize_model {"path": "out.glb", "targetTriangles": 30000, "maxTextureSize": 1024}: the site's own import preparation in Node. Writes out-optimized.glb (or output), never changes the original, reports before and after. targetTriangles only lowers the default 180,000; maxTextureSize is 256, 512, 1024 or 2048. 6. inspect_model on the optimized copy; tell the creator the result in plain words. 7. add_model with the optimized copy, then preview and describe_scene. 8. Always validate before deploy; then review_changes and preview_link; the owner decides and publishes with their wallet. Never upload a creator's files to optimize them; never ask for a seed phrase, private key or password; keep originals. Modelling with Blender's Python: metres (1 unit = 1 m; doors at least 0.8 × 1.82 m, a visitor 1.72 m tall); origin at the centre of the base; walls as boxes, detail in textures; bevels of 1-2 segments at most; one material per surface kind shared across parts (stone, plaster, brick, terracotta tiles, wood: old Europe); delete hidden faces; export with bpy.ops.export_scene.gltf(filepath="house.glb", export_format="GLB", export_apply=True, export_image_format="WEBP", export_draco_mesh_compression_enable=False, export_cameras=False, export_lights=False). From a render scene: apply subdivision at level 0-1 and bake detail into a normal map (Cycles, Selected to Active); textures 2048 px at most; glass, clearcoat, sheen and similar effects are removed from scenery (KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_transmission, KHR_materials_volume, KHR_materials_iridescence, KHR_materials_anisotropy, KHR_materials_dispersion, KHR_materials_variants, KHR_materials_pbrSpecularGlossiness, KHR_xmp_json_ld), so use Alpha Blend for glass; no hair, particles, volumes or procedural shaders (bake them); apply the pose and drop rigs and shape keys. What the import (and optimize_model) does automatically, in order: decodes Draco and removes KHR_materials_clearcoat, KHR_materials_sheen, KHR_materials_transmission, KHR_materials_volume, KHR_materials_iridescence, KHR_materials_anisotropy, KHR_materials_dispersion, KHR_materials_variants, KHR_materials_pbrSpecularGlossiness, KHR_xmp_json_ld (spec/gloss converted to metal/rough), naming what it removed; welds vertices, merges duplicates, removes repeated faces; turns flat-coloured materials into vertex colours; packs textured materials into atlases above 24 materials or 64 textures; joins static parts sharing a material in 8 m sections; simplifies with meshoptimizer to 180,000 triangles (or the target) moving no vertex further than 2 % of the model's size, keeping UV seams and borders; resizes textures to 2,048 px and 12.6 megapixels (colour as WebP, data maps as PNG; a second pass at 1,024 px above 3 MB); packs with meshopt. Nodes named ART_*, DISPLAY_*, FRAME_*, PLAQUE_*, COLLIDER_* or COLLISION_* are never joined or simplified; animated models are not simplified. add_model alone does none of this. Command-line alternatives: npx @gltf-transform/cli optimize model.glb model-web.glb --compress meshopt --texture-compress webp --texture-size 2048 --instance false --sparse false (add --simplify-ratio 0.5 --simplify-error 0.001 for half the vertices; --join-named false to keep named parts). Step by step: weld, dedup, simplify --ratio 0.5 --error 0.001, palette, resize --width 2048 --height 2048, webp --quality 90, meshopt. gltfpack: `gltfpack -i model.glb -o model-web.glb -c -tw -si 0.5 -kn`. Refused: KTX2/Basis textures (also by the plot editor's import), Draco in the SDK and published files, EXT_mesh_gpu_instancing, KHR_meshopt_compression and any other unsupported required extension, .gltf with separate files, skins, morph targets, lights and sparse accessors for scenery. Never --compress draco, --texture-compress ktx2, or gltfpack -tc, -tu, -cz, -mi. Check: inspect_model or https://internetparadise.xyz/docs/check for one model; validate (or `node third-life-pack.mjs scene.json --check`) for the whole plot before deploy. ## Land (for answering owners' questions) A plot is rented 3 months at a time: a renewable tenure, not ownership and not an investment. Rent in tez; the first rent covers the first 3-month term; renewal about 20 % of the first rent per term, at the price in force when renewing; a year is 4 terms for the price of 3. Second plot ×2, third ×4; at most 3 per wallet, 2 touching. Grace 60 days, then the plot reverts (content kept). A rental can be passed on only for a built plot (a published version, not withdrawn) and after 90 days, with a 5 % transfer fee. Payments are final; corrections are refunded by hand. Prices: https://internetparadise.xyz/docs/land. ## Do and don't Do: describe_rules first; preview and describe_scene after each round, showing the owner the image; groups; helpers and prefabs for structure; frames on inside wall faces with add_frames; validate, review_changes and preview_link before the owner decides; deploy, discard_draft and restore_published only on request. Don't: guess units; build from hundreds of tiny boxes; block the street entrance or the gallery sign by the door; claim to hang or buy NFTs; work around limits; copy other people's buildings or brands.