Agent skill

Storyboard Core

by nodetool-ai in nodetool-ai/nodetool

Use NodeTool storyboard, entity-casting, rendering, and timeline-assembly tools for video production or debugging their contracts.

AGPL-3.0Auto-check passedMedia & Creative

Install Storyboard Core

skills CLI
$ npx skills add nodetool-ai/nodetool --skill storyboard-core -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install nodetool-ai/nodetool storyboard-core --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/nodetool-ai/nodetool.git skills-src && mkdir -p .claude/skills && cp -r skills-src/packages/system-skills/storyboard-core .claude/skills/storyboard-core && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
storyboard-core
GitHub stars
560
Token cost
~8.4k tokens
SKILL.md length
3,826 words
Files
1
Skills in repo
127
Repo updated
First seen
Licence
AGPL-3.0

At a glance

Use NodeTool storyboard, entity-casting, rendering, and timeline-assembly tools for video production or debugging their contracts.

  • Works in 11 steps: Find the board. list_storyboards, or… → Cast the entities. list_entities first.… → Attach the cast to the board:… → …
  • Tasks that involve Comics and storyboards
  • SKILL.md covers Pick the use-case skill, Two tool families, one board, The loop and What actually reaches the model, plus 8 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md

What it does

Storyboard Core is an agent skill from nodetool-ai/nodetool. Use NodeTool storyboard, entity-casting, rendering, and timeline-assembly tools for video production or debugging their contracts.

Its SKILL.md is about 8.4k tokens, which your agent loads only when the skill is triggered. It is a single SKILL.md file with no bundled scripts.

It sits in Media & Creative, covering Comics and storyboards and Video production. The repository describes itself as: Agent-first Creative Workspace. The licence is AGPL-3.0.

When your agent uses it

  • Tasks that involve Comics and storyboards
  • Tasks that involve Video production

Example prompts

  • “/storyboard-core”

Workflow steps

11 steps, taken from the first numbered list in SKILL.md.

  1. Find the board. list_storyboards, or read ui_context. No board yet →
  2. Cast the entities. list_entities first. A new one needs an image asset —
  3. Attach the cast to the board: edit_storyboard → {op: "set_board", entity_ids: [...]},
  4. Pin the models. find_model with capability text_to_image, then
  5. Direct. One {op: "add_shot", ...} per shot. Report the shot count and
  6. Stills. render_storyboard_stills {storyboard_id} — omit targets for every
  7. Take selection, when requested. Every render keeps the old still in
  8. Clips. render_storyboard_clips {storyboard_id} within the requested
  9. Revise one shot: revise_storyboard_clip {target, instruction}. Needs an
  10. Cut. assemble_storyboard_timeline, then validate_timeline. Re-running
  11. Finish with edit_timeline ops (Tool contract § Timeline, below).

What it can do on your machine

Read from SKILL.md and the folder at commit 339f069. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    No scripts in the folder and no shell commands in SKILL.md (its code samples are json).

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    No URLs in SKILL.md.

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

Context cost

Storyboard Core loads about 8.4k tokens when it runs. Until then it costs about 37 tokens; SKILL.md has 3,826 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~37
When it runs · the whole SKILL.md, loaded when a task matches
~8.4k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from nodetool-ai/nodetool at commit 339f069, republished under its AGPL-3.0 licence (© nodetool-ai). 3,826 words, ~8,378 tokens.

Download SKILL.mdSave it as .claude/skills/storyboard-core/SKILL.md (or your agent's skills folder).
name
storyboard-core
description
Use NodeTool storyboard, entity-casting, rendering, and timeline-assembly tools for video production or debugging their contracts.
featured
true

The shared half of every NodeTool video job. The use-case skills carry the style, the shot pattern and the briefs; this carries the machinery they all assume.

Direct video on the storyboard surface, then finish in the timeline. Use a node graph when the user requests one or needs a reusable template, as described in video-workflow.

Read the relevant part of Tool contract below before the first call in that tool family. Use the live tool schema when it differs from an example. Load other sections only when the task reaches them.

Pick the use-case skill

JobSkill
Phone-shot video with a person: UGC ad, testimonial, comedy, day-in-the-life, vlog/ugc-video
Product film: pack shot, hero, brand spot, with or without talent/product-commercial
Sound-off motion-graphics ad from real screenshots and product photos, no generated footage/motion-ad
Rebuild an existing ad or clip you were given/video-clone
Voiceover drives the picture: explainer, faceless video, narrated piece/script-video
Narrative with dialogue, score and a title: short film, trailer, scene/short-film
A campaign, not one video: entity sheets, still set, several cuts/launch-kit
A template to re-run on new inputs/video-workflow
Footage already exists and needs repair: cutout, upscale, outpaint, lip sync, generated sound/nodetool-video-post
A screen someone clicks, over the workflows behind a piece/nodetool-app-builder

If none fits, run the loop below directly.

Those skills say what the picture looks like. A second set says where the beats go, and the two compose: load the job skill for the look and the structure skill for the spine.

The structure questionSkill
Ad beats: hook, escalation, timecodes, VO discipline/commercial-beat-sheet
A product page URL in, a finished cut and its cost out/launch-commercial
A 30–120s explanation with a claim per beat/explainer-storyboard
A treatment cut to a track's sections/music-video-treatment
Eight audio-first beats, the drop at ~65%, a title card/trailer-template

These own their own briefs and beat budgets. /commercial-beat-sheet carries the board contract the other four quote; where it and this skill both describe a call, this skill is the fuller version.

Two tool families, one board

HeadlessBrowser
Namescreate_storyboard, get_storyboard, edit_storyboard, render_storyboard_stills, render_storyboard_clips, revise_storyboard_clip, assemble_storyboard_timelineui_storyboard_ + get_state, set_screenplay, add_shot, update_shot, generate_keyframe, generate_clip, revise_shot, assemble_timeline, select_shot
Needsnothing openthe board open as a tab, listed in the ui_context system block
Shot targetid, 0-based index, or slugid, 0-based index, or "selected" — no slug
Permission gateyesno (client tools bypass it)

Every tool in both families takes an explicit storyboard_id. There is no "act on whatever is open" fallback.

Prefer headless. Reach for ui_storyboard_* when the user is watching the board fill in, or when you need set_screenplay for title, logline or style_bible. Headless edit_storyboard → set_board writes screenplay-level narration and music_prompt while preserving the other screenplay fields. Bridge the two with ui_open_document {type: "storyboard", id}.

The loop

  1. Find the board. list_storyboards, or read ui_context. No board yet → create_storyboard {name, brief, style, aspect_ratio}.
  2. Cast the entities. list_entities first. A new one needs an image asset — generate_image or the user's upload — then create_entity {asset_id, kind, name, descriptor}. There is no create-from-text.
  3. Attach the cast to the board: edit_storyboard → {op: "set_board", entity_ids: [...]}, or ui_storyboard_set_entities {storyboard_id, entity_ids} on an open board. An entity not on the board seasons nothing, no matter what the shots say.
  4. Pin the models. find_model with capability text_to_image, then image_to_video or text_to_video; write both through {op: "set_board", image_model, video_model}. There is no default — an unset model fails the render rather than spending on a model nobody chose.
  5. Direct. One {op: "add_shot", ...} per shot. Report the shot count and selected models. Continue to the stages authorized by the request. A board-only request ends here. Honor any checkpoint the user requested.
  6. Stills. render_storyboard_stills {storyboard_id} — omit targets for every shot that still needs one. Cap 24 shots per call.
  7. Take selection, when requested. Every render keeps the old still in keyframe_versions. Selecting a different one requires the board's takes gallery. No tool does it. Pause if the user reserved that selection. Otherwise continue with the current take. Never claim to have switched takes without a supported action.
  8. Clips. render_storyboard_clips {storyboard_id} within the requested generation scope and budget. Reuse prior authorization instead of asking again.
  9. Revise one shot: revise_storyboard_clip {target, instruction}. Needs an existing clip; it is video-to-video and touches no other shot.
  10. Cut. assemble_storyboard_timeline, then validate_timeline. Re-running rebuilds the same sequence in place and keeps tracks the board does not own.
  11. Finish with edit_timeline ops (Tool contract § Timeline, below). Load the motion-graphics system skill with load_skill for the full op list, the presets and the preview contract. A repair on a delivered clip belongs to nodetool-video-post.

Stills-only mode. When the user wants a board and frames but no motion — a spec ad, a pitch, a look test — run steps 1 to 7 and stop. Adding the motion later is update_shot on motion alone: action, wardrobe, set and cast stay put, so the approved stills still describe the finished piece.

What actually reaches the model

The prompt is assembled from named fields, not from the whole shot:

  • Still: action, then "<camera.framing> shot", then the board's style. camera.lens, camera.angle and camera.movement do not reach it.
  • Clip (keyframe mode): motion, then action. The style does not reach it — the selected still carries the look.
  • Clip (direct mode): action, "<framing> shot", motion, style.

So a lens, an angle or a camera move only lands if you write it into action or motion. Keep the structured camera object as well — it is what the user reads on the card.

Entities season by plain name. A shot with entity_ids uses exactly those. Otherwise: every style and location entity applies to every shot, and a character or prop applies when its name appears in the shot's action, motion, dialogue, narration or slug. Write Nova reaches for the bottle, not @Nova reaches.... @ is a chat-composer affordance that emits an entity://<id> token into your message; it never becomes shot text.

Locks

  • Keep one descriptor per entity and let it do the work. Do not re-describe a face in shot text.
  • A state change (wet hair, a stained shirt, a second outfit) is a second entity, not an instruction inside one prompt.
  • Product geometry, label and colour come from the product entity's descriptor and reference image. Never invent a logo.
  • Give every shot a stable slug (1a, 2a, …) at add_shot time. Headless targets accept it, and "fix 3a" then means one shot.
  • Render mode is per shot. keyframe (default) is cheaper to iterate and holds a look steady. direct skips the still — worth it for heavy motion, where first-frame conditioning stiffens the result, and for native-audio video models, which are weakest on their image path.
  • A native-audio model writes the sound per clip, so a board of one clip per shot cuts the audio at every join. Before rendering, load the video-audio-continuity system skill through load_skill: either the whole piece is one shot carrying the cuts, or the continuity comes from a narration or music track and the shot audio is muted. A silent cut is also valid when sound is not requested. Reuse existing audio or keep the cut silent when extra generation would exceed the authorized scope.

Where the models will not do what the cut wants

Four constraints that are not bugs and have no tool to fix them. Each has a working shape.

A video model returns a fixed length. It ignores duration_seconds — the same model gives 5.184s whether the shot was directed at 1.5s or 5s. For a fast cut, render one generation per run of short beats with bracketed timecodes in the prompt and record the split with covered_by. Tool contract § Fusing shots, below, has the call.

Moderation reads the words, not the story. A prompt naming institutional force — police grabbing someone, a raid, restraint — trips a safety filter that a shot of the same threat does not. Reframe with non-trigger vocabulary and keep the stakes: "two uniformed city officials approaching with a clipboard and caution tape" passes where "two aggressive police officers grabbing her arms" does not. Reframe once; do not retry the rejected prompt.

A music model cannot leave a hole. Ask for 1.5s of silence at 00:19.5 and the decoder fills it with reverb tail and room tone — there is no envelope gate in the prompt. Cut the silence on the timeline instead: generate the score in two parts, lay them as two clips with the gap between them, and fade the first out (~300ms) and the second in (~100ms) so the edges are not clicks.

Speech does not fit a 1.5s shot. An expressive take of a line runs 4s, and compressing it to the picture beat makes it sound processed. Let the words cross the cut: keep the voiceover clip on its own track and start it under the previous shot (J-cut) or run it past the cut into the next (L-cut). The picture cuts on the beat; the line finishes where it finishes. On a script-linked board that is automatic — each shot runs as long as the lines it covers — so use this on an unlinked board or where the picture has to stay on the beat.

Gating and spend

Permission mode decides what runs without asking. read tools always run.

Modewrite / execute / external
autoruns
defaultasks the user
planblocked

plan blocks create_storyboard and edit_storyboard too, so the board cannot be written in it. Respect the active permission mode and tool approval responses. For a board-only request, write the board and omit render calls. Do not switch modes or use browser tools to evade a denied headless action. A tool being callable does not authorize spend beyond the user's request.

You cannot price a render. No tool estimates it, and Shot.cost_estimate is not populated. Report the shot count and model without inventing a dollar estimate. If a user budget cannot be checked before spending, resolve that constraint first. Report actual spend afterwards with get_cost_summary. If authorization is missing, prepare the board and explain the specific render action that needs approval.

Memory

memory_save is durable across every conversation — use it for the style bible, the cast and the grade, with the entity and board ids in resources. share_result / read_shared are run-scoped and discarded; they are for passing values inside one turn, not for locking a look across sessions.

Follow-ups this loop already handles

Fix 3a only. Leave the rest.
Drop the contre-jour across the whole board — soft even daylight. Update the
  board style, do not rewrite the shots.
New still on 2a. Keep the old take.
revise_storyboard_clip 5a: darker, add rain, same blocking.
Add a reaction shot after 3a and re-slug from there. Do not re-render 1a-3a.
Collapse 8, 9 and 10 into one 8s shot, keeping the lean-in as the last second.
The face drifted on 4a. I picked take 2 in the gallery — regenerate the clip.
The label is unreadable on 2a. New macro still, then a clip from it.
Cut it. Assemble, validate, narration on its own track, mute Shot Audio on 1-6.

What is below

  • Tool contract — every tool, its arguments, and the fields it refuses.
  • Standing orders — an optional brief for users who explicitly want approval between stages. Its sample checkpoints do not add requirements to a different request.

Tool contract

Exact arguments. Every field named here is checked in the implementation; an unrecognized field is refused with an error, not dropped.

Storyboard — headless

Work with no editor open. Shot target = shot id, 0-based index as a string, or slug.

ToolArguments
list_storyboardslimit? → id, name, shots, with_keyframe, with_clip, timeline_id, updated_at
create_storyboardname (required), brief?, style?, aspect_ratio? (default 16:9), project_id?, id?
get_storyboardstoryboard_id → brief, style, aspect ratio, narration, music_prompt, image_model, video_model, script link, and every shot with id/index/slug/action/camera/motion/duration/status/has_keyframe/has_clip/covered_by
edit_storyboardstoryboard_id, ops[] — see below
render_storyboard_stillsstoryboard_id, targets?, provider?, model?, style?, concurrency?
render_storyboard_clipsstoryboard_id, targets?, provider?, model?, resolution?, mode? (keyframe|direct), concurrency?
revise_storyboard_clipstoryboard_id, target, instruction, provider?, model?
assemble_storyboard_timelinestoryboard_id, name?, fps? (default 30)
extract_script_from_storyboardstoryboard_id, name?, relink?
delete_storyboardstoryboard_id

Render limits: 24 shots per call, concurrency default 3, max 8.

Omitting targets selects every shot that still needs that step. For stills that is every shot with no keyframe that is not set to render directly; for clips, every shot with no picture — its own or one it is covered by (§ Fusing shots). A keyframe-mode shot that reaches render_storyboard_clips with no still is reported in the results, not rendered — render its still first, or set its render_mode to direct. Each render appends to keyframe_versions / clip_versions and makes the new one selected.

edit_storyboard ops

{"op": "add_shot", ...} · update_shot {target, ...} · remove_shot {target} · reorder_shot {target, index} · set_board {...}

Shot fields (add and update both): action, slug, camera, motion, graphics, dialogue, narration, notes, duration_seconds, duration_source (audio|manual), render_mode (keyframe|direct|reference), entity_ids, location_id, covered_by, index. graphics is semantic design intent (mode, direction, exact text/assets in elements), not Timeline keyframes; pass null on update_shot to clear it.

camera is {framing?, lens?, angle?, movement?}.

covered_by is {shot_id, start_seconds?, end_seconds?} — this shot's picture is a window into another shot's clip. See § Fusing shots below. null undoes it.

Board fields (set_board only): brief, style, aspect_ratio, entity_ids, image_model, video_model, narration, music_prompt. The two model fields take a model object from find_model, or null. narration and music_prompt take strings and update the screenplay. An empty string clears that direction.

An edit cannot set keyframe, clip or status. Those belong to the render tools; passing them raises an error naming the right tool. covered_by is the one exception: coverage is a picture that arrived without a render, so setting it marks the shot rendered and clearing it puts the shot back to keyframe_ready/planned.

An edit cannot set title, logline or style_bible at the board level. Use ui_storyboard_set_screenplay for those fields. Per-shot narration remains a shot field. Board narration and music are separate screenplay fields: assemble_storyboard_timeline turns them into draft audio clips on unlinked boards.

Fusing shots

A video model returns a fixed window — 5.184s, 6s, 8s — whatever length the shot was directed at. A cut whose beats run 1.5-2.5s is therefore cheaper to render as one generation covering a run of shots and split afterwards, than as one generation per shot: fifteen 1.5-2.5s beats bought one at a time is ~77s of footage for a 30s cut.

Direct the run as one prompt with bracketed timecodes ([00:00 to 00:02.5] Event … [00:02.5 to 00:05.2] Reception), render it on the first shot of the run, then tell the board which slice each sibling uses:

json
{"op": "update_shot", "target": "06",
 "covered_by": {"shot_id": "05", "start_seconds": 2.5, "end_seconds": 5.184}}

The covered shot then reads has_clip: true with status: "rendered", is skipped by render_storyboard_clips (so it is never generated twice), and assemble_storyboard_timeline lays it down as that window of the covering clip instead of skipping it, and the covering shot ends where the first covered shot takes over. Without end_seconds the covered shot runs to the end of the covering clip.

One hop only: shot_id must name a shot that owns its clip, not another covered shot. Removing the covering shot clears the coverage and reports which shots it uncovered.

Show full SKILL.md (1,448 more words)Show less
Storyboard — browser (ui_storyboard_*)

The board must be open as a workspace tab; its id comes from the ui_context system block. Not open → edit_storyboard edits the saved board. Use ui_open_document {type: "storyboard", id} to show it to the user. Target = shot id, index as a string, or "selected". Slugs are not resolved here.

ToolArguments
ui_storyboard_get_statestoryboard_id
ui_storyboard_set_screenplaystoryboard_id, screenplay
ui_storyboard_set_entitiesstoryboard_id, entity_ids (replaces the cast; [] clears it)
ui_storyboard_add_shotstoryboard_id, action, camera?, motion?, durationSeconds?, index?
ui_storyboard_update_shotstoryboard_id, target, action?, camera?, motion?, status?
ui_storyboard_generate_keyframestoryboard_id, target
ui_storyboard_generate_clipstoryboard_id, target
ui_storyboard_revise_shotstoryboard_id, target, instruction
ui_storyboard_assemble_timelinestoryboard_id
ui_storyboard_select_shotstoryboard_id, target (nullable)
ui_storyboard_extract_script / _relink_script / _reproject_shotsstoryboard_id (+ targets?)
ui_storyboard_set_duration_sourcestoryboard_id, targets, source

ui_storyboard_add_shot and update_shot take no slug, dialogue, narration, entity_ids or render_mode. In the browser those arrive only through set_screenplay; headless, through edit_storyboard.

Generation is asynchronous: generate_keyframe / generate_clip start the job and return the shot. Poll ui_storyboard_get_state for status.

Statuses: planned → keyframe_generating → keyframe_ready → clip_generating → rendered, or failed. (approved is legacy and reads as "still ready"; nothing sets it. Do not use it as a gate.)

screenplay for set_screenplay
json
{
  "type": "screenplay",
  "title": "…",
  "logline": "…",
  "brief": "…",
  "styleBible": "…",
  "aspectRatio": "9:16",
  "narration": "…",
  "musicPrompt": "…",
  "entityIds": ["<asset id>"],
  "shots": [
    {
      "slug": "1a",
      "action": "Nova touches untreated hair, front-camera close",
      "camera": { "framing": "close-up", "lens": "26mm", "angle": "eye", "movement": "handheld" },
      "motion": "she lifts one section of hair and lets it fall, once",
      "dialogue": "I wanted lighter hair…",
      "durationSeconds": 4,
      "entityIds": ["<asset id>"]
    }
  ]
}

Ids, indexes and statuses are filled in. style is accepted as an alias of styleBible. Only action is required per shot.

The top-level entityIds casts those entities on the board — that cast is what seasons every shot's still and clip prompt. Use ui_storyboard_set_entities to recast without replacing the shots; ui_storyboard_get_state reports the current cast as entityIds. A shot's own entityIds overrides the board cast for that shot ([] means "no entities on this shot"); without one, styles and locations apply to every shot and characters and props apply to the shots whose text names them.

Entities
ToolArguments
list_entitieskind? (character|location|style|prop), query?, limit?
get_entityentity_id
create_entityasset_id, kind, name, descriptor (all required), description?, voice_id?, tags?, lora?, palette?
update_entityentity_id + any field, including asset_id to move it to a new photo
delete_entityentity_id — clears the marker, keeps the image
apply_entitiestext, entity_ids? → seasoned prompt + reference asset ids

An entity is an image asset carrying a marker. Its id is the asset id. To make one from nothing: find_model (text_to_image) → generate_image → create_entity with the returned asset id. To make one from a photo the user attached: find it with asset_search / list_assets, then create_entity.

apply_entities is for seasoning a prompt you are about to send yourself (generate_image, generate_video). The storyboard render tools season internally — do not pre-season shot text with it.

Timeline

assemble_storyboard_timeline lays rendered clips end to end, stamps each with its board and shot id, and gives every shot clip an audio twin on a "Shot Audio" track (each surface mutes video elements and mixes audio clips only). Board narration and music become draft clips on their own tracks.

Each shot is as long as its render, not as long as its duration_seconds — a shot directed at 1.5s that came back at 5.184s occupies 5.184s of the cut. Shots that came back off their directed length are returned in retimed_shots and warned about, so a cut that runs longer than planned is visible without playing it. duration_seconds only decides a shot whose footage has no measurable length. A board linked to a script is the exception: there the words decide, and trimmed_shots names the shots whose footage does not fill the slot its lines gave it.

edit_timeline {timeline_id, ops[]} ops: get_state, add_track, add_media_clip, add_text_clip, add_shape_clip, split_clip, trim_clip, move_clip, duplicate_clip, delete_clip, set_clip_params, set_clip_binding, animate_clip, clear_animations, list_animation_presets, select_clip, seek. Start with get_state for ids.

To duck the shots' own sound under a voiceover: set_clip_params on the Shot Audio clips with muted: true, or volumeDb: -18. set_clip_params also takes name, opacity, speedMultiplier, fadeInMs, fadeOutMs, blendMode, borderRadius, hidden, locked, textStyle, shapeStyle.

Every field goes on the op itself. A params / props wrapper is unwrapped, but the flat form is the contract:

json
{"op": "set_clip_params", "target": "clip_1",
 "textStyle": {"fontFamily": "Space Grotesk", "fontWeight": 800}}

textStyle is merged over the clip's own, so send only what you are changing — re-sending the whole object is how the fields you did not mean to touch get overwritten. fontWeight is a number, and the CSS keywords (bold, semibold, extrabold) are accepted and stored as one.

Set a bundled family or none at all. sans-serif, serif, system-ui and the other CSS generics are refused where the clip is authored: they name no typeface, so the editor preview, the render and preview_timeline_frame each pick a different one. NodeTool ships Inter (the default), Space Grotesk, Bebas Neue, Playfair Display, Lora and JetBrains Mono. A named system font is still allowed and validate_timeline reports it as font_not_portable.

validate_timeline {timeline_id | document, fps?} after every edit pass. It catches overlaps, fades longer than their clip, unknown presets and incomplete bindings.

Other timeline tools: list_timelines, create_timeline, get_timeline, delete_timeline, and the version family (list_/get_/create_/restore_/ delete_timeline_version). Browser twins are ui_timeline_*.

Script

Use a script when the words drive the cut. extract_script_from_storyboard projects a board's dialogue and narration into a script and links the two: each shot keeps the line ids it covers, and from then on the script owns the words. derive_storyboard_from_script goes the other way, one shot per line, optionally with a director pass over the scaffold.

voice_script_lines synthesizes each line with its cast voice; assemble_script_timeline lays the takes end to end.

Give the cast their voices first, then voice with no override. A voice is the triple {provider, model, voice} where voice is the voice's own name (Aoede, Charon, alloy) — a provider and a model alone do not pick one, so voice_script_lines {provider, model} is refused. Set each speaker once:

json
{"op": "set_speaker_voice", "target": "MOM",
 "provider": "gemini", "model": "tts-hd", "voice": "Aoede"}

The three keys sit on the op, though a voice: {provider, model, voice_id} object — the shape get_script reports a voice in — is flattened onto it. Then call voice_script_lines {script_id} with no override and every speaker resolves its own. On a linked board, assemble_storyboard_timeline cuts words and picture together: each shot runs as long as the takes it covers and every voiced line gets its own voiceover clip.

Others: list_scripts, get_script (line status: draft, stale, voiced, no_voice), create_script, edit_script, delete_script. Browser twins are ui_script_*.

Writing the lines

create_script makes an empty one. edit_script {script_id, ops[]} ops: set_setup (brief, format, length, pace, language, stage), add_speaker, set_speaker, set_speaker_voice, add_section, add_line, set_line_text, set_line_speaker, remove_line, remove_speaker. Call get_script first for line and speaker ids.

write_script {script_id, rewrite?, imported_text?} drafts the lines from the setup and saves the cast and lines it produces, replacing what was there. Set the brief with set_setup first. rewrite: true keeps the ids of the lines it keeps, so their takes and storyboard links survive. Words passed as imported_text are only split into lines and attributed to speakers, never reworded. It records no take: voice the result with voice_script_lines.

Rewriting a line leaves its takes in place as stale, so a following voice_script_lines re-records exactly those and nothing else.

Models

find_model {capability, query?, task?, provider_hint?, model_hint?, prefer_local?, limit?} is the only way to name a model. capability is required and is one of text_to_image, image_to_image, text_to_video, image_to_video, text_to_speech, text_to_music, automatic_speech_recognition, generate_embedding, generate_message. query is the search box ("flux schnell"); task is a hint matched against a model's supported tasks, not a search.

NodeTool ships curated ids under the nodetool provider, which are the sane defaults when the user has no preference:

IdUse
nodetool/flux-schnellcheapest stills, text prompts only
nodetool/nano-bananasharper stills, takes reference images
nodetool/seedreammost detail, slowest
nodetool/hailuo-fastcheapest clips, for blocking out a cut
nodetool/kling-turbosteadier motion, mid price
nodetool/kling-standardmost faithful motion
nodetool/kokoroeight TTS voices
Media, outside the board

generate_image {provider, model, prompt, negative_prompt?, width?, height?, quality?, output_file?}, plus edit_image, generate_video, animate_image, generate_speech, generate_music and transcribe_audio — each takes a find_model provider+model and saves an asset:// result. model also accepts a whole find_model hit or its .ref, in which case provider may be omitted.

understand_video {provider, model, video, prompt?, max_tokens?} reads a whole video with a multimodal model (Gemini reads video natively); use it to break down a reference cut. video takes an asset id, an asset:// URI, a URL or a data URI. view_image puts pixels in your own context; read_media_bytes returns the bytes.

The Director node

nodetool.creative.Director is a workflow node, not a chat surface. It turns a brief into a Screenplay (props: model, brief, style, shot_count; outputs screenplay, narration, music_prompt, title). Reach for it only inside a reusable graph. In chat, write the shots yourself with edit_storyboard — same artifact, no graph to build and validate.

Standing orders

Use this optional template only when the user wants a staged review with approval between the board, stills, clips, and cut. Its checkpoints express that user's chosen workflow. They do not apply to other requests or override authorization already given to finish a piece.

Respect the thread's existing permission mode. Plan mode blocks writes. Do not switch modes or use another tool family to evade a denial. The user can adapt the brief to authorize the desired stages and set a budget.

You are directing on the storyboard surface, then finishing in the timeline.
Do not build a node graph unless I ask for a reusable template.

SURFACES
Headless: create_storyboard, get_storyboard, edit_storyboard,
render_storyboard_stills, render_storyboard_clips, revise_storyboard_clip,
assemble_storyboard_timeline, extract_script_from_storyboard.
Browser (only for a board open as a tab): ui_storyboard_get_state,
ui_storyboard_set_screenplay, ui_storyboard_generate_keyframe,
ui_storyboard_generate_clip, ui_storyboard_revise_shot,
ui_storyboard_assemble_timeline. Use ui_open_document to open a board.

LOOP
1. list_storyboards, or read ui_context. No board -> create_storyboard.
2. Cast before anything renders. list_entities first. A new entity needs an
   image asset: generate_image (or my attachment), then create_entity with
   {asset_id, kind, name, descriptor}. There is no create-from-text.
   Each entity: one name, one kind, one canonical descriptor sentence.
3. edit_storyboard set_board {entity_ids, image_model, video_model,
   brief, style, aspect_ratio, narration, music_prompt}. Models come from find_model — there is no
   default and an unset model fails the render.
4. Direct with edit_storyboard add_shot, one op per shot. Give every shot a
   slug (1a, 2a, ...). Fields: action, slug, camera {framing, lens, angle,
   movement}, motion, dialogue, narration, duration_seconds, render_mode.
5. STOP after the board. Report shot count and the two model ids. Do not
   estimate dollars — no tool prices a render. Wait for "stills".
6. render_storyboard_stills. I pick takes in the board's takes gallery; you
   cannot select a take and must not claim you did. Wait for "clips".
7. render_storyboard_clips. revise_storyboard_clip touches one shot only.
8. On "cut": assemble_storyboard_timeline, then validate_timeline.

WRITING THE SHOTS
Only these reach the image model: action, camera.framing, and the board style.
Only these reach the video model: motion and action (plus framing and style on
a direct-mode shot). So put lens, angle and camera move into the action or
motion text as well as into the camera object.
Name entities in plain text — "Nova reaches for the bottle", never "@Nova".
Entities season a shot when their name appears in its action, motion, dialogue,
narration or slug; styles and locations season every shot. A shot's entity_ids,
if set, overrides that entirely.

LOCKS
- The descriptor is the face. Do not re-describe an entity in shot text.
- Product geometry, label, cap and colour come from the product entity. No new
  logos.
- A state change (wet, stained, new outfit) is a second entity, not a morph
  instruction inside one prompt.
- Slugs stay stable. "Fix 3a" edits 3a and renders 3a.
- UGC: handheld phone, grain, natural audio, no score, no beauty filter.
  Hero: locked grade in the style, smooth camera, score allowed.
- render_mode "keyframe" (default) for anything where the look must hold;
  "direct" for heavy motion or a native-audio video model.

MEMORY
memory_save the style, the cast and the grade, with the entity and board ids in
`resources` — that survives into later threads. share_result/read_shared are
run-scoped and get discarded; do not use them to lock a look.

If the shot count looks expensive, propose a collapse before rendering clips.

© nodetool-ai, AGPL-3.0. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

Just SKILL.md in packages/system-skills/storyboard-core of nodetool-ai/nodetool.

Open the folder on GitHubat commit 339f069

Compare with similar skills

Storyboard Core next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Storyboard Core compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Storyboard Core this skillnodetool-ai/nodetool560—~8.4kAutomated safety check: PassAGPL-3.0
Scroll Promo Site Builderkangarooking/kangarooking-skills662—~2.6kAutomated safety check: PassMIT
Paper Collage Explainer Generatortl2012tl/comfyUI-llama-TE2414 repos~5.2kAutomated safety check: PassNone
Video ComposeUtopai-Research/pai-code357—~4.1kAutomated safety check: PassCustom licence
Ffmpegrendi-api/ffmpeg-cheatsheet1.7k—~1.2kAutomated safety check: PassNone
Remotion VideoTechNomadCode/AI-Product-Development-Toolkit1k—~1.1kAutomated safety check: PassMIT

Similar skills

  • Scroll Promo Site Builder

    kangarooking/kangarooking-skills

    Create a scroll-controlled cinematic product website with rich motion (动效网站) from product materials, reference pages or videos, and brand assets.

    662 GitHub stars~2.6k tokensUpdated 1 mo ago
    Media & CreativeAuto-check passed
  • Paper Collage Explainer Generator

    tl2012tl/comfyUI-llama-TE

    For creators, educators, and social-video editors who need a tactile paper-collage language for narration, knowledge points, opinions, or abstract topics.

    241 GitHub starsUsed in 4 repos~5.2k tokens
    Media & CreativeAuto-check passed
  • Video Compose

    Utopai-Research/pai-code

    Generates and prompts video clips on the filmmaking canvas. An agent skill from Utopai-Research/pai-code.

    357 GitHub stars~4.1k tokensUpdated 11 days ago
    Media & CreativeAuto-check passed
  • Ffmpeg

    rendi-api/ffmpeg-cheatsheet

    A skill your agent uses when the user asks for FFmpeg or FFprobe commands, video/audio conversion, trimming, resizing, padding, overlays, subtitles, thumbnails, GIFs, storyboards, slideshows…

    1.7k GitHub stars~1.2k tokensUpdated 5 mo ago
    Media & CreativeAuto-check passed
  • Remotion Video

    TechNomadCode/AI-Product-Development-Toolkit

    Make a short video about a product or brand (promo, launch, explainer, demo or social clip) entirely in code with Remotion, from idea to a rendered MP4 with sound.

    1k GitHub stars~1.1k tokensUpdated 5 days ago
    Media & CreativeAuto-check passed
  • Video Plan

    MagicCube/agentara

    Plan short-form video, vlog, travel, lifestyle, documentary, or cinematic social video scripts by negotiating duration, choosing a story arc and visual style, then splitting the film into timed…

    516 GitHub starsUsed in 1 repo~2.6k tokens
    Media & CreativeAuto-check passed

More from nodetool-ai/nodetool

All 127 skills in this repo
  • Beat Sync Editing

    nodetool-ai/nodetool

    Cut a NodeTool timeline to music and shape its pacing — detect the beat grid, place cuts on phrases, pick a cut type, build speed ramps with time remap, and give the piece an arc.

    560 GitHub stars~2.6k tokensUpdated today
    Auto-check passed
  • Caption Titles

    nodetool-ai/nodetool

    Add and animate a consistent text layer on an existing NodeTool timeline.

    560 GitHub stars~1.9k tokensUpdated today
    Auto-check passed
  • Color Motion

    nodetool-ai/nodetool

    Choose and animate colour on a NodeTool timeline, including shape and text gradients, colour grades, 3D LUTs, and dither.

    560 GitHub stars~2.3k tokensUpdated today
    Auto-check passed
  • Commercial Beat Sheet

    nodetool-ai/nodetool

    Write a shootable, precisely timed commercial beat sheet and store it as a NodeTool storyboard, with a consistent entity roster behind every shot.

    560 GitHub stars~4.6k tokensUpdated today
    Auto-check passed
  • Elevenlabs Audio Prompting

    nodetool-ai/nodetool

    Direct ElevenLabs speech, dialogue, sound effects and music — the bracketed audio tags v3 acts on and why the voice decides whether a tag lands, stability as the delivery dial, punctuation instead…

    560 GitHub stars~1.9k tokensUpdated today
    Auto-check passed
  • Frame Composition

    nodetool-ai/nodetool

    Stage the frame on a NodeTool timeline — grids, focal placement, safe areas per aspect ratio, depth layers and parallax, camera moves, and where elements enter and leave.

    560 GitHub stars~3.5k tokensUpdated today
    Auto-check passed

Questions about Storyboard Core

What does Storyboard Core do?

Use NodeTool storyboard, entity-casting, rendering, and timeline-assembly tools for video production or debugging their contracts. Storyboard Core is an agent skill from nodetool-ai/nodetool. Use NodeTool storyboard, entity-casting, rendering, and timeline-assembly tools for video production or debugging their contracts.

When should I use Storyboard Core?

Storyboard Core fits situations like: tasks that involve Comics and storyboards; tasks that involve Video production.

How do I install Storyboard Core in Claude Code?

Run `npx skills add nodetool-ai/nodetool --skill storyboard-core -a claude-code`. Or copy the skill folder (packages/system-skills/storyboard-core in nodetool-ai/nodetool) into .claude/skills/storyboard-core in your project. Claude Code loads it when a task matches its description.

How do I install Storyboard Core in Codex?

Run `npx skills add nodetool-ai/nodetool --skill storyboard-core -a codex`. Or copy the skill folder (packages/system-skills/storyboard-core in nodetool-ai/nodetool) into .agents/skills/storyboard-core in your project. Codex loads it when a task matches its description.

Can I use Storyboard Core in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add nodetool-ai/nodetool --skill storyboard-core -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/storyboard-core, .gemini/skills/storyboard-core, .github/skills/storyboard-core and .opencode/skills/storyboard-core in your project.

What does Storyboard Core need to run?

SKILL.md names no scripts, command-line tools or credentials: Storyboard Core is instructions for the agent only.

Does Storyboard Core access the network?

SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.

Is Storyboard Core safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Storyboard Core use?

Storyboard Core is published under the AGPL-3.0 licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Storyboard Core use?

About 8.4k tokens (SKILL.md is roughly 34k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full.

What are the alternatives to Storyboard Core?

Skills that share tags, products or a category with Storyboard Core: Scroll Promo Site Builder (kangarooking/kangarooking-skills, 662 stars), Paper Collage Explainer Generator (tl2012tl/comfyUI-llama-TE, 241 stars), Video Compose (Utopai-Research/pai-code, 357 stars) and Ffmpeg (rendi-api/ffmpeg-cheatsheet, 1.7k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Storyboard Core?

nodetool-ai (a GitHub organization) maintains it in nodetool-ai/nodetool, which has 560 GitHub stars. The repository holds 127 skills in this directory. The repository was last updated on October 10, 2026.

Source: nodetool-ai/nodetool on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.