> ## Documentation Index
> Fetch the complete documentation index at: https://docs.stackshift.cloud/llms.txt
> Use this file to discover all available pages before exploring further.

# Deterministic image, video, and audio transforms

> Define ordered v2 transforms for images, video renditions, audio extraction, and timestamp thumbnails; store eager presets or materialize durable derivatives.

<Tip>
  **Live.** This area is documented as current, user-reliable behavior.
</Tip>

## Goal

Produce repeatable media derivatives whose cache identity includes the canonical definition, source bytes, overlay bytes, and processor revision.

## Prerequisites

* An asset in the same account
* An `assets:process` token for transforms
* A clean, ready source before durable materialization

## Workflow

<Steps>
  <Step>
    Build a version 2 definition with the source media kind, ordered operations, and one output.
  </Step>

  <Step>
    Store it as a named preset when multiple assets use it; set `eager=true` to materialize after the clean scan gate.
  </Step>

  <Step>
    POST the definition or preset to the asset transforms route. Supply exactly one, never both.
  </Step>

  <Step>
    Poll the returned Assets job until it completes, then list derivatives and use only an `available` output.
  </Step>
</Steps>

## Definition contract and bounds

* `version` is exactly `2`; `media_kind` is `image` or `video`; operation order is significant.
* A definition contains 1–24 operations. Output kinds are image, video, audio, or thumbnail.
* Final images are limited to 4096×4096 and 16,777,216 pixels. DPR is 0.5–4; blur sigma is greater than 0 and at most 100; output quality is 1–100 and defaults to 82 for image/thumbnail outputs.
* Background is `transparent` or normalized 6/8-digit hex. Rotation is finite and normalized modulo 360.
* Video FPS is 1–60. Trim end must exceed start. Trim and thumbnail timestamps are checked against probed source duration during processing.
* Image formats are JPEG, PNG, WebP, and AVIF; video is MP4; extracted audio is MP3, AAC, or WAV; thumbnails are JPEG, PNG, or WebP.

## Timestamp thumbnail example

<CodeGroup>
  ```ts TypeScript theme={null}
  const definition = {
    version: 2 as const,
    media_kind: 'video' as const,
    operations: [
      { type: 'trim' as const, start_seconds: 4, end_seconds: 48 },
      { type: 'timestamp' as const, timestamp_seconds: 12.5 },
      { type: 'crop' as const, mode: 'fill' as const, width: 1200, height: 630 },
      { type: 'overlay' as const, asset_id: watermark.id, gravity: 'southeast' as const, opacity: 72, x: 24, y: 24 },
    ],
    output: { kind: 'thumbnail' as const, format: 'webp' as const, quality: 84 },
  }

  const job = await stackshift.assets.materializeTransform(
    video.id, { definition }, 'thumbnail:video-42:v1',
  )
  const completed = await stackshift.assets.job(job.job_id)
  const { derivatives } = await stackshift.assets.derivatives(video.id)
  ```

  ```go Go theme={null}
  definition := stackshift.AssetTransformDefinition{
    Version: 2, MediaKind: "video",
    Operations: []stackshift.AssetTransformOperation{
      {Type: "timestamp", TimestampSeconds: 12.5},
      {Type: "crop", Mode: "fill", Width: 1200, Height: 630},
    },
    Output: stackshift.AssetTransformOutput{Kind: "thumbnail", Format: "webp", Quality: 84},
  }
  job, err := client.Assets.MaterializeTransform(ctx, assetID,
    stackshift.AssetTransformMaterializeInput{Definition: &definition}, "thumbnail:video-42:v1")
  ```

  ```python Python theme={null}
  job = stackshift.assets.materialize_transform(
      video["id"],
      definition={
          "version": 2, "media_kind": "video",
          "operations": [{"type": "timestamp", "timestamp_seconds": 12.5}],
          "output": {"kind": "thumbnail", "format": "webp", "quality": 84},
      },
      idempotency_key="thumbnail:video-42:v1",
  )
  ```

  ```php PHP theme={null}
  $job = $assets->materializeTransform($videoId, [
      'definition' => [
          'version' => 2, 'media_kind' => 'video',
          'operations' => [['type' => 'timestamp', 'timestamp_seconds' => 12.5]],
          'output' => ['kind' => 'thumbnail', 'format' => 'webp', 'quality' => 84],
      ],
  ], "thumbnail:video-42:v1");
  ```

  ```bash CLI theme={null}
  stackshift asset transform-run "$ASSET_ID" --file ./thumbnail-v2.json --output json
  stackshift asset job "$JOB_ID" --output json
  stackshift asset derivatives "$ASSET_ID" --output json
  ```
</CodeGroup>

## Presets, eager processing, and v1 compatibility

* `POST /assets/transformations` continues to accept the legacy width/height/crop/format/quality fields and signed v1 specs.
* For v2, send `name`, `definition`, and `eager`. Stored presets expose `definition_version`, `media_kind`, normalized definition/spec, `eager`, and `revision`.
* `POST /assets/{assetID}/transforms` accepts `{definition}` or `{preset}` and returns an Assets job. If no idempotency key is supplied, the service derives one from asset ID, source checksum, and normalized spec.
* For CLI `transform-run`, the JSON passed to `--file` is the complete request body: wrap a v2 definition as `{ "definition": { ... } }`, or use `{ "preset": "name" }`.
* `GET /assets/{assetID}/derivatives` returns persisted output kind, MIME type, size, transform hash, dependency checksum, processor revision, and availability state.
* The service invokes libvips/FFmpeg/ffprobe through context-bound argument arrays, strips metadata, normalizes color, and marks output deliverable only after durable persistence and replication.

## Expected result

<Check>
  Identical source and transform dependencies collapse onto the same durable output, while any source, overlay, definition, or processor change produces a new identity.
</Check>

## Common failures

<Warning>
  * A request mixes image-only operations such as DPR or radius into a video definition.
  * A thumbnail omits its single timestamp, or an audio output includes an operation other than trim.
  * An overlay is remote, belongs to another account, is not clean and ready, or exceeds the four-overlay limit.
  * The caller treats `202 Accepted` as deliverable before the job persists and replicates the output.
</Warning>

## Related guides

<CardGroup cols={2}>
  <Card title="Media Workflows visual builder and API" href="/assets/media-workflows">
    Author editable templates or blank typed DAGs that coordinate asset gates, native StackShift services, bounded Stackie reasoning, and approved external integrations.
  </Card>

  <Card title="Assets REST API reference" href="/assets/api-reference">
    The routes, wire fields, response states, and concurrency rules shared by every official Assets SDK.
  </Card>

  <Card title="Video, scanning, and governance" href="/assets/video-scanning-and-governance">
    Process video asynchronously, deliver HLS and posters, expose scan gates, quarantine unsafe assets, and enforce account policies.
  </Card>
</CardGroup>
