بنقرة واحدة
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