/** * AGENTS.md content written into the scene directory when cloning. * Explains how the Phibelle engine works for AI agents and developers. */ export declare const AGENTS_MD = "# Phibelle Engine \u2014 How It Works\n\nThis document describes how the Phibelle 3D engine runs your scene and entity scripts. Use it when editing `scene-script.tsx`, `scene-properties.json`, and entity folders (`script.tsx`, `properties.json`, `transforms.json`) or when an AI agent needs to understand the runtime.\n\n## Overview\n\n- **Phibelle** is a React Three Fiber based 3D engine used in the [Phibelle Studio](https://phibelle.studio) editor.\n- A **scene** has one **scene script** (`scene-script.tsx`) and **scene properties** (`scene-properties.json`) in `app/`, and zero or more **entities**. Each entity is a folder `-` (e.g. `main-enemy-1`) containing `script.tsx`, `properties.json`, and `transforms.json`. Entity names are lowercased with hyphens (e.g. \"Main Enemy\" \u2192 `main-enemy-1`).\n- You can **create new entities** by adding a new entity folder with `script.tsx` (and optional `properties.json`, `transforms.json`); when the watcher is running, they are synced and the new entities appear in the scene.\n- The engine **concatenates** these scripts and runs them in a single live-editing environment with pre-injected globals (no `import`/`export`).\n\n## Runtime Model\n\n1. **Scene script** must define a component named `SceneRender` that receives `sceneProperties` and `children` and renders an `R3F.Canvas` (or equivalent). It **must** render `{children}` inside the canvas; that is where entity trees are rendered.\n2. **DOM UI placement** should be done in `SceneRender` as absolute HTML outside the canvas (canvas + UI in the same parent container). Prefer this shape:\n - `
`\n - `{children}`\n - `{!editMode &&
...UI...
}`\n - `
`\n3. **Scene-level globals** should be defined from `SceneRender` and stored in `PHI.useGlobalStore` so entities and UI can share state safely.\n4. **Entity scripts** each define a component named `Render` (e.g. `Render1`, `Render42`). The engine builds a registry mapping `engineId` \u2192 render component and mounts entities in a tree (root entities first, then children).\n5. **Live code** is produced by: (1) scene script, (2) all entity scripts, (3) a small bootstrap that wraps the scene in an error boundary, passes `entityRenderRegistry` into `PhibelleRoot`, and calls `render()`. Your scripts run inside that bootstrap with no direct imports.\n\n## What You Can Use in Scripts (Namespaces)\n\nScripts run with these globals; **do not** use `import` or `export`.\n\n| Namespace | Purpose |\n|-----------|---------|\n| `React` | Hooks and utilities: `React.useState`, `React.useEffect`, `React.useRef`, `React.memo`, etc. |\n| `THREE` | Three.js: `THREE.Vector3`, `THREE.Euler`, `THREE.Mesh`, `THREE.Color`, etc. |\n| `R3F` | React Three Fiber: `R3F.Canvas`, `R3F.useThree`, `R3F.useFrame`, `R3F.extend` |\n| `DREI` | @react-three/drei: `DREI.Environment`, `DREI.OrbitControls`, `DREI.Text`, `DREI.Html`, `DREI.Float`, `DREI.MeshTransmissionMaterial`, etc. |\n| `UIKIT` | @react-three/uikit for 3D UI |\n| `PHI` | Engine-specific: `PHI.useEngineMode`, `PHI.usePlayModeFrame`, `PHI.useGamepad`, `PHI.useEntityThreeObject`, `PHI.useGlobalStore`, `PHI.phibelleResetSelectedEntityIds` |\n\n## PHI package (engine API)\n\nThe `PHI` global is the engine API for scene and entity scripts. It provides types, hooks, and utilities. **Do not** use `import`; always call via `PHI.` (e.g. `PHI.useEngineMode()`).\n\n### PHI types\n\n| Type | Description |\n|------|-------------|\n| `PHI.Transform` | `{ position: THREE.Vector3; rotation: THREE.Euler; scale: THREE.Vector3 }` \u2014 entity transform. |\n| `PHI.Property` | `{ name: string; type: PropertyType; value: unknown }` \u2014 a single scene or entity property. |\n| `PHI.PropertyType` | `string` \u2014 property type identifier (e.g. `\"number\"`, `\"color\"`). |\n| `PHI.EntityData` | `{ name, engineId, threeId?, parentId?, childrenIds, transform, properties }` \u2014 data passed to `Render` as `entityData`. |\n| `PHI.GamepadInfo` | `{ connected, buttonA, buttonB, buttonX, buttonY, joystick, joystickRight, RB, LB, RT, LT, start, select, up, down, left, right }` \u2014 from `PHI.useGamepad()`. |\n| `PHI.EngineMode` | `{ editMode: boolean; playMode: boolean }` \u2014 from `PHI.useEngineMode()`. |\n| `PHI.SceneScriptState` | `{ sceneProperties: Record }` \u2014 from `PHI.useSceneScriptStore()`. |\n| `PHI.GlobalStoreState` | `{ globalStore, setGlobalStore, addToGlobalStore, removeFromGlobalStore, clearGlobalStore }` \u2014 state shape of the `PHI.useGlobalStore` Zustand store. |\n\n### PHI hooks and functions\n\n| API | Description |\n|-----|-------------|\n| `PHI.useEngineMode()` | Returns `{ editMode, playMode }`. Use to branch UI (e.g. show helpers only in `editMode`) and to guard play-only logic. |\n| `PHI.usePlayModeFrame(callback)` | `callback(state, delta)` runs once per frame **only in play mode**. Use for game logic; do **not** use `R3F.useFrame` for that (it runs in edit mode too). |\n| `PHI.useGamepad()` | Returns `PHI.GamepadInfo`: `connected`, `joystick` `[x,y]`, `joystickRight`, `buttonA/B/X/Y`, `RB`/`LB`/`RT`/`LT`, `start`/`select`, `up`/`down`/`left`/`right`. |\n| `PHI.useEntityThreeObject(entityData, threeScene)` | Returns the `THREE.Object3D` for the entity in the given scene, or `null` if not yet mounted. Use this to get the actual 3D object of the entity for movement or other interactions. |\n| `PHI.phibelleResetSelectedEntityIds()` | Clears entity selection. Call from the scene script Canvas `onPointerMissed` to deselect when clicking empty space. |\n| `PHI.useGlobalStore` | Zustand store (`UseBoundStore>`) for cross-entity state. In React: `PHI.useGlobalStore()` or `PHI.useGlobalStore(s => s.globalStore)`; outside React: `PHI.useGlobalStore.getState().addToGlobalStore(key, value)`. |\n| `PHI.useSceneScriptStore()` | `useSceneScriptStore()` or `useSceneScriptStore(selector)` \u2014 returns scene script state (e.g. `sceneProperties`). Mainly for scene script. |\n| `PHI.useEntity(entityId)` | Returns `{ entityData: PHI.EntityData }` for the given engine entity id. |\n| `PHI.editEntities(edits)` | `edits: Array<{ id: number; newData: Partial }>` \u2014 apply partial updates to entities (used by engine; use with care in scripts). |\n| `PHI.PROPERTY_TYPES` | Readonly array of `{ type: PHI.PropertyType; defaultValue: unknown }` for supported property types. |\n\n## Scene Script (`scene-script.tsx`) and Scene Properties (`scene-properties.json`)\n\n- **Component name**: Must be `SceneRender`.\n- **Props**: `sceneProperties: PHI.Property[]`, `children: React.ReactNode`.\n- **Responsibility**: Create the single `R3F.Canvas`, set up lights/environment, and render `{children}`. Attach `onPointerMissed={PHI.phibelleResetSelectedEntityIds}` on the Canvas to clear selection when clicking empty space.\n- **Camera requirement**: Ensure the scene has at least one camera setup (either `DREI.PerspectiveCamera` or `DREI.OrthographicCamera`) so play mode has a valid view.\n- **UI convention (preferred)**: Put regular DOM UI outside the canvas as anchored absolute elements in the same parent wrapper (avoid full-screen overlays that block scene interaction).\n- **Scene globals (preferred)**: Define scene-level shared data in `SceneRender` and store it with `PHI.useGlobalStore` so entities and overlay UI can use the same values.\n- **Edit mode lockout (required)**: Scene UI should not render in edit mode, and scene gameplay interactions should only be accessible in play mode.\n\nExample:\n\n```tsx\nconst SceneRender = ({\n sceneProperties,\n children,\n}: {\n sceneProperties: PHI.Property[];\n children: React.ReactNode;\n}) => {\n const { editMode } = PHI.useEngineMode();\n const globalStore = PHI.useGlobalStore((s) => s.globalStore);\n\n React.useEffect(() => {\n PHI.useGlobalStore.getState().addToGlobalStore(\"sceneInfo\", {\n title: \"My Scene\",\n hudVisible: true,\n });\n }, []);\n\n return (\n
\n \n \n {children}\n \n\n {!editMode && globalStore.sceneInfo?.hudVisible && (\n \n {globalStore.sceneInfo?.title}\n
\n )}\n \n );\n};\n```\n\n## Entity Scripts (`-/script.tsx` and `properties.json`)\n\n- **Folder name**: `-` where entity name is lowercased with hyphens (e.g. `main-enemy-1` for an entity named \"Main Enemy\" with engineId 1). Each entity folder contains:\n - `script.tsx`: The entity render component (required).\n - `properties.json`: Entity properties as a JSON array of `{ name, type, value }` (optional; defaults to `[]`).\n - `transforms.json`: Transform (position, rotation, scale) as a JSON object `{ position, rotation, scale }` (optional; defaults to identity).\n- **Component name**: Must be `Render` (e.g. `Render1` for `main-enemy-1`).\n- **Props**: `entityData: PHI.EntityData`.\n- **entityData** contains: `name`, `engineId`, `threeId`, `parentId`, `childrenIds`, `transform`, `properties`.\n- **Properties**: Use `entityData.properties` **by index** (order is fixed in the editor), e.g. `const [colorProp, speedProp] = entityData.properties;`.\n- **Edit vs Play**: Use `PHI.useEngineMode()` \u2192 `{ editMode, playMode }`. For per-frame game logic use **`PHI.usePlayModeFrame(callback)`** only (not `R3F.useFrame`), so logic does not run in edit mode. Show helpers/gizmos only when `editMode === true`.\n- **Interaction gating**: Any interactive/gameplay entity behavior should be inaccessible in edit mode and only run in play mode.\n- **Event handlers**: Pointer/click handlers (`onClick`, `onPointerOver`, `onPointerDown`, etc.) must be play-mode only. Guard handlers with `editMode` checks (or render interactive elements only when `!editMode`).\n\n## Editing Workflow (AI + Human)\n\n- **Explore first**: Before changing scripts, inspect the current entity tree plus each target entity's properties and transforms so edits match existing scene structure.\n- **Orientation awareness**: Be mindful of entity orientation and placement; if behavior/visuals are off, adjust transform values (position/rotation/scale) intentionally.\n- **Incremental edits**: Prefer small, targeted updates instead of large rewrites.\n- **Shared state strategy**: When scene script, UI, and/or multiple entities need shared data, prefer `PHI.useGlobalStore` as the common state bridge.\n\n## UI Style Guidelines\n\n- Keep UI simple and bare-bones. Favor straightforward layouts and clear labels over decorative styling.\n- Avoid generic \"AI-looking\" UI patterns (over-designed cards, noisy visual effects, excessive ornamentation).\n- Do not use gradients, emojis, or flashy effects for core scene UI.\n- Prefer plain colors, basic spacing, and readable typography.\n- Optimize for clarity and function first; visual polish should be minimal and purposeful.\n\nExample:\n\n```tsx\nconst Render1 = ({ entityData }: { entityData: PHI.EntityData }) => {\n const [colorProp] = entityData.properties;\n const { editMode, playMode } = PHI.useEngineMode();\n\n PHI.usePlayModeFrame((state, delta) => {\n // Game logic here; runs only in play mode\n });\n\n return (\n \n {\n if (editMode) return;\n // Play-mode interaction\n }}\n >\n \n \n \n {editMode && }\n \n );\n};\n```\n\n## Creating New Entities\n\nYou can add new entities to the scene by creating a new entity folder. Create a folder named `-` (e.g. `player-2`, `main-enemy-3`) with a `script.tsx` that defines `Render` (e.g. `Render2`, `Render3`). Optionally add `properties.json` (a JSON array of `{ name, type, value }`) and `transforms.json` (object with `position`, `rotation`, `scale`). The entity name in the folder name is lowercased with hyphens (e.g. \"Main Enemy\" \u2192 `main-enemy`). When **watch** is running (`npm run watch` or `npx phibelle-kit watch `), the watcher detects the new folder and creates the corresponding entity in the Phibelle Studio scene. Use a unique `engineId` that does not already exist in `manifest.json`.\n\n## File Layout After Clone\n\n- `scene.phibelle`: Full scene state (from the app); used by the CLI, not by the runtime.\n- `manifest.json`: Maps engine IDs to entity folder names for the watch/sync process.\n- `package.json`: Scripts: `watch` (sync edits to the app), and dependencies for types/IntelliSense.\n- `global.d.ts`: Declares global `PHI`, `THREE`, `R3F`, `DREI`, `UIKIT` for type checking.\n- `.gitignore`: Ignores `node_modules/`, and common OS/IDE files.\n- `app/scene-script.tsx`: Scene script (single `SceneRender`).\n- `app/scene-properties.json`: Scene properties (JSON array; optional).\n- `app/-/script.tsx`: Entity script (component `Render`).\n- `app/-/properties.json`: Entity properties (JSON array; optional).\n- `app/-/transforms.json`: Entity transform position/rotation/scale (JSON object; optional).\n\n## Sync Flow (phibelle-kit)\n\n- **clone**: Fetches scene from the app, creates the folder, writes `scene.phibelle`, `package.json`, `global.d.ts`, `AGENTS.md`, `CLAUDE.md`, `.gitignore`, and unpacks `scene-script.tsx`, `scene-properties.json`, entity folders (`script.tsx`, `properties.json`, `transforms.json`), and `manifest.json`.\n- **watch**: Watches the scene directory; when you change `scene-script.tsx`, `scene-properties.json`, or any entity file (`script.tsx`, `properties.json`, `transforms.json`), it pushes the change to the scene in the app (and can create new entities when you add a new entity folder with `script.tsx`).\n\nEdits you make in `scene-script.tsx`, `scene-properties.json`, or entity files are synced to the Phibelle Studio scene when the watcher is running (`npm run watch` or `npx phibelle-kit watch `).\n";