| name | sts2-card-construction |
| description | Use when creating or updating Slay the Spire 2 cards with BaseLib. Trigger phrases: build card, create card, card code, card keywords, card portrait, card localization, add cards.json, add card_keywords.json, Snakebite card, STS2 card mod. |
STS2 Card Construction Skill
Purpose
Provide an end-to-end workflow for building STS2 cards with BaseLib:
- card model code,
- keyword wiring,
- portrait path strategy,
- localization text,
- validation,
- reusable task summary writeback.
Required Context
Before writing code, gather these inputs from user or repository:
- card class name and desired card fantasy,
- cost, type, rarity, target,
- primary and secondary effects,
- pool choice,
- localization language(s),
- whether this should mirror a vanilla card style.
If information is missing, ask concise questions first.
Source Priority
- tutorials/sts2-card-mod-guide-zh-cn.md
- STS2 decompiled source and BaseLib source at E:/STS2
- External docs (including https://glitchedreme.github.io/SlayTheSpire2ModdingTutorials/docs/03-baselib/)
When conflicts exist, prefer observed source behavior.
Build Workflow
Step 1: Dependencies and registration checks
Confirm both are present:
- snakebite.csproj references BaseLib.
- snakebite.json contains dependencies with BaseLib.
Step 2: Create card model
Default: inherit from CustomCardModel.
Add pool attribute for intended color pool.
Keep constructor semantics aligned with behavior.
Implementation rules:
- Keep OnPlay deterministic and await each action in logical order.
- For enemy-target cards, null-check target before effect execution.
- Keep CanonicalVars, ExtraHoverTips, and CanonicalKeywords in sync with gameplay and text.
- OnUpgrade should only adjust declared values.
- First playable version should be minimal and testable.
Step 3: Dynamic values and hover tips
Use canonical dynamic vars where possible:
- DamageVar, BlockVar, CardsVar, PowerVar.
If using custom dynamic vars:
- define a unique key,
- add tooltip binding,
- add localization in static_hover_tips.json when needed.
Use ExtraHoverTips for:
- powers,
- generated cards,
- custom keywords.
Step 4: Card keywords
For built-in keywords, use CanonicalKeywords directly.
For custom keywords:
- create keyword declaration class with CustomEnum and KeywordProperties,
- reference custom keyword in CanonicalKeywords,
- add localization file card_keywords.json with title and description.
Step 5: Card portrait strategy
Implement portrait path explicitly, either per-card or in a shared base class.
Recommended stable pattern:
- use Id.Entry.ToLowerInvariant() in resource path,
- keep images under a predictable folder structure.
Important naming caveat:
- card IDs are often namespaced (
modid-card_entry).
- if art files are stored without mod prefix (for example
snakebite_storm.png), strip modid- before composing filename, or name file with full ID (snakebite-snakebite_storm.png).
- mismatch here causes blank art with log errors like
No loader found for resource.
Art notes:
- any dimension is accepted,
- official common card art ratio examples are documented by the tutorial,
- keep naming deterministic to avoid missing-resource runtime issues.
Step 6: Localization text
Create or update:
- {modId}/localization/zhs/cards.json
- {modId}/localization/zhs/card_keywords.json when custom keywords are used
Text rules:
- Use {VarKey:diff()} for dynamic values that should color on change.
- Ensure text order matches actual OnPlay effect order.
- Do not duplicate keyword prose if keyword is already auto-rendered by engine behavior.
Step 7: Validation
At minimum verify:
- card can be obtained from intended pool,
- OnPlay resolves without target or null issues,
- upgrade values and text placeholders match,
- portrait displays correctly,
- hover tips and keyword display are correct.
Runtime validation checklist (highly recommended):
- open
godot.log and search card ID.
- if text shows key name (for example
cards.SNAKEBITE-...title), verify localization key exists in localization/zhs/cards.json and resource source matches current packaging mode.
- if portrait is blank, check for loader errors and compare requested path with actual filename exactly.
- for generated assets, confirm latest timestamps are deployed (stale pck frequently masks recent fixes).
If full runtime validation is unavailable, explicitly report what was not validated.
Packaging Modes (Do Not Mix)
Choose exactly one mode per run.
Mode A: PCK-first (recommended for release)
snakebite.json: set has_pck to true.
- deploy exactly three artifacts:
snakebite.dll, snakebite.json, snakebite.pck.
- pck filename must exactly match mod id (
snakebite.pck).
- after resource/text edits, re-export pck before testing.
Mode B: Loose-file (recommended for rapid iteration)
snakebite.json: set has_pck to false.
- deploy
dll + json + localization + images directories.
- do not rely on stale pck from previous builds.
Common deployment pitfalls
has_pck=true but missing/wrongly named pck -> resource load failures.
has_pck=false while assuming pck carries latest assets -> old or missing text/art.
- building while game process is running -> dll copy fails due to file lock.
- mixed source trees (for example both project root and nested
snakebite/) -> copied wrong asset set.
Output Contract For Agent
When completing a card task with this skill, produce:
- changed files list,
- concise behavior summary,
- validation results with pass/fail,
- known gaps and next checks.
Reusable Templates
Use assets in templates/:
- templates/card_model_template.cs
- templates/custom_keyword_template.cs
- templates/cards.localization.zhs.example.json
- templates/card_keywords.localization.zhs.example.json
Completion Memory Requirement
After each completed task, append one entry to ai-memory/task-summaries.md.
Use this format:
[YYYY-MM-DD HH:mm]
- Request:
- Changes:
- Validation:
- Decisions:
- Reuse Notes:
- <pattern, caveat, or snippet reusable next time>
- Next Options:
- <optional follow-up 1>
- <optional follow-up 2>
Rules:
- append-only; do not overwrite history,
- if no code changed, use Changes: NO_CHANGE,
- Reuse Notes must contain at least one concrete reusable point.