npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

keyframe-mcp

v0.8.0

Published

MCP server for Keyframe.it — let Claude (or any MCP client) rig, animate and export 2D skeletal animations in the free Keyframe.it editor, rig, animate, play-test and export pixel-art sprites in Sprite Puppeteer, and rig and animate 3D models in MeshForge

Readme

keyframe-mcp

Create, inspect and export 2D skeletal animations in Keyframe.it, rig, animate, play-test and export pixel-art sprites in Sprite Puppeteer, and rig and animate 3D models in MeshForge, from any MCP client.

Install

Requires Node 18+ and Google Chrome. No browser download or Keyframe account is needed.

claude mcp add keyframe -- npx -y keyframe-mcp

Other clients:

{"mcpServers":{"keyframe":{"command":"npx","args":["-y","keyframe-mcp"]}}}

Version 0.2.0 adds persistent projects, named tools with validated schemas, complete clip creation, animation checks, editable image layers and file exports. Restart the MCP client after updating. For a local checkout, run npm ci in mcp/, then configure node with the absolute path to mcp/server.mjs.

Version 0.2.1 adds ownership metadata for the official MCP Registry, where the server is listed as io.github.kendall8388/keyframe.

Version 0.3.0 adds 18 puppeteer_* tools for Sprite Puppeteer: sample and your own characters, camera sets and directions, contact sheets, keyframed moves, and sheet, Godot, Unity, GameMaker, PNG-frame, Spine, GIF and project exports.

Version 0.8.0 adds meshforge_add_part, meshforge_set_clip_parts and meshforge_split_objects (33 meshforge_* tools in all). meshforge_add_part puts another library model on the open one, such as a tool in a hand, a pack on the back or a hat, riding that joint in every animation and saved with the model; meshforge_set_clip_parts picks which parts each animation shows, so one model can hold an axe in Chop, a pickaxe in Mine and a load in Carry. Humanoid rigs from meshforge_start_rig now get finger and thumb bones and fit T-poses; animation keys take hands (open, relaxed, grip, fist) and bones {curl}. meshforge_split_objects separates a generation of several props in one mesh into its own library models, filed under the original. meshforge_remesh gains quads, a free quad remesh (Instant Meshes, run in the browser) whose quads follow the shape, and meshforge_export gains obj-quads.

Version 0.7.0 adds meshforge_free_arm (30 meshforge_* tools in all): on a rig draft it cuts an arm the model has fused to its body free along the crease and closes both sides, so the arm can be raised without dragging the body. meshforge_add_prop can move a prop that stands apart into the hand first (hold: "hang" for a lantern or a bag, or holdAt), and the skeleton is now fitted to the body alone, ignoring pieces standing beside it.

Version 0.6.0 adds meshforge_remesh (29 meshforge_* tools in all): a free remesh that rebuilds the model as an even mesh with new UVs and its texture baked across. meshforge_reduce can also scale textures down (maxTexture), and the motion presets gain actions: punch, claw swipe, kick, hit reaction, jump, death and taunt. Through meshforge_call there are rig markers (setRigMarkers), a stretch check (stretchCheck) and a local weight smooth (smoothWeightsAt).

Version 0.5.0 adds four more meshforge_* tools (28 in all): a weight fix, a flex test, free walk/run/idle cycles and free polygon reduction; binding now uses bone heat, like Blender's automatic weights, and there is a humanoid-with-a-tail skeleton. Version 0.4.0 added the first 24: rig a 3D model in the browser (template skeleton, joints read off a measuring grid, automatic skin weights), give held props their own rigid bone, animate from keyframe specs written in character space, judge motion from contact sheets and measurements, save to the library and export GLB.

Workflow

  1. keyframe_open resumes a dedicated Chrome profile and waits for saved projects to restore.
  2. Read keyframe_methods, keyframe_call {method:"recipes"} and the current document with keyframe_call {method:"getState"}.
  3. Build a complete clip with keyframe_build_animation. All poses are validated before the document changes. Partial transform values carry forward from setup. loop:true copies the first pose to the end; replace:true replaces all tracks in an existing clip. FPS applies to the entire project.
  4. Review keyframe_contact_sheet and keyframe_check_animation. Inspect motion with keyframe_call {method:"renderClip",args:["idle"]}. Warnings can be intentional; contact-sheet framing is fitted to the clip, and loop transform checks exclude springs.
  5. keyframe_export {format:"project"} writes an editable JSON file. Use gif for a preview or spine for a ZIP with skeleton, atlas, textures and test.html. Files return as MCP resource links plus local paths; supporting clients can read them with resources/read.
  6. keyframe_open_result saves and opens visible Chrome so the user can continue editing. The window lasts while the connector is running; saved projects persist after shutdown.

Example clip tool arguments (use real bone names from the project):

{"spec":{"name":"idle","duration":2,"fps":24,"loop":true,"poses":[{"time":0,"bones":{"root":{"y":0,"scaleY":1}}},{"time":1,"bones":{"root":{"y":-6,"scaleY":1.03}}}]}}

Read keyframe_session and pass its projectId and revision in expected to build/configure/layer edits to reject stale commands. Requests run sequentially. Changes are saved before the tool responds. If saving fails after a mutation, the error says applied:true; retry keyframe_save before closing.

Tools

| Tool | Purpose | | --- | --- | | keyframe_open | Open/resume the editor, optional URL | | keyframe_methods | Discover all scripting methods | | keyframe_call | Call a method with positional JSON arguments; image results appear inline | | keyframe_session | Active project and revision | | keyframe_list_projects / keyframe_open_project | Find and reopen saved projects | | keyframe_save | Wait for browser storage to commit | | keyframe_build_animation | Create a complete validated clip in one undo step | | keyframe_configure_animation | Duration and project FPS | | keyframe_apply_pose | Batch named bone transforms in the active clip | | keyframe_contact_sheet | Timestamped pose grid, empty/edge-frame checks | | keyframe_check_animation | Loop, visibility and rig diagnostics | | keyframe_image_layers / keyframe_image_layer_png | Inspect editable layers and pixels | | keyframe_edit_image_layers | Atomic layer add/update/reorder/delete, including editable text | | keyframe_export | Project JSON, GIF or Spine ZIP as files | | keyframe_open_result | Save and show the editable result | | keyframe_screenshot | Whole editor UI |

Every named tool advertises its JSON Schema. Errors use MCP isError:true and {ok:false,error}. The generic call tool remains available for rigging, slicing, meshes, physics and other advanced methods.

Sprite Puppeteer

Sprite Puppeteer rigs and animates pixel-art sprites and lets you play-test them in an arena. It opens as a second page in the same connector profile. There are two kinds of character: rigged (one image with a skeleton, built-in moves plus moves you create) and sprite-sheet (every frame already drawn, in camera sets such as side, isometric and top-down, with up to eight directions).

  1. puppeteer_open (optionally {sample:"orc"} or {sample:"golem"}), or puppeteer_load_image {path:"/abs/path/hero.png"} for your own art (PNG, GIF, WebP, JPEG, Aseprite or PSD; the skeleton auto-fits).
  2. puppeteer_state lists moves, camera sets and directions (or views), and settings.
  3. Judge motion with puppeteer_contact_sheet {move:"walk"}; pick angles with puppeteer_set_view {set:"iso8", dir:"S"}.
  4. Rigged characters: read puppeteer_move_guide, then puppeteer_create_move with keys that list only the channels that change. Check it with a contact sheet and refine with replace.
  5. puppeteer_export {format:"godot", moves:"all", dirs:"8"} (or sheet, unity, gm, frames, spine, gif, project) writes the file and returns a resource link and local path.
  6. puppeteer_open_result shows the page in visible Chrome.

Example move for the sample golem (puppeteer_open {sample:"golem"} first):

{"spec":{"name":"Overhead slam","dur":1.1,"loop":false,"keys":[{"t":0,"pose":{}},{"t":0.35,"ease":"out","pose":{"y":18,"torso":-12,"uarmR":150,"uarmL":150}},{"t":0.55,"ease":"snap","pose":{"y":6,"torso":30,"uarmR":-40,"uarmL":-40}},{"t":1.1,"pose":{}}],"events":[{"t":0.55,"type":"slam"}]}}

| Tool | Purpose | | --- | --- | | puppeteer_open | Open Sprite Puppeteer, optionally with a sample | | puppeteer_methods / puppeteer_call | Every scripting method, and a generic call | | puppeteer_state | Character, moves, camera or views, settings | | puppeteer_play_move | Show a move on the stage | | puppeteer_set_view | Camera set and direction (sheets), view (rigged), facing | | puppeteer_settings | Background, fps, pixel scale, speed, effects, export options | | puppeteer_move_guide / puppeteer_create_move | Pose channels and conventions; add or replace a keyframed move | | puppeteer_contact_sheet / puppeteer_render_frame | Frames as images | | puppeteer_load_image | Your sprite from disk as a new rigged character | | puppeteer_export | Sheet, Godot, Unity, GameMaker, PNG frames, Spine, GIF or project file | | puppeteer_list_projects / puppeteer_open_project / puppeteer_save | Projects in the connector profile | | puppeteer_screenshot / puppeteer_open_result | The page, and handoff to visible Chrome |

The page's API is window.spritePuppeteer; any browser automation can call it directly. See llms.txt.

MeshForge

MeshForge turns images into 3D models (on the user's own fal.ai key) and rigs, animates and renders them in the browser. It opens as a third page in the same connector profile; a new profile starts with an example orc (rigged, 18 animations). Positions and directions are in character space: +x the character's right, +y up from the floor, +z the way it faces, in metres.

Animate a rigged model:

  1. meshforge_open (optionally {model:"Orc"}), meshforge_models, meshforge_open_model, or meshforge_import_model {path:"/abs/path/hero.glb"}.
  2. Read meshforge_animation_guide once: it explains the spec and lists the skeleton with each bone's rest aim.
  3. meshforge_build_animation with keys whose bones take {aim:[x,y,z]} (point the bone that way), {rot:{yaw,pitch,roll}} (degrees from rest) or {rest:true}. Feet stay on the floor automatically; root.move[1] is jump height.
  4. Judge it with meshforge_contact_sheet (front and side) and the measurements in the result (feetToFloor, footSlide, loopGap); refine with replace:true.
  5. meshforge_save keeps it in the library; meshforge_export writes a .glb.

Rig an unrigged model (free, no API key):

  1. Over ~150k triangles? meshforge_reduce {triangles:40000} then meshforge_save {asNew:true} (free; UVs, textures and weights carry over). A messy generated surface? meshforge_remesh {quads:12000} rebuilds it as quads that follow the shape (or {triangles:30000} as even triangles) with a baked texture.
  2. meshforge_start_rig {template:"humanoid"} (or humanoid_tail, quadruped, chain) fits a skeleton to the mesh.
  3. meshforge_render_rig shows the joints over a measuring grid from the front and side. Read the right coordinates off the grid and fix joints with meshforge_set_joints {joints:{forearmR:[0.55,0.74,0.05]}} (mirrored by default). Joints belong inside the body.
  4. An arm fused to the body (a sleeve grown into a robe)? meshforge_free_arm {side:"R"} cuts it free along the crease so it can be raised cleanly.
  5. Props: meshforge_add_prop {name:"axe", parent:"handR", select:{capsule:{a:[…],b:[…],radius:0.08}}}. A prop standing apart, like a lantern on the ground: {name:"lantern", parent:"handL", select:{piece:[x,y,z]}, hold:"hang"} moves it into the hand first. Preview a selection with meshforge_render_rig {select:…} (orange); added props show purple.
  6. meshforge_bind_rig (bone heat, like Blender's automatic weights). If its weight check reports strays, meshforge_fix_weights. Then meshforge_flex_test and a contact sheet of "Flex test".
  7. meshforge_preset_animation {kind:"walk"} (or run, idle, punch, swipe, kick, hit, jump, death, taunt) adds free motion fitted to the rig; tune with speed, stride, arms, bounce, tail. Then save.

Example (the example orc, meshforge_open {model:"Orc"} first):

{"spec":{"name":"chop","duration":1.2,"keys":[{"t":0,"bones":{"upper_armR":{"rest":true},"forearmR":{"rest":true},"spine1":{"rest":true}}},{"t":0.45,"ease":"easeOut","bones":{"upper_armR":{"aim":[0.3,1,-0.4]},"forearmR":{"aim":[0,0.3,-1]},"spine1":{"rot":{"pitch":-12,"yaw":-15}}}},{"t":0.65,"ease":"easeIn","bones":{"upper_armR":{"aim":[0.2,-0.3,1]},"forearmR":{"aim":[0,-0.8,1]},"spine1":{"rot":{"pitch":20,"yaw":10}}}},{"t":1.2,"bones":{"upper_armR":{"rest":true},"forearmR":{"rest":true},"spine1":{"rest":true}}}]}}

| Tool | Purpose | | --- | --- | | meshforge_open | Open MeshForge, optionally a library model | | meshforge_methods / meshforge_call | Every scripting method, and a generic call | | meshforge_state / meshforge_models / meshforge_open_model | The open model, the library, opening one | | meshforge_import_model | A .glb from disk into the library | | meshforge_generate / meshforge_wait | Image → 3D on the user's fal.ai key (paid: needs confirmCost:true) | | meshforge_skeleton / meshforge_animation_guide | Bones in character space; how to write a spec | | meshforge_build_animation | Keyframe spec → animation, with measurements | | meshforge_contact_sheet / meshforge_render_frame / meshforge_inspect | Frames as images; numbers | | meshforge_start_rig / meshforge_render_rig / meshforge_set_joints / meshforge_bind_rig | Rigging in the browser | | meshforge_free_arm | Cut an arm fused to the body free before binding | | meshforge_add_part | Another library model on this one: a tool in a hand, a pack, a hat | | meshforge_set_clip_parts | Which parts each animation shows (one model, many tools) | | meshforge_split_objects | Separate the objects in one generation into their own library models | | meshforge_add_prop | A rigid bone for a held weapon, shield or lantern (draft or bound rig); can move it into the hand | | meshforge_save / meshforge_export | Library entry; .glb file (or .obj with quads) | | meshforge_screenshot / meshforge_open_result | The page, and handoff to visible Chrome |

Unlike the other pages, MeshForge doesn't save after every call (a save writes a whole model): results say unsaved until meshforge_save, and the connector saves on handoff and shutdown. The page's API is window.meshforge.

Storage and handoff

The connector uses its own Chrome profile, not existing personal Chrome tabs. Projects belong to that profile and site origin. Export project JSON and import it in your usual browser to transfer work. Existing projects from version 0.1.0's temporary browser profile cannot be recovered unless previously exported.

| Variable | Default | Purpose | | --- | --- | --- | | KEYFRAME_URL | https://www.keyframe.it.com/ | Editor URL; HTTP allowed for localhost development | | KEYFRAME_PROFILE_DIR | ~/.keyframe-mcp/profile | Persistent browser storage; use separate directories for concurrent instances | | KEYFRAME_HEADLESS | 1 | Set 0 to watch work; open_result switches to visible Chrome | | KEYFRAME_EXPORT_DIR | ~/.keyframe-mcp/exports | Downloaded artifacts; files remain after shutdown |

Close or Apply the human image editor before agent layer edits. Layers retain text, visibility, opacity, blend modes and locks. The composite stays compatible with existing rig/export tools. See the full API reference for operation examples and limits.

Development

npm test runs schema, protocol, persistence, serialization, error and file-resource tests with a fake browser. ../e2e/agent-workflow.html exercises the real editor API, canvas renders, layer compositing, exports and save/reload through a Vite dev server.

MIT — see LICENSE. This license covers the connector; the editor is a separate hosted application.