Install
openclaw skills install @vargai/find-referencesFind real, human-made references before anything is made, for AI image, video and music and for video made with code. Turns a request into one query pack per job (light first, then framing, people, location, texture, type, motion, palette, music and a "never" board), searches each source in its own words, opens everything it keeps, proves who made it, measures what code can measure, checks light with an LLM judge, and hands a person three candidates per job. Use when someone says "find references", "reference board", "what should this look like", "lighting reference", "framing reference", "texture reference", "font reference", "motion reference", "casting reference", "music reference", "moodboard references", "make it not look like AI", "avoid slop", "rank these references", or starts a video with no look yet. Not for writing the look from chosen references (video-moodboard, varg-video-prompting), building the cast (character-passport) or downloading one known link (media-download).
openclaw skills install @vargai/find-referencesStep 1 of 10 in How to make a video with an AI agent in ten steps. The full guide, with every test and source: https://varg.ai/how-to/find-references-for-an-ai-video (as Markdown: add
.md).
Without a reference an agent falls back to its default look: "centered text, gradient background, everything fading in" (https://x.com/rexan_wong/status/2103707054108299437). Adding more words does not fix it. Three facts shape this skill:
references/evidence.md). A judge answers literal questions about what is
visible, and nothing else.So each part does what it can do. Code owns facts in pixels and timing. Records own who made it and the rights. The LLM owns literal yes/no checks and the shortlist. A named person owns meaning and the final pick.
Some things only a person can find. In the cold run on an ad (tested 2026-11-03), no open source returned the
inside of an old Portuguese tile shop, the thing that person loved most. Finding that out early and writing the link is a
good result. Say so plainly, and do not pass off something near it as the thing.
Read this file and references/queries.md. Then read only the job files this piece needs. Every rule that matters for
the whole run is in this file. Job files hold routes, traps and queries.
Run from the project folder. Call scripts by absolute path. Never write into the skill folder. Use -I when a folder
holds downloads, which is nearly every folder here, so the commands below all have it.
S=<skill folder>/scripts # absolute path
python3 -I "$S/search.py" sources
| Script | Does | Needs |
|---|---|---|
search.py | 22 open sources, person-only links, fusion, the search log | Python 3 |
board.py | the board page | Python 3 |
sun.py | sunrise, sunset, sun altitude and azimuth | Python 3 |
ai_marker.py, hdri_light.py, mcp_call.py | AI marker scan; light in an HDRI; any MCP tool with no client | Python 3 |
frame_light.py | bright side, contrast, colour | ffmpeg |
motion_read.py | cuts, holds, camera, elements, scale | ffmpeg and uv, in the uv run form below |
judge.py | blind, read, enforce, aggregate, pairs, rank | magick. read and pairs use the person's logged-in claude or codex CLI |
brief.json the request as 11 fields, each marked said, assumed or asked
queries.md one query pack per job, plus the whole-brief control query
search_log.jsonl source, exact query, status, rank and count for each search
never.md reject-if tests, with a positive translation for prompts
want/<job>.txt one want card per job, frozen before you look
refs/<job>/ every frame or clip you opened and kept, named NN-job-source.ext
refs.md one job card per kept candidate; picks are marked when the person picks
links.md searches only a person may open, with a one-line reason each
board.html three candidates per job, shuffled, no scores, for the person to pick
DESIGN.md coded only: hex, type, grid, motion, each value labelled measured, record, by eye or assumed
timing.md coded only: beat, seconds, frames, what moves first, ease, source
For a coded piece the picks become numbers in those two files. With nobody there to pick, write them from the first passers
and head them PROVISIONAL. For a generated piece the picks become role lines and words. See references/templates.md.
Priority depends on the method. Generated: light first, because people and machines both read it badly. Coded: type,
motion and palette first, and light only where a shot has it (a 3D scene, a single still, an HDRI). Change the order to fit
the piece, and say so in queries.md. Run only the jobs a piece needs: People only with a cast or one generated person,
Characters only with a cast. Queries and sources are a floor to start from, not a limit.
| Job | What the reference proves | Queries, sources | Agent starts with | Person gets links to | Read |
|---|---|---|---|---|---|
| Never | what the default looks like, so it can be rejected | 2, 2 | Refs obvious query; generated: Commons deepcat:; coded: Impeccable | Meta Ad Library and TikTok Creative Center for ads; Kagi ai:only, r/aislop | references/never.md |
| Light | one source, a side, a hardness, and why it is there | 6, 3 | Deakins site, Met by artist, Commons, LoC; Poly Haven for code | Film-Grab, ShotDeck | references/light.md |
| Framing | shot size, height, angle, where the subject sits | 4, 2 to 3 | Met, Commons, ShotOnWhat | Film-Grab, Shot Cafe, Frame Set | references/framing.md |
| People | who this person is, apart from pose, place, expression, clothes | 4, 2 to 3 | LoC FSA/OWI, Commons | Flickr group 100 Strangers, ShotDeck | references/people.md |
| Characters | shape language and how a non-human moves | 2, 2 | Sakugabooru metadata, Are.na | ArtStation | references/characters.md |
| Location | a real place, decade and region | 3, 2 | Commons categories, LoC HABS, TheFilmMap MCP | Street View, Atlas Obscura | references/location.md |
| Texture | one named material or process, at pixel level | 2 to 3, 2 | Commons, LoC, ambientCG; Flickr feed for leads | filmdev.org, Camera-wiki, Lomography | references/texture.md |
| Palette | colours and proportions from a named frame | 2, 2 | your candidates' frames, Wada JSON, Meditations in Color | Movies in Color, Screenmusings | references/palette.md |
| Type, graphics | a real use of a named typeface, or its class, in a year | 2 to 3, 2 | Fonts In Use numbered paths, Art of the Title, Poster House, a Commons category of the genre's posters | Fonts In Use search | references/type-graphics.md |
| Motion | timing you can measure and rebuild | 3, 2 | Refs, Commons filetype:video for clips you may process, Sakugabooru metadata, Motionographer | whatships films, Instagram Reels, Meta Ad Library, TikTok Creative Center, Ads of the World, Vimeo Staff Picks | references/motion.md |
| Music, voice | tempo, instruments, era, for a person to hear. Voice: a casting line (age, region, texture, pace), and video-sound casts candidates | 3, 2 | Discogs, MusicBrainz, ListenBrainz, NTS | Rate Your Music, Bandcamp pages | references/music.md |
Style is not a job. It comes from a board (references/style-boards.md), which answers how a piece should feel; archives
answer who and where. A style you cannot break into these jobs is a mood, not a reference.
candlelight, one has a single low candle and one has no
candle at all. Write one line saying only what you can see. Delete what you could not open.references/never.md):
HUMAN-PROVEN (a verified film title or a named archive or museum as holder, or a named author plus a date before
2022 plus a body of work or credits), LIKELY HUMAN (a named author or a date, with nothing against), UNKNOWN
(nothing proven: mood only, no measurements, no feeding) or AI (a marker, or the maker says so: never board only).
"No AI marker" and "the detector says human" are never a pass.agent, token, person or dead (references/sources.md). Never fetch a
person-only site, not even to check a link. Never spoof a user agent, sign in for someone or download store previews.
links.md.Retry-After says, or 60 s, try once more, then stop using that source for this
run.feed, words or look.
feed may go to a generator: yours, licensed for this use, CC0 or public domain, and no identifiable person.words is read and described. CC BY and BY-SA are words by default; a person may clear them for feeding.look is seen by a person, and nobody keeps a copy.words, even in a public-domain photo. Copyright and likeness are separate rights.feed, but start from words: whether paint texture comes back is untested, so
feed one only after a test frame.references/music.md.@Image1 defines the light only. Do not copy the room, the person or the colours from @Image1. Scores fell as reference count rose in the benchmarks we found.
Keep identity sheets flatly lit so the light reference can work (references/queries.md).references/judge.md).brief.json: idea (what the viewer should believe afterwards), feeling (two adjectives and one opposite), subject, world
(place and decade), medium, audience, platform (aspect ratio, length), method (coded, generated, hybrid, filmed),
constraints, loves, hates. Mark each said, assumed or asked.
Ask at most two questions: what they hate, and the method if you cannot infer it. Assume the rest out loud. Also ask for
real assets (product, UI, founder, brand), which does not count as a question: real material beats any reference. If the
request is vague, show three territories and ask one question: references/queries.md.
Search the plainest words (coffee, coffee ad). Say what the results actually show, and name what they share.
python3 -I "$S/search.py" refs '{"query":"coffee","ai_made":false,"limit":8}' --log search_log.jsonl
Refs may not show the obvious thing: in the cold run 17 of 48 cards were about coffee, and 9 of those were Nespresso. Mark anything you expected and could not confirm. For ads, the real picture of a category is in Meta Ad Library and TikTok Creative Center, which are person-only, so write those links.
Write never.md from the search you ran and from the person's stated hates. Each entry is a test a stranger can check, on
a frame, a clip or a text as fits. At intake, drop a reference only if what matches a never test is what it lends: a
painting that shows people drinking can still lend only light. Details: references/never.md.
Each pack has up to five slots, shaped for the engine that reads it: L literal, C caption (skip it if you have no semantic
engine), N named, A adjacent, X excluded. references/queries.md has the slots, a bad-to-good table per job and the
feeling table. Add one whole-brief control query.
references/light.md). Read the author
field of good Commons hits: institutions upload whole collections. Ask a local archive by name.python3 -I "$S/search.py" met "Georges de La Tour" --artist --public-domain --medium Paintings --log search_log.jsonl > light-1.json
python3 -I "$S/search.py" commons '"low key" portrait' --log search_log.jsonl > light-2.json
python3 -I "$S/search.py" commons-cat "Category:Diners in New Jersey" --log search_log.jsonl > location-1.json
python3 -I "$S/search.py" loc "mechanic" --collection fsa-owi-black-and-white-negatives --log search_log.jsonl > people-1.json
python3 -I "$S/search.py" links "sodium street night" --job light # that job's person-only links, nothing is fetched
status: ok, error, blocked or rate_limited, and anything but ok exits 1.
search.py paces itself across processes, handles a 429 as rule 5 says, and logs every outcome. Add a row by hand for
anything you fetch another way (WebFetch, curl, mcp_call.py), including silent zeros and blocks.image is often a sized copy, and original can be a 272 MB TIF (cold run on a coded film). Check width, height and
bytes first. Use a sized copy for layout and palette (--width 1920 on commons and commons-cat sets Commons
iiurlwidth), and the original only for a 100% texture check.references/sources.md.references/light.md).Fusion merges duplicates and rank across queries. It does not cut by maker: one pick per maker happens only at the shortlist, after opening. Across different sources few items overlap (6 of 119 in the cold run), so read the top of each query too.
python3 -I "$S/search.py" fuse light-1.json light-2.json light-3.json --limit 20
Open every candidate you keep and write what you can see. Then prove provenance from records: a named maker and date, a
holding archive, or an oldest copy. Run python3 -I "$S/ai_marker.py" refs/ on what you download: a hit rejects, and a
miss proves nothing, because any re-encode erases the marker.
Write a want card per job in want/<job>.txt before you look at candidates, with values only and no praise words:
job: light | direction: any | hardness: soft (assumed) | source: window or practical lamp | shadow side: near black
assumed, and it cannot be core. If you invented a side, write direction: any, and
the judge skips L2. It also skips a question whose value says (assumed).Every kept candidate passes the gates, for every job: opened, provenance, source allowed, rights, identity safety, no
duplicate (references/judge.md). Then measure. Gates, code and the person are usually enough.
python3 -I "$S/frame_light.py" refs/light/07-light-met.jpg # bright side, contrast in stops, highlight and shadow colour
uv run --no-project --python 3.12 --with scenedetect --with opencv-python python -I "$S/motion_read.py" cuts refs/motion/12-motion-archive.mp4
Generated: judge Light by default, and only if more than 3 candidates survive the gates. Coded: usually no judge,
since the answers come from records and code. Run one only on a generated still's light, when more than 3 candidates
survive. We have not run the demographic swap, so for light prefer frames without people, and a person confirms the rest.
For other jobs the criteria tables are a draft, off by default. On a small budget: Light only, 2 reads per family. Ask
binary questions about visible things only, with labels stripped and order shuffled, then take the best few to pairs in
both orders. No API key: read uses the person's own logged-in claude or codex CLI.
C="$S/../assets/criteria/light.json"
python3 -I "$S/judge.py" blind refs/ blinded/ # no metadata, random ids, never upscales, ledger kept apart
python3 -I "$S/judge.py" read blinded/light --family claude --want want/light.txt --criteria "$C" --reads 3 --out reads.jsonl
python3 -I "$S/judge.py" read blinded/light --family codex --want want/light.txt --criteria "$C" --reads 3 --out reads.jsonl
python3 -I "$S/judge.py" enforce reads.jsonl --criteria "$C" > enforced.jsonl
python3 -I "$S/judge.py" aggregate enforced.jsonl --criteria "$C" > shortlist.json
Pairs, prompts, criteria and the budget rules are in references/judge.md. What we measured on this judge is in
references/judge-evidence.md. It is weakest on rooms with no face, so a person looks at anything the checks rank low that
fits the brief.
Put three candidates per job on the board, grouped by job, shuffled, with no scores until they choose. Reference lists ranked in one column raise fixation (Chan et al. 2024), so do not make one.
python3 -I "$S/board.py" board.json board.html --seed 7 # input shape in references/templates.md
board.py numbers candidates after shuffling. A look reference goes on as a link with no image. Do not use
varg-mockups for this: it is a storyboard template. If nobody is there, name the first passer per job and say so.
Close the loop for one or two rounds. Picks go to "more like this": FrameThrower /similar, the Are.na connection walk
(python3 -I "$S/search.py" arena-walk <block>), a person's Google Lens. Rejects go to never.md with the reason.
One per kept candidate, in refs.md (template in references/templates.md). Mark the picks when the person picks.
id · job · URL · maker · year · what I see · lends (one thing, with numbers from a measurement or record) ·
must not copy · rights (feed | words | look) · provenance label · query and rank that found it
Then pass on. Generated: the look comes next, in video-moodboard. Coded: DESIGN.md and timing.md go to hyperframes,
code-to-video-previz, kinetic-type-art or motion-formats. Anyone who recurs: character-passport.
When the piece rides a trend, search X for the format (references/experts.md). If the person asks for visual ideas, write
up to ten in ideas.md, each built from two or more references of different jobs (references/templates.md).
| Coded (HyperFrames, Remotion, three.js) | Generated (Seedance, Kling, Veo, Nano Banana) | |
|---|---|---|
| Light | none on a flat film. Where a shot has it: HDRI choice, key angle, shadow softness, glow values | real-looking source: direction, hardness, colour |
| Framing | grid, margins, scale ratios, safe zones | shot size, lens, staging |
| Texture | noise, grain shader, PBR maps | material words, or a neutral close-up reference |
| Palette | exact hex and contrast | named colours and a chosen frame, loosely held |
| Type | exact licensed font, tracking, size in px | avoid in frame; overlay in code |
| Motion | seconds per beat, ease curve, what moves first, stagger | camera verb, subject action, cut rate |
| Rights question | shipped fonts, textures, code licences, any generated person | every fed image |
| Output | DESIGN.md plus timing.md | role lines plus a look description |
Hybrid is often the answer: generate plates, and set type and data in code.
brief.json exists, with each field marked, and queries.md shows a pack for each job this piece needs.never.md has tests from a search you ran and from the person's stated hates, each one a stranger could check.refs.md has a job card per kept candidate, with what you saw, one job, what not to copy, rights and provenance.search_log.jsonl records each search, including silent zeros and blocks.links.md lists the searches only a person may open, and says what you could not find.board.html shows three candidates per job, and the person has picked, or you said why not.DESIGN.md and timing.md exist, with every value labelled measured, record, by eye or assumed.Claims in these files carry a label: tested 2026-11-03 (run that day), reported (read, not reproduced), our proposal
(a synthesis nobody has validated).
| File | Use it for |
|---|---|
references/queries.md | always: from a request to query packs, fusion, the feeling table, one worked brief |
references/light.md | the priority job for generated work: read light, search it, verify it |
references/framing.md, texture.md, palette.md, type-graphics.md, motion.md | one job each |
references/people.md, characters.md, location.md, style-boards.md, music.md | one job each |
references/never.md | never board, dated tells, keeping slop out, provenance labels |
references/judge.md | the judge protocol, commands and criteria |
references/judge-evidence.md | our bench, published bias findings, the prompts as tested, how to test your own judge |
references/sources.md | who may read what, person-run link templates, unstable endpoints |
references/experts.md | who to learn from per job, how to search X, MCP servers that exist |
references/evidence.md | what is measured, what is only our proposal, what nobody has tested |
references/templates.md | file templates: brief, want card, job card, never, links, board input, ideas, DESIGN.md, timing.md |
references/goal-prompt.md | the whole skill as one prompt to paste after /goal or into any agent, and short prompts per job |
Judge questions per job: assets/criteria/.
video-moodboard: turns chosen references into a checked board. It is the next step for generated work.hyperframes, code-to-video-previz, kinetic-type-art, motion-formats: the next step for coded work, from
DESIGN.md and timing.md.character-passport: builds the cast once the identity card is written, for anyone who recurs. Not for one still.video-sound: makes the sound once the music reference is picked, and casts voice candidates.media-judge: judges finished takes. This skill judges references.how-to-make-ai-video: the whole ten-step film. This skill is its step 1.curl -s "https://varg.ai/how-to/api/search?q=coffee+ad". It
returns how-to guides and skills to install, not references.