Thumbnail Generator
Agent workflow + deterministic renderer, adaptable to any channel. The package supplies style rules, layout templates, fonts, frame tools and the renderer; the host agent supplies understanding and judgment.
Workflow
- Video brief (host understanding, package evidence): read the video's title, description, chapters/transcript and sample frames.
scripts/video_brief.py --video V --transcript subs.srt --scenes --out brief.jsonassembles the evidence: transcript term frequencies (plain word counts, no model) and scene-cut timestamps via ffmpeg. The host then fills the brief'smain_question,showandavoid_implyingfields - what the thumbnail must honestly communicate and what it must NOT imply. The package does not understand video content by itself; it needs a host that can read video metadata, frames and text. Candidate frames:scripts/extract_frames.py VIDEO --out frames/(even sampling) or--scenes(frames at the strongest scene cuts - moments where something changed, not proof of which moment matters). - Reference selection (host agent capability): from the creator's private reference library, pick 2-3 references whose composition fits this video's subject, and note the concrete patterns (text size/placement, colour contrast, subject position).
scripts/analyze_references.py FOLDER [--labels sources.csv]gives pixel-level stats (brightness, contrast, dark/colourful share) over the creator's own local library folder to ground those choices; the library never leaves local disk and is never shipped inside this package. For larger libraries, the host can do ONE vision pass over the folder and record each reference's topics/mood/composition in a privatereference_tags.json(schema inexamples/example_reference_tags.json);scripts/match_references.py --tags reference_tags.json --topic ... --mood ...then shortlists candidates by tag overlap for the host to view. The tags file stays outside the repo next to the library, exactly like the images. - Collect missing inputs: thumbnail text (2-4 words, honest to the video), the ONE accent word, layout, style mood (one of the five in
styles.json), language (Hindi/English), and the chosen frame (a real video moment that matches the subject, not just the sharpest still). A channel profile (profiles.json) can supply defaults; explicit choices always override. Ask the creator for anything still missing. - Character reaction edit and cutout (optional; host image-editing capability): when the thumbnail needs the video's character to show a specific reaction (shock, joy, anger) that fits the video's moment, the host may edit the chosen frame with an image-editing model: preserve the character's identity, illustration style and background; change only the expression. For the cut-out look (subject lifted off the background with an outline, the dominant pattern in the reference library), have the host place the character on a flat uniform background (green screen works best) and run
scripts/make_cutout.py shot.png --out subject.png- the keying runs fully locally; only producing the uniform-background shot needs the host's image tool. Compose with--subject subject.png(stack-left/bottom-left: subject on the right with pop outline and shadow, text kept clear of it). This package contains no image model - edits use whatever image-editing capability the host environment provides, with no paid provider or signup assumed. When no such capability exists, skip this step and pick a frame whose existing expression already fits. Rules: only edit illustrated/avatar assets from the creator's own video; never fabricate a real person's expression for a real-event claim; record every edit in the run manifest (--reaction-edit) so the creator knows the expression was edited. - Distinct concepts, not colour rotations: for each video, design 2-3 genuinely different concepts - different hook, different frame/scene, different composition - and render them in one run:
scripts/run_thumbnail.py --video V --concepts concepts.json --out set.jpg(each entry in the JSON has its own title, frame, layout, concept note and optional subject/reaction_edit; one manifest records the whole set).--variants Nremains for style/layout rotations of the SAME text, which is a weaker choice for real decisions. - Render + manifest:
scripts/run_thumbnail.py --video V --title T --accent A [--profile P] [--style S] [--layout L] [--variants N] [--label K] [--lang hi] [--reaction-edit "what was edited"] [--subject subject.png] [--brief brief.json] [--channel NAME] --frame F --frame-time SECONDS --concept "..." --refs IDs --ref-notes "..." --out thumb.jpgwrites up to N variants and a*.manifest.jsonrun record (input video identity, profile, references inspected, concept, chosen frame, any reaction edit, every output). With--brief, each output getshook_evidence: transcript lines sharing the hook's words plus a warning when the hook makes an absolute claim (dead/khatam/over/...) the transcript never makes - evidence for the truthfulness review, NOT a truth verdict; a hook can share words and still misrepresent. With--channel, a per-channel design memory (.thumbnail-history/, outside the repo) warns when the new render would repeat the channel's recent pattern (same style family or layout 3 in a row, cut-out subject 3 of last 4) - warnings, never blocks, and deliberate series styling is fine; the run is then recorded. For a quick render without a manifest usescripts/make_thumbnail.pydirectly;--mobile-previewadds a 380px-wide render for the phone-size readability check. - Quality gate, two layers:
- Automatic (measurable only):
run_thumbnail.pyalready runsscripts/check_thumbnail.pyon every output and records the results in the manifest (quality_checks); warnings/fails print during the run. Checks: 1280x720 dimensions, 2MB YouTube limit, text-zone contrast at 380px phone size, and pasted-cutout brightness when a--subjectcutout was used. The subject check reads the cutout's KNOWN placement - it is not a face detector and says nothing about faces inside a background frame; frame-based renders still need your eyes. You can also run it standalone:python3 scripts/check_thumbnail.py thumb.jpg --layout stack-left --subject subject.png(exit 1 on FAIL, so it can gate a workflow). - Semantic (host judgment, never guaranteed): review what pixels cannot: (1) hook truthfulness - the text must be a question the video actually asks or a claim it supports, never an absolute invented for clicks (use the manifest's
hook_evidenceas the starting evidence, then judge); (2) imagery-topic match - the frame must belong to the video's subject (a religious or historical painting behind a tech-explainer hook is a reject); (3) style-mood fit - giant condensed hype text suits dramatic topics, calmer explainers may read better with a quieter composition; (4) variety - not the same layout + same expression on every video. Then open the image and the mobile preview: accent word is the highlighted one, no overlap with the frame's subject, edited expression still looks like the same character.
- Automatic (measurable only):
- Approve: creator approves before any upload. Targeted edits: re-run
make_thumbnail.py --spec thumb.spec.jsonwith only the changed flags.
Scope - what this package does and doesn't
- It DOES: extract/score video stills, apply the style system (fonts, colours, 4 layouts), render variants in Hindi or English, analyze a local reference folder for grounded style choices, keep an editable spec and a run manifest per thumbnail.
- It does NOT: understand the video semantically, choose the hook or concept by itself, edit images by itself (reaction edits use the host's own image-editing capability; the package only records them), verify honesty of the message, or upload anything. Those are host-agent/creator judgments and host capabilities, supplied as declared inputs. CTR learning would need channel analytics access and controlled data - not part of this package.
Layouts and styles
Four layouts (bottom-left, stack-left, center-big, split), learned from the dominant patterns in a 97-image reference library: stacked huge words with a highlight bar, centred destination titles, before/after splits, and bottom-left blocks over graded frames. Five colour combos in styles.json (documentary, finance, tech, podcast, boldred): one background, one text colour, one accent. Rules: 2-4 words, ONE accent word (highlighted), one font family.
Requirements
Python 3 with Pillow and numpy; ffmpeg on PATH for frame extraction and video metadata. No network needed at render time.
Reference library
Design patterns are learned from the creator's private reference library (97 thumbnails across reaction-face, bold typography, podcast, gaming, travel and other families). The library stays private: never include its images in this package or any distribution. analyze_references.py reads only a local folder the creator points it at.