phibelle-kit 1.0.8 → 1.0.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* AGENTS.md content written into the scene directory when cloning.
|
|
3
3
|
* Explains how the Phibelle engine works for AI agents and developers.
|
|
4
4
|
*/
|
|
5
|
-
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.tsx` and `entity-*.tsx` files 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.tsx`) and zero or more **entity scripts** (`entity-<engineId>.tsx`).\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. **Entity scripts** each define a component named `Render<engineId>` (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).\n3. **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(<PhibelleScene />)`. 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| `RAPIER` | @react-three/rapier for physics: `RAPIER.Physics`, `RAPIER.RigidBody`, `RAPIER.Collider`, etc. |\n| `PHI` | Engine-specific: `PHI.useEngineMode`, `PHI.usePlayModeFrame`, `PHI.useGamepad`, `PHI.useEntityThreeObject`, `PHI.phibelleResetSelectedEntityIds`, `PHI.globalStore` |\n\n## Scene Script (`scene.tsx`)\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\nExample:\n\n```tsx\nconst SceneRender = ({\n sceneProperties,\n children,\n}: {\n sceneProperties: PHI.Property[];\n children: React.ReactNode;\n}) => (\n <R3F.Canvas\n shadows\n frameloop=\"always\"\n gl={{ preserveDrawingBuffer: true }}\n onPointerMissed={PHI.phibelleResetSelectedEntityIds}\n >\n <DREI.Environment preset=\"city\" />\n {children}\n </R3F.Canvas>\n);\n```\n\n## Entity Scripts (`entity-<engineId>.tsx`)\n\n- **Component name**: Must be `Render<engineId>` (e.g. `Render1` for `entity-1.tsx`).\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\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 <group>\n <mesh>\n <boxGeometry args={[1, 1, 1]} />\n <meshStandardMaterial color={colorProp.value} />\n </mesh>\n {editMode && <DREI.Helper type={THREE.BoxHelper} args={[\"yellow\"]} />}\n </group>\n );\n};\n```\n\n## File Layout After Clone\n\n- `scene.json`: Full scene state (from the app); used by the CLI, not by the runtime.\n- `scene.tsx`: Scene script (single `SceneRender`).\n- `entity-<engineId>.tsx`: One file per entity; each exports a `Render<engineId>` component by convention.\n- `manifest.json`: Maps engine IDs to filenames 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`, `RAPIER` for type checking.\n\n## Sync Flow (phibelle-kit)\n\n- **clone**: Fetches scene from the app, creates the folder, writes `scene.json`, `package.json`, `global.d.ts`, `AGENTS.md`, and unpacks `scene.tsx`, `entity-*.tsx`, `manifest.json`.\n- **watch**: Watches the scene directory; when you change a script file, it pushes that file\u2019s content back to the scene in the app (and can create new entities when you add `entity-<id>.tsx`).\n\nEdits you make in `scene.tsx` or `entity-*.tsx` are synced to the Phibelle Studio scene when the watcher is running (`npm run watch` or `npx phibelle-kit watch <sceneId>`).\n";
|
|
5
|
+
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.tsx` and `entity-*.tsx` files 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.tsx`) and zero or more **entity scripts** (`entity-<engineId>.tsx`).\n- You can **create new entities** by adding new entity script files (`entity-<engineId>.tsx`); 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. **Entity scripts** each define a component named `Render<engineId>` (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).\n3. **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(<PhibelleScene />)`. 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| `RAPIER` | @react-three/rapier for physics: `RAPIER.Physics`, `RAPIER.RigidBody`, `RAPIER.Collider`, etc. |\n| `PHI` | Engine-specific: `PHI.useEngineMode`, `PHI.usePlayModeFrame`, `PHI.useGamepad`, `PHI.useEntityThreeObject`, `PHI.phibelleResetSelectedEntityIds`, `PHI.globalStore` |\n\n## Scene Script (`scene.tsx`)\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\nExample:\n\n```tsx\nconst SceneRender = ({\n sceneProperties,\n children,\n}: {\n sceneProperties: PHI.Property[];\n children: React.ReactNode;\n}) => (\n <R3F.Canvas\n shadows\n frameloop=\"always\"\n gl={{ preserveDrawingBuffer: true }}\n onPointerMissed={PHI.phibelleResetSelectedEntityIds}\n >\n <DREI.Environment preset=\"city\" />\n {children}\n </R3F.Canvas>\n);\n```\n\n## Entity Scripts (`entity-<engineId>.tsx`)\n\n- **Component name**: Must be `Render<engineId>` (e.g. `Render1` for `entity-1.tsx`).\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\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 <group>\n <mesh>\n <boxGeometry args={[1, 1, 1]} />\n <meshStandardMaterial color={colorProp.value} />\n </mesh>\n {editMode && <DREI.Helper type={THREE.BoxHelper} args={[\"yellow\"]} />}\n </group>\n );\n};\n```\n\n## Creating New Entities\n\nYou can add new entities to the scene by creating new entity script files. Add a file named `entity-<engineId>.tsx` (e.g. `entity-2.tsx`, `entity-3.tsx`) with a component `Render<engineId>` (e.g. `Render2`, `Render3`). When **watch** is running (`npm run watch` or `npx phibelle-kit watch <sceneId>`), the watcher detects the new file 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.json`: Full scene state (from the app); used by the CLI, not by the runtime.\n- `scene.tsx`: Scene script (single `SceneRender`).\n- `entity-<engineId>.tsx`: One file per entity; each exports a `Render<engineId>` component by convention.\n- `manifest.json`: Maps engine IDs to filenames 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`, `RAPIER` for type checking.\n\n## Sync Flow (phibelle-kit)\n\n- **clone**: Fetches scene from the app, creates the folder, writes `scene.json`, `package.json`, `global.d.ts`, `AGENTS.md`, and unpacks `scene.tsx`, `entity-*.tsx`, `manifest.json`.\n- **watch**: Watches the scene directory; when you change a script file, it pushes that file\u2019s content back to the scene in the app (and can create new entities when you add `entity-<id>.tsx`).\n\nEdits you make in `scene.tsx` or `entity-*.tsx` are synced to the Phibelle Studio scene when the watcher is running (`npm run watch` or `npx phibelle-kit watch <sceneId>`).\n";
|
|
@@ -10,6 +10,7 @@ This document describes how the Phibelle 3D engine runs your scene and entity sc
|
|
|
10
10
|
|
|
11
11
|
- **Phibelle** is a React Three Fiber based 3D engine used in the [Phibelle Studio](https://phibelle.studio) editor.
|
|
12
12
|
- A **scene** has one **scene script** (\`scene.tsx\`) and zero or more **entity scripts** (\`entity-<engineId>.tsx\`).
|
|
13
|
+
- You can **create new entities** by adding new entity script files (\`entity-<engineId>.tsx\`); when the watcher is running, they are synced and the new entities appear in the scene.
|
|
13
14
|
- The engine **concatenates** these scripts and runs them in a single live-editing environment with pre-injected globals (no \`import\`/\`export\`).
|
|
14
15
|
|
|
15
16
|
## Runtime Model
|
|
@@ -91,6 +92,10 @@ const Render1 = ({ entityData }: { entityData: PHI.EntityData }) => {
|
|
|
91
92
|
};
|
|
92
93
|
\`\`\`
|
|
93
94
|
|
|
95
|
+
## Creating New Entities
|
|
96
|
+
|
|
97
|
+
You can add new entities to the scene by creating new entity script files. Add a file named \`entity-<engineId>.tsx\` (e.g. \`entity-2.tsx\`, \`entity-3.tsx\`) with a component \`Render<engineId>\` (e.g. \`Render2\`, \`Render3\`). When **watch** is running (\`npm run watch\` or \`npx phibelle-kit watch <sceneId>\`), the watcher detects the new file and creates the corresponding entity in the Phibelle Studio scene. Use a unique \`engineId\` that does not already exist in \`manifest.json\`.
|
|
98
|
+
|
|
94
99
|
## File Layout After Clone
|
|
95
100
|
|
|
96
101
|
- \`scene.json\`: Full scene state (from the app); used by the CLI, not by the runtime.
|