Compose3D is a modern web-based 3D scene composition tool built with Next.js, React, and Three.js. It allows users to create, manipulate, and describe 3D scenes interactively, supporting object placement, camera control, lighting, and exporting structured JSON for downstream AI or rendering workflows. Compose3D integrates with the Fibo API to generate images from your scene: your scene is converted to a structured prompt (using buildFiboJSON), sent to the Fibo API via a backend route, and the resulting image is displayed in the app once generation is complete.
Key Features:
- Drag-and-drop 3D object placement and manipulation
- Human and non-human object support with rich appearance options
- Camera and lighting controls
- Scene templates and backgrounds
- Real-time JSON export describing the scene for AI or rendering
- Integrated Fibo API image generation: turn your scene into an AI-generated image with one click
- Modern, modular UI with panels for properties, global settings, and more
- Node.js (v18+ recommended)
- npm, yarn, pnpm, or bun
git clone <your-repo-url>
cd compose3D
npm installnpm run devVisit http://localhost:3000 in your browser.
npm run build
npm startcompose3D/
├── app/
│ ├── api/ # API routes (e.g., /api/fibo)
│ ├── components/ # All React UI components
│ ├── editor/ # Main editor page
│ ├── lib/ # Core logic, utilities, and data models
│ ├── models/ # Object, pose, and type definitions
│ ├── store/ # Zustand state management
│ ├── globals.css # Global styles
│ └── layout.tsx, page.tsx# App layout and entry
├── public/ # Static assets
├── package.json # Project metadata and dependencies
├── README.md # Project documentation
└── ... # Config files, etc.
Key Modules:
components/: UI panels, 3D object renderers, toolbars, etc.lib/: Scene logic, JSON builders, constants, and utilities.store/: Zustand store for global state.models/: TypeScript types for objects, scenes, and more.
- Add, select, duplicate, and remove 3D objects.
- Drag objects in the viewport; properties panel for fine-tuning.
- Supports both human and non-human objects.
- Appearance customization: color, texture, pose, clothing, etc.
- Orbit, pan, and zoom camera controls.
- Preset camera views and manual adjustment.
- Lighting panel for scene illumination.
- Choose from predefined templates or customize backgrounds.
- Generates a structured JSON description of the scene, including object properties, relationships, camera, and lighting.
- SceneObject: Renders and manages a 3D object. Props:
object,selected,onSelect,onDrag. - PropertiesPanel: Edits properties for the selected object or scene. Props:
selectedObject,onChange. - CameraController: Handles camera movement and view switching. Props:
camera,onChange. - ObjectSidebar: Lists available objects and templates. Props:
onAddObject,objects. - TopToolbar: Main toolbar for global actions (generate, preview, etc.).
- GlobalPanel: Controls for lighting, camera, and scene template.
- GridFloor: Visual ground plane and deselect handler.
- ImageViewer: Displays generated images. Props:
imageUrl,onClose.
- buildFiboJSON: Main entry for generating the Fibo-compatible prompt from scene state.
- buildJSONParts/: Modularized logic for object description, position, lighting, etc.
- appearance.ts: Types and helpers for object appearance.
- constants.ts: UI and logic constants (options, presets, etc.).
- fibo.ts: Handles Fibo API integration and image generation from scene JSON.
Compose3D uses Zustand for global state management, defined in app/store/editorStore.ts.
- objects: Array of all scene objects (id, preset, position, rotation, scale, appearance)
- camera: Camera state (view, fov, zoom, position, orthographic, etc.)
- lighting: Lighting state (type, intensity, color, etc.)
- sceneTemplate: Current scene template
- selection: Currently selected object id
- UI state: Flags for modes, panels, image generation, etc.
Accessing State:
import { useEditorStore } from "@/app/store/editorStore";
const objects = useEditorStore(state => state.objects);
const selectedId = useEditorStore(state => state.selectedId);Updating State:
const addObject = useEditorStore(state => state.addObject);
addObject(newObject);
const setCamera = useEditorStore(state => state.setCamera);
setCamera(newCameraState);Example: Selecting and Updating an Object
const selectedId = useEditorStore(state => state.selectedId);
const updateObject = useEditorStore(state => state.updateObject);
// ...
updateObject(selectedId, { position: [1, 2, 3] });State updates propagate to all components using the useEditorStore() hook, ensuring UI stays in sync.
- Add a new object definition to
app/models/objects.ts(see existing objects for structure). - Update the sidebar in
ObjectSidebar.tsxto include your new object.
- Create a new component in
app/components/. - Connect it to the store using
useEditorStore()for state. - Add it to the editor layout as needed.
- Update
appearance.tsto add new appearance fields or helpers. - Add new options to
constants.tsif needed.
- Add a new template to
sceneTemplates.ts. - Reference it in the UI for selection.
Compose3D integrates with the Fibo API to generate images from your composed scene. The integration is handled via a backend API route (/api/fibo) that receives a structured prompt (generated by buildFiboJSON, validates it, and communicates with the Fibo API. The backend polls for image generation status and returns the final image URL.
- Method: POST
- Request Body:
{ "structured_prompt": { /* prompt object matching ImageAnalysisSchema, generated by buildFiboJSON */ } } - Response:
- On success:
{ "image_url": "https://.../generated-image.png" } - On error:
{ "error": "Error message" }
- On success:
- Validates the prompt structure (returns error for invalid/malformed input)
- Handles Fibo API errors (network, validation, generation failures)
- Throws errors for timeouts or unknown status
- Returns clear error messages in the response
FIBO_API_KEYmust be set in your environment for Fibo API access- Create a
.env.localfile in your project root:FIBO_API_KEY=your_fibo_api_key_here
import { buildFiboJSON } from "@/app/lib/buildJSON";
// ...
const fiboPrompt = buildFiboJSON(objects, lighting, camera, { sceneTemplate, context });
const response = await fetch('/api/fibo', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ structured_prompt: fiboPrompt })
});
const data = await response.json();
if (data.image_url) {
// Display the generated image
} else {
// Handle error: data.error
}graph TD
UI[User Interface] -->|Edit Scene| Store[Zustand Store]
Store -->|State Updates| Editor[Editor Components]
Editor -->|Export Scene| BuildJSON[buildFiboJSON]
BuildJSON -->|Prompt Payload| API[API Route: /api/fibo]
API -->|Request| FiboAPI[Fibo API]
FiboAPI -->|Generated Image| API
API -->|Image URL| UI
- Fibo API errors: Ensure your
FIBO_API_KEYis set and valid. Check.env.local. - Image not generating: Check browser console and server logs for errors. Confirm prompt structure.
- UI not updating: Ensure state updates use
useEditorStore()hooks. - Build issues: Run
npm installto ensure all dependencies are present.
- Build the app:
npm run build
- Set environment variables in your deployment platform (e.g., Vercel, Netlify):
FIBO_API_KEY
- Start the server:
npm start
- Fork the repo and create a feature branch.
- Follow the code style (Prettier, ESLint).
- Add/modify tests if needed.
- Open a pull request with a clear description.