{/* The Fig tags come from the site-wide mdxComponents map in
    site.config.ts — no import needed. Beyond the install commands,
    this page carries no code: every SDK call it describes is written
    out in /annotations/reference. */}

# Annotations

  An annotation is where your **labeled data** lives — your workflow does the labeling, the
  annotation stores its output. One episode is one raw video plus any number of annotation layers:
  anything you can pin to that video's clock. Layers are independent and open-ended — send what you
  have, add the rest later.

## Public catalog reads

`GET /namespaces/:slug/annotations` accepts requests without an Authorization
header. Anonymous callers and authenticated nonmembers receive only live public
annotation rows; namespace members retain access to their private rows. A supplied
invalid or expired token returns 401.

Public annotation details (`GET /namespaces/:slug/annotations/:name`) and
content reads (`POST /namespaces/:slug/annotations/:name/presign-read`) also accept
anonymous requests. Both check the annotation's current visibility. Private,
missing and deleted annotations return 404 to callers without access; namespace
members can still read their private annotations. Presigned reads retain the
existing path validation and expiry limits. Upload credentials, creation,
editing and deletion still require authentication and membership.

## Browsing in the app

`/<namespace>/profile?tab=annotations` and `/<namespace>/annotations` share the
same catalog. Personal owners and organization members see the resources and
operations permitted to them; anonymous visitors and visitors to someone else's
namespace see public annotations only. Profile has an identity rail, while the
application has resource navigation for the URL's namespace.

Public details open without a sign-in redirect and retain the namespace sidebar.
The detail header returns anonymous readers to the Profile annotations tab and
signed-in readers to `/<namespace>/annotations`. Embedded viewers return to their
containing project. See [Profiles and workspaces](/workspaces.md).

## Prerequisites

```bash
curl -fsSL https://dl.dreamlake.ai/install.sh | bash   # the dreamlake CLI
pip install dreamlake dreamdb   # SDK + storage engine
brew install ffmpeg             # transcoding (any install method works)
dreamlake login                 # browser sign-in; CI uses DREAMLAKE_API_KEY
```

Windows, what the installer puts where, release channels, and auto-update:
[Install](/index.md#install).

## Upload it

One call. The video is transcoded for the browser, each layer is stored
against its clock, and adding a layer later just means passing one more
argument. Give the episode an id you'll recognise — that's the handle for
coming back.

## Keep adding

Open an annotation by name on any day and add to it. Revisions never overwrite —
newest wins, history stays.

| Later, you can                    | Effect                                         |
| --------------------------------- | ---------------------------------------------- |
| add another episode               | the annotation grows                           |
| revise a layer                    | newest wins, old versions kept                 |
| add a layer you skipped           | it shows up on an episode you already uploaded |
| add a layer type that ships later | same thing — just another revision             |
| add a camera angle                | views share one clock; video is add-only       |
| make it public                    | anyone can open it, no login                   |

Nothing you upload today has to be re-uploaded to benefit from what ships
tomorrow.

## Watch it

Open the web app → **Annotations** → your annotation → your episode.

How a layer is drawn follows from how it's pinned — which is why the list can
grow without the picture changing:

| A layer pinned to | Is drawn                                       | Shipping today                     |
| ----------------- | ---------------------------------------------- | ---------------------------------- |
| a frame           | on the picture, tracking playback              | joint skeletons, 3D reconstruction |
| an interval       | as labeled bars on the timeline; click to seek | action segments                    |
| the whole episode | as episode metadata                            | task labels                        |

Each is optional. The player shows what you have and skips what you don't —
a bare video simply streams.

## When there's no overlay yet

Every annotation page has two views, and the second one always works.

**Preset view** is what the last section showed: the annotation's type label
matches a preset, and you get the player with its overlays.

**Raw tracks view** ignores presets and lists every track straight off the
manifest — name, kind, values along the timeline. Label, JSON, embedding,
video; it doesn't matter.

| If your data        | You get                                           |
| ------------------- | ------------------------------------------------- |
| matches a preset    | the rendered view, overlays and all               |
| doesn't, or not yet | the raw track view — nothing hidden, nothing lost |
| gets a preset later | the rendered view, with no re-upload              |

So a new kind of data is **useful the day you upload it**.

## Bring your own schema

The same machinery with the lid off: declare any columns you like — sensor
readings, JSON, images, embeddings — anchored to timestamps, or to row
numbers when your data has no clock. It's also the escape hatch when the
layer you need doesn't exist yet.

| Rule                    | What it means for you                                 |
| ----------------------- | ----------------------------------------------------- |
| append-only, write-once | a value at a given time and column is never rewritten |
| one commit per write    | send batches, not one point at a time                 |
| one writer at a time    | parallel writers to the same annotation will clash    |

Custom annotations appear in the catalog under their own type label; today
you read them back through the SDK.

## Share it

Annotations are **private** by default.

|                        | Who can view                      |
| ---------------------- | --------------------------------- |
| 🔒 private _(default)_ | you and members of your namespace |
| 🌐 public              | anyone, no login                  |

Names can be scoped to a team, too: a bare name is yours, an organisation
prefix targets that org, and membership is checked per request.

## Let Claude do it

Add the [annotations skill](https://github.com/dreamlake-ai/dreamlake-skills) and
skip the SDK — describe what you want, it makes the calls:

| You say                                                          | It does                                     |
| ---------------------------------------------------------------- | ------------------------------------------- |
| _"upload this clip with its hand skeletons and action segments"_ | creates the annotation, uploads the episode |
| _"add the 3D reconstruction to ep-001"_                          | fills in the missing layer                  |
| _"add a wrist camera to ep-001"_                                 | attaches the second view                    |
| _"make this annotation public"_                                  | flips visibility                            |

## Next steps

    The manual — every method, argument and data shape, with the code this page leaves out.

    Every layer's exact fields, including 3D reconstruction.
