Polymodal File Store Documentation
Complete guide to using the file store system for managing your Polymodal PRN assets.
๐ Getting Started
The Polymodal File Store is a comprehensive asset management system designed for storing and organizing 3D assets, textures, skyboxes, meshes, audio files, and more.
http://localhost:3001API Base:
http://localhost:3001/api
๐ Categories
- Skybox - Environment maps, HDR images, cubemaps
- Mesh - 3D models, geometry files (OBJ, FBX, GLTF, etc.)
- Texture - Material textures, images, bump maps
- Audio - Sound effects, music, spatial audio
- Other - Miscellaneous assets
๐ค Uploading Files
Web Interface
- Click the "+ Upload" button in the header
- Drag & drop a file or click to browse
- Select a category and optionally add a custom name and description
- Click "Upload"
CLI Upload
./upload.js /path/to/file.hdr \
--category skybox \
--description "Beautiful sunset skybox"
API Upload (JavaScript)
const formData = new FormData();
formData.append('file', fileBlob);
formData.append('category', 'skybox');
formData.append('description', 'Beautiful sunset skybox');
formData.append('custom_name', 'my-sunset-skybox'); // optional
const response = await fetch('http://localhost:3001/api/upload', {
method: 'POST',
body: formData
});
const data = await response.json();
๐ Searching Files
Use the search bar at the top to find files by name and description. The search uses full-text indexing (FTS5) for fast results and can optionally filter by category type (skybox, texture, mesh, audio, other).
// API Search - all categories
fetch('http://localhost:3001/api/search?q=sunset')
.then(r => r.json())
.then(data => console.log(data.files));
// API Search - filtered by category
fetch('http://localhost:3001/api/search?q=mountain&category=texture')
.then(r => r.json())
.then(data => console.log(data.files));
๐ API Reference
Complete API documentation for the Polymodal File Store.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| category | stringoptional | Filter by category (skybox, mesh, texture, audio, other) |
| limit | integeroptional | Number of results per page (default: 100, max: 1000) |
| offset | integeroptional | Number of results to skip (default: 0) |
| sort | stringoptional | Field to sort by (upload_date, size, original_name) |
| order | stringoptional | Sort order: ASC or DESC (default: DESC) |
curl "http://localhost:3001/api/files?category=skybox&limit=10"
{
"files": [
{
"id": 1,
"filename": "1762802859311-777c7e0e2244c1c2.hdr",
"original_name": "sunset.hdr",
"hash": "3a31ade447...",
"size": 2048576,
"mime_type": "application/octet-stream",
"category": "skybox",
"description": "Beautiful sunset skybox",
"metadata": {},
"upload_date": 1762802859314,
"updated_date": 1762802859314
}
],
"count": 1
}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| id | integerrequired | Unique file identifier |
curl "http://localhost:3001/api/files/1"
{
"id": 1,
"filename": "1762802859311-777c7e0e2244c1c2.hdr",
"original_name": "sunset.hdr",
"hash": "3a31ade447...",
"size": 2048576,
"mime_type": "application/octet-stream",
"category": "skybox",
"description": "Beautiful sunset skybox",
"metadata": {},
"upload_date": 1762802859314,
"updated_date": 1762802859314
}
Query Parameters
| Parameter | Type | Description |
|---|---|---|
| q | stringrequired | Search query - searches across both filename and description fields (supports wildcards with *) |
| category | stringoptional | Filter results by category type: skybox, texture, mesh, audio, or other |
| limit | integeroptional | Maximum results to return (default: 50) |
# Search for "sunset" across all categories
curl "http://localhost:3001/api/search?q=sunset"
# Search for "sunset" in skybox category only
curl "http://localhost:3001/api/search?q=sunset&category=skybox"
# Search for "mountain" in textures with limit
curl "http://localhost:3001/api/search?q=mountain&category=texture&limit=10"
{
"files": [...],
"count": 5
}
Form Data Parameters
| Parameter | Type | Description |
|---|---|---|
| file | filerequired | Binary file data (max 100MB) |
| category | stringoptional | File category: skybox, texture, mesh, audio, or other (default: other) |
| custom_name | stringoptional | Custom display name for the file (uses original filename if not provided) |
| description | stringoptional | File description (searchable) |
| metadata | stringoptional | JSON string with custom metadata |
curl -X POST "http://localhost:3001/api/upload" \
-F "file=@./skybox.hdr" \
-F "category=skybox" \
-F "description=Beautiful sunset skybox"
{
"message": "File uploaded successfully",
"file": {
"id": 1,
"filename": "1762802859311-777c7e0e2244c1c2.hdr",
"original_name": "skybox.hdr",
...
},
"duplicate": false
}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| id | integerrequired | Unique file identifier |
JSON Body Parameters
| Parameter | Type | Description |
|---|---|---|
| category | stringoptional | New category |
| description | stringoptional | New description |
| metadata | stringoptional | New metadata (JSON string) |
curl -X PUT "http://localhost:3001/api/files/1" \
-H "Content-Type: application/json" \
-d '{"category": "texture", "description": "Updated description"}'
{
"message": "File updated successfully",
"file": { ... }
}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| id | integerrequired | Unique file identifier |
curl -X DELETE "http://localhost:3001/api/files/1"
{
"message": "File deleted successfully"
}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
| id | integerrequired | Unique file identifier |
curl -o sunset.hdr "http://localhost:3001/api/download/1"
Returns binary file data with appropriate Content-Type and Content-Disposition headers.
curl "http://localhost:3001/api/categories"
{
"categories": [
{
"category": "skybox",
"count": 10
},
{
"category": "mesh",
"count": 5
}
]
}
curl "http://localhost:3001/api/stats"
{
"total_files": 42,
"total_size": 104857600,
"by_category": [
{
"category": "skybox",
"count": 10,
"total_size": 20971520
}
]
}
Request Body (JSON)
| Parameter | Type | Description |
|---|---|---|
| prompt | stringrequired | Text prompt describing the image to generate |
| negative_prompt | stringoptional | Negative prompt (things to avoid) |
| size | stringoptional | Image dimensions: 512x512, 768x768, 1024x1024, 512x768, 768x512 (default: 512x512) |
| steps | integeroptional | Number of diffusion steps (10-100, default: 30) |
| tags | stringoptional | Comma-separated tags for the generated image |
| description | stringoptional | Description for the generated image |
curl -X POST "http://localhost:3001/api/generate-image" \
-H "Content-Type: application/json" \
-d '{
"prompt": "A beautiful sunset over mountains, highly detailed, 4k",
"negative_prompt": "blurry, low quality",
"size": "512x512",
"steps": 30,
"tags": "ai-generated,landscape,sunset",
"description": "AI-generated sunset landscape"
}'
{
"message": "Image generated successfully",
"file": {
"id": 15,
"filename": "1762934567890-abc123def456.png",
"original_name": "ai-generated-1762934567890.png",
"size": 458752,
"category": "texture",
"tags": ["ai-generated", "landscape", "sunset"]
},
"duplicate": false,
"url": "http://localhost:3001/uploads/1762934567890-abc123def456.png",
"download_url": "http://localhost:3001/api/download/15"
}
Request Body (JSON)
| Parameter | Type | Description |
|---|---|---|
| prompt | stringrequired | Text prompt describing the audio/music to generate |
| duration | integeroptional | Audio length in seconds (1-190, default: 190) |
| steps | integeroptional | Number of generation steps: stable-audio-2.5 (4-8, default: 6), stable-audio-2 (30-80, default: 30) |
| cfg_scale | numberoptional | How closely to follow the prompt (0-10, default: 1) |
| model | stringoptional | Audio model: stable-audio-2 or stable-audio-2.5 (default: stable-audio-2.5) |
| output_format | stringoptional | Output format: mp3 or wav (default: mp3) |
| custom_name | stringoptional | Custom display name (uses sanitized prompt if not provided) |
| description | stringoptional | Description for the generated audio |
curl -X POST "http://localhost:3001/api/generate-audio" \
-H "Content-Type: application/json" \
-d '{
"prompt": "Ambient electronic music with deep bass and ethereal synths",
"duration": 30,
"steps": 8,
"cfg_scale": 1,
"model": "stable-audio-2.5",
"output_format": "mp3",
"description": "AI-generated ambient background music"
}'
{
"message": "Audio generated successfully",
"file": {
"id": 42,
"filename": "ambient-electronic-music-with-deep-bass-a1b2c3d4.mp3",
"original_name": "ambient-electronic-music-with-deep-bass.mp3",
"size": 1048576,
"category": "audio",
"mime_type": "audio/mpeg"
},
"duplicate": false,
"url": "http://localhost:3001/uploads/ambient-electronic-music-with-deep-bass-a1b2c3d4.mp3",
"download_url": "http://localhost:3001/api/download/42"
}
curl "http://localhost:3001/api/ai/status"
{
"available": true,
"provider": "Stability AI",
"default_model": "flash",
"models": {
"flash": {"credits": 2.5, "description": "Fastest and cheapest - SD 3.5 Flash"},
"core": {"credits": 3.0, "description": "Higher quality - Stable Image Core"},
"ultra": {"credits": 8.0, "description": "Highest quality - Stable Image Ultra"}
}
}
๐จ๐ต AI Content Generation
The file store integrates with Stability AI to generate both images and audio from text prompts. Generated content is automatically saved to the file store with metadata for easy retrieval.
โ Textures (512x512 to 1024x1024 square images)
โ Skyboxes (360ยฐ panoramic images in equirectangular format)
โ Images / Concept Art (various aspect ratios)
โ Audio / Music / Sound Effects (MP3 or WAV, 1-190 seconds)
โ 3D Meshes (not supported by Stability AI)
โ True HDR/EXR (generates PNG for images)
Setup
AI generation uses Stability AI's cloud API. No local installation required!
Configuration
Configure your API keys in keys.json:
{
"stability_ai": {
"api_key": "your-api-key-here",
"image_api_url": "https://api.stability.ai/v2beta/stable-image/generate",
"audio_api_url": "https://api.stability.ai/v2beta/audio/stable-audio-2/text-to-audio"
}
}
Get your API key from platform.stability.ai. The keys.json file is ignored by git for security.
Available Models
Image Generation:
- SD 3.5 Flash (default) - 2.5 credits per image - Fastest and cheapest
- Stable Image Core - 3.0 credits per image - Higher quality
- Stable Image Ultra - 8.0 credits per image - Photorealistic, highest quality
Audio Generation:
- Stable Audio 2.5 (default) - Best quality, supports music and sound effects
- Stable Audio 2 - Previous version, still supported
Generate via Web Interface
Click the ๐จ Generate button in the header to open the AI generation modal:
- Select Asset Category (Texture, Skybox, Audio, or Other/Image)
- Enter your Prompt describing what to generate
- For images: Add optional Negative Prompt, choose size and steps
- For audio: Set Duration (1-190s), choose model (2.5 or 2), select format (MP3/WAV)
- Add optional Custom Name and Description
- Click Generate and wait for the AI to create your content
Generated files automatically appear in your file list with the correct category and prompt-based names.
Generate via API
Example 1: Generate a Texture
const response = await fetch('http://localhost:3001/api/generate-image', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
asset_type: 'texture',
prompt: 'Seamless wood planks texture, high quality, 4k',
negative_prompt: 'blurry, low quality',
size: '1024x1024',
steps: 40,
tags: 'wood,planks,seamless'
})
});
Example 2: Generate a Skybox Preview
const response = await fetch('http://localhost:3001/api/generate-image', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
asset_type: 'skybox',
prompt: '360 panoramic sunset over ocean, equirectangular',
negative_prompt: 'seam, distorted',
size: '1280x720',
steps: 30
})
});
Example 3: Generate Concept Art
const response = await fetch('http://localhost:3001/api/generate-image', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
asset_type: 'concept',
prompt: 'Futuristic cyberpunk city at night',
negative_prompt: 'blurry, low quality',
size: '768x512',
steps: 40
})
});
Find Generated Images
Generated images are automatically tagged based on their asset type and can be searched:
# Search for all AI-generated images
curl "http://localhost:3001/api/search?q=ai-generated"
# Search for AI-generated textures
curl "http://localhost:3001/api/search?q=ai-generated+texture"
# Search for AI-generated skyboxes
curl "http://localhost:3001/api/search?q=ai-generated+skybox"
๐พ Database
Files are stored in a SQLite database with full-text search capabilities (FTS5). Each file has:
- ID - Unique identifier
- Filename - Stored filename (timestamped)
- Original Name - User's original filename or custom display name
- Hash - SHA-256 hash for deduplication
- Size - File size in bytes
- MIME Type - File content type
- Category - Asset category (skybox, texture, mesh, audio, other)
- Description - Text description (searchable)
- Metadata - Custom JSON data
- Upload Date - When file was uploaded
- Updated Date - Last modification
- Parent ID - For cubemap faces, references parent skybox
- Cubemap Face - Face name for cubemap images (front, back, left, right, up, down)
๐ Integration Examples
Three.js - Load Skybox
// Fetch skybox from file store
const response = await fetch(
'http://localhost:3001/api/search?q=sunset&category=skybox'
);
const { files } = await response.json();
const skybox = files[0];
// Load with RGBELoader
const loader = new THREE.RGBELoader();
const url = `http://localhost:3001/uploads/${skybox.filename}`;
const texture = await loader.loadAsync(url);
texture.mapping = THREE.EquirectangularReflectionMapping;
scene.background = texture;
scene.environment = texture;
Python - Upload File
import requests
with open('./skybox.hdr', 'rb') as f:
files = {'file': f}
data = {
'category': 'skybox',
'description': 'Sunset skybox'
}
response = requests.post(
'http://localhost:3001/api/upload',
files=files,
data=data
)
print(response.json())
cURL - Download File
# Download file by ID
curl -o skybox.hdr http://localhost:3001/api/download/1
# Download with original filename
curl -OJ http://localhost:3001/api/download/1
โ๏ธ Advanced Features
- Duplicate Detection - Files are deduplicated by SHA-256 hash
- Direct URLs - Each file has a direct access URL
- Metadata Storage - Store custom JSON metadata with files
- CORS Enabled - Access from any origin (development mode)
- File Size Limit - 100MB per file
๐ ๏ธ CLI Commands
# Install dependencies
./install.sh
# Start server
./start.sh
# Stop server
./stop.sh
# Upload file
./upload.js file.hdr --category skybox --description "My skybox"
# View logs
tail -f server.log
๐ Response Format
All API responses are in JSON format:
{
"files": [
{
"id": 1,
"filename": "1762802859311-777c7e0e2244c1c2.hdr",
"original_name": "sunset.hdr",
"hash": "3a31ade447...",
"size": 2048576,
"mime_type": "application/octet-stream",
"category": "skybox",
"description": "Beautiful sunset skybox",
"metadata": {},
"upload_date": 1762802859314,
"updated_date": 1762802859314
}
],
"count": 1
}