Skip to content
Back to skills

Adding A Character

ASecurity

Add a Pokémon or character to pokemanion from image files the user has — installing a sprite pair, cutting cycles out of a sheet, keying a background off, judging whether art will read at pane size. Use when someone wants a new sprite, character or Pokémon in their pokemanion pane, or hands you a gif or png and asks to make it a resident.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 29, 2026
ai-agentsgonodeaws

Works with

  • terminal

Security analysis

A100/100

Scanned September 29, 2026

npx -y skills add khatriadbhut/pokemanion --skill adding-a-character --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Adding A Character?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Adding A Character
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/khatriadbhut-adding-a-character/badge)](https://www.skillsdirectory.com/skills/khatriadbhut-adding-a-character)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: adding-a-character
description: Add a Pokémon or character to pokemanion from image files the user has — installing a sprite pair, cutting cycles out of a sheet, keying a background off, judging whether art will read at pane size. Use when someone wants a new sprite, character or Pokémon in their pokemanion pane, or hands you a gif or png and asks to make it a resident.
---

The user has a picture and wants it living in their terminal. Your job is the
judgement: which frames, whether the art will survive being shrunk, and what to
write on its Pokédex card. The mechanical half is one command.

## What to ask

They may arrive here by typing `--pokemanion add brock`, which does nothing but
hand you this job. Ask one thing at a time and wait — several questions at once
gets one answer.

1. **The resting animation.** A gif or png of what it does while waiting. They
   can drag the file in.
2. **The working animation** — what it does while the agent is busy. The same
   file again is fine when both cycles live in one sheet.
3. **Whether anything needs cutting.** Say what you can see, so they are
   choosing rather than guessing: "this has 36 frames, so it looks like four
   walk cycles — shall I take the front-facing ones for resting and the side-on
   ones for working?" A sheet of figures side by side needs `crop` instead, and
   two halves whose colours disagree need `recolour`.

If they gave you everything in the first message, do not ask again — go and
look at the files.

Everything here needs a source install — it writes to `src/roster.mjs`. A plugin
copy is version-stamped and replaced on the next `/plugin update`, so anything
added there is lost. If they installed the plugin, say so before starting.

## The one command

```sh
npm run add -- <name> <resting-file> <working-file> [--resting=A-B] [--working=A-B] [--halo]
```

It prepares the art, copies it into `assets/` under the next free number, writes
the roster entry, regenerates the gallery, every count and the credits, stages
the files, and tells you what it did. Afterwards `--<name>`, `claude --<name>`,
`--dex <name>`, the picker and did-you-mean all work.

| | |
| --- | --- |
| `--resting=0-8` | use only those frames of the resting file — zero-based, inclusive |
| `--working=12-17` | the same for the working half |
| `--halo` | also remove the pale fringe a blurry upscale leaves around a figure |

A flat background is always keyed out by filling in from the edges, so a white
card goes while a white shirt stays. `--halo` goes further and takes every pale
colourless pixel, including pockets a fill cannot reach — the gaps between
Brock's hair spikes. It would also blind a sprite with white eyes, so it is
asked for rather than assumed.

## Look at the art first

Two things have sunk every sprite tried in this project, and both are visible
before you install anything.

**A working half that cannot move.** A single frame is a picture, not an
animation. Attempts to animate a still here — growing a water jet out of a
Squirtle, alternating two poses — were all reverted for looking synthesised,
because they were. If the working file has one frame, say so and ask for
another.

**Art that was resampled rather than drawn.** Decode it and look at the run
lengths along a row: pixel art repeats each pixel by its upscale factor, so a
clean 3x upscale gives runs of 3, which `recoverNative` divides back out. Runs
of 1 in a large image mean it was resized with smoothing, there is no grid to
recover, and it will read soft beside sprites that snap to the terminal's cells.
Runs of 1 in a *small* image are simply what pixel art is.

`npm run add` reports both of these before it copies anything.

## Then look at it at the size it will be drawn

This is the step that has been right every time measurements were wrong. The
pane draws a sprite about 68 pixels tall. Decode the gif, scale a few frames to
that height onto a dark background, magnify for your own eyes, write a png and
**read it**.

```js
import { readFileSync, writeFileSync } from 'node:fs'
import { decodeGif } from './src/gif.mjs'
import { encodePng } from './src/pngwrite.mjs'
```

A filmstrip of every frame side by side is the fastest way to see whether a
cycle actually cycles, and whether the frames belong to one direction or four.

## Cutting a sheet apart

Sprite sheets arrive in two shapes, and they need different tools.

**Several cycles across the frames of one gif** — a four-direction walk is
usually front, side, back, side. Find the boundaries by rendering the frames and
reading them, then pass `--resting=0-8 --working=12-17`.

**Several figures side by side in one image** — use `npm run crop` first:

```sh
npm run crop -- sheet.gif out.gif --find=3      # the third figure along
npm run crop -- sheet.gif out.gif 40 0 66 85    # or x y w h
```

`--find=N` groups the inked columns into runs and takes the Nth, which is how
Ash was cut out of a sheet of five trainers.

## The rest of the toolbox

| | |
| --- | --- |
| `npm run key -- in.gif out.gif` | make a flat background transparent, no re-encode |
| `npm run recolour -- a.gif b.gif out.gif` | repaint one palette to match another |
| `npm run flip -- in.gif out.gif` | mirror left to right |
| `npm run dex -- <name>` | check whether a name is a real Pokémon before using it |
| `npm test` | sprites committed, counts right, cards fit the pane |

Two palettes that disagree are worth fixing: alternating a blue pose with a teal
one reads as a colour flashing rather than as a character moving.

## Cards, for anyone who is not a Pokémon

The bundled Pokédex is built from Showdown's data and contains no people, so a
human resident needs a `card` in their roster entry or `--dex brock` has nothing
to answer with. `npm run add` writes the shape and leaves it empty:

```js
card: {
  title: 'Brock',
  blurb: 'The Rock-type Gym Leader of Pewter City, who handed the gym to his father and left to travel with Ash…',
  facts: [['species', 'Human'], ['from', 'Pewter City'], ['goal', 'Pokémon Breeder']],
  pane: ['Brock', 'Pewter City Gym', 'Type : Rock', 'Goal : Pokemon Breeder'],
}
```

`blurb` is the paragraph in the conversation. `pane` is what fits beside the
sprite, so keep every line short — `npm test` fails if one is too wide.

## When you are done

`npm test`, then tell them to open a new session. A pane already running was
started before the entry existed and cannot know about it. Neither Ghostty nor
the agent needs restarting.

## Worked example

A user drops in one gif of a character walking in four directions and asks for
them as a resident:

1. Decode it. 36 frames, 283x199, runs of 1 — a resampled upscale, so warn them
   it will read soft, and expect a pale halo.
2. Render the frames as a filmstrip and read the directions off it: 0-8 face
   you, 12-17 are side on, the rest walk away.
3. Front for resting, side for working, because that is the division that reads
   as waiting versus working.
4. `npm run add -- brock sheet.gif sheet.gif --resting=0-8 --working=12-17 --halo`
5. Render the result at 68 pixels tall and look at it before believing any of
   the above.
6. Write the card, run `npm test`, tell them to open a new session.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…