Install
openclaw skills install yumfuMultiplayer text RPG with 10 playable worlds — play together in Telegram groups! Worlds: 笑傲江湖, Harry Potter, Warrior Cats, F15 Down, 龙虾三国, 倚天屠龙记, Game of Thrones, Lord of the Rings, 西游记 (Journey to the West), 战国乱世 (Sengoku Chaos). Each player gets their own character in a shared world with AI art every scene. PvP, team quests, natural language — no commands needed. Use when: /yumfu, group RPG, text adventure, 武侠, 西游记, 孙悟空, LOTR, 指环王, 权力的游戏, 三国, 张无忌, 战国, 织田信长, 丰臣秀吉, 德川家康, 武田信玄.
openclaw skills install yumfuMulti-world text adventure RPG with AI art. Play solo or with friends across 10 universes.
Start: /yumfu start | Continue: /yumfu continue
If YumFu is useful to you, you can support future development here: Donate via Stripe: https://buy.stripe.com/8x26oHc329ha6GvaiggjC00
Just talk naturally after starting — no commands needed. Say what you want to do and the story unfolds.
| World | Genre | Status |
|---|---|---|
| ⚔️ 笑傲江湖 | Wuxia / 武侠 | ✅ Ready |
| ⚡ Harry Potter | Magic school | ✅ Ready |
| 🐱 Warrior Cats | Animal clan | ✅ Ready |
| 🛵 F15 Down | Modern military | ✅ NEW |
| 🧙 Lord of the Rings | Epic fantasy | ✅ Playable |
| 🐉 Game of Thrones | Political | 🚧 Soon |
| ⚔️ 倚天屠龙记 | Jin Yong wuxia | 🚧 Soon |
| 🏯 战国乱世 | Sengoku alt-history | ✅ NEW |
This is a modern AI MUD — high tolerance, natural language first.
If the user is:
Just respond and continue the story. No slash commands required.
Input tolerance:
Only use /yumfu start and /yumfu continue as entry points. Everything else = natural language.
Then you MUST:
load_game.py
1b. ✅ For normal gameplay turns, prefer building hidden turn context via uv run ~/clawd/skills/yumfu/scripts/build_gameplay_context.py --user-id <id> --universe <world> --player-input "..."
save_game.py/yumfu continue re-entry, briefly remind the player of the current main line when useful, especially after detours, battles, travel, or offline timeuv run ~/clawd/skills/yumfu/scripts/story_spine_state.py --set ... so later turns, daily evolution, and continue/re-entry all stay alignedDO NOT:
This ensures:
Read full spec: ~/clawd/skills/yumfu/DEEP_NARRATIVE_ENGINE.md
1. Every choice opens a door, never closes the game
1b. Choice presentation must be visually clear
1 / 2 / 3 for Chinese gameplay and A / B / C or 1 / 2 / 3 for English gameplay你现在可以: / Choose your next move:1. ...2. ...3. ...2. Three-Arc Story Structure
Arc 1 (20%): Establishment - character, world, first crisis
Arc 2 (60%): Development - conflicts, relationships, moral dilemmas
Arc 3 (20%): Climax - final choices, multiple endings
3. Hidden Tracking Stats (ALL worlds)
{
"reputation": 50, // affects NPC attitudes
"moral_alignment": 50, // 0=dark, 100=light
"risk_exposure": 0, // danger level
"npc_trust": {} // per-NPC trust values
}
Plus 2-4 world-specific stats (e.g., 武功 for 笑傲江湖, magic power for HP)
4. NPC Memory System
5. Consequence Types
6. Image Generation - MANDATORY at:
6b. Telegram Image+Text Delivery - CRITICAL:
⚠️ NEVER send image and story text as two separate messages on Telegram. This causes the text to appear AFTER the image and get ignored/folded.
✅ CORRECT pattern — put ALL story text in the image caption:
message(action="send", media="path/to/image.jpg", message="[full story text here]", target=...)
✅ CRITICAL tool rule for YumFu gameplay:
Use an image generation path that writes a local file only and does not auto-send media to the chat by itself.
For official YumFu turns, prefer local-file generators such as scripts/generate_image.py or an equivalent wrapper that returns only a saved path.
✅ Image backend fallback order — REQUIRED:
uv run ~/clawd/skills/yumfu/scripts/generate_image.py ... (always use uv run, not plain python3, so inline dependencies load correctly)GEMINI_API_KEY / GOOGLE_API_KEY is missing, provider auth is unavailable, the local script errors, or the local runtime/import path is broken, immediately fall back to OpenClaw image_generate and then deliver the resulting local media path through the normal YumFu turn-delivery flow⚠️ Never silently skip the image step. Either deliver the image, or clearly state that the turn is temporarily running without image support.
❌ Do not use any image tool/path that auto-inserts or auto-delivers the generated image into the current chat before the turn delivery logic runs.
❌ WRONG pattern — two separate messages:
message(action="send", message="story text") # DON'T
message(action="send", media="path/to/image.jpg") # DON'T
❌ ALSO WRONG — send image first, then send image+caption again:
message(action="send", media="path/to/image.jpg")
message(action="send", media="path/to/image.jpg", message="story text")
This causes the same turn to feel like a duplicate image send.
Telegram caption limit is 1024 chars. If story text exceeds that:
This ensures the image and story are always visually paired together.
For each gameplay turn, enforce a single turn_id and delivery state.
Default implementation path (MANDATORY):
Use uv run ~/clawd/skills/yumfu/scripts/deliver_yumfu_turn.py ... as the default per-turn delivery preparation helper.
This helper is now the standard YumFu path for:
For Telegram/group gameplay, do not hand-roll turn delivery if this helper can be used.
Hard limits per turn:
Preferred delivery order:
deliver_yumfu_turn.py to prepare assets/state for the turnimage_generate and continue the same turn delivery flowFallback sequencing rule:
7. World-Specific Art Styles
8. Random Events (every 3-5 nodes) Trigger one of: Encounter / Crisis / Discovery / Opportunity / Echo (delayed consequence)
CRITICAL Save/Load Rules:
~/clawd/skills/yumfu/scripts/load_game.py~/clawd/skills/yumfu/scripts/save_game.py~/clawd/skills/yumfu/scripts/SAVE_LOAD_REFERENCE.mdSee detailed instructions in "💾 Save File Management" section below.
First time? Start with language selection:
/yumfu start
You'll see / 你会看到:
🌍 Welcome to YumFu! | 欢迎来到YumFu!
1. 中文 (Chinese) - 武侠世界
2. English - Fantasy Realms
Reply: /yumfu lang <1|2>
Then choose your world / 然后选择世界:
After world + character setup, ask one more onboarding question (MANDATORY):
This is a unified YumFu rule across worlds, not a one-off reminder.
Daily evolution is always optional, but the system should proactively ask during /yumfu start so the player does not need to remember to enable it later.
Do you want this world to evolve automatically every day, even when you're offline?
1. Yes — send me one daily world update with art
2. No — only progress when I play
If the player says Yes, enable Daily Evolution Mode for that save. If the player says No, keep the default manual-only mode.
中文 (Available Now):
战国乱世专用 start 路径(MANDATORY when selected)
If the player chooses 战国乱世 / Sengoku Chaos during /yumfu start, route the setup through:
python3 ~/clawd/skills/yumfu/scripts/start_sengoku_game.py \
--user-id {user_id} \
--name {player_name} \
--role {selected_role_id} \
--faction {selected_faction_id} \
--scenario {selected_scenario_id} \
--language {zh|en} \
--daily-evolution {yes|no} \
--target {chat_id}
Then:
rendered_opening.image_promptrendered_opening.player_opening_message with that image as the first playable opening sceneEnglish (Available Now):
Coming Soon: LOTR, Game of Thrones, The Witcher, 倚天屠龙记, 射雕英雄传
所有指令以 /yumfu 或 /江湖 开头
All commands support both English and Chinese aliases:
| English | 中文 | Action |
|---|---|---|
/yumfu start | /yumfu 开始 | Start new game / 开始新游戏 |
/yumfu continue | /yumfu 继续 | Continue saved game / 继续游戏 |
/yumfu status | /yumfu 状态 | Show character stats / 显示状态 |
/yumfu help | /yumfu 帮助 | Show all commands / 显示帮助 |
/yumfu go <place> | /yumfu 去 <地点> | Travel to location / 前往某地 |
/yumfu look | /yumfu 看 | Look around / 查看四周 |
/yumfu map | /yumfu 地图 | Show map / 显示地图 |
/yumfu fight <target> | /yumfu 战 <对手> | Start combat / 发起战斗 |
/yumfu train <skill> | /yumfu 练 <功法> | Train skill / 修炼武功 |
Use the language that matches your selected world!
/yumfu start 或 /yumfu 开始 — 开始新游戏(创建角色)/yumfu continue 或 /yumfu 继续 — 继续已保存的游戏/yumfu save — 保存当前游戏状态/yumfu status 或 /yumfu 状态 — 显示角色属性、物品、位置/yumfu help 或 /yumfu 帮助 — 显示所有指令🚨 First-time users: If you try any command and see "Welcome! You don't have a character yet", use /yumfu start to create your character first. The system will auto-detect this and guide you!
/yumfu continue Workflow (详细流程)Before resuming active play, also check whether a daily evolution sidecar exists:
python3 ~/clawd/skills/yumfu/scripts/build_reentry_context.py \
--user-id {user_id} \
--universe {selected_world}
Then prepare the actual continue-time delivery bundle:
python3 ~/clawd/skills/yumfu/scripts/prepare_continue_reentry_delivery.py \
--user-id {user_id} \
--universe {selected_world} \
--target {chat_id}
If a sidecar exists:
save.language unless the player explicitly switched play languageWhen user says /yumfu continue:
Step 1: Check for existing saves
python3 ~/clawd/skills/yumfu/scripts/load_game.py \
--user-id {user_id} \
--check-all \
--pretty
Step 2: Parse results
/yumfu startStep 3: Display saves (if multiple) Example output:
🎮 You have 3 saved games:
1. 🗡️ 笑傲江湖 - 小虾米 (Lv.3)
📍 Location: 华山派·思过崖
🕐 Last played: 2 days ago
2. 🪄 Harry Potter - Tom Brady (Lv.5)
📍 Location: Gryffindor Common Room
🕐 Last played: 1 hour ago
3. 🐱 Warrior Cats - Tumpaw (Lv.2)
📍 Location: ThunderClan Camp
🕐 Last played: 3 days ago
Which adventure do you want to continue?
Reply: 1, 2, 3, or world name (xiaoao/harry/warrior)
Step 4: Load selected world
python3 ~/clawd/skills/yumfu/scripts/load_game.py \
--user-id {user_id} \
--universe {selected_world} \
--pretty
Step 5: Resume gameplay Continue from their last location with a recap:
欢迎回来,小虾米!
你站在华山派思过崖边缘,冷风呼啸。上次你刚从山洞中获得了一本破旧的剑谱...
[内力] 250/300 [体力] 180/200
[装备] 长剑(品质:普通)
[任务] 破解剑谱秘密 (进度: 30%)
你打算做什么?
/yumfu go <地点> 或 /yumfu 去 <地点> — 前往某地/yumfu look 或 /yumfu 看 — 查看当前位置/yumfu map 或 /yumfu 地图 — 显示已知地点/yumfu fight <目标> 或 /yumfu 战 <对手> — 发起战斗/yumfu attack <招式> 或 /yumfu 攻 <招式> — 战斗中使用特定招式/yumfu defend 或 /yumfu 守 — 防御姿态/yumfu flee 或 /yumfu 逃 — 尝试逃跑/yumfu train <功法> 或 /yumfu 练 <功法> — 修炼武功/yumfu meditate 或 /yumfu 打坐 — 恢复体力/内力,有机会顿悟/yumfu skills 或 /yumfu 武功 — 列出已学武功和等级/yumfu talk <NPC> 或 /yumfu 对话 <人物> — 与NPC对话/yumfu join <门派> 或 /yumfu 拜入 <门派> — 加入武林门派/yumfu reputation 或 /yumfu 名望 — 查看各门派声望/yumfu inventory 或 /yumfu 背包 — 显示背包/yumfu use <物品> 或 /yumfu 用 <物品> — 使用物品/yumfu buy <物品> 或 /yumfu 买 <物品> — 从当前商店购买/yumfu sell <物品> 或 /yumfu 卖 <物品> — 向当前商店出售/yumfu team create <队名> — 创建队伍/yumfu team invite @用户 — 邀请队友/yumfu team join <队名> — 加入队伍/yumfu team leave — 离队/yumfu team status — 查看队伍状态/yumfu team list — 列出所有队伍/yumfu duel @用户 — 友谊切磋(点到为止)/yumfu duel @用户 --death-match — 生死决斗(战至一方HP=0)/yumfu watch — 观战当前战斗/yumfu world — 查看世界状态(NPC位置、门派控制)/yumfu events — 查看今日江湖大事/yumfu leaderboard — 查看排行榜/yumfu players — 查看在线玩家友谊切磋(默认):
生死决斗:
1. NPC 击杀
2. 门派争霸
3. 秘籍争夺
4. 声望系统
金庸、古龙经典武侠世界:
memory/yumfu/
├── world-state.json # 共享世界状态(NPC、秘籍、门派控制)
├── saves/
│ ├── xiaoao/ # 笑傲江湖存档目录
│ │ ├── user-123456789.json
│ │ └── user-2345678901.json
│ ├── harry-potter/ # Harry Potter存档目录
│ │ └── user-123456789.json
│ └── warrior-cats/ # Warrior Cats存档目录
│ └── user-123456789.json
├── teams/
│ └── team-华山论剑.json # 临时队伍状态
└── events/
└── 2026-04-01.json # 今日江湖大事
Note: Each world uses a separate subfolder to prevent save conflicts.
{
"version": 1,
"game_time": { "year": "南宋", "season": "春", "day": 1 },
"npcs": {
"洪七公": {
"location": "洛阳",
"hp": 1000,
"status": "alive",
"reputation": {
"user-123456789": 50,
"user-2345678901": -20
},
"killed_by": null
}
},
"world_events": [...],
"faction_control": { "洛阳": "丐帮" },
"rare_items": {
"九阴真经": { "owner": "user-123456789", "status": "owned" }
},
"leaderboards": {
"level": [...],
"morality": [...],
"wealth": [...]
}
}
{
"version": 2,
"user_id": "123456789",
"language": "zh",
"universe": "xiaoao",
"character": { "name": "大红虾🦐", "level": 1, ... },
"location": "洛阳城",
"inventory": [...],
"skills": [...],
"quests": [...],
"team_id": null,
"in_combat_with": null,
"tts": {
"enabled": true,
"provider": "edge-tts",
"delivery": "voice-bubble",
"language_voices": {
"zh": "zh-CN-XiaoxiaoNeural",
"en": "en-GB-SoniaNeural"
},
"current_voice": "zh-CN-XiaoxiaoNeural",
"last_language": "zh",
"switch_policy": "keep same voice for same language within one save unless user explicitly asks to change"
},
"daily_evolution": {
"enabled": false,
"cadence": "daily",
"channel": "telegram",
"last_tick_at": null,
"next_tick_at": null,
"cron_id": null,
"last_summary": null
}
}
Important: Save path is ~/clawd/memory/yumfu/saves/{universe}/user-{id}.json
CRITICAL: Persist game state after every significant action to prevent data loss!
🚨 CRITICAL: Character creation MUST save immediately before any other actions!
DO NOT manually construct save logic. Use the standard scripts to avoid format errors:
# Load specific user's save
uv run ~/clawd/skills/yumfu/scripts/load_game.py \
--user-id 1309815719 \
--universe xiaoao \
--quiet
# Check all worlds for a user
uv run ~/clawd/skills/yumfu/scripts/load_game.py \
--user-id 1309815719 \
--check-all
Output (JSON):
{
"exists": true,
"data": { "character": {...}, "location": "...", ... },
"character_name": "小虾米",
"level": 1,
"location": "洛阳城·同福客栈门口",
"save_path": "/Users/tommy/clawd/memory/yumfu/saves/xiaoao/user-1309815719.json"
}
# Save from JSON string
uv run ~/clawd/skills/yumfu/scripts/save_game.py \
--user-id 1309815719 \
--universe xiaoao \
--data '{"character": {"name": "小虾米", "level": 2, ...}, "location": "华山派"}'
# Or pipe JSON (preferred for large saves)
echo '{"character": {...}}' | \
uv run ~/clawd/skills/yumfu/scripts/save_game.py \
--user-id 1309815719 \
--universe xiaoao
Output:
✅ Game saved successfully!
📁 Path: /Users/tommy/clawd/memory/yumfu/saves/xiaoao/user-1309815719.json
💾 Backup: /Users/tommy/clawd/memory/yumfu/backups/user-1309815719-xiaoao-20260404-101234.json
👤 Character: 小虾米 (Lv.2)
import json
# 1. Load existing save (or detect new user)
# Note: user_id should be validated/sanitized by OpenClaw before reaching this point
result = exec({
"command": f"uv run ~/clawd/skills/yumfu/scripts/load_game.py --user-id {user_id} --universe {universe} --quiet"
})
save_data = json.loads(result.stdout)
if not save_data["exists"]:
# New user - guide to character creation
return "Welcome! Use /yumfu start to create your character."
# 2. Modify game state
save_data["data"]["character"]["hp"] -= 15
save_data["data"]["location"] = "华山派·练武场"
# 3. Save back using stdin (avoids command injection)
save_json = json.dumps(save_data["data"])
result = exec({
"command": f"uv run ~/clawd/skills/yumfu/scripts/save_game.py --user-id {user_id} --universe {universe}"
})
# Pass JSON via stdin to avoid shell escaping issues
process.write({"sessionId": result.sessionId, "data": save_json, "eof": True})
/tmp/0 = success, 1 = failure{
"team_name": "华山论剑",
"created": "2026-04-01T22:00:00",
"leader": "user-123456789",
"members": [
{ "user_id": "123456789", "name": "大红虾🦐", "hp": 90 },
{ "user_id": "2345678901", "name": "小龙虾", "hp": 100 }
],
"exp_share": true,
"loot_mode": "leader"
}
Agent 就是游戏引擎:
EVERY command (except /yumfu start and /yumfu help) MUST start with this check:
import os
import json
def check_or_create_save(user_id, universe="xiaoao"):
"""Auto-detect save file. If missing, guide user to create character."""
save_path = os.path.expanduser(f"~/clawd/memory/yumfu/saves/{universe}/user-{user_id}.json")
if os.path.exists(save_path):
with open(save_path, 'r') as f:
return (True, json.load(f))
else:
return (False, None)
# Usage at START of every command handler:
user_id = message_context.get("sender_id") or message_context.get("user_id")
has_save, save_data = check_or_create_save(user_id)
if not has_save:
return """🌍 Welcome to YumFu! You don't have a character yet.
Let's create one! Use: /yumfu start
Available worlds:
⚔️ Xiaoao Jianghu (笑傲江湖)
⚡ Harry Potter
🐱 Warrior Cats"""
This prevents "no save found" errors and auto-guides new players.
world-state.jsonPurpose: keep the world moving even when the player is offline, so they receive one short daily update with fresh context, image, and meaningful pressure to come back.
Use a unified YumFu framework for this feature, but make the actual evolution content dynamic at runtime.
Fixed / shared across YumFu:
Dynamic at runtime (NOT hardcoded event scripts):
Do not hardcode daily story content unless absolutely necessary.
This feature should feel like a living world, not a rotating calendar of canned events. The best approach is:
During /yumfu start, after world choice and initial character setup, ask:
Exact onboarding flow for any world:
python3 ~/clawd/skills/yumfu/scripts/handle_daily_evolution_choice.py \
--user-id {user_id} \
--universe {selected_world} \
--target {chat_id} \
--choice yes|no \
--channel telegram \
--time 10:00 \
--tz America/Los_Angeles
message_zh / message_en as the short confirmation to the playerThis is world-agnostic. Any YumFu world should use the same post-start activation flow.
If the player later disables it:
~/clawd/skills/yumfu/scripts/disable_daily_evolution_cron.pyBefore generating the update, load and consider:
Each daily evolution update should include:
The recap is mandatory. Do not assume the player remembers yesterday's update, the hidden faction line, or why the current image matters.
Daily evolution is not text-only. If a daily evolution update is delivered to the player, the default delivery bundle is:
The player-facing text should normally read like:
Rules:
save.tts.enabled != false, generate and send TTS for daily evolution too.message(..., asVoice=true)).The core goal is not to generate a long lore report. The core goal is to pull the player back into the current scene naturally and easily.
For daily evolution pushes, that re-entry starts immediately with a short recap. If the update opens cold, the player forgets the plot and the image loses meaning.
That recap should usually answer 3 things in compact form:
But those answers must be rendered as story, not as backend labels. The player should feel scene pressure and purpose, not see the scaffolding behind it.
Daily evolution should feel like:
It should not feel like:
Every daily evolution update should end with a simple re-entry hook the player can answer naturally. Good examples:
Bad examples:
The update should make it easy for the player to resume with a short natural reply. Ideally the player should be able to continue by replying with:
This feature exists to increase re-engagement, not to increase reading burden.
Daily evolution updates should respect the player's established language, instead of switching arbitrarily.
Gameplay TTS is enabled by default for each save unless the player explicitly turns it off.
TTS rules:
save.tts.Supporting scripts:
scripts/resolve_tts_voice.py — resolve stable per-save TTS settings and language-matched voicesscripts/generate_turn_tts.py — generate one gameplay-turn TTS file using the save's stable current voiceUse this priority order:
save.language if present (canonical per save)Examples:
The daily update should feel like a natural continuation of how the player has already been playing.
Most days should be light but meaningful:
Major movement should be rare, but possible, so the world feels alive.
Daily evolution may stay light on many days, but at least once per 7 days of real time the player should receive a more substantive advancement signal tied to the current arc.
That weekly advancement should usually include at least one of:
Implementation expectation:
last_major_advancement_at in the evolution sidecaradvancement_level=majorThe goal is to avoid the feeling that the game only emits atmospheric nudges forever. Even when the player is absent, the world should occasionally become more legible and more playable.
If there is meaningful risk of corrupting or derailing the player's real save, do not mutate the main player save at all.
Preferred design for MVP:
This means the daily evolution system should generate:
...without force-changing the player's core location, inventory, quest completion, or irreversible main-story state.
Store daily evolution context in a separate file such as:
~/clawd/memory/yumfu/evolution/{universe}/user-{id}.json
Supporting scripts:
scripts/set_daily_evolution.py — enable/disable sidecar statescripts/load_daily_evolution.py — inspect sidecar statescripts/detect_recent_language.py — infer preferred recent player languagescripts/handle_daily_evolution_choice.py — world-agnostic post-start yes/no activation handlerscripts/story_spine_state.py — read/update the save-side current story spinescripts/build_gameplay_context.py — build hidden normal-turn context from save + world + story spine before writing a regular gameplay turnscripts/daily_evolution_prepare.py — build dynamic runtime contextscripts/run_daily_evolution_job.py — generate a daily evolution updatescripts/run_daily_evolution.py — persist generated result into sidecarscripts/prepare_daily_evolution_delivery.py — prepare image/text/TTS delivery plan for one daily evolution tickscripts/execute_daily_evolution_delivery.py — emit exact send/mark/apply steps for one daily evolution tick with low freedomscripts/create_daily_evolution_cron.py — create per-player daily cronscripts/disable_daily_evolution_cron.py — disable per-player daily cronscripts/build_reentry_context.py — merge save + sidecar for continue flowscripts/render_continue_reentry.py — render a concise continue-time re-entry promptassets/yumfu-logo.png — corner logo stamped onto YumFu-generated imagesscripts/init_sengoku_save.py — initialize a 战国乱世 / Sengoku Chaos starting savescripts/start_sengoku_game.py — initialize Sengoku save + daily evolution choice + opening scene payloadThis sidecar can track:
When the player returns, the game engine may read both:
Then merge them narratively:
For now, default to:
Default-route behavior:
default_route, treat it as the current active_route unless a newer active route replaces itOnly after the system is proven safe should limited main-save mutation be considered.
If the daily evolution message is already delivered to the intended player/channel, do not send a separate “report generated” notification. Only send the actual in-world update.
Daily evolution adds new sidecar workflows, but it must not weaken older YumFu guarantees. The following original behaviors remain mandatory unless the user explicitly requests otherwise:
Even though the content is dynamically generated, it must still stay grounded in each world’s canon/setting documents.
Do not let YumFu worlds flatten into generic atmosphere. Whenever active play, daily evolution, or continue/re-entry is generated, actively look for chances to surface concrete detail from the save/world state such as:
Also make sure those details are not random garnish — they should help the player re-understand the main story line and the current major task of this run.
If you use hidden route logic internally, translate it into natural stakes, rumors, orders, temptations, battlefield pressure, travel needs, or NPC requests before showing anything to the player.
The player should feel there is a world with people, loyalties, and usable leads — not just tone.
Examples of what the AI should infer dynamically:
Daily evolution should nudge the player, not replace the game. It must create pressure, intrigue, and hooks — but should not auto-finish the main story without player participation.
Narrative style adapts to the world:
[体力 -15] [内力 +5][HP -15] [Stamina +5]Universal:
Target: 150-300 words per turn (每回合150-300词)
⚠️ Avoid these extremes:
❌ Too short (< 100 words): Feels lazy, lacks immersion
❌ Too long (> 400 words): Overwhelming, slows gameplay
✅ Ideal structure (150-300 words):
Example (good length):
你推开酒楼木门,一阵酒肉香气扡19面而来。厅内三五江湖人士正低声交谈,角落里一名蒙面人独自饮酒。小二点头哈腰:“客官里边请!”
你刚坐下,那蒙面人忽然抬头,目光如电。他缓缓起身,手按刀柄:“华山派的?”声音冰冷而警惕。周围食客纷纷侧目,空气骤然紧绗。
[内力] 95/100 [体力] 80/100
你可以:1) 回应他的质问 2) 装作不闻 3) 先发制人
(~150 words - perfect!)
Remember: Quality over quantity. Make every word count.
使用透明的随机系统:
# 百分比检定
shuf -i 1-100 -n 1
# D20检定
shuf -i 1-20 -n 1
# 战斗示例
攻击检定: 1d20+5 = 18 (成功!)
伤害: 2d10+3 = 16
⚔️ 大红虾 vs 小龙虾
[回合1] 大红虾使用【降龙十八掌】
[投骰] 攻击检定: 1d20+5 = 18 (命中!)
[投骰] 伤害: 2d10+3 = 16
💥 小龙虾未能闪避!
[体力] 小龙虾 100 → 84
[回合2] 小龙虾使用【玉女剑法】
...
🚨 CRITICAL RULE: EVERY game turn MUST generate an image BEFORE narration. No exceptions.
🔴 MANDATORY: Generate image for EVERY game response
If the user's message is a game action (not /yumfu status, /yumfu help, or meta commands):
✅ ALWAYS generate image FIRST, then narrate ✅ Generate exactly ONE primary scene image per game turn
That means:
Execution order (STRICT):
DO NOT:
Why every turn needs an image:
🔍 PRE-CHECK before EVERY response:
/yumfu start counts as a full game opening turn, so it also MUST generate an opening image before narrationWhen user takes ANY game action:
/yumfu start special case:
Image-exempt commands (only these!):
/yumfu status / /yumfu 状态 - Character sheet/yumfu help / /yumfu 帮助 - Command list/yumfu save - Save operationEverything else = Image required!
For active gameplay, the default contract is:
Only break this when the user explicitly asks for:
If none of those were asked for, do not send a second image for the same turn.
Example Flow:
User: "I want to talk to Firestar"
→ Agent: "This is NPC encounter trigger!"
→ IMMEDIATELY run generate_image.py
→ Send image + start dialogue
→ NOT: Start dialogue, then "oh wait, I should generate image"
uv run ~/clawd/skills/yumfu/scripts/generate_image.py \
--prompt "<scene prompt>" \
--filename "~/.openclaw/media/outbound/yumfu/$(date +%Y%m%d-%H%M%S)-<scene>.png" \
--resolution 2K
Do not use python3 ~/clawd/skills/yumfu/scripts/generate_image.py ... directly unless the equivalent dependencies are already installed in that exact interpreter; the supported/default path is uv run.
Note: Script does NOT auto-send. After generation, send the image through the normal YumFu turn delivery flow. In Telegram group chats, this means the image must be delivered back into that same group for the turn.
Each world has its own signature art style. ALWAYS include the style prefix in prompts.
Global anti-text rule (MANDATORY for every YumFu image prompt):
Append an explicit negative constraint such as:
No text, no words, no letters, no captions, no signs, no speech bubbles, no book pages, no paragraph blocks, no watermark, no logo, image-only illustration.
If the model still renders text-like artifacts, strengthen the next prompt further instead of accepting the bad output as final turn art.
Chinese wuxia ink wash painting style (水墨武侠风), dramatic cinematic composition, muted earth tones with selective vivid accents (red, gold), atmospheric fog and light rays, textured rice paper background,
Hogwarts watercolor illustration style, magical atmosphere, warm candlelight and moonlight, storybook composition, detailed wizarding world architecture, enchanted particle effects, painterly texture,
Semi-realistic warrior cats art style, forest atmosphere with dappled sunlight, detailed cat anatomy and expressions, natural woodland setting, dramatic lighting through trees, storybook illustration quality,
Bright classic Journey to the West fairytale illustration style, colorful and simple mythic Chinese storybook aesthetic, cloud-edged shapes and auspicious 祥云 motifs, clean outlines, vivid but gentle colors, playful heavenly atmosphere, classic children's mythology illustration feeling, not wuxia, not xianxia, not dark realism,
[风格前缀] wide establishing shot of <地点>, <时间>, <天气/氛围>, small figure of a lone swordsman in the scene, architectural details of <建筑>, <自然元素>
[风格前缀] medium close-up portrait of <NPC描述>, <表情>, <特征>, <服饰细节>, <背景>, dramatic side lighting
[风格前缀] dynamic action shot, <角色> vs <敌人/玩家>, <正在使用的招式>, motion blur on weapon, debris/leaves flying, intense facial expressions, <环境>
多人战斗:
[风格前缀] chaotic multi-person combat, 3-5 martial artists in intense battle, various weapons and techniques, swirling energy effects, dramatic composition, <location>
[风格前缀] serene composition, <角色> in <修炼姿势>, <地点>, mystical qi energy swirling around body as translucent wisps, soft golden light, tranquil atmosphere
[风格前缀] dramatic still life or vignette, <关键物品或象征>, <氛围光>, cinematic depth of field, <相关元素>
[风格前缀] warm interior scene, <商店/客栈描述>, lantern light, wooden beams, <NPC和物品>, cozy detailed atmosphere, period-accurate props
[风格前缀] group portrait, <team members> standing together in heroic formation, various weapons and martial arts stances, sense of camaraderie, <location background>
message tool 发送图片(media 参数)~/.openclaw/media/outbound/yumfu/Each world has unique progression systems designed for its target age group:
核心系统:
防速通机制:
核心系统:
防速通机制:
核心系统:
防速通机制:
YumFu works across multiple AI platforms with varying feature sets:
Full multiplayer experience:
Best for: Group adventures, PvP, shared world events
Single-player mode:
Best for: Solo story-driven campaigns
Text-only mode:
Best for: Quick casual play, testing stories
OpenClaw (Telegram/Discord):
@我 /yumfu start~/clawd/memory/yumfu/saves/{universe}/user-{platform_id}.json@我 /yumfu continueuser-{telegram_id}.jsonworld-state.json(NPC状态、世界变化)@我 /yumfu duel @玩家B/yumfu events 查看Every single game turn MUST be logged for storybook generation.
Suggested onboarding wording:
这局默认会自动记录并整理成可生成 Storybook 的旅程档案;如果你不想记录,我也可以关掉。This run will be auto-recorded for an illustrated storybook by default; if you don't want that, I can turn it off.After EVERY player action, immediately run:
from scripts.session_logger import log_turn
# Log complete turn
log_turn(
user_id="1309815719", # Telegram user ID
universe="warrior-cats", # Current world
player_input="/yumfu look", # What player typed
ai_response="You see...", # Your narrative response
image="tumpaw-camp-123.png" # Optional: if image generated this turn
)
player_inputai_responseimage filenamelog_turn() with all 3 componentsturn_id and initialize delivery state with:python3 ~/clawd/skills/yumfu/scripts/turn_delivery_state.py \
--user-id {user_id} \
--universe {universe} \
--turn-id {turn_id}
save.tts.enabled != false → Generate turn TTS with:python3 ~/clawd/skills/yumfu/scripts/generate_turn_tts.py \
--user-id {user_id} \
--universe {universe} \
--language {active_language} \
--text "{final_story_text}"
message(..., asVoice=true))# 1. Player types: "/yumfu look"
player_input = "/yumfu look"
# 2. Generate response
ai_response = "You see the ThunderClan camp bustling with activity. Warriors share tongues near the fresh-kill pile..."
# 3. Check if image should be generated (see Image Generation rules)
image_filename = None
if should_generate_image("location"): # Location arrival
image_filename = generate_image("tumpaw-thunderclan-camp")
# Returns: "tumpaw-thunderclan-camp-20260403-075523.png"
# 4. Log the turn BEFORE sending
from scripts.session_logger import log_turn
log_turn(
user_id="1309815719",
universe="warrior-cats",
player_input=player_input,
ai_response=ai_response,
image=image_filename
)
# 5. Send response to user
reply(ai_response)
if image_filename:
send_image(image_filename)
The storybook should not read like a raw terminal log forever. During logging and later compilation:
A, 1, go, attack him, 跟上 into clearer narrative intent inside the book version~/clawd/memory/yumfu/sessions/{universe}/user-{id}/session-{timestamp}.jsonl
Example:
~/clawd/memory/yumfu/sessions/warrior-cats/user-1309815719/session-20260403-001349.jsonl
Each line in the log file:
{"timestamp": "2026-04-03T00:15:23", "type": "turn", "player": "/yumfu look", "ai": "You see...", "image": "tumpaw-camp-123.png"}
Logging is NOT optional. Every turn must be logged or storybook generation will be incomplete.
当玩家消息以下列任一开头时激活:
/yumfu/江湖群聊支持:
@我 /yumfu <指令> 即可触发武侠江湖,等你来闯!邀上好友,共闯江湖! ⚔️
NEW: Every adventure is automatically recorded and can be turned into a beautiful PDF storybook!
1. During Gameplay:
scripts/session_logger.py (see Mandatory Logging above)~/clawd/memory/yumfu/sessions/{universe}/user-{id}/session-{timestamp}.jsonl2. Generate Storybook:
# V3 - Full conversation flow (canonical)
uv run ~/clawd/skills/yumfu/scripts/generate_storybook_v3.py \
--user-id 1309815719 \
--universe warrior-cats
# Auto-detects latest session or specify one:
uv run ~/clawd/skills/yumfu/scripts/generate_storybook_v3.py \
--user-id 1309815719 \
--universe warrior-cats \
--session-id 20260403-001349
# Ending / retire / archive branch (preferred for final delivery)
uv run ~/clawd/skills/yumfu/scripts/deliver_yumfu_turn.py \
--user-id 1309815719 \
--universe warrior-cats \
--language en \
--turn-id warrior-cats-final-001 \
--story-text "<final in-world ending text>" \
--ending-storybook \
--session-id 20260403-001349
3. Output:
~/clawd/memory/yumfu/storybooks/warrior-cats/user-1309815719-20260403-075523/
├── storybook.html # canonical shareable artifact (HTML first)
└── images/ # copied source images for local reference
├── tumpaw-ceremony-20260403.png
├── tumpaw-firestar-20260403.png
└── tumpaw-fishing-20260403.png
The V3 generator creates a complete dialogue flow storybook:
[Tumpaw's Adventure - Title Page]
▶️ Player: /yumfu look
You see the ThunderClan camp bustling with activity. Warriors share tongues
near the fresh-kill pile while apprentices practice battle moves...
[Image: ThunderClan Camp - embedded here]
▶️ Player: /yumfu train swimming
Willowpelt leads you to the river border. "Swimming is unusual for ThunderClan,"
she purrs, "but if you have the talent, we'll develop it..."
▶️ Player: /yumfu go river
You pad down to the river. The water flows swiftly, sunlight glinting off the surface...
[Image: Tumpaw at River - embedded here]
---
[Final Stats & Achievements]
Key difference from V2:
Trigger storybook generation when:
/yumfu storybook or asks for PDF)When a run reaches a meaningful ending or the player explicitly says they want to stop / end / archive / retire that game record:
\u9aa8\u602a\u7cbe\u7075) before rendering titles / proseWatch / ThreadRecommended helper:
uv run ~/clawd/skills/yumfu/scripts/prepare_end_storybook.py --user-id <id> --universe <world> [--session-id ...]uv run ~/clawd/skills/yumfu/scripts/deliver_yumfu_turn.py ... --ending-storybook [--session-id ...]If daily evolution is enabled and a storybook source already exists for that save:
file:// or local-path link as if it were usable on chat surfacesWhen player requests storybook or reaches milestone:
# 1. Generate HTML storybook first
result = exec({
"command": "uv run ~/clawd/skills/yumfu/scripts/generate_storybook_v3.py --user-id 1309815719 --universe warrior-cats"
})
# 2. Confirm the HTML uses scene-bound layout
# Each major scene should read as:
# image
# matching scene/dialogue text
# not: detached image gallery + separate prose dump
# 3. Send HTML as the canonical deliverable
message({
"action": "send",
"channel": "telegram",
"target": "1309815719",
"media": html_file_path,
"message": "📖 Your illustrated storybook is ready in HTML. This version keeps each image paired with its matching scene text."
})
# 4. Only generate/send PDF if the layout is visually confirmed good
pdf_path = browser({
"action": "pdf",
"url": f"file://{html_file_path}",
"path": "~/.openclaw/media/outbound/tumpaw-adventure.pdf"
})
When the run has clearly reached an ending, death, finale, retirement, archive, or explicit stop:
--ending-storybook so the normal turn package and the ending storybook are prepared together.next_actions.send_end_storybook_html == true, send the generated HTML file back into chat.storybook_sent so the same ending storybook is not re-sent repeatedly.Default ending-branch workflow:
uv run ~/clawd/skills/yumfu/scripts/deliver_yumfu_turn.py \
--user-id <id> \
--universe <world> \
--language <zh|en> \
--turn-id <stable-ending-turn-id> \
--story-text "<final in-world ending text>" \
--ending-storybook \
[--session-id <session-id>]
Then, from the returned JSON:
end_storybook.html back into chat as the canonical final storybook deliverablePreferred OpenClaw workflow:
# For normal manual storybook export
cd ~/clawd/skills/yumfu
uv run scripts/generate_storybook_v3.py --user-id 1309815719 --universe warrior-cats
# For ending / retire / archive branches, prefer the delivery helper
uv run scripts/deliver_yumfu_turn.py ... --ending-storybook [--session-id ...]
# Ship HTML first if it reads well in-chat
# Only convert to PDF after verifying the HTML layout preserves scene binding