一键导入
add-feature
Scaffold a new toggleable feature with full structure, storage, API exposure, and bootstrap registration
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Scaffold a new toggleable feature with full structure, storage, API exposure, and bootstrap registration
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Create a new card part within a section with factory/class pattern, Card wrapper, and proper cleanup
Add a new Jotai atom to the state system with type definitions, registry, and Store API access
Create a reusable UI component with factory pattern, theme compatibility, and proper cleanup
Create a reactive global variable that derives from atoms with subscription support
Create a game UI injection that modifies existing game elements with proper cleanup
Create a new core infrastructure module with standard API, lazy init, and proper structure
| name | add-feature |
| description | Scaffold a new toggleable feature with full structure, storage, API exposure, and bootstrap registration |
| aliases | ["new-feature","create-feature","scaffold-feature"] |
/add-feature <featureName>
Before creating files, gather this information:
Does this feature need game data?
A) Static data → MGData
B) Real-time state → Globals
C) Both → MGData + Globals
D) None
If A or C (Static data), specify which:
[ ] Plants - definitions, growth stages, harvest data
[ ] Items - definitions, categories, properties
[ ] Pets - definitions, abilities, stats
[ ] Mutations - definitions, effects
[ ] Shops - configurations (not stock)
[ ] Recipes - crafting recipes
[ ] Other: ___________
If B or C (Real-time), specify which:
[ ] currentTile - player's current tile
[ ] myGarden - player's garden state
[ ] myInventory - player's inventory
[ ] myPets - player's pets
[ ] players - other players in room
[ ] shops - current shop stock
[ ] weather - current weather
[ ] gameMap - full map data
[ ] Other: ___________
A) Gemini HUD only - UI in Gemini overlay
B) Game UI injection - Modifies existing game UI (src/ui/inject/qol/<name>/)
C) Both - Feature logic + game UI injection
D) No UI - Backend/logic only
Does the UI need game sprites?
A) Yes → MGSprite.show() / MGSprite.toCanvas()
B) No - Text/icons only
If A, which types?
[ ] Plant sprites [ ] Item sprites [ ] Pet sprites
[ ] Cosmetic sprites [ ] Tile sprites [ ] Other: ___
Does the UI need existing components?
→ REUSE, never recreate!
[ ] ArcadeButton, GeminiIconButton → Buttons
[ ] Modal → Dialogs/popups
[ ] ProgressBar → Progress indicators
[ ] SegmentedControl → Tab-like selection
[ ] Tab → Tabs
[ ] SoundPicker → Audio selection
[ ] Other from src/ui/components/
[ ] MGCalculators - XP, prices, growth time calculations
[ ] MGCosmetic - Player cosmetic data
[ ] MGTile - Map/tile utilities
[ ] MGAudio - Sound effects, notifications
[ ] MGShopActions - Buy/sell operations
[ ] MGEnvironment - World/environment data
[ ] None
A) Outgoing actions - Sends messages (api.ts)
B) Incoming handlers - Reacts to server messages
C) Middleware - Intercept/block/modify outgoing messages
D) Multiple (specify which)
E) None
If C (Middleware), specify:
[ ] Intercept specific message types
[ ] Modify payload before sending
[ ] Block messages based on conditions
[ ] Log/track outgoing messages
Which message types? ___________
One sentence for documentation:
src/features/<featureName>/
├── types.ts # Config, constants, types
├── state.ts # Storage operations
├── index.ts # Public API (MG<FeatureName>)
├── logic/
│ └── core.ts # Business logic
├── ui.ts # (if HUD UI)
├── handler.ts # (if incoming WS)
└── middleware.ts # (if WS middleware)
camelCase → src/features/autoHarvest/MG<PascalCase> → MGAutoHarvestSCREAMING_SNAKE → AUTO_HARVESTfeature:<camelCase>:config → feature:autoHarvest:config| File | Purpose |
|---|---|
types.ts | Config interface with enabled: boolean, STORAGE_KEY, DEFAULT_CONFIG |
state.ts | loadConfig(), saveConfig(), updateConfig() |
index.ts | MG<Name> with init, destroy, isEnabled, setEnabled |
logic/core.ts | start(), stop(), cleanups[] array |
ui.ts | HUD components (reuse existing!) |
handler.ts | registerHandlers() for incoming WS |
middleware.ts | registerFeatureMiddleware(), unregisterFeatureMiddleware() |
Read existing features for templates: src/features/*/
src/utils/storage.tsexport const FEATURE_KEYS = {
// ... existing
<FEATURE_NAME>: 'feature:<featureName>:config',
} as const;
src/features/index.tsexport { MG<FeatureName> } from './<featureName>';
export type { <FeatureName>Config } from './<featureName>';
src/api/index.tsimport { MG<FeatureName> } from "../features/<featureName>";
Features: {
<FeatureName>: MG<FeatureName>,
}
src/ui/loader/bootstrap.tsimport { MG<FeatureName> } from "../../features/<featureName>";
{ name: "<FeatureName>", init: () => MG<FeatureName>.init() }
Create structure in src/ui/inject/qol/<featureName>/:
├── index.ts # init(), destroy(), isEnabled()
├── inject.ts # DOM injection logic
├── styles.css.ts # Scoped styles
└── state.ts # (optional)
import { getMyInventory } from '../../../globals/variables/myInventory';
const cleanups: (() => void)[] = [];
function start(): void {
const unsub = getMyInventory().subscribe((inventory) => {
// React to changes
onInventoryChange(inventory);
});
cleanups.push(unsub);
}
function stop(): void {
cleanups.forEach(fn => fn());
cleanups.length = 0;
}
import { registerMiddleware } from '../../websocket/middlewares/registry';
let unregister: (() => void) | null = null;
export function registerFeatureMiddleware(): void {
if (unregister) return;
unregister = registerMiddleware((message) => {
// Return message (pass), modified message, or null (block)
return message;
});
}
export function unregisterFeatureMiddleware(): void {
unregister?.();
unregister = null;
}
import { createArcadeButton, createProgressBar } from '../../ui/components';
function buildUI(container: HTMLElement): void {
const button = createArcadeButton({ label: 'Action', onClick: handleClick });
const progress = createProgressBar({ value: 0, max: 100 });
container.appendChild(button.root);
container.appendChild(progress.root);
// Track for cleanup
cleanups.push(() => {
button.destroy();
progress.destroy();
});
}
types.ts with enabled: boolean in configindex.ts exports MG<FeatureName>init, destroy, isEnabled, setEnabledlogic/ folder for business logicinit() is idempotent (safe to call multiple times)destroy() cleans up ALL resourcesFEATURE_KEYS (not MODULE_KEYS)MGData.get('plants'/'items'/'pets'/...)MGSprite.show() / MGSprite.toCanvas()MGCalculators.subscribe() + unsubscribe in cleanupdestroy() called in cleanupwebsocket/api.ts onlyregisterHandler()message or null, never throwsdestroy()protocol.ts enumssrc/utils/storage.tssrc/features/index.tssrc/api/index.tssrc/ui/loader/bootstrap.ts.claude/rules/features.md, .claude/rules/core.mdsrc/features/*/src/modules/*/ (MGData, MGSprite, MGCalculators, etc.)src/globals/variables/src/websocket/ (api.ts, middlewares/, handlers/)src/ui/components/src/ui/inject/qol/, .claude/rules/ui/ui.inject.md