Artifacts
An artifact is one renderable file — an HTML page, a React component, a Markdown doc, an SVG, a Mermaid diagram, or a code snippet — that you push from the terminal and view as a live page in the dashboard.
Preview spacing
Artifact previews start with zero page margin and padding. This applies to the
shared renderer and the default HTML document inside its isolated iframe.
HTML and React authors can add spacing explicitly within their content; the
preview does not add an outer gutter. To show an image edge to edge, remove
padding from its authored container and use display: block on the image.
Fit preserves the image's aspect ratio, so a differently shaped viewport can
still leave unused space; zero padding does not crop or stretch the image.
Reference an artifact from a Note (development preview)
In the development UI, click the #… ID badge in the artifact header to copy
the complete :artifact[namespace/id] reference. The badge displays only the last
six ID characters; the copied reference includes the owner namespace and full ID.
This copy action does not create a share link or change permissions.
Use the owner namespace and stable artifact ID returned by the artifact CLI.
Brackets hold primary content; optional named attributes belong in braces, following
the remark-directive extension, not core CommonMark.
DreamLake defines the resource semantics. Saved :artifact{namespace="geyang" id="pitch-deck"}
and #artifact:geyang/pitch-deck also work in the local development
UI. The tag resolves the title and opens the artifact panel to the right of the Note without changing
permissions or visibility. Static API HTML preserves the reference as an unresolved,
atomic source span; it does not embed artifact content or share-token URLs.
Production deployment is not yet verified. See Notes reference syntax.
Slide and section reference syntax
:artifact[geyang/pitch-deck#slide-3] retains an existing target ID; #/3 is
valid only if the artifact defines that route. Clicking sends the fragment to
the reusable panel through dreamlake.route.hash, retaining its running iframe. See fragment syntax.
Browsing in the app
/<namespace>/profile?tab=artifacts and /<namespace>/artifacts reuse the same
Artifacts 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.
Shared with me, trash and modification controls remain restricted to permitted member views. Public artifacts can be read without sign-in. Private share links require the recipient to 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=artifacts
and signed-in readers to /<namespace>/artifacts. Details opened inside a project
retain their return-to-project action. There is no extra sign-in navigation bar.
Push one
That's it. The CLI prints an open link — click it to see your artifact
rendered at dreamlake.ai/<you>/artifacts.
| Kind | File |
|---|---|
html | Any self-contained page |
react | A component file that defines App |
markdown | .md docs |
svg / mermaid | Diagrams |
code | Anything else — rendered with syntax highlighting |
Version it
Push the same --id again and you get a new version — nothing is overwritten,
and the viewer has a version picker.
Share it
Artifacts are private by default. Two ways to open them up:
| Command | Who can view | |
|---|---|---|
| 🔒 private | (default) | Only you and namespace members |
| 🔗 share link | push --share | Signed-in recipients with a valid share token |
| 🌐 public | push --visibility public | Anyone, no login |
You can also toggle visibility and copy links from the artifact's page — the Share button does the same thing.
Delete it (safely)
delete is a soft delete: the artifact moves to your gallery's trash tab
and any share link stops working. Restore it any time — or erase it forever.
Let Claude do it
Add the artifacts skills and ask Claude to "push this dashboard as a dreamlake artifact and share it":
Install both skills: one publishes, the other prepares content for the offline
rendering frame. To update both, run git -C ~/dreamlake-skills pull --ff-only.
Use a project's .claude/skills/ directory for project scope. If a skill already
exists, inspect and preserve local edits before replacing it with a symlink.
Next steps
Every flag — ids, kinds, namespaces, visibility.
The REST endpoints behind push, share, and trash.
Artifact paths and local routing
The artifact render iframe uses a meaningful resource path and ordinary local query/fragment state:
There is no internal instance ID in its URL. The path identifies the resource; it is not authorization. The DreamLake viewer performs the authorized content read, then sends the content to this isolated frame through a validated handshake. The frame never receives the viewer's authentication or share token.
The corresponding shareable viewer link is:
Only this outer viewer query uses art. to distinguish artifact state from
host parameters such as share. The fragment is ordinary #overview on both
URLs. Earlier development links using #art=overview are still read, but new
links use the plain fragment. The art. prefix never reaches the frame query.
Opening the frame address directly shows an explicit embed-only page with a
link to the authorized DreamLake viewer. It does not fetch private content,
invent a public read endpoint, or copy capability query fields into that link.
Public/private/share-link rules continue to be enforced by the viewer and API.
Ad-hoc Note/file previews have no catalog identity and use /_preview; catalog
thumbnails and artifact detail viewers use the actual namespace/artifact path.
Inside HTML and React artifacts this becomes dreamlake.route.search === '?slide=3&view=chart' and dreamlake.route.hash === '#overview'. Read strings
with new URLSearchParams(dreamlake.route.search). Values can contain Unicode,
spaces, JSON text, or other strings; use URLSearchParams to encode queries
and encodeURIComponent for a fragment when building a URL. Repeated keys and
empty values are supported. Parse numbers/JSON and validate their meaning in
your artifact. Route data is public, user-controlled state, never a secret.
navigate({search?, hash?}, {replace?: boolean}) merges omitted fields with
the current route and returns a Promise. Set a field to '' to clear it.
It pushes browser history by default; {replace: true} replaces the current
entry. subscribe(callback) returns an unsubscribe function; callbacks read
the new snapshot using getSnapshot() or the search/hash getters. React
artifacts can use React.useSyncExternalStore(route.subscribe, route.getSnapshot).
Use an effect cleanup for other subscriptions.
Back/forward and incoming route changes update the running artifact without
reloading its iframe or resetting forms, React state, or WebGL scenes. The
outer render frame's location.pathname, location.search, and location.hash
reflect the clean artifact address. Use dreamlake.route for navigation without
reloads and for a common API across HTML and React. HTML still runs inside an
opaque, sandboxed about:srcdoc child; its own location is not the outer frame
URL. The route API supplies the same values without weakening that sandbox.
The host owns browser history; the frame mirrors route changes with
replaceState, preventing duplicate history entries. Reloading the iframe
performs a fresh handshake and reloads authorized content for the same path.
Directly assigning location.search in React reloads the frame; prefer
route.navigate to preserve component state. Native React fragment changes
mirror to the host using replace semantics; native HTML anchors stay in the
opaque child. Use the route API when an HTML route should survive sharing.
Only the standalone artifact detail page binds this API to browser history. Gallery thumbnails, file/Note previews, and project-embedded viewers do not inherit the surrounding page's query/fragment. Interactive previews can use the route API locally. The detail Share/Copy link includes the current route. Public links contain no share token; private sharing adds only the intended read-capability token. Updating a route preserves host authorization in the address bar but never exposes it to artifact code.
Parameter names (after removing art.) must match
[A-Za-z][A-Za-z0-9_.-]{0,63}. Reserved names, case-insensitively, are share,
token, auth, authorization, cookie, project, namespace, instanceId,
__proto__, prototype, constructor, and dreamlake, including names
followed by ., _, or -. Search plus hash is limited to 8192 characters.
Invalid API navigation rejects; invalid link parameters are ignored and an
oversized link route becomes empty. Host parameters such as share, auth,
and project fields are never blanket-forwarded. A parameter is ordinary data,
not permission to query private resources or escape the sandbox. The existing
query/download bridge and its authorization/confirmation rules still apply.
For a deep link from a Note, use an ordinary Markdown link with this URL, or
:artifact[namespace/id#slide-3] to open its hash route in a right-hand panel.
Do not put a share token inside rich-reference attributes.
This contract requires the companion frame and app changes. Release the frame
first, including its SPA fallback (/* /index.html 200), then the app. The new
frame accepts old root /#af... handshakes for existing hosts; only legacy root
URLs interpret the fragment as protocol state. Modern paths use a per-document
boot challenge and host instance identity exchanged exclusively in messages,
checked together with the source window and allowed/pinned parent origin.
Repeated readiness for the same document does not reinitialize the artifact.
After reload, messages from the previous document cannot complete new requests.
The new host can answer an old frame's ready message if that renderer loads, but older frame deployments may lack the clean-path fallback and route API. Do not deploy the host before the new frame is verified. Source validation does not mean this feature is deployed. No server API or CLI change is required.
Artifact panels in Notes (development preview)
Use :artifact[namespace/id] to open the shared artifact viewer beside a Note,
including Notes within a project. Append the artifact's own hash route to select
a slide: :artifact[geyang/landing-pages#slide-3]. Clicking a second reference to
the same artifact selects its existing panel and applies the new fragment. The
artifact receives it through dreamlake.route.hash; its own code defines what
that fragment means. The surrounding Note/project URL stays unchanged.
This is the same viewer used by standalone artifact pages and project items, including version selection, preview zoom, and permission-checked management controls. Closing the panel leaves the Note open. Tags grant no access, and never contain a share capability. Full artifact links remain available with Control/Command-click. These panel changes require the companion UI release; publishing these docs or uploading an artifact alone does not deploy them.
Manage an existing link
CLI 0.32.4 adds artifact share get/create/revoke and artifact visibility
without another upload. Inspect with get before changing access and after the
requested change. Follow the complete CLI sharing recipe.
Omitting --share on a later push preserves the existing token; it does not
stop sharing. Use dreamlake artifact share revoke <id> to clear the token.
Revocation blocks link-derived access while sharing is disabled; recorded
recipients may regain access if sharing is enabled again. Public visibility
and namespace membership are independent of the link.