Paper2Galgame
Set SKILL_DIR to the absolute path of the directory containing this SKILL.md, then use the cross-platform Node launcher. It requires Node.js 18 or newer and selects P2G_CLI_PATH, a checked-out CLI, a global installation, or the published npm package in that order:
SKILL_DIR="<absolute path to this skill directory>"
node "$SKILL_DIR/scripts/paper2gal.cjs" <command> [options]
Use the same node <absolute-launcher-path> form on Windows; do not invoke Bash or WSL. P2G_CLI_PATH must point to the CLI JavaScript file, not an npm .cmd shim.
Authentication
Before the first account operation, run:
node "$SKILL_DIR/scripts/paper2gal.cjs" auth:status
If unauthenticated, run auth:login. Tell the user that Paper2Gal opens a browser for OAuth consent and explicitly announce this skill-caused pause. The login uses Authorization Code + S256 PKCE and saves a dedicated API token in ~/.paper2gal/config.json with owner-only permissions. If the browser does not open or the page reports a missing client_id or redirect_uri, retry with auth:login --no-browser and open the complete URL printed by the CLI. Do not reconstruct or shorten that URL.
Never ask the user to paste a password or expose a token in chat. Do not use --token unless the user explicitly asks for ephemeral environment-based authentication. If browser SSO is unavailable on an older CLI, use config:set-token only after the user creates a token in Paper2Gal settings.
One-shot flow (一句话快速流程,推荐)
When the user wants a topic turned into a finished, saveable story with a playable link in one go (e.g. "帮我用宁宁做一个关于上海葱油拌面的介绍"), use the bundled one-click script instead of running separate CLI stages:
node "$SKILL_DIR/scripts/oneclick.cjs" "/absolute/path/topic.md" <characterId> [--voice]
characterId defaults to u_nenen (宁宁); other common values: RUKA (辉夜露卡), or any id from characters:list.
The script does everything in one pass: fetch character → POST /api/v1/stories/generate (jobId) → poll → POST /api/v1/saves → print JSON with title, frames, saveId, playUrl, savesPage.
Steps the assistant should take for a one-shot request:
1. If the user gave only a topic (not a file), first write a rich markdown draft of the content to a temp file (history, craft details, local color, a fitting tone for the chosen character), then pass that file to oneclick.cjs.
2. Run auth:status first if the account has never been checked this session.
3. characterId: use u_nenen when the user says 宁宁 (that is the user's own character). Run characters:list if unsure.
4. Report: title, frame count, character, saveId, and the playUrl. Never paste raw JSON.
Important API facts (verified 2026-08):
- Directly POSTing stories/generate with only characterId returns 503 "角色暂时不可用". You MUST first GET /api/v1/characters/{id} and attach a customCharacter object ({name, dbId, synthesisVersion, prompt, encrypted:false} or {name, dbId, isBorrowed:true}). oneclick.cjs already does this.
- --wait on the CLI occasionally 502s; the script's generate→poll loop is the stable path. On a timed-out/failed job, poll the returned jobId — never resubmit (quota).
- Playable URL format is https://paper2gal.com/?save=<saveId> (the web player reads the ?save= / ?sharedSave= query or /share/<id> path, then loads /api/public/saves/<id>).
- A save only plays publicly when isShared=true. The CLI token cannot set it (the web-only PATCH /api/saves/{id}/share endpoint rejects the CLI token with 401). Tell the user: open the save in the web app's 我的保存 and click the share button to get a public link, or paste the saveId for account-local playback.
- Saves written via POST /api/v1/saves live on the same account; saves:list shows them. The web app's own list endpoint is GET /api/saves (web token only).
Core workflow
- Resolve every input file to an absolute path and verify it exists.
- Run
auth:status, thencharacters:listif the user did not choose a character. - For PDF or DOCX, default to
--parse-mode local; usesmartwhen the user requests intelligent parsing or local extraction is unsuitable. PPT/PPTX should usesmart. - Use
--waitwhen the user wants a completed result in the current task. Add--saveonly when the user asks to save it to their Paper2Gal account. - Return the story title, completion state, character, and save ID when present. Do not paste a huge raw JSON response unless requested.
Example:
node "$SKILL_DIR/scripts/paper2gal.cjs" stories:generate \
--file "/absolute/path/paper.pdf" \
--parse-mode local \
--character RUKA \
--blackboard \
--wait \
--save
Local character assets
Prefer local files over external image URLs. Resolve each file to an absolute path and verify it exists before mutation. Character creation and updates support:
--avatar-file--neutral-file--angry-file--surprised-file--thinking-file--cg-file, repeatable up to three times--voice-filefor a local reference voice
Local character images require Paper2Gal CLI 0.2.1 or newer. Before the first image upload, inspect the CLI --help output and confirm it lists --avatar-file. If not, report that the selected CLI is too old and use P2G_CLI_PATH with a current checkout or ask the user to update the installed package; do not silently fall back to URL fields.
Local files take precedence over matching URL fields. On update, one or more local CG files replace the complete existing CG list. After every characters:create or characters:update, run characters:get <id-or-characterId> and verify the returned image fields before reporting success.
Example:
node "$SKILL_DIR/scripts/paper2gal.cjs" characters:update my_character \
--avatar-file "/absolute/path/avatar.png" \
--neutral-file "/absolute/path/neutral.webp" \
--cg-file "/absolute/path/cg-1.png"
node "$SKILL_DIR/scripts/paper2gal.cjs" characters:get my_character
When only an external image is available, verify its HTTP status, response MIME type, decodability, dimensions, and visual content. Download it to a temporary local file and upload that file instead of saving an unverified hotlink. Do not trust a filename extension or search-result description as proof of image content.
Commands
- Account:
me,auth:login,auth:status,auth:logout,config:get - Characters:
characters:list,characters:get,characters:create,characters:update,characters:delete - Community:
community:search,community:borrow - Backgrounds:
backgrounds:list,backgrounds:upload,backgrounds:delete - Saves:
saves:list,saves:import - Stories:
stories:generate,stories:poll,stories:status
Prefer JSON output (the default) when another step must consume results. Use --table only for concise user-facing inspection.
Mutation safeguards
Treat generation, character creation/update, borrowing, background upload, save import, and saving a generated story as normal requested writes. Require explicit confirmation immediately before deleting a character or background. A failed or timed-out generation must not be automatically resubmitted because doing so may consume quota; poll the returned job ID instead.
On HTTP 429, report the rate limit and retry timing when available. Do not loop aggressively. On generation responses containing jobId, prefer stories:poll <jobId> or stories:status <jobId> instead of submitting again.