FrameThrower API

Curated film frames, searchable by concept, color, mood, composition, and image similarity. Built for agents, creative tools, and production pipelines.

Every response returns metadata, thumbnail URLs, and deep links — never raw image bytes. Reference use, with attribution.

Get Started

The FrameThrower API gives you programmatic access to the same cinematography reference library that filmmakers use on the website — text search, image search, color matching, craft-attribute filtering, and a growing film catalog. It's designed to be read by humans, agents, and LLMs alike.

1

Create a FrameThrower account

Sign up for free — Google or email. Takes 30 seconds.
2

Complete onboarding

Accept the Terms of Service and set your content preferences. This is required for API access because the API exposes the same content as the website.
3

Subscribe to a paid plan

API access is available on Pro, Studio, and Friend plans. See pricing. Pro starts with a 7-day free trial.
4

Create an API token

Go to Settings → API and click + Create token. Copy the token — it's shown only once.
5

Make your first request

curl -X POST https://framethrower.ai/api/v1/search \
  -H "Authorization: Bearer ft_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "neon-lit rainy street at night", "limit": 5}'

Or from JavaScript, with the official SDK:

npm install framethrower-ai

What You Can Build

The API is built for creative workflows. Here are things you (or your agent) can do:

Script → Visual References

Hand the API a screenplay or scene description. For each scene, search by mood, lighting, and setting to find matching cinematography references. Build a lookbook automatically.

// Scene: "INT. WAREHOUSE - NIGHT. Rain hammers the skylights.
// A single fluorescent tube flickers over the interrogation chair."

const scene = await fetch("https://framethrower.ai/api/v1/search", {
  method: "POST",
  headers: { "Authorization": "Bearer ft_...", "Content-Type": "application/json" },
  body: JSON.stringify({
    query: "warehouse interior night rain flickering fluorescent interrogation",
    limit: 10
  })
}).then(r => r.json());

// Refine: find more like the best match
const similar = await fetch("https://framethrower.ai/api/v1/similar", {
  method: "POST",
  headers: { "Authorization": "Bearer ft_...", "Content-Type": "application/json" },
  body: JSON.stringify({ frameId: scene.data[0].id, mode: "visual", limit: 5 })
}).then(r => r.json());

Color Palette Matching

Start with a hex color or palette from your brand guidelines or mood reference. Find frames that match those tones — useful for pitch decks, site hero sections, or color-grading references.

// Find frames matching a warm amber + deep teal palette
const res = await fetch("https://framethrower.ai/api/v1/search/color", {
  method: "POST",
  headers: { "Authorization": "Bearer ft_...", "Content-Type": "application/json" },
  body: JSON.stringify({ colors: ["#e8a87c", "#1b4332"], limit: 10 })
}).then(r => r.json());

Cinematography Study

Explore how a specific director or DP uses light, lens, and framing. Browse by craft attributes — no text query needed — to find every anamorphic close-up, every high-key daylight wide, every Deakins night exterior.

// All anamorphic night exteriors by Roger Deakins' regular directors
const res = await fetch("https://framethrower.ai/api/v1/browse", {
  method: "POST",
  headers: { "Authorization": "Bearer ft_...", "Content-Type": "application/json" },
  body: JSON.stringify({
    lens_character: "anamorphic",
    setting: "exterior",
    time_of_day: "night",
    limit: 20
  })
}).then(r => r.json());

Reference Images for Creative Briefs

Building a site, app, or campaign? Drop in a reference image and find frames with similar composition, color, and mood. Use the results as a shared visual language with your team or client.

// "Find frames that look like this reference photo"
const res = await fetch("https://framethrower.ai/api/v1/search/image", {
  method: "POST",
  headers: { "Authorization": "Bearer ft_...", "Content-Type": "application/json" },
  body: JSON.stringify({
    imageUrl: "https://example.com/my-reference.jpg",
    limit: 10
  })
}).then(r => r.json());

Connect

REST API (direct integration)

Use your API token as a Bearer token in the Authorization header. All endpoints accept JSON and return JSON.

Authorization: Bearer ft_your_token_here
Content-Type: application/json

From an AI agent (Claude, ChatGPT, Cursor, etc.)

If you're using an AI agent that supports custom tools or API integrations, configure it with:

Base URLhttps://framethrower.ai/api/v1
AuthBearer ft_your_token
Docs URLhttps://framethrower.ai/developers

Point your agent at this page (/developers) — it can read the endpoint reference and examples to understand what's available. The agent makes requests on your behalf using your token, so it has the same access as you do on the website.

OpenAPI / tool definitions

For agents that consume OpenAPI specs or tool schemas, you can describe each endpoint as a tool. Here's a minimal tool definition for search:

{
  "name": "framethrower_search",
  "description": "Search FrameThrower's film frame library by concept, mood, lighting, color, or composition. Returns thumbnails + metadata + deep links. Use for finding visual references.",
  "parameters": {
    "type": "object",
    "properties": {
      "query": { "type": "string", "description": "Natural language search (e.g. 'overhead dinner table warm candlelight')" },
      "limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10 }
    },
    "required": ["query"]
  }
}

All Endpoints

Base URL: https://framethrower.ai/api/v1. All responses use { data, meta } format.

POST
/search

Text search — concept, mood, scene, composition

POST
/search/image

Image search — find frames matching a reference image

POST
/search/color

Color search — find frames by hex color or palette

POST
/browse

Browse by craft — filter by shot type, lens, lighting, director, genre

POST
/similar

Similar frames — find more like a specific frame

GET
/frames?id=...

Frame detail — full metadata for a single frame

GET
/frames/random

Random frames — diverse sample for inspiration or seeding

GET
/suggest?q=...

Autocomplete — match film titles and people by name

GET
/films

Film catalog — paginated, searchable by title or director

GET
/films/:slug

Film detail — plot, runtime, palette, sample frames

GET
/films/frames?slug=...

Film frames — all frames for a specific film

POST /api/v1/search

Search the frame library with natural language. Describe a mood, scene, composition, or visual — the search understands cinematography.

{
  "query": "neon-lit rainy street at night",
  "limit": 20,       // 1-50, default 20
  "mode": "hybrid"   // "hybrid" | "semantic" | "description"
}

Modes: hybrid (default) fuses visual + text embeddings. semantic uses image-derived embeddings. description searches text metadata only.

POST /api/v1/search/image

Find frames that match a reference image by visual similarity, color, and semantic meaning.

{ "imageUrl": "https://example.com/reference.jpg", "limit": 20 }

JavaScript SDK

framethrower-ai wraps every endpoint on this page — same token, no HTTP plumbing. TypeScript types are bundled.

npm install framethrower-ai
import FrameThrower from 'framethrower-ai'

const ft = new FrameThrower('ft_YOUR_TOKEN')

// Search by text, colour, or image
const frames = await ft.search('neon rain at night')
const warm   = await ft.searchByColor(['#e8a87c', '#1b4332'])
const like   = await ft.searchByImage('https://example.com/photo.jpg')

// Browse by craft, then follow a frame into its film
const shots = await ft.browse({ shot_type: 'close-up', lens_character: 'anamorphic' })
const detail = await ft.frame(frames[0].id)   // detail.prompt is a composed image prompt
const more   = await ft.similar(frames[0].id, { mode: 'visual' })

const films = await ft.films({ q: 'kubrick', sort: 'frames' })
const film  = await ft.film(films[0].slug)

Source and full reference: npmjs.com/package/framethrower-ai.

POST /api/v1/search/color

Find frames dominated by specific colors. Pass one hex color or a palette of up to 6.

// Single color
{ "color": "#e94560" }

// Palette (blended)
{ "colors": ["#e94560", "#1a1a2e", "#16213e"], "limit": 20 }

Browse by Craft

POST /api/v1/browse

Filter frames by cinematography attributes — no text query needed. Combine any filters. This is the unique surface: search by how a shot was made, not just what it shows.

{
  "shot_type": "close-up",          // or "wide", "medium", "extreme-close-up"
  "lens_character": "anamorphic",   // or "spherical", "vintage_soft"
  "setting": "exterior",            // or "interior"
  "time_of_day": "night",           // or "day", "golden_hour", "blue_hour"
  "camera_angle": "low_angle",      // or "high_angle", "eye_level", "overhead"
  "visual_style": "noir",           // or "naturalistic", "stylized"
  "director": "Denis Villeneuve",
  "genre": "Science Fiction",
  "era": "2010s",
  "year_min": 2010,
  "year_max": 2025,
  "limit": 20
}

Similar Frames

POST /api/v1/similar

Find frames similar to one or more reference frames. The "more like this" flow.

// Single frame
{ "frameId": "abc123", "mode": "semantic", "limit": 20 }

// Multiple frames (averaged — finds the centroid)
{ "frameIds": ["abc", "def", "ghi"], "mode": "visual", "limit": 20 }

// Modes: "semantic" | "visual" | "color"

Frame Detail

GET /api/v1/frames?id=FRAME_ID

Full metadata for a single frame — film info, cinematography attributes, colors, mood, and a ready-to-use AI image prompt.

// Response shape
{
  "data": {
    "id": "abc123",
    "imageUrl": "https://frames.shotspot.pro/core/...",
    "thumbUrl": "https://frames.shotspot.pro/thumb/...",
    "deepLink": "https://framethrower.ai/#frame/abc123",
    "prompt": "A lone figure walks through dense orange haze toward a distant structure. Set in exterior, day. Diffused amber backlight with atmospheric haze. Desaturated warm tones dominated by deep orange and ochre. Naturalistic style with a melancholy, atmospheric, isolation mood.",
    "film": {
      "title": "Blade Runner 2049", "year": 2017,
      "director": "Denis Villeneuve", "dp": "Roger Deakins",
      "genres": ["Science Fiction", "Drama"],
      "tmdbId": 335984, "imdbId": "tt1856101"
    },
    "metadata": {
      "sceneDescription": "A lone figure walks through orange haze...",
      "shotType": "wide", "cameraAngle": "eye_level",
      "lensCharacter": "anamorphic",
      "lightingKey": "low_key",
      "lightingDescription": "Diffused amber backlight with atmospheric haze",
      "moods": ["melancholy", "atmospheric", "isolation"],
      "colorPalette": ["#c45a28", "#1a1a2e", "#e8a87c"],
      "era": "2010s", "setting": "exterior", "timeOfDay": "day"
    }
  }
}

Random Frames

GET /api/v1/frames/random?limit=20

Get a diverse random sample. Useful for seeding a UI, inspiration, or sampling the catalog.

Autocomplete

GET /api/v1/suggest?q=kub

Fuzzy-match film titles and director/DP names. Returns up to 5 films and 3 people.

// Response
{
  "data": {
    "films": [
      { "type": "film", "title": "2001: A Space Odyssey", "year": 1968,
        "director": "Stanley Kubrick", "posterUrl": "...", "imdbId": "..." }
    ],
    "people": [
      { "type": "person", "name": "Stanley Kubrick", "slug": "stanley-kubrick",
        "portraitUrl": "...", "filmCount": 12 }
    ]
  }
}

Film Catalog

GET /api/v1/films?page=1&per_page=50&q=kubrick

Browse the full film catalog. Paginated, filterable by title or director name.

Film Detail

GET /api/v1/films/:slug

Full detail for a film — plot, runtime, MPAA rating, dominant color palette, and sample frames.

GET /api/v1/films/blade-runner-2049-2017

Film Frames

GET /api/v1/films/frames?slug=blade-runner-2049-2017

Get all frames for a specific film (up to 500). Each includes a thumbnail, deep link, and scene description.

Full Examples

curl — search and refine

# Search
curl -s -X POST https://framethrower.ai/api/v1/search \
  -H "Authorization: Bearer ft_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query": "overhead shot dinner table warm light"}' \
  | jq '.data[:3] | .[] | {title: .film.title, url: .deepLink}'

# Browse by craft
curl -s -X POST https://framethrower.ai/api/v1/browse \
  -H "Authorization: Bearer ft_YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"shot_type": "close-up", "lens_character": "anamorphic", "limit": 5}' \
  | jq '.data | length'

# Autocomplete
curl -s "https://framethrower.ai/api/v1/suggest?q=nolan" \
  -H "Authorization: Bearer ft_YOUR_TOKEN" \
  | jq '.data.films[].title'

Python

import requests

TOKEN = "ft_YOUR_TOKEN"
H = {"Authorization": f"Bearer {TOKEN}"}

# Search by concept
r = requests.post(f"https://framethrower.ai/api/v1/search", headers=H,
    json={"query": "anamorphic close-up blue hour", "limit": 5})
for f in r.json()["data"]:
    print(f'{f["film"]["title"]} — {f["deepLink"]}')

# Find by color
r = requests.post(f"https://framethrower.ai/api/v1/search/color", headers=H,
    json={"colors": ["#c45a28", "#1a1a2e"]})
print(f'{len(r.json()["data"])} frames match that palette')

# Browse craft
r = requests.post(f"https://framethrower.ai/api/v1/browse", headers=H,
    json={"director": "Wong Kar-wai", "time_of_day": "night"})
for f in r.json()["data"]:
    print(f'{f["film"]["title"]} — {f["metadata"]["lensCharacter"]}')

JavaScript / TypeScript

const TOKEN = "ft_YOUR_TOKEN";
const api = (path, body) =>
  fetch(`https://framethrower.ai/api/v1${path}`, {
    method: body ? "POST" : "GET",
    headers: { "Authorization": `Bearer ${TOKEN}`, "Content-Type": "application/json" },
    body: body ? JSON.stringify(body) : undefined,
  }).then(r => r.json());

// Script → visual references workflow
async function findRefsForScene(sceneDescription) {
  // 1. Search by scene text
  const { data: results } = await api("/search", {
    query: sceneDescription, limit: 10
  });

  // 2. Pick the best match, find more like it
  if (results.length > 0) {
    const { data: similar } = await api("/similar", {
      frameId: results[0].id, mode: "visual", limit: 5
    });
    return [...results.slice(0, 5), ...similar];
  }
  return results;
}

// Use it
const refs = await findRefsForScene(
  "candlelit dinner party in a grand ballroom, wide shot, warm"
);
refs.forEach(f => console.log(f.film.title, f.thumbUrl));

Response Format

Every endpoint returns JSON with this shape:

{
  "data": [ ... ] or { ... },   // the result(s)
  "meta": {                      // context about the request
    "total": 20,
    "query": "...",
    "mode": "hybrid",
    ...
  }
}

Frames always include: id, imageUrl (full-size original), thumbUrl (1280px WebP thumbnail), deepLink (opens on FrameThrower), film (title, year, director, dp, genres), metadata (scene description, shot type, camera angle, lens, lighting, moods, colors, etc.). Frame detail also includes prompt — a composed AI image prompt.

Errors return { "error": "message" } with the appropriate HTTP status (400, 401, 403, 404, 500).

The API surfaces frames as reference material — metadata, thumbnail URLs, and deep links back to FrameThrower. It never returns raw image bytes.

By using the API you agree to the Terms of Service and Intended Use Policy. Bulk redistribution and automated scraping are prohibited. Rights to the original films remain with their respective rights holders.

Questions? contact@framethrower.ai

FrameThrower API v1 · 11 endpoints · No rate limits during preview.