Agent skill

Frame Composition

by nodetool-ai in 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.

AGPL-3.0Auto-check passedMedia & Creative

Install Frame Composition

skills CLI
$ npx skills add nodetool-ai/nodetool --skill frame-composition -a claude-code

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

GitHub CLI
$ gh skill install nodetool-ai/nodetool frame-composition --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/frame-composition .claude/skills/frame-composition && 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
frame-composition
GitHub stars
560
Token cost
~3.5k tokens
SKILL.md length
1,920 words
Files
1
Skills in repo
127
Repo updated
First seen
Licence
AGPL-3.0

At a glance

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.

  • A layout must survive 16:9 and 9:16
  • SKILL.md covers Four coordinate spaces, and…, Text is placed by containers, Grid and One focal point, plus 7 more sections
  • Instructions only: no scripts, shell commands, URLs or credentials in SKILL.md
  • A parallax move

What it does

Frame Composition is an agent skill from 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. Use when placing titles, lower thirds, shapes or overlays, when a layout must survive 16:9 and 9:16, when adding a push or a parallax move, or when a frame reads flat or cramped. Not for what a clip says or when it cuts.

Its SKILL.md is about 3.5k 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. The repository describes itself as: Agent-first Creative Workspace. The licence is AGPL-3.0.

When your agent uses it

  • A layout must survive 16:9 and 9:16
  • A parallax move
  • A frame reads flat

Example prompts

  • “/frame-composition”

What it can do on your machine

Read from SKILL.md and the folder at commit 58765d3. 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 javascript and 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

Frame Composition loads about 3.5k tokens when it runs. Until then it costs about 102 tokens; SKILL.md has 1,920 words of instructions outside code blocks.

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

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 58765d3, republished under its AGPL-3.0 licence (© nodetool-ai). 1,920 words, ~3,505 tokens.

Download SKILL.mdSave it as .claude/skills/frame-composition/SKILL.md (or your agent's skills folder).
name
frame-composition
description
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. Use when placing titles, lower thirds, shapes or overlays, when a layout must survive 16:9 and 9:16, when adding a push or a parallax move, or when a frame reads flat or cramped. Not for what a clip says or when it cuts.
featured
true

Frame Composition → staging on the timeline

Where things sit, how deep the frame is, and how the camera moves through it. motion-graphics is the build loop; timeline-edit-ops carries the op contract. This decides the coordinates you pass either.

Four coordinate spaces, and mixing them is the usual bug

WhatSpaceRead as
shapeStyle.x/y/width/height, x2/y2, d0..1 of the frame0.5 is the frame's middle
set_mask x/y/width/height, d0..1 of the layer0.5 is the clip's own middle, not the frame's
positionX / positionY curvescanvas pxAbsolute, and folds as replace
offsetX / offsetY curvescanvas px, addedComposes with everything else
slide distance, kenBurns driftX/driftYfraction of frame width or height0.3 travels 30% of the frame
anchorX / anchorY0..1The point a scale or a rotation pivots on
textStyle.fontSizePxsequence pxAgainst height from get_timeline, not the preview width
transform.depthPx, camera2d.position/depthPx/focalLengthPxsequence pxPerspective; clip depth also orders clips within one track
layout.gap, layout.paddingsequence pxFlex container spacing, measured against its children's rendered boxes

Read width, height and fps off get_timeline before you compute anything. A layout authored against 1920×1080 and saved onto a 1080×1920 sequence is off by more than a crop.

Text is placed by containers

Building with @nodetool-ai/sandbox-timeline (see motion-graphics for when code is the right surface)? A container decides where its children sit — you almost never write x/y for text. s.stack(children, o) and s.row(children, o) build a real Yoga flex container and reparent children onto it as its real children — nest freely, a row of stacks or a stack holding a nested row both resolve correctly. A text child reflows to whatever width Yoga offers it, not a guessed line length.

The container's own placement in the frame is o.at ({x, y}, default the frame centre) plus o.anchor (default "center"): anchor names the point of the container's own computed box that lands at at — the name "left" puts that box's left edge at at.x, no measuring a sibling's width required. Named anchors: "top-left", "top", "top-right", "left", "center", "right", "bottom-left", "bottom", "bottom-right", or pass {x, y} fractions directly. o.align (cross axis, default "start") and o.justify (main axis, unset) are the Yoga alignItems/justifyContent. A child's own flex sizing is o.flexItem on that child's own call (grow, width, alignSelf, …); absolute: true on a rect/ellipse (or any clip) takes it out of flow and resizes it to fill its flex parent's box exactly — how a plate sits behind a card's text with no pixel math.

Reach for explicit x/y only for decoration (a stray mark, a background shape) or a deliberate free placement that has nothing to do with reading order. Anything a viewer reads — a title, a kicker, a caption, a row of stats — goes in a container.

Title block — kicker, title, sub, stacked with a shared rhythm:

js
// fragment
const kicker = s.kicker("LAUNCHING TODAY");
const title = s.text("Round-ups", { size: 120, weight: 700 });
const sub = s.text("on every card", { size: 40 });
s.stack([kicker, title, sub], { gap: 20 });

Lockup — a mark beside its wordmark, one row:

js
// fragment
const mark = s.image(logoAssetId);
const wordmark = s.text("Northwind", { size: 64, weight: 700 });
s.row([mark, wordmark], { gap: 16, align: "center" });

Card — a padded column over an absolute plate:

js
// fragment
const plate = s.rect(1, 1, "#0c2a21", { r: 24, absolute: true });
const heading = s.text("Plan Pro", { size: 48, weight: 700 });
const price = s.text("$12/mo", { size: 32 });
s.stack([plate, heading, price], { gap: 8, padding: 24 });

List / grid — a row that wraps into a grid when it runs out of width:

js
// fragment
const chips = ["Round-ups", "Instant transfers", "No fees"].map((t) => s.pill(t));
s.row(chips, { gap: 12, wrap: true });

Grid

Twelve columns for landscape, six for vertical. For a 1920-wide frame with a 100px outer margin and a 24px gutter:

content = 1920 − 2×100 = 1720
column  = (1720 − 11×24) / 12 = 121.3px

Space everything in multiples of 8. fontSizePx for body copy sits near 2.5–4% of frame height; below 2.5% validate_timeline reports text_illegible. Choose the family, weights, and title scale from motion-direction § Typography before placing text on this grid.

One focal point

Place the subject on a thirds power point, not dead centre, unless the piece uses symmetry deliberately. The intersections:

SequencePower points (px)
1920×1080x 640 / 1280, y 360 / 720
1080×1920x 360 / 720, y 640 / 1280
1080×1080x 360 / 720, y 360 / 720

Rank the eye's path by size, then contrast, then colour, then position. One primary per frame; everything else supports. Leave negative space around it — a frame filled edge to edge reads as cheap and gives the motion nowhere to go.

Depth: planes and track order

Split the picture into background, midground and foreground. Track index controls order between tracks: lowest index draws on top. Within one track, clips sort by transform.depthPx: farther values draw first and nearer, positive values draw later, in front. The same depth controls perspective under the sequence's camera2d. Moving a clip to another track changes its overlap order but not its camera distance.

PlaneSuggested track indexClip depthMotion and look
ForegroundlowestNearer, positiveThe move the eye follows; sharp unless focus shifts
MidgroundmiddleAround zeroThe subject and contrast peak
BackgroundhighestFarther, negativeSmall drift and lower contrast

For flat parallax, run three speeds over one window. One kenBurns per layer with zoom: 0 and a different drift is a fullClip preset, so all three cover the same span:

json
{"role": "loop", "preset": "kenBurns",
 "params": {"zoom": 0, "driftX": -0.02, "driftY": 0}}

Background −0.02, midground −0.06, foreground −0.12. One layer at one speed is not parallax, it is the template moving.

For a shared 2.5D move, give the layers distinct transform.depthPx values and keyframe the sequence's camera2d. Its absolute timeMs keyframes interpolate camera position and depth linearly. focusDepthPx and aperturePx control depth of field. Use one camera move to connect the planes, then inspect a middle frame for unwanted scale or blur. Set track indexes for overlap between tracks and clip depth for order within a track.

For a tilted card wall, parent the cards to a group with the wall's 2D rotation, rotationX, and perspective. Give each card its own depthPx and scroll curve, then use camera2d for the shared push and depth blur. This is a flat card projection: preview the wall at several frames to check that spacing, overlap, and blur read as one assembly.

For a move with a shape of its own, write a custom curve instead and mind the role: an in window holds its t=0 values before it and contributes nothing after, an out window holds its t=1 values after it, and a loop repeats its cycle — so a one-way travel that must stay where it landed is an out, and a loop curve has to return to the value it started on or it jumps every cycle.

Parent the assembly to a group when the layers must hold their relationship through a move: add_group, then animate the group. Children keep their own tracks, so grouping never changes what covers what. For a transition on the assembled picture, set transitionIn on the group. The children stay parented on their own tracks while the transition acts once on their precomposed surface.

Shape geometry is rasterized inside a frame-sized source surface before the clip is placed. Keep normalized shapeStyle geometry inside that surface, then move the clip or parent group with transform.position or custom offsetX/offsetY curves for scrolling walls and flying cards. Geometry authored outside the source surface clips before placement.

Show full SKILL.md (812 more words)Show less

Camera moves

Choose between a sequence camera move and a local clip move. camera2d keyframes move the view across all depth planes. A layer animation moves one clip, and its anchor decides where scale or rotation pivots.

MoveHowTiming
Push / pullkenBurns with zoom 0.08–0.2 and direction in or out1500–4000ms, easeInOut
DriftkenBurns driftX / driftY, ±0.02–0.08Same window as the zoom
Pancustom curve on offsetX across the clip800–2000ms, easeInOut
WhipoffsetX over 150–250ms with a blur effect at 12–24pxOn a cut, never mid-shot
FollowoffsetX and offsetY tracking the subject, subject held off-centre and leadingWhatever the action takes

camera2d is a document field. set_clip_params changes a clip's transform but refuses camera2d, layout, repeater, motionBlur, and other new document fields. Read the full document with get_timeline, change the relevant fields, then write the full document with set_timeline_document. Keep its tracks, clips, markers, tempo, setup, media tracks, template identity, and other fields in the write. timeline-edit-ops carries the op contract.

kenBurns is fullClip: it ignores durationMs and delayMs and runs across the whole clip. To time a push to something shorter, write it as a custom scale curve instead.

One move per beat. A push plus a pan plus a rotate reads as chaos, and the three fold together into a direction nobody chose.

Enter and exit

Motion that follows reading direction feels natural; reversing it reads as going back. Match slide's direction to intent — it names the edge the element arrives from:

  • New content: from the right, or from below.
  • Dismissing or undoing: reverse the entrance.
  • Drilling in: pop, or a scale curve rather than a travel.

Enter and leave through the nearest edge. Keep distance at or below 0.35 or the travel reads as a slide of the whole template — pair a longer move with a scale or opacity change on the same window. Same vocabulary on the cut: set_transition direction on wipe, push and slide also names the edge the incoming clip arrives from.

Safe areas

Keep titles, logos, faces and calls to action inside the margin. The numbers are fractions of the frame, so convert against width and height.

AspectTopBottomSides
16:95%5%5%
9:1612–14%18–20%6%
1:17%7%7%
4:58%8%6%

On 1080×1920 that leaves the usable band roughly y 250 to y 1570. A caption clip already sits at bottomMarginFrac 0.12 by default, which is inside the phone UI zone on some platforms — raise it rather than assuming.

One layout, several aspects

Master in the widest target with the focal point inside the centre band, then restack for vertical: move the headline above the subject, pull the subject up out of the bottom UI zone, and raise fontSizePx by about 20%. Cropping a 16:9 layout to 9:16 clips whatever sat in the outer columns, which is usually the logo and the call to action.

Building in code, restacking is usually one option change on the container above — flip s.row to s.stack (or its align/justify), or move it to a new at/anchor — not a rebuild of every child's x/y.

On the ops path, layout: {display: "flex", flexDirection: "row" | "column", gap} on a group clip keeps its real children (their parentId names the group) laid out with ordinary CSS flexbox — justifyContent/alignItems position them, padding insets the container. For a shape behind text, give the shape flexItem: {position: "absolute", inset: 0} inside a padded flex column holding the text: the shape's box resizes to the text's padded box, including an animated font size, with no manual pixel math. These relations avoid redoing pixel math for each text change. A 16:9 document still needs a separate placement pass for 9:16, with safe areas checked at that size.

Check the frame, not the document

preview_timeline_frame composites the real picture — every track in order, transforms and opacity applied, animations mid-flight. Read the layer list it returns beside each frame: it names the stack top first with each layer's z_index, opacity and wipe progress, which answers most staging questions without looking at a pixel.

Preview at the midpoint of every move, not at its ends. What frames catch and a validator cannot: a title that slid outside the frame, a scrim covering the face it was meant to sit beside, a lower third under the wrong element because two track indexes are the wrong way round, a layer that never draws because it is on an audio track.

Before you finish

  • One focal point, on a power point or deliberately centred.
  • Every element assigned a track for overlap order and a depth plane when the camera moves.
  • One camera move or eased layer move, 800–4000ms.
  • Entrances through the nearest edge, distance ≤ 0.35 or paired with a second channel.
  • Critical content inside the safe margin for every target aspect, vertical restacked rather than cropped.
  • Previewed at the midpoints, and the layer stack read.

© 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/frame-composition of nodetool-ai/nodetool.

Open the folder on GitHubat commit 58765d3

Compare with similar skills

Frame Composition 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.

Frame Composition compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Frame Composition this skillnodetool-ai/nodetool560—~3.5kAutomated safety check: PassAGPL-3.0
Guizang Social Cardsop7418/guizang-social-card-skill7.4k1 repos~7.8kAutomated safety check: PassAGPL-3.0
Weekly Changelog Videoheygen-com/hyperframes59k—~3.3kAutomated safety check: PassApache-2.0
Anthropic Brand Stylinganthropics/skills180k30 repos~559Automated safety check: PassApache-2.0
MoneyPrinterTurbo Video Generatorharry0703/MoneyPrinterTurbo129k—~2.1kAutomated safety check: WarnMIT
Brag Slim Launch Video Makerlatent-spaces/brag14k1 repos~1.9kAutomated safety check: PassMIT

Similar skills

  • Guizang Social Cards

    op7418/guizang-social-card-skill

    Produces social card sets for Xiaohongshu and WeChat: carousels, Live Photo motion cards and puzzle layouts, and WeChat cover pairs, rendered from single-file HTML.

    7.4k GitHub starsUsed in 1 repo~7.8k tokens
    Media & CreativeAuto-check passed
  • Weekly Changelog Video

    heygen-com/hyperframes

    Turns a weekly changelog markdown file into a branded HyperFrames video with voiceover, animated mock-UI scenes and captions, using fonts, background and scripts bundled in the skill.

    59k GitHub stars~3.3k tokensUpdated today
    Media & CreativeAuto-check passed
  • Anthropic Brand Styling

    anthropics/skills

    Official

    Applies Anthropic's brand colors and fonts to artifacts such as PowerPoint slides, using fixed hex values for text and accents, Poppins headings and Lora body text.

    180k GitHub starsUsed in 30 repos~559 tokens
    Media & CreativeAuto-check passed
  • MoneyPrinterTurbo Video Generator

    harry0703/MoneyPrinterTurbo

    Installs and runs MoneyPrinterTurbo to turn a topic or script into a finished short video with voice-over, subtitles, stock footage and music.

    129k GitHub stars~2.1k tokensUpdated today
    Media & CreativeAuto-check: warnings
  • Builds a short, shareable launch video with music and motion from a project directory or a website URL, using only tools already on the machine.

    14k GitHub starsUsed in 1 repo~1.9k tokens
    Media & CreativeAuto-check passed
  • HyperFrames Media Use

    heygen-com/hyperframes

    Finds, generates and edits media for HyperFrames video projects: music, sound effects, images, icons, logos, voiceovers, captions and color grades.

    59k GitHub stars~2.4k tokensUpdated today
    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
  • Gpt Image 2 Prompting

    nodetool-ai/nodetool

    Prompt OpenAI's GPT Image 2 — the five-slot Scene/Subject/Details/Use case/Constraints template it responds to, the change-versus-preserve shape for edits, labelled multi-image compositing, and how…

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

Questions about Frame Composition

What does Frame Composition do?

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. Frame Composition is an agent skill from 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.

When should I use Frame Composition?

Frame Composition fits situations like: A layout must survive 16:9 and 9:16; A parallax move; A frame reads flat.

How do I install Frame Composition in Claude Code?

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

How do I install Frame Composition in Codex?

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

Can I use Frame Composition 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 frame-composition -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/frame-composition, .gemini/skills/frame-composition, .github/skills/frame-composition and .opencode/skills/frame-composition in your project.

What does Frame Composition need to run?

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

Does Frame Composition 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 Frame Composition 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 Frame Composition use?

Frame Composition 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 Frame Composition use?

About 3.5k tokens (SKILL.md is roughly 14k 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 Frame Composition?

Skills that share tags, products or a category with Frame Composition: Guizang Social Cards (op7418/guizang-social-card-skill, 7.4k stars), Weekly Changelog Video (heygen-com/hyperframes, 59k stars), Anthropic Brand Styling (anthropics/skills, 180k stars) and MoneyPrinterTurbo Video Generator (harry0703/MoneyPrinterTurbo, 129k stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Frame Composition?

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 9, 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.