File size: 8,876 Bytes
9f57754
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
# Local studio API

[← Meridian](../README.md) · [Studio and deployment](studio.md) · [Method](method.md)

The FastAPI service exposes the same preparation and rendering operations used by the studio.
This is a development API for a trusted, single-GPU deployment—not an authenticated multi-user
service. Requests are plain JSON except for multipart upload. All source indices refer to the
**normalized 24 fps clip**, not the original upload's timestamps.

## Request flow

```text
/upload or /sample → /prepare → /warp → inspect → /render → /job/{job} → /take/{job}/{name}
```

`/prepare` must populate the source-span cache before `/warp` or `/render`. Keep the same `clip`,
`start`, and `span_end` across those calls. If that cache entry is evicted or the service restarts,
prepare again. Do not change requests while assuming a previously inspected preview still applies.

## Shared fields

| Field | Meaning |
|---|---|
| `clip` | ID returned by `/upload` or `/sample`. |
| `start` | First source frame of the prepared span, inclusive. |
| `span_end` | Last source frame of that span, inclusive. Must satisfy `0 <= start < span_end < clip.frames`. |
| `frames` | Output length. Use one of `73, 90, 107, 124, 141, 158, 175, 243` for generation. |
| `pivot` | Optional `[u, v]` in normalized source-image fractions; default `[0.5, 0.5]`. Sets the depth-scale neighborhood. |
| `pivot_frame` | Source frame at which to measure pivot depth; set it explicitly, normally to `start`. |
| `seed` | Generation seed, default `1234`. |
| `path` | List of at least two camera keys. |

The current API's per-endpoint validation is limited; unsupported output lengths may fail only when
loading conditioning assets. Validate requests before submitting expensive GPU work. Choose a
continuous source span: the browser avoids detected cuts, but the API does not enforce that policy.

### Camera keys

| Field | Meaning |
|---|---|
| `pos` | `[x, y, z]` position in the coordinate frame of the source camera at `start`, in units of `zm`. |
| `look` | Look-at point in the same frame and units. |
| `src` | Absolute source-frame index, within the prepared span. |
| `t` | Output-frame index. First key is `0`, last is `frames - 1`; intermediate values strictly increase. |
| `ease` | Optional boolean, default `false`. Eases camera position/look-at motion in the segment leaving this key. |
| `focal` | Optional positive focal multiplier, default `1`, relative to that source frame's estimated lens. |

Axes are **x right, y down, z forward**. Source indices must be non-decreasing. Position and look-at
points follow slope-limited cubic Hermite/Catmull-Rom interpolation; source indices and focal
multipliers interpolate linearly. Source indices are rounded to integers. Orientation is derived
from the look-at direction with zero roll. Equal adjacent `src` values create a hold.

## Minimal walkthrough

Start the [service](studio.md#start-the-service), then upload a continuous clip containing at least
73 normalized frames:

```bash
curl -sS -F 'file=@clip.mp4' http://127.0.0.1:8412/upload
```

Copy the response's `clip` value into the following JSON and save it as `take.json`. This example
slides the camera right by `0.15 zm` while looking toward a point one depth unit ahead of the initial
camera. For subject-specific framing, use the `piv` returned by `/prepare` as your look-at reference.

```json
{
  "clip": "CLIP_ID_FROM_UPLOAD",
  "start": 0,
  "span_end": 72,
  "frames": 73,
  "pivot": [0.5, 0.5],
  "pivot_frame": 0,
  "seed": 1234,
  "path": [
    {"pos": [0, 0, 0], "look": [0, 0, 1], "src": 0, "t": 0, "ease": true, "focal": 1},
    {"pos": [0.15, 0, 0], "look": [0, 0, 1], "src": 72, "t": 72, "ease": false, "focal": 1}
  ]
}
```

Prepare the geometry, then produce a preview. `/prepare` ignores the extra path fields:

```bash
curl -sS -H 'Content-Type: application/json' --data-binary @take.json \
  http://127.0.0.1:8412/prepare

curl -sS -H 'Content-Type: application/json' --data-binary @take.json \
  http://127.0.0.1:8412/warp
```

Open the returned `truth` and `holes` URLs relative to the service origin, and inspect `ahead`,
`moved`, and `speed`. Generation is a separate, expensive step:

```bash
curl -sS -H 'Content-Type: application/json' --data-binary @take.json \
  http://127.0.0.1:8412/render
```

Copy the returned job ID into the commands below. Poll until `done` is true, and check that there is
**no `error`** before downloading; failed jobs also set `done: true`.

```bash
curl -sS http://127.0.0.1:8412/job/JOB_ID_FROM_RENDER
curl -f -o out.mp4 http://127.0.0.1:8412/take/JOB_ID_FROM_RENDER/out.mp4
```

`/render` does not enforce the browser's clearance or camera-change gates and does not require that
`/warp` was called first. This walkthrough includes preview inspection intentionally. A returned job
ID means the background task was started, not that input validation or generation succeeded.

## Endpoints

Paths below are relative to the service origin. “Shared fields” refers to the table above; not every
endpoint consumes every field.

| Endpoint | Request | Response |
|---|---|---|
| `GET /` | — | Studio HTML. |
| `GET /samples` | — | Array of available sample MP4 filenames. |
| `POST /upload` | Multipart `file`. | `{clip, frames, w, h, name, cuts, seconds, lengths}`. |
| `POST /sample` | `{name}` from `/samples`. | Same clip metadata as upload. |
| `POST /prepare` | `clip, start, span_end`; optional `pivot, pivot_frame`. | `{box, canvas, cond_canvas, ms, src_poses, piv, zm}`. |
| `POST /cloud` | Shared fields plus absolute source `frame`, optional `stride` (default `5`). | `{n, zm, pts, rgb}`; flattened triples in path coordinates. |
| `POST /warp1` | Shared fields plus `src, pos, look`; optional `focal`. | One geometry-reference JPEG at conditioning resolution. |
| `POST /warp` | Shared fields plus `path`; optional `lite`. | Gauges, cameras, source mapping, and preview URLs. `lite: true` omits the hole/sketch previews. |
| `POST /render` | Shared fields plus `path`. | `{job}`; rendering continues in a background thread. |
| `GET /job/{job}` | — | Status including `stage, pct, done, payload`; `t`, `error`, or `gauges` when available. |
| `GET /frame/{clip}/{i}.jpg` | Source index in the URL. | JPEG of the normalized source frame. |
| `GET /warpfile/{clip}/{name}` | Use a URL returned by `/warp`. | Preview file. |
| `GET /take/{job}/{name}` | Completed job ID and filename. | `out.mp4`, `source.mp4`, `render.mp4`, `grid.mp4`, or `last.png`. |

`lengths` in upload metadata is the studio's four-option length menu, not an exhaustive list of
asset-supported lengths. `src_poses[i]` in `/prepare` corresponds to absolute source frame
`start + i`; each entry includes `pos`, `look`, `roll`, and normalized lens values `k`.

Job `t` is elapsed time **since submission, including queue wait**. It first appears when processing
starts and updates at stage transitions, not continuously on polling. It is not a pure render-time
measurement.

### Warp response

- **`truth`**: grey-hole reference MP4 at conditioning resolution.
- **`holes`**: magenta-hole diagnostic MP4, unless `lite` is true.
- **`sketch`**: output-resolution geometric rasterization, unless `lite` is true; not the final
  conditioning-resolution reference.
- **`canvas`, `cond_canvas`**: `[width, height]` for the target and references.
- **`tmap`**: selected source index for every output frame.
- **`cams`**: per-output-frame position/look-at description; `piv` and `zm` describe the pivot/scale.
- **`speed`**: source-frame rate per key segment; zero is a hold, one preserves the input pace.
- **`coverage`**: mean geometric coverage at the rasterization resolution, not a calibrated quality score.
- **`ahead`, `near`, `behind`, `coll`, `moved`**: geometric diagnostics. See [Preview checks](studio.md#preview-checks).
- **`ms`**: elapsed time for the warp endpoint, including preview encoding.

`turned` and `zoomed` are computed by the browser from keys; they are not fields returned by `/warp`.

## Operational boundaries

One process serializes GPU work through a lock. The API has no cancellation, durable queue, session
restoration, authentication, or automatic file retention policy. Clip and geometry caches can evict
entries while files remain on disk. Do not assume an old ID remains usable after a restart or eviction.

Assertions and runtime failures may surface as HTTP errors rather than structured validation
responses. Render failures can arrive asynchronously through `/job/{job}`. The automatically served
FastAPI schema does not describe these JSON payloads fully because the handlers read request bodies
directly; use this guide alongside [`service/app.py`](../service/app.py).

For service flags, cache behavior, and deployment precautions, see [Studio](studio.md#memory-and-lifecycle).