summerengine/summer/character-model

Claude Code and agent skill by summerengine/summer

Trust tier 2
  • community
LLM review pending
Source check pending

Checking that the SKILL.md file is still in the repository.

Generate a rigged humanoid (player, NPC, enemy, boss) from a T-pose reference, previewed before rigging.

Install

npx vskill@latest install summerengine/summer/character-model

SKILL.md

Character Model — T-Pose to Rigged Humanoid, Gated

This is the canonical auto-rig pipeline. It produces a humanoid .glb with a skeleton that generate-motion can drive directly. The work is two paid passes with a mandatory user-review gate between them: the rig pass costs more credits, so the user must see the un-rigged preview and approve it first.

The whole flow:

1. T-pose reference image → assets.generate_image (~10s)
2. Un-rigged 3D mesh → assets.generate_3d(image-to-3d) → a job (~60s)
3. ── USER REVIEW GATE ──
4. Rigged .glb → assets.rig(approved asset ID) → a job (~90s)
5. Import → editor RESTART → wire as CharacterBody3D / Node3D
6. Hand off to generate-motion for clips

The animation skill (generate-motion) requires a rigged humanoid; a static .glb won't drive motion.

assets.generate_3d returns a job. assets.rig returns a job for a new rig, or a completed result if the asset is already rigged. Follow a running job with jobs.wait({ jobId, timeoutSeconds: 50 }); repeat until result.finished is true, then check result.job.state is done before using result.job.result. A failed or cancelled job is not a successful result. Both passes spend credits: use dryRun: true to check the estimate before getting permission to spend.

When to use

  • "Make a knight character for the player to control."
  • "I need a goblin enemy."
  • "Generate an old wizard NPC for the tavern."
  • "Create a boss — a four-armed demon."
  • The user is about to ask for animations and has nothing rigged yet.

When NOT to use

  • Static statue / mannequin display piece (no rig needed) → prop-model.
  • Vehicle with a "driver" silhouette but no skeleton needed → vehicle-model.
  • Quadruped (wolf, horse, dragon) → Meshy auto-rig is humanoid-only. Generate the mesh here for visuals, but skip the rig step — animation will need a hand-authored skeleton or a quadruped-specific provider (out of scope for this skill).
  • The user already has a rigged character and just wants a re-skin — that's a retexture pass, not this skill.
  • Facial blendshapes / lipsync rig → facial-and-lipsync.

Polycount targets

Choose a target for the character's role and platform, and check that the selected model supports it before generation. Targets are approximate, not guarantees. Hunyuan Pro accepts an explicit target of at least 40,000 faces; the example below leaves it unset for the provider's automatic default. Inspect the generated mesh before approval, particularly for mobile or crowded scenes. Rigging can change geometry and weights, so verify the resulting model rather than assuming its topology is unchanged.

Steps

1. Generate the T-pose reference image

The rig pass requires a front-facing T-pose with arms out and legs slightly apart. If the reference is in an action pose, the rig will bend wrong and locomotion clips will look broken (knees inverted, elbows snapped — common Meshy failure mode).

assets.generate_image({
prompt: "A fantasy knight in full plate armor, red cape, T-pose, arms straight out horizontal, legs slightly apart, front-facing, neutral expression. Game character asset, stylized, clean white background, soft studio lighting, full body in frame, ready for 3D mesh generation.",
model: "nano-banana-2",
aspectRatio: "3:4"
})

The phrase T-pose, arms straight out horizontal, legs slightly apart, front-facing is load-bearing — drop any of those and the model will drift toward A-pose or a hero stance.

If the user already has a concept image in an action pose, re-pose it to T-pose via img2img without re-rolling the design:

assets.generate_image({
referenceImageUrl: "<existing concept image>",
prompt: "<character> in T-pose, arms extended horizontally, neutral facing camera, white background, clean lighting"
})

Use result.assets[0].fileUrl from the completed assets.generate_image response as the image URL in step 2. If no file URL is present, resolve the asset with assets.get before continuing.

Show the image to the user:

Generated the T-pose reference. [link]. Approve to proceed to mesh generation, or regenerate?
2. Generate the un-rigged 3D mesh
assets.generate_3d({
kind: "image-to-3d",
imageUrl: "<image url from step 1>",
model: "hunyuan"
})
jobs.wait({ jobId: "<job.id>", timeoutSeconds: 50 }) // again until finished

The finished job's result has assetId and fileUrl — an un-rigged static .glb. Use the asset ID as the stable handle. Import it for preview only:

assets.get({ assetId: "<assetId>" })
summer_import_asset_by_id(
assetId="<assetId>",
path="res://assets/characters/knight_unrigged.glb"
)
3. STOP: USER REVIEW GATE — DO NOT SKIP

Before paying for the rig pass, surface the un-rigged mesh:

Un-rigged knight mesh ready: res://assets/characters/knight_unrigged.glb ([preview link]; report the measured polygon count if known).
Next step is the rig pass (uses credits, ~90s). It attempts to add a humanoid skeleton to this saved mesh. Once you approve I'll run it.
Approve the mesh and proceed to rig? Or regenerate the mesh first (different prompt, different polycount, different model)?

If the user wants changes, loop back to step 1 or 2. Do NOT silently run the rig pass — it spends more credits.

4. Run the rig pass

Use the approved saved mesh's asset ID, not the original image. Keep the unrigged preview file from step 2 before rigging: for an asset owned by the caller, rigging updates the same asset record to point to the rigged file.

assets.rig({ assetId: "<assetId>", dryRun: true }) // show estimate and get approval
assets.rig({ assetId: "<assetId>" }) // only after approval

If the call returns status: "running", wait for its job.id:

jobs.wait({ jobId: "<job.id>", timeoutSeconds: 50 })

Repeat while result.finished is false. When finished, require result.job.state to be done; otherwise report the failure and stop. The completed rig job supplies result.job.result.assetId. If the rig call instead returns status: "done" with result.alreadyRigged, use its result.assetId. Do not assume the job result has a rigAssetId or a top-level fileUrl.

Resolve the returned ID with assets.get and use the asset's current fileUrl for the rigged GLB. Save this ID as rigAssetId for assets.generate_motion. Import to a separate path, so the unrigged preview remains available:

assets.get({ assetId: "<rigAssetId>" })
summer_import_asset_by_id(
assetId="<rigAssetId>",
path="res://assets/characters/knight.glb"
)

Inspect the rig and mesh before claiming animation readiness; a successful job does not guarantee provider quality.

5. WARNING: Restart the editor

Known gotcha: after importing a rigged .glb, the Skeleton3D node appears stale in the scene dock — bones are missing, skeleton.get_bone_count() returns 0, and AnimationPlayer libraries fail to bind. The fix:

The rigged mesh is imported. Please restart the Summer Engine editor (close and reopen) so the Skeleton3D rebuilds correctly. Without the restart, animations will fail to bind.

No programmatic workaround is known. Tell the user, wait, then continue.

6. Wire as CharacterBody3D or Node3D — pick the right parent
Use caseParent typeWhy
Player or enemy that moves with code, collides with walls, jumpsCharacterBody3Dmove_and_slide() API, kinematic physics, slope handling
Cinematic NPC (talks, idles, never moves under physics)Node3DNo physics overhead; cheaper for crowds
Pure-visual character (background extra, dialogue head)Node3DSame as above
Ragdoll-on-death enemyCharacterBody3D while alive, swap to RigidBody3D skeleton on deathTwo-mode rig; see procedural-animation

Three things the call shapes below encode:

  • Every scene tool, `summer_run_script` included, takes an explicit `scenePath`, and the scene need not be the active editor tab.
  • A character is several nodes: build it in one `summer_run_script`, not a chain of single calls.
  • A `.glb` is instantiated, not assigned. There is no scene property on Node3D, and an imported .glb is a scene rather than a Mesh — on the shipped 4.6.1 binary ResourceLoader.get_recognized_extensions_for_type("Mesh") returns ["tres", "mesh", "res"], with no glb. Use ctx.instance_scene in a script, or summer_instantiate_scene for one model.

CharacterBody3D wiring (player / enemy):

summer_run_script(scenePath="res://main.tscn", source="""
func run(ctx):
var knight = ctx.add_node("CharacterBody3D", "Knight", ctx.find("World"), {"position": Vector3(0, 0, 0)})
ctx.instance_scene("res://assets/characters/knight.glb", knight, "Mesh")
var capsule := CapsuleShape3D.new()
capsule.height = 1.7
capsule.radius = 0.4
ctx.add_node("CollisionShape3D", "Collider", knight, {"shape": capsule})
ctx.save_scene()
""")

Build the shape as a real resource and size it before you assign it. Later, one size change on that shape is one summer_set_resource_property (nodePath, resourceProperty="shape", subProperty, value, plus scenePath).

Node3D wiring (cinematic NPC):

summer_instantiate_scene(scenePath="res://main.tscn", parent="./World/Tavern", scene="res://assets/characters/wizard.glb", name="OldWizard")
summer_save_scene(scenePath="res://main.tscn")

The imported .glb includes its own Skeleton3D and AnimationPlayer (empty library). The animation skill writes into that AnimationPlayer.

7. Hand off to animation
Knight is wired at ./World/Knight with an auto-rigged skeleton. rigAssetId saved.
Next: generate-motion to add idle / walk / run / attack
clips. Example call: `assets.generate_motion({ rigAssetId: "<saved id>",
backend: "meshy-library", motionNames: ["walk"] })`. For custom actions, use
text-to-motion (backend: "text-to-motion").

Anti-patterns

  • Skipping the user-review gate. Spends the rig credits, locks the design, and removes the user's chance to course-correct cheaply.
  • Generating the mesh from a non-T-pose image. Locomotion will look broken (inverted knees, snapped elbows). Always re-pose first.
  • Forgetting the editor restart. Animations will appear to bind successfully but play to a stale skeleton — the character T-poses motionless. The fix is always restart, never code.
  • Wrapping a cinematic NPC in CharacterBody3D. Wastes physics ticks; use Node3D.
  • Wrapping the player in Node3D. No move_and_slide(), no collision — the player walks through walls.
  • Picking the rig pass before approving the silhouette. The mesh defines what the character looks like; once the rig is on, you can't cheaply iterate the design.
  • Using `meshy` model for the mesh step. Legacy. hunyuan is the default and produces cleaner topology that Meshy's auto-rig handles better.

Edge cases

This is the start of the file. Read the full SKILL.md on GitHub.

Security

  • Security scanPassed, 100 of 100Pattern checks on the skill's files.
  • Model reviewNot runA model review is scheduled for the next rescan.

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

Repository stars
90
Repository forks
9
7-day trend score
21

Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/summerengine/summer/character-model/badge)](https://verified-skill.com/skills/summerengine/summer/character-model)

Something wrong with this skill or its page? Tell us.