Envs
An env is a simulation environment — a directory holding one MJCF scene or one URDF robot, plus its assets — that you push from the terminal and open as a live, interactive 3D page in the dashboard.
Browsing in the app
/<namespace>/profile?tab=envs and /<namespace>/envs reuse the same
Environments catalog. Your own namespace and organizations you belong to show
resources and actions allowed by your permissions. Signed-out visitors and
signed-in visitors to other namespaces see public resources only, without
creation or modification controls. Profile uses an avatar rail; the application
uses resource navigation for the namespace in the URL.
Your own Envs catalog also includes recent environments from your organizations. Public environments and valid Env share-token links open without sign-in.
The application sidebar shows the resource owner's avatar and links, including for anonymous public readers. Your signed-in identity and personal/organization switcher are separate from that owner. See Profiles and workspaces.
The detail header returns anonymous readers to /<namespace>/profile?tab=envs
and signed-in readers to /<namespace>/envs. Details opened inside a project
retain their return-to-project action. There is no extra sign-in navigation bar.
Generate with chat
Members can also create and edit envs from the browser, by prompting an embedded agent that runs the scene-generation skill. The chat panel ships with the web app — it appears once an app deployment that includes env chat reaches your server:
- In your namespace's Envs catalog, click + new env — in the page
header next to the Environments/Libraries switch, and offered again by
the empty catalog's placeholder. One click opens a fresh draft with an
auto-minted name (
env_xxxxxx) — no dialog, nothing to type first, and nothing exists on the server until the agent's first successful push. - The draft opens straight into the intro composer — describe the
scene there; the agent sources assets, measures, composes, validates,
and publishes with
dreamlake env push. - On the first successful push the draft becomes the saved preview — the interactive viewer on the pushed version, chat still beside it.
- Follow-up prompts create new versions of the same env. The viewer tracks the latest; picking an older version in the header pins it, and a "vN available" button jumps back to latest.
- Editing an existing env works the same: open its page as a member and prompt the chat panel next to the viewer. Read-only viewers, share links, and anonymous visitors never see the chat.
- To grow a new env out of an existing one, start from the catalog, not from the source env's page — the chat edits the env whose page it sits on. Click + new env for a fresh draft, then ask it to start from the source env at a pinned version; the source env keeps its own versions, untouched (details in the Quickstart).
The env chat opens in Auto permission mode, so one prompt can carry
through the whole workflow — the agent runs the scene tools and
dreamlake env push without per-command approval. The composer's
permission control still works as usual: switch to Ask permissions or
Plan mode for a read-only conversation (the agent inspects and answers
but does not generate or push), and switch back to Auto when you want it
to build. A read-only choice is respected for as long as you keep it — the
page sets the mode only once, on open, and never overrides your selection.
Env membership still governs what a push may touch: the mode routes what
the agent may run, not what your account may write.
The install-and-use guide for the same workflow from a local agent — ordinary create / edit / reuse prompts included — is the Scene Generation Quickstart.
Troubleshooting the preview when running the app from source. If the
viewer panel shows an error fallback instead of the scene and the console
logs R3F: Hooks can only be used within the Canvas component!, that is a
dev-server fault, fixed in the app source on 2026-09-29: the dev server
could load two copies of the 3D renderer and which copy a session got
depended on load order — so the crash appears and disappears between
checkouts, and its absence on one run proves nothing. If you see it, your
source checkout predates the fix: update to a checkout that carries it and
restart the dev server. In that source's dependency graph the production build
resolves a single renderer copy, which bounds the fault to the dev server
— an inference about the current source only, not an audit of anything
previously deployed. Count the scene as loaded only when its actual
geometry is visible and the simulation controls respond; that console
error is failure evidence, and a page shell or a bare <canvas> is not
success — the canvas can mount and then unmount again while the model
loads.
Push one
The entry file is auto-detected — the one root-level *.xml/*.mjcf
containing <mujoco>, or (with no MJCF around) the one root-level *.urdf
containing <robot>, which also sets the env's type to urdf. Relative
<include>, <mesh file="…"> and package:// references keep working
exactly as they do on disk. The CLI prints an open link.
| Flag | What it does |
|---|---|
--entry scene.mjcf | Pick the entry when there are several candidates |
--type isaaclab | Simulator family — stored and pullable; mujoco and urdf have viewers |
--visibility public | Anyone can open the viewer, no login |
--name, --title | Identity (defaults to the directory name) |
--thumbnail cover.png | Set the gallery cover yourself (PNG ≤ 512 KiB) — see Thumbnails |
Version it — only changes upload
Push the same env again and you get v2. Files are content-addressed, so unchanged meshes and textures are never uploaded or stored twice — the CLI tells you exactly what moved:
Drive it
For a mujoco env the viewer is a real simulation, not a screenshot: the engine runs on load, and the toolbar gives you play / pause / reset / speed.
- Sliders — every actuator (
ctrl, with its real range) and every hinge/slide joint, straight from the model. - t = 0 is your authored initial state — when the model defines a
<keyframe>, the viewer opens at (and reset returns to) keyframe 0, including itsctrl; without one it uses the compiled defaults (qpos0). Keyframe honoring is a source change awaiting the next viewer deployment: the prior source baseline (and its wasm runtime) opens at qpos0 regardless of keyframes, so until the deploy — verify in the app — expect qpos0. - ⌥ / Alt + drag — pull any body with a mass-scaled spring force, like the MuJoCo app's perturbation.
- files — the version's full file listing, entry highlighted.
- The first member visit renders the gallery thumbnail — see Thumbnails for how the angle is chosen and how to control it.
A urdf env opens as a poseable robot instead — no physics, pure
kinematics: every non-mimic revolute / continuous / prismatic joint gets a
slider with its real limits, dragging a link in the scene rotates its
joint directly (orbit pauses while you hold it), and reset returns the
pose to zero. Meshes referenced as relative paths or package:// URIs
resolve against the pushed directory.
Thumbnails
The env grid's cover image is rendered in the browser the first time a member opens a new version: a fixed 16:10 PNG with a transparent background, at the scene's initial (t=0) pose — physics is held until the capture, so the cover shows the authored t=0 state (see Drive it), not half a second of free fall.
The camera angle is chosen from the scene itself, in priority order:
-
A camera named
thumbnail— add one to your MJCF and the cover (and the viewer's opening shot) is exactly that camera: -
The first
<camera>in the model (including<include>d files) — scenes authored with a hero camera need no rename. -
The free-camera stance MuJoCo's own viewer would use —
<visual><global azimuth="…" elevation="…"/></visual>plus<statistic center="x y z" extent="…"/>when authored. This is the cheapest lever: two lines, and the cover matches what you see insimulate: -
A geometry fit — bounding sphere of all geoms (ground planes excluded), from a three-quarter angle. URDF robots always use this fit.
Two overrides beat all of the above:
- The camera button in the viewer toolbar (members only, latest version): orbit to any angle and click it — that exact view becomes the cover, and the angle is remembered, so future versions auto-capture from it too.
dreamlake env push --thumbnail cover.pngstores your own image (≤ 512 KiB PNG) and marks it manual, so the viewer won't overwrite it for that version. Works on a no-change push (thumbnail-only update).
Pull it back
Every file is verified against its content hash on the way down — the directory you get is byte-identical to the one that was pushed.
Env layers
An env can also be composed from other envs. A layer stack
(dreamlake.layers.json) is an ordered list of ops — one flat object
per line, in the vocabulary of vuer's imperative updates — and
materializes into an ordinary mujoco env. No layer has a special role,
and later ops win; swapping the gripper is editing one line and
re-pushing. The pushed version carries both the flat artifact (what every
viewer and SDK reads) and the pinned stack, so any composed env can be
reopened, edited, and recomposed later.
| op | what it does |
|---|---|
Merge | union the env's MJCF into the stack — a same-name collision is an error |
Attach | graft the env's subtree at a target under the identity root key (right makes right:palm), with a mount pose and joint mode |
Update | inline sparse opinions: key addresses one element, every other prop is an MJCF attribute — nothing else is touched |
Remove | delete the addressed element and its subtree — drop the line and it's back |
Patch | Update-style opinions from a sparse-MJCF file or env, for big opinion sets |
src is one string: ns/name[@v] is a registry env (unversioned floats),
a ./-prefixed path is a local directory or file.
Materialization is a real MuJoCo build, so dreamlake env compose
delegates it to the engine in dreamlake-py — install it with
pip install "dreamlake[compose]" (Python + MuJoCo) on the composing
machine. Push / pull / list need no Python.
Every field, the exact semantics, and six annotated stacks: Env Layers Reference.
Under the hood
Uploads go straight to storage with short-lived scoped credentials, and reads
are presigned URLs — env bytes never pass through the API server. The
read side is two plain REST calls (…/versions and …/versions/:v), so any
HTTP client can list and download an env without special tooling.
Delete it (safely)
Let Claude do it
Add the envs skill, point at a repo, and say "push the MuJoCo scenes in here to DreamLake":
Update with git -C ~/dreamlake-skills pull --ff-only. If a skill already
exists, preserve local edits before replacing it with a symlink.
The dreamlake-envs skill does the part that isn't a single command:
extracting a self-contained directory from a scene that references
meshes outside itself (collecting the robot folders, rewriting the relative
paths), verifying the result still compiles before pushing, and running the
pull-back round-trip check after.
Next steps
Recorded teleop episodes don't live here — they play back inside sources, each dataset carrying its own model snapshot, with the env itself unchanged: visualize a source.
One skill install, then build / edit / reuse scenes with ordinary prompts — locally or from the env page's chat.
The dreamlake.layers.json contract — merge / attach / override, field
by field, with annotated stacks.
Every flag — names, types, entries, visibility, limits.
The REST endpoints behind push, versions, and presigned reads.