From 5ec3d8319672669902fae4769c04f0c55512b868 Mon Sep 17 00:00:00 2001 From: AlexZ005 Date: Thu, 1 Oct 2026 20:50:17 +0300 Subject: [PATCH 1/2] [docs] 1.19: levels of detail - the LOD section, pack lods, VR force Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/lod.md | 77 +++++++++++++++++++++++++++++++++++++++++++++++++++++ mkdocs.yml | 1 + 2 files changed, 78 insertions(+) create mode 100644 docs/lod.md diff --git a/docs/lod.md b/docs/lod.md new file mode 100644 index 0000000..e8293c1 --- /dev/null +++ b/docs/lod.md @@ -0,0 +1,77 @@ +# Levels of Detail (LOD) + +A **level of detail** is a simpler version of a model that draws instead of the full one when the +model is small on screen. Far-away objects then cost a fraction of their triangles — which is what +keeps a big scene smooth on a phone or a Quest — and up close you still see every detail. + +theprototype.app does this two ways: + +- **Automatically** — any dense model you load (3000+ triangles) gets simplified levels in the + background, built once and shared by every copy. You can switch this off in **Settings ▸ + Simplify distant models** (this device only). +- **A LOD group on an object**, edited in its properties like in a professional 3D package + (Unity's *LOD Group*, Unreal's *LOD settings*). Pack items that ship LOD files come with one + already. A LOD group is part of the scene: it is saved, it undoes, and everyone in the session + sees the same levels. + +## The LOD section + +Select an object and open its **Properties**; the **LOD** section shows its group. + +- **The level bar** runs from 100% of the screen height on the left to 0% on the right. Each + coloured segment is one level — **LOD0** is the object itself, then LOD1, LOD2… — and names its + triangle count. A white tick under the bar shows how big the object is on screen right now, and + a dot marks the level being drawn. +- **Drag an edge** between two segments to choose when the next level takes over. The labels under + the bar read the thresholds (`LOD0 < 30%` means "LOD1 draws once the object is under 30% of the + screen height"). A drag is one undo step. +- **Force LOD** draws one level whatever the distance (*Auto* = by screen size). Use it for a + background prop that never needs full detail, or to check how a level looks. +- **Cull when smaller than the last level's size** stops drawing the object entirely once it is + tinier than the last threshold — good for clutter far away. +- **Show LOD level in the viewport** paints every LOD-managed object in its level's colour + (green LOD0, yellow LOD1, orange LOD2, red LOD3…). Only on your screen. + +### Selecting and editing a level + +**Click a segment** to select that level. While it is selected the viewport **shows that level** +(on your screen only) so you can see what you are editing; click it again — or select another +object — and the object goes back to *Auto*. + +For a selected level you can: + +- **Replace with** another object in the scene, or **drop a model from the Explorer** on the bar — + the level then draws that model instead (e.g. a hand-made low-poly version). +- **Move level** puts the transform gizmo on the level: line a replacement model up with the + original. The object itself does not move; the level's offset is saved with the group. +- **Own material for this level** gives the level its own colour, roughness and metalness. + Without it, a level uses the object's own materials — so a colour change on the object shows on + every level. +- **Triangles %** (generated levels): how much of the original the level keeps; **Rebuild** applies it. +- **Remove level**. + +**Generate levels** builds three simplified levels (50%, 25% and 10% of the triangles) with +meshoptimizer, off the main thread. **+ Level** adds one more; **Remove group** goes back to the +automatic behaviour. + +## Pack items with LODs + +Pack items can ship their own LOD files (made offline by the pack tools). Placing one adds its LOD +group to the object; the level files are only downloaded when the object is first small enough to +need one, and once for every copy in the scene. Pieces placed before their pack had LOD files pick +them up automatically. Pack authors: see the `lods` field in the core repo's `PACKS.md`. + +## In VR + +The VR **Properties** panel has a **LOD** row: it reads the level being drawn (`Auto · LOD1`, or +`LOD2 forced`), and left/right on the stick (or the − / + buttons) cycles **Force LOD** through +Auto, LOD0, LOD1… + +## How it works (for the curious) + +The scene itself never changes: a level is swapped in only while a frame is being drawn, so +picking, physics, the mesh tools and every save always see the full object. A level made from a +pack file is matched to the object **by node name** and draws with the object's own material, +which is why an animated door keeps animating at every level. Switching back to a finer level +needs the object to grow a little past the threshold first (hysteresis), so an object sitting on +an edge does not flicker between levels while you move. diff --git a/mkdocs.yml b/mkdocs.yml index 55ddd1c..e2dc761 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -9,6 +9,7 @@ nav: - Building: - Explorer: explorer.md - Packs: packs.md + - Levels of Detail: lod.md - Prefabs: prefabs.md - Mesh Editing: mesh-editing.md - Splines: splines.md From 89c9c01049918cd5f1ec036d4e38b7b8f64d8c93 Mon Sep 17 00:00:00 2001 From: AlexZ005 Date: Fri, 2 Oct 2026 13:20:32 +0300 Subject: [PATCH 2/2] [docs] 1.19: the new kits, functional pack items, scene switching + Clear scene, toolbar order, FPS/draw calls, VR grabs, SDK additions Co-Authored-By: Claude Opus 5.5 (1M context) --- docs/controls.md | 12 ++++++++++-- docs/module-sdk.md | 22 ++++++++++++++++++++++ docs/modules.md | 3 +++ docs/packs.md | 29 +++++++++++++++++++++++++++-- docs/saving.md | 19 ++++++++++++++++++- docs/vr.md | 6 ++++-- 6 files changed, 84 insertions(+), 7 deletions(-) diff --git a/docs/controls.md b/docs/controls.md index 80702b4..16356ef 100644 --- a/docs/controls.md +++ b/docs/controls.md @@ -31,8 +31,9 @@ If the guess is still wrong on your hardware, pick it yourself: right-click the ### Edit and Interact -The editor has two click modes. Switch with the **Interact mode** cell at the end of the bottom -bar, or press **I**: +The editor has two click modes. Switch with the **Interact mode** cell on the bottom bar (it sits +between the transform tools and Play — the default order is Move, Rotate, Scale, Interact, Play, +Object list, Node editor, Explorer, Animation), or press **I**: - **Edit** (the default) — every click selects, so every object, module pieces included, can be picked and moved. @@ -42,6 +43,13 @@ bar, or press **I**: **Play** is the third mode, entered with the play button as before. +In **Edit inside a running game**, every object can be moved: a body you drop stays where you put +it (it is parked out of the simulation) until you leave Edit. + +**FPS and draw calls** — *Settings ▸ Interface ▸ Viewport* shows a small counter in any mode: +frames per second, frame time, draw calls and triangles. Draw calls turn amber above 120 and red +above 150, the budget of a Quest headset; in VR the same counter is a strip in front of you. + ### Clicking through glass A see-through wall no longer steals the click from what is behind it: shells that are nearly diff --git a/docs/module-sdk.md b/docs/module-sdk.md index 257aec6..fded85f 100644 --- a/docs/module-sdk.md +++ b/docs/module-sdk.md @@ -350,6 +350,12 @@ api.game.addSetting?.({ onChange: (v) => setBoard(v) }); setBoard(api.game.setting?.('board') ?? 'globe'); // the stored choice at load +``` + +A choice row with `onLevels: true` (1.19) is ALSO drawn as tabs above the Levels page in the +headset — Untangle's Globe / 2D board. + +```js api.game.setSetting?.('board', '2d'); // your in-game button writes the same row api.game.onSettingsChange?.((values) => console.log(values.board, values.sfx)); ``` @@ -492,6 +498,22 @@ the scene, keyed by uuid, and `recent` is the last 32 hits in order. It is runti state — a late joiner's log starts empty, so a module that needs history keeps its own through `registerStateSync`. +## New in 1.19 + +- **`api.inScene()`** — false once a scene switch LEFT your module behind (the person chose *Keep* + when opening a scene that does not use you). Core already keeps your levels, help, settings rows, + Restart, music and spawn out of the new game; stand your own drawing and listening down while it + reads false (a gun in the hand, a HUD of your own). +- **`api.behavior`** — `list()` (the functional pack items in the scene: doors, lids, levers, with + their type and whether they are open), `state(uuid)` and `trigger(uuid, open?)` (open, close or + toggle one — replicated like a click). +- **`api.claimInput('sticks')`** — claim BOTH VR thumbsticks (move, turn, teleport stand down) to + read `input().axes` yourself; returns true on a core that knows the scope, so feature-detect it. +- **`api.lod(object)`** handles gain `force(n)` (pin a level; `null` back to automatic) and + `levels()`. +- `api.music` is owned by your module: `stop()` stops only your track, and unloading your module + stops it. + ## Lifecycle - Core modules load at boot unless disabled in the manager; user modules load diff --git a/docs/modules.md b/docs/modules.md index c86e60b..4d9323d 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -11,6 +11,9 @@ Open it from **Menu ▸ Modules**. - **⬇ Download as example** exports a core module as a zip — the best starting point for writing your own. - Peers exchange module lists when they connect and show a toast if a module is missing or a different version on the other side. The session still works, but that module's behavior may differ — treat *same modules everywhere* as part of the session contract. +When you open another scene, the modules the last scene brought can be unloaded or kept — see +[Opening another scene, and modules](saving.md#opening-another-scene-and-modules). + ## What modules can add - **Flow nodes** — new node groups in the palette, driving per-frame effects through the Object Selector like built-in nodes. diff --git a/docs/packs.md b/docs/packs.md index 2e91ed6..68b149f 100644 --- a/docs/packs.md +++ b/docs/packs.md @@ -51,8 +51,33 @@ A kit piece in your scene is saved as a **reference to its pack**: a level of 15 server. A piece you edit (a mesh change, a new colour) is saved in full, as before. Placing a kit piece is undoable like any other object. -Three walkable example levels built from the kits are in **Templates ▸ General**: *Castle -Courtyard*, *Forest Clearing* and *Tavern Interior*. Press Play to walk them. +Walkable example levels built from the kits are in **Templates ▸ General**: *Castle Courtyard*, +*Forest Clearing*, *Tavern Interior*, *Wizard's Tower*, *Market Town Square* and the *Architecture +shell*. Press Play to walk them; their doors open. + +## The kits (1.19) + +| Pack | What is in it | +|---|---| +| **Interiors: Home, Tavern & Office** | 30 pieces of furniture, kitchen, bar, lights and decor, plus wall trims (skirting, wainscot, cornice) that snap to the architecture kit's walls | +| **Town & Market** | 27 pieces — seamless street tiles (road, curb, corner, crossing, sidewalk), a fountain, market stalls, a well, lamps, a clock tower top and a garden gate that opens | +| **Interactive Kit** | 19 pieces that **move when you use them**: doors with their frames, gates, a portcullis, a trapdoor, shutters, a chest, drawers, a cabinet, a lever, a pressure plate, a wall button, and an ambient torch, banner and ceiling fan | +| **Arcane Study** | seven wizard's-study props — an alchemy table, a potion shelf, a crystal ball, a lectern, a telescope, an armillary sphere, a rune rug | + +**Doors, lids and levers.** A piece with a ▶ badge in the Explorer is *functional*. In Edit it +rests (a door stays shut, nothing plays by itself — placing or loading it never starts an +animation). In **Interact** or **Play**, click it (or point the VR laser at it, poke it, or knock +on it) and it opens with a sound; click again and it closes. Everyone in the session sees the same +door, and you can walk through an open one. A sliding door may open as you walk up to it. Only +ambient pieces (a banner, a fan, a torch flame) move on their own, and only in Interact and Play. +The Animation panel can preview a clip in Edit without changing your scene. + +**Levels of detail.** Every pack piece comes with lighter versions of itself that are drawn when +it is far away. See [Levels of detail](lod.md) to force a level, edit one or tune the distances. + +**Draw calls.** Every copy of the same pack piece is drawn in one go (*Settings ▸ Performance ▸ +Draw repeated kit pieces together*, on by default) — a furnished tavern stays inside a headset's +budget. ## For pack authors diff --git a/docs/saving.md b/docs/saving.md index a75094d..512199b 100644 --- a/docs/saving.md +++ b/docs/saving.md @@ -22,7 +22,7 @@ had nothing open will not close the panels *you* have open. **Menu ▸ Templates** opens a picker of ready-made scenes, in four tabs: -- **General** — starting points, including a **Blank** card that clears the scene (it asks first). +- **General** — starting points and walkable kit levels, including a **Blank** card that clears the scene (it asks first). - **Examples** — worked showcases to pull apart and learn from. - **Games** — playable scenes. A game is a scene plus, sometimes, a module: a card wears a *Needs …* badge when it depends on one, and loading it offers to install it — every player needs their own copy. **Towers**, the first one, is co-op crate stacking built from flow nodes, the HUD and the Collectibles module. **Stars Room** is the second: a zero-gravity room of glowing stars you [knock](physics.md#the-knock) about, with an optional round on the P menu — pure app, nothing to install. - **Community** — scenes other people published from the app; see [Community](community.md). @@ -31,6 +31,23 @@ Templates load through the same path as a `.tpscene` file, so with peers connect Each card also has a small **save to Library** button in its corner (*Save "Towers" to your Library as a new scene*). It files the starter as a new scene in your [Explorer](explorer.md) without loading it — the scene you have open stays as it is — so you can collect a few and open them later. +## Opening another scene, and modules + +A game usually brings a module with it (Waves brings *Waves* and *Health*). When you open another +scene that does not need them, the app **asks**: *Unload* (the default — the modules are switched +off and the new scene starts clean), *Keep* (they stay loaded; their music, menus, levels and spawn +stop counting until you go back to their scene), or *Cancel*. Tick *Remember my choice*, or set it +in **Settings ▸ Scene ▸ When opening another scene** (Ask / Keep modules / Unload modules). Modules +you installed as tools and no scene uses are never asked about. Opening a scene that needs a module +you unloaded offers to turn it back on. + +**Clear scene** asks what to clear: *Clear objects* (the default), or tick *Also reset the game +setup and unload its modules* to **Clear everything** — the game's menu, HUD, flow nodes, play and +physics settings, sky and look go too, so no leftover Menu or Play button stays behind. + +Big scenes **load without freezing the app**: a progress bar shows what is loading and how far it +has got, pieces stream in, and *Cancel* stops the load and takes back what it had added. + ## Scene (`.tpscene`) — recommended A `.tpscene` file is a zip bundle containing everything a scene needs: diff --git a/docs/vr.md b/docs/vr.md index ea9aae1..522411c 100644 --- a/docs/vr.md +++ b/docs/vr.md @@ -87,12 +87,13 @@ Grid toggle, **World 1:1** (reset a scaled/rotated world grab), **Settings**, ** - **Move** — push the left thumbstick. With **VR flying** on, forward follows where your controller aims; otherwise it stays level. Hold the **left grip** to switch the stick to panning and elevation. - **Teleport** — push the **right thumbstick up** to arc a beam, release to blink to the landing spot (on the ground or any upward-facing surface). Toggle teleport in Settings. - **Snap-turn** — flick the right thumbstick left/right to rotate in fixed steps. The **snap angle** is Off / 15° / 30° / 45° (default 45°), shown live in the Scene radial and VR Settings; **Mirror snap turn** flips the direction. -- **World grab** — grip with **both hands in empty air** to grab the whole world: pull your hands apart/together to scale, twist to rotate, move to reposition. **System ▸ World 1:1** snaps it back to normal. +- **World grab** — grip with **both hands in empty air** to grab the whole world: pull your hands apart/together to scale, twist to rotate, move to reposition. **System ▸ World 1:1** snaps it back to normal. Holding the world with **one** grip, push the stick **up/down** to send it away or bring it closer, as with an object. ## Grabbing, scaling and stretching - **Grip** an object to grab it. The default *rigid* grab treats the controller as a handle — the grabbing hand's thumbstick reels the object nearer/farther and scales it. (Other grab styles are available via **System ▸ Grab mode**.) -- **Two hands** on the same object scales it uniformly by the distance between them. +- **Two hands** on the same object scales it uniformly by the distance between them. Two hands on **two different** objects hold one each (Towers' blocks): letting go of one never freezes the other. +- In **Edit**, walls and floors are scenery and a grip on them moves the world — **select** one first to grip it. - **VR Stretch** — non-uniform, per-axis scaling. From the Edit menu, grab the **W/H/D slider handles** and drag horizontally to stretch that axis; the result is baked when you confirm. - **Box Select** (Tools ▸ Box Select) — pull the trigger to anchor one corner, drag out a box, release to select everything inside it. @@ -143,6 +144,7 @@ Reachable from **System ▸ Settings** in VR, and mirrored in the desktop **Sett | Hold to move vertex | on / off | | Refresh rate | Max / 90 / 120 Hz | | Peer hand style | Model / Hands / Spheres | +| FPS and draw calls | on / off (a strip in front of you; draw calls red above 150) | | My hand model | any GLB in your library | | VR menu on left | on / off | | Passthrough (AR) | on / off (applies next entry) |