Nodes/FrameThrower Reference/FrameThrower Reference Node
ComfyUI Node

FrameThrower Reference Node

Search 410,000 film stills without leaving your graph — the FrameThrower reference node

By framethrower-ai·Created 26 days ago·Updated 15 days ago· 1
FrameThrower Reference Node
    • image
    • depth
    • pose
    • lineart
    • prompt (text)
    • credit (text)
    query
    modehybrid
    index0
    pinned
    filters
    smarttrue
    auto
    lineart_strength3.0
    query_in

    Between "scrape a movie screenshot and hope nobody notices" and "spend an hour on a stock site" there's a better way to get a reference frame: search a curated film-still library from inside your graph. That's what the FrameThrower Reference Node does. Type a description, get a grid of stills from 5,490 films (roughly 410,000 of them), click the one whose lighting or composition you want, and out comes the frame, its scene description, its credit line, and - if you ask - depth, pose and lineart. It's a moodboard you can wire into a ControlNet.

    The pack is basically this one node. It's the ComfyUI door into framethrower.ai, a film-still search app. Don't confuse it with an API-wrapper generator: it's not calling a closed model. It searches a library, and the parts that touch your generation - depth, pose, lineart - run on your own machine. No key in a widget, no phone-home for inference.

    How it works

    The node carries its own little web UI - a search box and results grid inside the node body. Click a frame and it gets "pinned": that exact frame is what executes, because the search is not re-run at queue time - a queued graph can't quietly swap in a different picture than the one you clicked.

    Two ways to drive it, and they behave differently on purpose. Click a frame and it pins - deterministic, what-you-see-is-what-executes. Or wire a string into query_in and set index: nothing is pinned, the node searches at execution time and takes result n. That's the batch and automation mode - query_in is "automatic," the grid follows the wire live as you type upstream. The auto widget is grid bookkeeping, not for typing.

    The inputs and outputs that matter

    A beginner actually sets maybe three. query (the big multiline one) is what you search for - "neon rain at night" is the placeholder, and a good example. mode defaults to hybrid (text + visual meaning), nearly always the right answer; description matches text metadata only. index picks which result executes (0–499), mostly relevant when you're driving from query_in. The rest - pinned, filters, smart, auto, lineart_strength - the node's own UI writes for you.

    The outputs are where it gets fun. image is the frame, straight into a VAE Encode, an IPAdapter, or a ControlNet. Then depth, pose, lineart - and here's the part people miss: those three only run if you wire them. The node inspects the executing graph, sees nothing reading the socket, and skips the processor; unwired, a socket outputs a single black pixel rather than nothing (Comfy has no null on an IMAGE socket). Depth is Depth-Anything-V2-Small via the transformers pipeline ComfyUI already ships; pose is a tiny detector (yolos-tiny) finding people plus ViTPose on the joints, rendered in OpenPose's layout so pose ControlNets know what to do with it; lineart is a gradient-magnitude pass with a lineart_strength dial (default 3.0) controlling how much detail survives. All local, all one-time weight downloads - the README claims depth in ~65ms against nearly a minute on a cold cloud model.

    The two text outputs are easy to trip over. prompt (text) is the frame's scene description as plain text - wire it into CLIP Text Encode and it becomes conditioning. credit (text) is the Blade Runner (1982) - dir. Ridley Scott line. To see them, wire into the node called Preview as Text (its internal id is PreviewAny - search the menu for the display name), or Save Text to write them beside the picture. Don't wire into a Primitive String node - it makes text rather than showing it, so the wire can't even be made.

    Install

    ComfyUI Manager: search FrameThrower, Install, restart. Or by hand:

    cd ComfyUI/custom_nodes
    git clone https://github.com/framethrower-ai/comfyui-framethrower
    

    Restart, then Add Node → FrameThrower → Reference Node. Needs ComfyUI 0.3.30 or newer. No pip step - dependencies = [] in the pyproject, because torch/transformers/PIL all ship with ComfyUI. The only downloads are the preprocessor weights on first use.

    There's no key to copy. Click Connect on the node, it shows a short code, you approve it at framethrower.ai/link, and the token lands in ComfyUI/user/framethrower/config.json (mode 600). It's deliberately not a widget: widget values serialize into the workflow .json, so a shared workflow would carry your key around. Headless or shared box? Set FT_API_TOKEN in the environment instead; it overrides the file.

    Gotchas

    • Node draws as a stack of plain widgets? Your frontend is older than 1.16 - update ComfyUI.
    • "Not connected to FrameThrower" on execute. The Connect flow never finished, or FT_API_TOKEN is stale. Check that config.json.
    • Connect says it can't write. Rare - ComfyUI/user/ is read-only. Use FT_API_TOKEN.
    • It costs credits. Searches are metered against your framethrower.ai balance (signup gives you credits, no card). But the node hashes its inputs via IS_CHANGED, so re-queueing an unchanged graph is a cache hit and spends nothing - leave the node in a workflow and iterate the sampler side forever without burning balance.

    If you already have a solid depth/pose pipeline, ignore three of the image sockets entirely - grab the frame and the description, and go steal some lighting.

    CategoryFrameThrower

    Inputs (9)

    NameTypeDefaultDescription
    querySTRING
    modeCOMBOhybrid2 options: hybrid, description
    indexINT00–499
    pinnedSTRING
    filtersSTRING
    smartBOOLEANtrue
    autoSTRING
    lineart_strengthSTRING3.0
    query_inoptSTRINGWords to search for, from another node. Automatic — the grid follows the wire as you type upstream, no queue needed.

    Outputs (6)

    NameTypeDescription
    imageIMAGEThe frame itself. Into Preview Image, Save Image, or a VAE Encode / ControlNet / IPAdapter that takes an IMAGE.
    depthIMAGEDepth map. Into a depth ControlNet. Runs only while this socket is wired.
    poseIMAGEPose skeleton, OpenPose layout. Into a pose ControlNet. Runs only while this socket is wired, and is empty when nobody is in the frame.
    lineartIMAGELineart. Into a lineart ControlNet. Runs only while this socket is wired.
    prompt (text)STRINGThe frame's scene description, as plain text — not conditioning. Into CLIP Text Encode, which turns it into conditioning. To read it on the canvas, add the node called 'Preview as Text'. Not a Text node: that one makes text rather than showing it.
    credit (text)STRINGTitle, year and director, as text. Into 'Preview as Text' to read it, or 'Save Text' to write it beside the picture, so the attribution travels with whatever you make.