Skip to content

カーソルAgents · Cursor

The same trick, for Cursor.

Cursor’s agent loads skills from .cursor/skills/. This one ships two interchangeable helper scripts, Node and Python (standard library only), so it works whichever runtime your project has.

Fastest way

Paste one prompt.

Copy this prompt into Cursor's agent. It creates the files below with the exact contents shown on this page.

Preview the prompt
Install the AnimeAPI agent skill in this project. Create these three files exactly:

.cursor/skills/animeapi/SKILL.md
```markdown
---
name: animeapi
description: Generate anime-style images (characters, scenes, sprites, backgrounds, key art) and short anime video clips with AnimeAPI and save them to disk. Use when the user asks for anime or manga style images, animations or visual assets.
---

# AnimeAPI: anime image and video generation

Generate anime-style images (and, when asked, short anime video clips) through
AnimeAPI and save them into the project.

## Setup

`ANIMEAPI_KEY` must be set in the environment the agent runs in (for example
`export ANIMEAPI_KEY=ank_...` in your shell profile). A `.env` file is not
read automatically. Keys: https://animeapi.ai/dashboard/api-keys

## How to generate

Run:

```bash
node .cursor/skills/animeapi/scripts/generate.mjs "<prompt>" <output-file> [model] [orientation]
```

Needs Node 18+. If Node isn't available, the same arguments work with
`python3 .cursor/skills/animeapi/scripts/generate.py` (standard library only).

- `model`: `anime` (default, $0.003, best for characters, tag-based),
  `ultra` ($0.01, follows long sentences, renders legible text) or
  `ultra-max` ($0.02, highest detail).
- `orientation`: `portrait` (default), `square` or `landscape`.
- Use a `.webp` output path for `anime` and `.png` for the ultra tiers.
- The script prints `enhanced_prompt` (what the model actually read) and the
  remaining `balance_usd`.

## Writing prompts

- anime: describe the character first (who, hair, outfit, pose), then the
  place and light. Your prompt is rewritten into Danbooru tags automatically.
  It is strongly biased toward drawing a person; for animals or objects as the
  subject, use ultra.
- ultra / ultra-max: write a full sentence; an anime style is added
  automatically. Put any text that must appear in the image in quotes.

## Errors

- 401 INVALID_KEY: ANIMEAPI_KEY is missing or revoked.
- 402 INSUFFICIENT_BALANCE: tell the user to top up at
  https://animeapi.ai/dashboard/billing. Do not retry.
- 400 MODERATION_BLOCKED (ultra tiers): rephrase the prompt.
- 500 GENERATION_FAILED: the charge was refunded; one retry is fine.

Each image costs money. Generate one image, show it, and ask before making
batches.

## Videos

Only when the user asks for a video or animation. Videos are MP4 (24 fps, with
sound), 5 to 15 seconds, billed per second up front: $0.016/s at 480p,
$0.04/s at 768p (a 5-second 768p clip is $0.20). State the price and ask
before anything longer than 5 seconds or more than one clip.

1. Start a job (build the JSON with `jq -n` if the prompt has quotes):

   ```bash
   curl -sS https://animeapi.ai/api/videos -H "Authorization: Bearer $ANIMEAPI_KEY" \
     -H "Content-Type: application/json" \
     -d '{"prompt": "<what happens>", "resolution": "768p", "duration": 5, "orientation": "landscape"}'
   ```

   It returns 202 with an `id`. Optional `first_frame` / `last_frame`: an
   image URL or a `data:image/png;base64,...` data URI (up to 10 MB) that the
   clip starts / ends on; the first frame sets the shape. For a local image,
   pipe it through jq into a file (too long for a command-line argument):

   ```bash
   base64 < in.webp | tr -d '\n' | jq -Rs --arg p "<what happens>" \
     '{prompt: $p, duration: 5, first_frame: ("data:image/webp;base64," + .)}' > /tmp/video.json
   curl -sS https://animeapi.ai/api/videos -H "Authorization: Bearer $ANIMEAPI_KEY" \
     -H "Content-Type: application/json" -d @/tmp/video.json
   ```

2. Poll every 5 seconds until `status` is `succeeded` or `failed`:

   ```bash
   curl -sS https://animeapi.ai/api/videos/<id> -H "Authorization: Bearer $ANIMEAPI_KEY"
   ```

3. On `succeeded`, download `video_url` into the project (`curl -sS -o out.mp4 <video_url>`).
   On `failed`, the charge was refunded and `error` says why.
```

.cursor/skills/animeapi/scripts/generate.mjs
```javascript
#!/usr/bin/env node
// Usage: node generate.mjs "<prompt>" <output-file> [model] [orientation]
import { mkdir, writeFile } from "node:fs/promises";
import { dirname } from "node:path";

const [prompt, out, model = "anime", orientation = "portrait"] = process.argv.slice(2);
if (!prompt || !out) {
  console.error('usage: node generate.mjs "<prompt>" <output-file> [model] [orientation]');
  process.exit(2);
}
if (!process.env.ANIMEAPI_KEY) {
  console.error("Set ANIMEAPI_KEY first: https://animeapi.ai/dashboard/api-keys");
  process.exit(2);
}

const res = await fetch("https://animeapi.ai/api/generate", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANIMEAPI_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ prompt, model, orientation, allowNSFW: false }),
});
const data = await res.json();
if (!res.ok) {
  console.error(`AnimeAPI error ${res.status} ${data.code ?? ""}: ${data.error}`);
  process.exit(1);
}

const image = await fetch(data.image_url);
if (!image.ok) {
  console.error(`Could not download ${data.image_url} (${image.status})`);
  process.exit(1);
}
await mkdir(dirname(out), { recursive: true });
await writeFile(out, Buffer.from(await image.arrayBuffer()));

console.log(`saved: ${out}`);
console.log(`enhanced_prompt: ${data.enhanced_prompt}`);
console.log(`balance_usd: ${data.balance_usd}`);
```

.cursor/skills/animeapi/scripts/generate.py
```python
#!/usr/bin/env python3
"""Usage: python3 generate.py "<prompt>" <output-file> [model] [orientation]

Standard library only.
"""
import json
import os
import sys
import urllib.error
import urllib.request
from pathlib import Path

API_URL = "https://animeapi.ai/api/generate"
UA = {"User-Agent": "animeapi-skill/1.0"}


def main() -> int:
    if len(sys.argv) < 3:
        print(__doc__, file=sys.stderr)
        return 2
    prompt, out = sys.argv[1], Path(sys.argv[2])
    model = sys.argv[3] if len(sys.argv) > 3 else "anime"
    orientation = sys.argv[4] if len(sys.argv) > 4 else "portrait"
    key = os.environ.get("ANIMEAPI_KEY")
    if not key:
        print("Set ANIMEAPI_KEY first: https://animeapi.ai/dashboard/api-keys", file=sys.stderr)
        return 2

    body = json.dumps(
        {"prompt": prompt, "model": model, "orientation": orientation, "allowNSFW": False}
    ).encode()
    req = urllib.request.Request(
        API_URL,
        data=body,
        headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json", **UA},
    )
    try:
        with urllib.request.urlopen(req, timeout=180) as res:
            data = json.load(res)
    except urllib.error.HTTPError as err:
        detail = json.loads(err.read() or b"{}")
        print(f"AnimeAPI error {err.code} {detail.get('code', '')}: {detail.get('error')}", file=sys.stderr)
        return 1

    out.parent.mkdir(parents=True, exist_ok=True)
    with urllib.request.urlopen(urllib.request.Request(data["image_url"], headers=UA), timeout=120) as img:
        out.write_bytes(img.read())

    print(f"saved: {out}")
    print(f"enhanced_prompt: {data['enhanced_prompt']}")
    print(f"balance_usd: {data['balance_usd']}")
    return 0


if __name__ == "__main__":
    sys.exit(main())
```

→Or install it by hand

  1. Export your key

    The agent runs scripts in your terminal environment. A project .env is not read automatically.

    ~/.zshrc
    export ANIMEAPI_KEY="ank_your_key_here"
  2. Add SKILL.md

    The folder name must match name in the frontmatter. For every project on your machine, use ~/.cursor/skills/animeapi/ and adjust the script paths.

    .cursor/skills/animeapi/SKILL.md
    ---
    name: animeapi
    description: Generate anime-style images (characters, scenes, sprites, backgrounds, key art) and short anime video clips with AnimeAPI and save them to disk. Use when the user asks for anime or manga style images, animations or visual assets.
    ---
    
    # AnimeAPI: anime image and video generation
    
    Generate anime-style images (and, when asked, short anime video clips) through
    AnimeAPI and save them into the project.
    
    ## Setup
    
    `ANIMEAPI_KEY` must be set in the environment the agent runs in (for example
    `export ANIMEAPI_KEY=ank_...` in your shell profile). A `.env` file is not
    read automatically. Keys: https://animeapi.ai/dashboard/api-keys
    
    ## How to generate
    
    Run:
    
    ```bash
    node .cursor/skills/animeapi/scripts/generate.mjs "<prompt>" <output-file> [model] [orientation]
    ```
    
    Needs Node 18+. If Node isn't available, the same arguments work with
    `python3 .cursor/skills/animeapi/scripts/generate.py` (standard library only).
    
    - `model`: `anime` (default, $0.003, best for characters, tag-based),
      `ultra` ($0.01, follows long sentences, renders legible text) or
      `ultra-max` ($0.02, highest detail).
    - `orientation`: `portrait` (default), `square` or `landscape`.
    - Use a `.webp` output path for `anime` and `.png` for the ultra tiers.
    - The script prints `enhanced_prompt` (what the model actually read) and the
      remaining `balance_usd`.
    
    ## Writing prompts
    
    - anime: describe the character first (who, hair, outfit, pose), then the
      place and light. Your prompt is rewritten into Danbooru tags automatically.
      It is strongly biased toward drawing a person; for animals or objects as the
      subject, use ultra.
    - ultra / ultra-max: write a full sentence; an anime style is added
      automatically. Put any text that must appear in the image in quotes.
    
    ## Errors
    
    - 401 INVALID_KEY: ANIMEAPI_KEY is missing or revoked.
    - 402 INSUFFICIENT_BALANCE: tell the user to top up at
      https://animeapi.ai/dashboard/billing. Do not retry.
    - 400 MODERATION_BLOCKED (ultra tiers): rephrase the prompt.
    - 500 GENERATION_FAILED: the charge was refunded; one retry is fine.
    
    Each image costs money. Generate one image, show it, and ask before making
    batches.
    
    ## Videos
    
    Only when the user asks for a video or animation. Videos are MP4 (24 fps, with
    sound), 5 to 15 seconds, billed per second up front: $0.016/s at 480p,
    $0.04/s at 768p (a 5-second 768p clip is $0.20). State the price and ask
    before anything longer than 5 seconds or more than one clip.
    
    1. Start a job (build the JSON with `jq -n` if the prompt has quotes):
    
       ```bash
       curl -sS https://animeapi.ai/api/videos -H "Authorization: Bearer $ANIMEAPI_KEY" \
         -H "Content-Type: application/json" \
         -d '{"prompt": "<what happens>", "resolution": "768p", "duration": 5, "orientation": "landscape"}'
       ```
    
       It returns 202 with an `id`. Optional `first_frame` / `last_frame`: an
       image URL or a `data:image/png;base64,...` data URI (up to 10 MB) that the
       clip starts / ends on; the first frame sets the shape. For a local image,
       pipe it through jq into a file (too long for a command-line argument):
    
       ```bash
       base64 < in.webp | tr -d '\n' | jq -Rs --arg p "<what happens>" \
         '{prompt: $p, duration: 5, first_frame: ("data:image/webp;base64," + .)}' > /tmp/video.json
       curl -sS https://animeapi.ai/api/videos -H "Authorization: Bearer $ANIMEAPI_KEY" \
         -H "Content-Type: application/json" -d @/tmp/video.json
       ```
    
    2. Poll every 5 seconds until `status` is `succeeded` or `failed`:
    
       ```bash
       curl -sS https://animeapi.ai/api/videos/<id> -H "Authorization: Bearer $ANIMEAPI_KEY"
       ```
    
    3. On `succeeded`, download `video_url` into the project (`curl -sS -o out.mp4 <video_url>`).
       On `failed`, the charge was refunded and `error` says why.
  3. Add the helper scripts

    .cursor/skills/animeapi/scripts/generate.mjs
    #!/usr/bin/env node
    // Usage: node generate.mjs "<prompt>" <output-file> [model] [orientation]
    import { mkdir, writeFile } from "node:fs/promises";
    import { dirname } from "node:path";
    
    const [prompt, out, model = "anime", orientation = "portrait"] = process.argv.slice(2);
    if (!prompt || !out) {
      console.error('usage: node generate.mjs "<prompt>" <output-file> [model] [orientation]');
      process.exit(2);
    }
    if (!process.env.ANIMEAPI_KEY) {
      console.error("Set ANIMEAPI_KEY first: https://animeapi.ai/dashboard/api-keys");
      process.exit(2);
    }
    
    const res = await fetch("https://animeapi.ai/api/generate", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.ANIMEAPI_KEY}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({ prompt, model, orientation, allowNSFW: false }),
    });
    const data = await res.json();
    if (!res.ok) {
      console.error(`AnimeAPI error ${res.status} ${data.code ?? ""}: ${data.error}`);
      process.exit(1);
    }
    
    const image = await fetch(data.image_url);
    if (!image.ok) {
      console.error(`Could not download ${data.image_url} (${image.status})`);
      process.exit(1);
    }
    await mkdir(dirname(out), { recursive: true });
    await writeFile(out, Buffer.from(await image.arrayBuffer()));
    
    console.log(`saved: ${out}`);
    console.log(`enhanced_prompt: ${data.enhanced_prompt}`);
    console.log(`balance_usd: ${data.balance_usd}`);
    .cursor/skills/animeapi/scripts/generate.py
    #!/usr/bin/env python3
    """Usage: python3 generate.py "<prompt>" <output-file> [model] [orientation]
    
    Standard library only.
    """
    import json
    import os
    import sys
    import urllib.error
    import urllib.request
    from pathlib import Path
    
    API_URL = "https://animeapi.ai/api/generate"
    UA = {"User-Agent": "animeapi-skill/1.0"}
    
    
    def main() -> int:
        if len(sys.argv) < 3:
            print(__doc__, file=sys.stderr)
            return 2
        prompt, out = sys.argv[1], Path(sys.argv[2])
        model = sys.argv[3] if len(sys.argv) > 3 else "anime"
        orientation = sys.argv[4] if len(sys.argv) > 4 else "portrait"
        key = os.environ.get("ANIMEAPI_KEY")
        if not key:
            print("Set ANIMEAPI_KEY first: https://animeapi.ai/dashboard/api-keys", file=sys.stderr)
            return 2
    
        body = json.dumps(
            {"prompt": prompt, "model": model, "orientation": orientation, "allowNSFW": False}
        ).encode()
        req = urllib.request.Request(
            API_URL,
            data=body,
            headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json", **UA},
        )
        try:
            with urllib.request.urlopen(req, timeout=180) as res:
                data = json.load(res)
        except urllib.error.HTTPError as err:
            detail = json.loads(err.read() or b"{}")
            print(f"AnimeAPI error {err.code} {detail.get('code', '')}: {detail.get('error')}", file=sys.stderr)
            return 1
    
        out.parent.mkdir(parents=True, exist_ok=True)
        with urllib.request.urlopen(urllib.request.Request(data["image_url"], headers=UA), timeout=120) as img:
            out.write_bytes(img.read())
    
        print(f"saved: {out}")
        print(f"enhanced_prompt: {data['enhanced_prompt']}")
        print(f"balance_usd: {data['balance_usd']}")
        return 0
    
    
    if __name__ == "__main__":
        sys.exit(main())

→Use it

  • “Generate a square avatar for the demo user, anime style, save to public/avatars/demo.webp”
  • “Make a landscape title-screen background for the game into assets/title.webp”
  • “Turn assets/title.webp into a 5-second intro clip, save to assets/intro.mp4”

Cursor also reads .claude/skills/, but the Claude Code version uses ${CLAUDE_SKILL_DIR}, which only Claude Code expands. Use this version for Cursor.