Build Orchestration, Asset Interchange, Engine Bridge, and Remote-Control Platform
This document specifies what the Bellona domain actually implements in the
Oshun monorepo. Every schema, field, enum value, command, and event listed below
is traceable to source code under libs/bellona/* and apps/bellona/*. Items
named in a design backlog but not yet present in code are explicitly labelled
(planned).
1. Domain Layout#
Bellona is an Nx domain. It has 34 libraries under libs/bellona/ and 12
applications under apps/bellona/. There is no services/bellona/ directory.
1.1 Libraries (libs/bellona/)#
The following table is the complete, authoritative list of Bellona libraries. Each row shows the directory name, its NPM package identifier, and a brief summary of its role.
| Library | Package | Role |
|---|---|---|
3dsmax |
@bellona/3dsmax |
3ds Max bridge runtime and workflow contracts |
adapters |
@bellona/adapters |
Engine-adapter infrastructure (BaseBridge, queues, state) |
asset-export |
@bellona/asset-export |
CGI-scene asset export readiness/conversion planning |
audio |
@bellona/audio |
Audio processing and transcoding contracts |
blender |
@bellona/blender |
Blender engine adapter |
blender-agent |
@bellona/blender-agent |
Blender-native agent runtime (RPC bridge, action schemas, macros) |
bridge-core |
@bellona/bridge-core |
WebSocket bridge protocol foundation |
client |
@bellona/client |
TypeScript SDK |
cross-dcc-consistency |
@bellona/cross-dcc-consistency |
Cross-DCC workflow consistency / compatibility contracts |
database |
@bellona/database |
Prisma schema and generated client |
davinci |
@bellona/davinci |
DaVinci Resolve integration |
editor-productization |
@bellona/editor-productization |
Editor release/onboarding/recovery/diagnostics contracts |
event-handlers |
@bellona/event-handlers |
Cross-domain event subscriptions |
event-publisher |
@bellona/event-publisher |
Type-safe cross-domain event publishing |
gameplay-systems |
@bellona/gameplay-systems |
Engine-agnostic gameplay systems |
godot |
@bellona/godot |
Godot engine adapter |
houdini |
@bellona/houdini |
Houdini integration |
integration |
@bellona/integration |
Cross-domain consumers/compilers (Hathor, Isis) |
interchange |
@bellona/interchange |
3D asset format conversion pipeline |
interchange-models |
@bellona/interchange-models |
Interchange data schemas |
maya |
@bellona/maya |
Maya bridge runtime and workflow contracts |
mcp-gateway |
@bellona/mcp-gateway |
Remote-control MCP gateway server and stdio transport |
metahuman |
@bellona/metahuman |
MetaHuman pipeline contracts |
mocap |
@bellona/mocap |
Motion-capture streaming, retargeting, frame-snap |
openusd |
@bellona/openusd |
OpenUSD pipeline |
remote-protocol |
@bellona/remote-protocol |
Canonical remote-control protocol contracts |
sdk-cpp |
@bellona/sdk-cpp |
C++ native SDK sources |
unity |
@bellona/unity |
Unity engine adapter |
unity-agent |
@bellona/unity-agent |
Unity Editor MCP server package and orchestration wrapper |
unreal |
@bellona/unreal |
Unreal engine adapter (+ BellonaUnrealEditor plugin) |
video |
@bellona/video |
Video processing contracts |
virtual-production |
@bellona/virtual-production |
Virtual production contracts |
xr |
@bellona/xr |
XR (visionOS, Meta Quest, WebXR) contracts |
1.2 Applications (apps/bellona/)#
The following table is the complete, authoritative list of Bellona applications.
| App | Role |
|---|---|
build-api |
Event-driven build/export orchestration module |
build-worker |
Background job processor (4 worker types) |
render-api |
Render-job caching and output validation module |
cli |
bellona command-line tool (Commander.js) |
bridge-unity |
Unity WebSocket bridge (port 9004) |
bridge-unreal |
Unreal WebSocket bridge (port 9003) |
bridge-godot |
Godot WebSocket bridge (port 9002) |
bridge-blender |
Blender WebSocket bridge (port 9001) |
control-room |
Browser-first remote-control operator UI (React/Vite) |
remote-gateway |
Remote-control gateway service (device/session/approval broker) |
remote-host |
Remote-control host agent (engine + desktop + browser adapters) |
1.3 Implementation Status#
All 34 libraries and 11 of 12 apps contain real TypeScript (or C++) source
files. libs/bellona/sdk-cpp and apps/bellona/render-api ship without a
package.json but contain implementation source. The @bellona/blender-agent
and @bellona/unity-agent packages are implemented, not planned — every
module in their runtime catalogs carries status: 'implemented'.
The remote-control subsystem (remote-protocol, mcp-gateway, control-room,
remote-gateway, remote-host) is a self-described "walking skeleton" /
scaffold layer: source and tests exist, and the apps' own package.json
descriptions call them walking-skeleton services.
2. Database Schema#
Bellona has a single PostgreSQL database that persists all build jobs,
artifacts, bridge sessions, worker registrations, and audit records. The schema
is managed by Prisma and lives entirely in the bellona datasource.
Database: PostgreSQL ORM: Prisma (prisma-client-js generator) Schema
file: libs/bellona/database/prisma/schema.prisma (673 lines) Generated
client output: libs/bellona/database/src/generated/client Datasource env
var: BELLONA_DATABASE_URL Preview features: fullTextSearch,
fullTextIndex Migration:
libs/bellona/database/prisma/migrations/20260416000000_phase_8_bellona_initial/
The schema declares 11 models and 14 enums.
2.1 Models#
Build (builds)#
The central record for a build job. It tracks every aspect of the job's lifecycle: current status, which platforms to target, which assets to include, which worker is processing it, error details if it fails, and timing for performance analysis.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String (cuid) |
auto | Primary key, VarChar(25) |
projectId |
String |
— | Owning project, VarChar(50) |
status |
BuildStatus |
PENDING |
Lifecycle status |
priority |
JobPriority |
NORMAL |
Queue priority |
progress |
Int |
0 |
0–100 percentage |
targetPlatforms |
Platform[] |
[] |
Target build platforms |
optimizationLevel |
OptimizationLevel |
BASIC |
NONE / BASIC / FULL |
includeDebugSymbols |
Boolean |
false |
Include debug symbol files |
compressionLevel |
CompressionLevel |
MEDIUM |
LOW / MEDIUM / HIGH |
incremental |
Boolean |
false |
Incremental build flag |
assetIds |
String[] |
[] |
Asset IDs to include |
errorMessage |
String? |
— | Failure message (Text) |
errorCode |
String? |
— | Failure code (VarChar(50)) |
retryCount |
Int |
0 |
Retry attempts made |
maxRetries |
Int |
3 |
Max retry attempts |
workerId |
String? |
— | Assigned worker ID |
queuePosition |
Int? |
— | Position in queue |
userId |
String |
— | Owner user ID |
organizationId |
String? |
— | Owner organization |
metadata |
Json |
{} |
Arbitrary metadata |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp (@updatedAt) |
startedAt |
DateTime? |
— | Processing start |
completedAt |
DateTime? |
— | Processing end |
estimatedCompletionAt |
DateTime? |
— | ETA |
deletedAt |
DateTime? |
— | Soft-delete timestamp |
duration |
Int? |
— | Duration in milliseconds |
Relations: artifacts (BuildArtifact[]), logs (BuildLog[]), exports
(ExportJob[]). Indexes: status, priority, projectId, userId,
organizationId, workerId, createdAt, [status, priority],
[projectId, status], deletedAt.
BuildArtifact (build_artifacts)#
Output files produced by a build, stored in S3-compatible object storage. The
storageBucket and storageKey together form the canonical address for
retrieving the artifact. The checksum enables content-addressable cache
lookups.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
buildId |
String |
— | FK → Build (onDelete: Cascade) |
name |
String |
— | Artifact filename (VarChar(255)) |
platform |
Platform |
— | Target platform |
path |
String |
— | File path (VarChar(500)) |
size |
BigInt |
— | File size in bytes |
checksum |
String |
— | File checksum (VarChar(128)) |
storageBucket |
String |
— | Object storage bucket |
storageKey |
String |
— | Object storage key |
mimeType |
String? |
— | MIME type |
metadata |
Json |
{} |
Arbitrary metadata |
createdAt |
DateTime |
now() |
Creation timestamp |
expiresAt |
DateTime? |
— | Artifact expiration |
deletedAt |
DateTime? |
— | Soft-delete timestamp |
Unique: [storageBucket, storageKey]. Indexes: buildId, platform,
createdAt, expiresAt, deletedAt. No updatedAt field.
BuildLog (build_logs)#
Structured log entries emitted during build execution. Each entry captures the
emitting component (source), the pipeline step (step), and a severity level
alongside the message text, enabling structured querying for debugging.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
buildId |
String |
— | FK → Build (onDelete: Cascade) |
level |
LogLevel |
— | DEBUG / INFO / WARNING / ERROR |
message |
String |
— | Log message text (Text) |
details |
Json? |
— | Structured detail object |
source |
String? |
— | Emitting component name |
step |
String? |
— | Pipeline step name |
timestamp |
DateTime |
now() |
Log timestamp |
Indexes: buildId, level, timestamp. No updatedAt field.
ExportJob (export_jobs)#
An export packaging job that wraps build artifacts into a downloadable
engine-native format. The format enum selects the packaging strategy; the
downloadUrl is a presigned URL provided once the export is COMPLETED.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
projectId |
String |
— | Project reference |
buildId |
String? |
— | Optional FK → Build |
status |
ExportStatus |
PENDING |
Export lifecycle status |
progress |
Int |
0 |
0–100 percentage |
format |
ExportFormat |
— | ZIP / TAR_GZ / UNITYPACKAGE / UASSET / GODOT_PCK |
targetEngine |
EngineType? |
— | Target game engine |
includeSource |
Boolean |
false |
Include source files |
compression |
CompressionLevel |
MEDIUM |
Compression intensity |
assetIds |
String[] |
[] |
Asset selection |
downloadUrl |
String? |
— | Presigned download URL |
size |
BigInt? |
— | Output size in bytes |
checksum |
String? |
— | Output checksum |
storageBucket |
String? |
— | Object storage bucket |
storageKey |
String? |
— | Object storage key |
errorMessage |
String? |
— | Failure error message |
errorCode |
String? |
— | Failure error code |
userId |
String |
— | Owner user ID |
organizationId |
String? |
— | Owner organization |
metadata |
Json |
{} |
Arbitrary metadata |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp |
completedAt |
DateTime? |
— | Completion timestamp |
expiresAt |
DateTime? |
— | Download link expiration |
deletedAt |
DateTime? |
— | Soft-delete timestamp |
duration |
Int? |
— | Duration in milliseconds |
Relations: build (Build?). Indexes: status, projectId,
buildId, userId, organizationId, format, createdAt, expiresAt,
deletedAt.
EngineProject (engine_projects)#
A record of a generated engine project scaffold — the set of files and
configurations generated for a specific engine and platform combination. The
settings JSON field holds engine-specific configuration that does not fit into
the normalized columns.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
projectId |
String |
— | Source project reference |
engine |
EngineType |
— | Target engine |
engineVersion |
String |
— | Engine version string |
modules |
String[] |
[] |
Engine modules to include |
plugins |
String[] |
[] |
Engine plugins to include |
platforms |
Platform[] |
[] |
Target platforms |
outputPath |
String |
— | Output directory path |
templateId |
String? |
— | Build template reference |
includeAssets |
Boolean |
true |
Include project assets |
assetIds |
String[] |
[] |
Specific asset selection |
settings |
Json |
{} |
Engine-specific settings |
status |
BuildStatus |
PENDING |
Generation status |
errorMessage |
String? |
— | Failure error message |
fileCount |
Int? |
— | Number of generated files |
totalSize |
BigInt? |
— | Total output size in bytes |
dependencies |
String[] |
[] |
External dependencies |
warnings |
String[] |
[] |
Generation warnings |
userId |
String |
— | Owner user ID |
organizationId |
String? |
— | Owner organization |
metadata |
Json |
{} |
Arbitrary metadata |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp |
completedAt |
DateTime? |
— | Completion timestamp |
deletedAt |
DateTime? |
— | Soft-delete timestamp |
duration |
Int? |
— | Duration in milliseconds |
Indexes: projectId, engine, status, userId, organizationId,
createdAt, deletedAt.
BridgeSession (bridge_sessions)#
A session record for a live connection between the Bellona platform and a game
engine editor. Tracks connection state (via status), sync progress (via
syncedAssetCount), and the heartbeat timestamp used to detect dead sessions.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
projectId |
String |
— | Project reference |
engine |
EngineType |
— | Connected engine |
engineVersion |
String? |
— | Engine version |
status |
ConnectionStatus |
DISCONNECTED |
CONNECTED / DISCONNECTED / SYNCING / ERROR |
hostname |
String? |
— | Engine hostname |
port |
Int? |
— | Engine port |
pid |
Int? |
— | Engine process ID |
sessionToken |
String? |
— | Session auth token |
lastSyncAt |
DateTime? |
— | Last sync timestamp |
syncDirection |
SyncDirection? |
— | PUSH / PULL / BIDIRECTIONAL |
syncedAssetCount |
Int |
0 |
Number of synced assets |
userId |
String |
— | Owner user ID |
organizationId |
String? |
— | Owner organization |
metadata |
Json |
{} |
Arbitrary metadata |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp |
connectedAt |
DateTime? |
— | Connection established |
disconnectedAt |
DateTime? |
— | Connection dropped |
deletedAt |
DateTime? |
— | Soft-delete timestamp |
lastHeartbeat |
DateTime? |
— | Last heartbeat received |
Relations: conflicts (SyncConflict[]). Indexes: projectId,
engine, status, userId, organizationId, createdAt, lastHeartbeat,
deletedAt.
SyncConflict (sync_conflicts)#
An asset version conflict detected during bidirectional sync, where the same
asset was modified independently on both the Oshun side (localVersion) and the
engine side (remoteVersion). The resolution field records how the conflict
was resolved once a decision is made.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
sessionId |
String |
— | FK → BridgeSession (onDelete: Cascade) |
assetId |
String |
— | Conflicting asset ID |
assetPath |
String? |
— | Asset file path |
localVersion |
String |
— | Local version identifier |
remoteVersion |
String |
— | Remote (engine) version identifier |
localChecksum |
String? |
— | Local file checksum |
remoteChecksum |
String? |
— | Remote file checksum |
resolution |
String? |
— | local / remote / manual (VarChar(20)) |
resolvedAt |
DateTime? |
— | Resolution timestamp |
resolvedBy |
String? |
— | User who resolved |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp |
Indexes: sessionId, assetId, createdAt.
BuildWorker (build_workers)#
Registration record for a build worker node. Each worker declares its
capabilities at registration time (jobTypes, platforms, engines) so the
scheduler can route jobs only to workers capable of processing them. The
lastHeartbeat timestamp is used to detect dead workers.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
name |
String |
— | Worker display name |
hostname |
String |
— | Hostname (unique) |
jobTypes |
JobType[] |
[] |
Supported job types |
platforms |
Platform[] |
[] |
Supported platforms |
engines |
EngineType[] |
[] |
Supported engines |
concurrency |
Int |
1 |
Max concurrent jobs |
status |
WorkerStatus |
OFFLINE |
IDLE / BUSY / PAUSED / STOPPING / STOPPED / OFFLINE |
currentJobId |
String? |
— | Currently processing job ID |
lastHeartbeat |
DateTime? |
— | Last heartbeat timestamp |
totalJobsProcessed |
Int |
0 |
Lifetime job count |
successfulJobs |
Int |
0 |
Successful job count |
failedJobs |
Int |
0 |
Failed job count |
averageJobDuration |
Float? |
— | Average duration in ms |
version |
String? |
— | Worker software version |
metadata |
Json |
{} |
Arbitrary metadata |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp |
Unique: hostname. Indexes: status, lastHeartbeat.
AssetCache (asset_cache)#
Cached metadata for assets imported from other domains (Isis, Hathor), scoped
per project. Storing this metadata locally avoids round-trips to the upstream
domain's asset store for every build. The engineData JSON column holds
engine-specific derived data, such as pre-computed import settings.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
projectId |
String |
— | Project reference |
assetId |
String |
— | Asset reference |
name |
String |
— | Asset name |
type |
AssetType |
— | Asset classification |
path |
String |
— | Asset file path |
size |
BigInt |
— | File size in bytes |
checksum |
String |
— | File checksum |
tags |
String[] |
[] |
Searchable tags |
metadata |
Json |
{} |
General metadata |
engineData |
Json |
{} |
Engine-specific cached data |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp |
lastAccessedAt |
DateTime? |
— | Last access timestamp |
Unique: [projectId, assetId]. Indexes: projectId, type,
updatedAt.
BuildTemplate (build_templates)#
A reusable build configuration that captures a complete set of build settings so
teams do not need to re-specify platform combinations, optimization levels, and
engine settings for every build. Templates can be marked as the organization
default with isDefault.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
name |
String |
— | Template name |
description |
String? |
— | Template description |
platforms |
Platform[] |
[] |
Target platforms |
engines |
EngineType[] |
[] |
Target engines |
optimizationLevel |
OptimizationLevel |
BASIC |
NONE / BASIC / FULL |
includeDebugSymbols |
Boolean |
false |
Include debug symbols |
compressionLevel |
CompressionLevel |
MEDIUM |
LOW / MEDIUM / HIGH |
settings |
Json |
{} |
Additional settings |
isActive |
Boolean |
true |
Template is available |
isDefault |
Boolean |
false |
Is the org default |
organizationId |
String? |
— | Owning organization |
createdBy |
String |
— | Creator user ID |
createdAt |
DateTime |
now() |
Creation timestamp |
updatedAt |
DateTime |
auto | Update timestamp |
Indexes: isActive, organizationId.
AuditLog (audit_log)#
An immutable audit trail for all entity changes within the Bellona database.
Every mutation to a tracked entity produces an audit record that stores the
actor, the before state, the after state, and the diff. The requestId
correlates an audit entry back to the originating HTTP request.
| Field | Type | Default | Notes |
|---|---|---|---|
id |
String |
auto | Primary key |
action |
String |
— | Action performed (VarChar(50)) |
entityType |
String |
— | Entity type changed |
entityId |
String |
— | Entity ID changed |
previousState |
Json? |
— | State before change |
newState |
Json? |
— | State after change |
changes |
Json? |
— | Diff of changes |
userId |
String? |
— | Actor user ID |
ipAddress |
String? |
— | Actor IP address (VarChar(45)) |
userAgent |
String? |
— | Actor user agent string (Text) |
requestId |
String? |
— | Correlation request ID |
metadata |
Json |
{} |
Arbitrary metadata |
createdAt |
DateTime |
now() |
Creation timestamp |
Indexes: [entityType, entityId], userId, action, createdAt. No
updatedAt field.
2.2 Enumerations#
The 14 enums below define all categorical values used throughout the schema. Every enum value is referenced by at least one model column above.
| Enum | Values |
|---|---|
BuildStatus |
PENDING, QUEUED, RUNNING, COMPLETED, FAILED, CANCELLED |
JobPriority |
LOW, NORMAL, HIGH, CRITICAL |
Platform |
WINDOWS, MACOS, LINUX, IOS, ANDROID, WEBGL, PLAYSTATION, XBOX, SWITCH |
EngineType |
UNITY, UNREAL, GODOT, BLENDER, WEB |
ExportFormat |
ZIP, TAR_GZ, UNITYPACKAGE, UASSET, GODOT_PCK |
ExportStatus |
PENDING, PROCESSING, COMPLETED, FAILED, EXPIRED |
OptimizationLevel |
NONE, BASIC, FULL |
CompressionLevel |
LOW, MEDIUM, HIGH |
LogLevel |
DEBUG, INFO, WARNING, ERROR |
ConnectionStatus |
CONNECTED, DISCONNECTED, SYNCING, ERROR |
SyncDirection |
PUSH, PULL, BIDIRECTIONAL |
AssetType |
TEXTURE, MODEL, AUDIO, ANIMATION, MATERIAL, PREFAB, SCRIPT, CONFIG, OTHER |
JobType |
ASSET_BAKE, VALIDATE, ENGINE_PROJECT_GENERATE, EXPORT_PACKAGE |
WorkerStatus |
IDLE, BUSY, PAUSED, STOPPING, STOPPED, OFFLINE |
2.3 Schema Conventions#
The following conventions apply uniformly across all 11 models, ensuring consistency that simplifies queries and ORM integration.
- All primary keys use CUID (
@default(cuid()),@db.VarChar(25)). - Every model has
createdAt; eight models haveupdatedAt(@updatedAt).BuildArtifact,BuildLog, andAuditLogdo not haveupdatedAt. Build,BuildArtifact,ExportJob,EngineProject,BridgeSessioncarry adeletedAtsoft-delete timestamp.size/totalSizeuseBigIntto support files larger than 2 GB.metadata,engineData,settings,previousState,newState,changes, anddetailsare PostgreSQLjsonb.- Array fields (
assetIds,modules,plugins,platforms,engines,tags,warnings,dependencies,jobTypes) are PostgreSQL arrays. BuildWorker.hostnameis unique;AssetCacheis unique on[projectId, assetId];BuildArtifactis unique on[storageBucket, storageKey].
3. Build / Export Job Lifecycle#
3.1 Build Status State Machine#
The BuildStatus enum drives the complete build lifecycle from submission to
final outcome. A build enters PENDING when enqueued, moves to QUEUED when a
worker picks it up, and progresses to RUNNING while the worker executes. It
then either reaches COMPLETED, FAILED (retryable up to maxRetries), or
CANCELLED by user request.
PENDING ──> QUEUED ──> RUNNING ──> COMPLETED
│
├──────> FAILED (retryable up to maxRetries)
└──────> CANCELLED (user request)
A build's retryCount increments on transient failure until it reaches
maxRetries (default 3). The build-worker job queue (JobStatus: pending,
queued, running, completed, failed, cancelled) mirrors this lifecycle
at the worker level.
3.2 Export Status State Machine#
Export jobs follow a simpler lifecycle. Once COMPLETED, a presigned download
URL is generated that expires at expiresAt, at which point the job status
transitions to EXPIRED.
PENDING ──> PROCESSING ──> COMPLETED ──> EXPIRED (after expiresAt)
│
└────────> FAILED
3.3 Worker Status State Machine#
A build worker's status reflects its current operational mode. Normal operation
cycles through OFFLINE → IDLE → BUSY. The PAUSED, STOPPING, and STOPPED
states support controlled drains during deployments. Dead workers are identified
when their lastHeartbeat becomes stale.
BuildWorker.status transitions across OFFLINE → IDLE → BUSY during normal
operation, and PAUSED, STOPPING, STOPPED during controlled drains.
3.4 Job Priority#
The build-worker priority queue
(apps/bellona/build-worker/src/queues/job-queue.ts) orders pending jobs by
numeric priority: critical=4, high=3, normal=2, low=1. Higher-priority
jobs are always dequeued before lower-priority ones regardless of submission
order.
4. Build API (apps/bellona/build-api)#
The Build API is a Node.js module, not an HTTP server. It exposes a
programmatic lifecycle API and subscribes to cross-domain events. It does not
bind a TCP port itself; the 4005 port number is the documented domain
assignment (libs/bellona/README.md) used by sibling services.
4.1 Programmatic API#
@bellona/build-api exports the following entry points from index.ts. The
initialize() function is the only required setup step — it wires the cache,
queues, and event subscriptions. After that, the module stays alive processing
events passively.
import {
initialize,
shutdown,
getCacheService,
getBuildCacheService,
isHealthy,
getHealthStatus,
} from '@bellona/build-api';
await initialize();
const health = await getHealthStatus();
// {
// status: 'healthy' | 'degraded' | 'unhealthy',
// cache: boolean,
// uptime: number,
// cacheStats?: { hitRate: number, totalEntries: number }
// }
const cache = getCacheService(); // BuildCacheService
await shutdown();
initialize() performs three steps in order:
- Constructs the
BuildCacheService(Redis-backed content-addressable cache) - Initializes a dedicated Redis connection for job queues
- Wires cross-domain event handlers via
@bellona/event-handlers
On startup the process logs "Service ready and listening for events" and stays alive to process events; it does not accept HTTP requests.
4.2 Cache Service exports#
@bellona/build-api also exports BuildCacheService,
createBuildCacheService, setBuildCacheService, clearBuildCacheService, and
the BuildCacheServiceConfig type. The cache service supports
content-addressable storage, compression, deduplication, in-memory + Redis
tiers, and Redis PubSub invalidation.
4.3 Type surface#
The module re-exports a large typed surface from types.ts. The types are
organized into the following groups:
- Branded IDs —
BuildJobId,ArtifactId,ProjectId,AssetId,ContentHash(and their constructorscreateBuildJobId,createArtifactId,createProjectId,createAssetId,createContentHash) - Job types —
BuildJob,BuildJobType,BuildJobStatus,BuildJobPriority,BuildError,BuildProgress - Artifact types —
Artifact,ArtifactType,ArtifactMetadata,TargetPlatform,TargetEngine - Cache types —
CachedArtifact,CachedBuildJob,CacheEntry,CacheEntryMetadata,CacheLookupResult,CacheStats,CacheConfig - Build input types —
BuildInput,TextureBuildInput,MeshBuildInput,ShaderBuildInput,AudioBuildInput,AnimationBuildInput - Dependency types —
DependencyNode,DependencyGraph - Event types —
BuildEvent,BuildEventType - Config types —
BuildApiConfig,BuildApiHealth
4.4 Job-queue adapters#
main.ts builds a BuildQueueInterface and ExportQueueInterface. When
REDIS_URL is set, jobs are persisted in Redis (bellona:queue:* keys: a job
hash, a priority-scored :pending sorted set, and a per-project index set).
When REDIS_URL is unset, an in-memory Map is used as a fallback. The build
queue supports enqueue, getStatus, and cancel; the export queue supports
enqueue and getStatus.
5. Build Worker (apps/bellona/build-worker)#
A poll-based background processor. The JobQueue class is a priority queue with
poll-based dequeue (pollInterval default 1000 ms, concurrency default 1).
5.1 Worker types#
JobType is the union
asset-bake | validate | engine-project-generate | export-package. Each job
type has a dedicated worker module under
apps/bellona/build-worker/src/workers/:
| Job type | Worker module | Responsibility |
|---|---|---|
asset-bake |
asset-bake-worker.ts |
Texture / model / audio / animation baking |
validate |
validation-worker.ts |
Build-input and output validation |
engine-project-generate |
engine-project-worker.ts |
Engine project scaffold generation |
export-package |
export-package-worker.ts |
Package and export build artifacts |
5.2 Worker type surface#
build-worker/types.ts declares branded IDs (JobId, WorkerId, ProjectId,
AssetId), JobType, JobStatus, JobPriority, and per-job-type request and
result types:
- asset-bake —
AssetBakeRequest/AssetBakeResult/AssetBakeJob(withTextureBakeOptions,ModelBakeOptions,AudioBakeOptions,AnimationBakeOptions) - validate —
ValidationRequest/ValidationResult/ValidateJob(withValidationSeverity,ValidationType,ValidationIssue) - Format unions —
AssetFormat,TextureFormat,ModelFormat,CompressionQuality
6. Render API (apps/bellona/render-api)#
An internal Node.js module (no HTTP port, no package.json) providing
render-job caching, GPU queueing, and output validation.
import {
initialize,
shutdown,
getCacheService,
getRenderCacheService,
isHealthy,
getHealthStatus,
} from '@bellona/render-api';
6.1 Components#
The render-api is composed of three service components, each with factory and singleton accessor functions:
RenderCacheService— Redis-backed render cache (createRenderCacheService,setRenderCacheService,clearRenderCacheService, config typeRenderCacheServiceConfig).OutputValidator— render output quality validation (createOutputValidator,getOutputValidator,setOutputValidator), withValidationSeverity,ValidationCategory,ValidationIssue,OutputValidationResult,JobValidationResult,ValidationOptions.GpuRenderQueue— GPU device allocation and queued job management (createGpuRenderQueue,getGpuRenderQueue,setGpuRenderQueue,clearGpuRenderQueue), withGpuDevice,GpuAllocationRequest,GpuAllocation,QueuedJob,GpuQueueStats,GpuQueueEvents,GpuQueueConfig.
6.2 Type surface#
render-api/types.ts declares the following types for render job management:
- Job and output —
RenderJobId,RenderOutputId,RenderJob,RenderOutput,RenderConfig,RenderSettings,RenderProgress,RenderError - Classification —
RenderEngine,OutputFormat,QualityPreset,RenderStatus - Animation —
AnimationSettings,FrameRange,Resolution - Cache —
CachedRenderJob,CachedRenderOutput,RenderCacheMetadata,RenderCacheStats - Queue —
RenderQueueItem,RenderQueueStatus - Events —
RenderEvent,RenderEventType - Config —
RenderApiConfig - ID constructors —
createRenderJobId,createRenderOutputId
7. WebSocket Bridge Protocol#
The four engine bridge apps (bridge-blender, bridge-godot, bridge-unreal,
bridge-unity) all build on @bellona/bridge-core (createBridgeServer). The
protocol follows the same pattern for every engine: a handshake and ping
command are registered first (identical across all bridges), followed by
engine-specific commands.
7.1 Connection endpoints#
| Engine | Default endpoint | Port env var | Host env var |
|---|---|---|---|
| Blender | ws://localhost:9001/blender |
BLENDER_BRIDGE_PORT |
BLENDER_BRIDGE_HOST |
| Godot | ws://localhost:9002/godot |
GODOT_BRIDGE_PORT |
GODOT_BRIDGE_HOST |
| Unreal | ws://localhost:9003/unreal |
UNREAL_BRIDGE_PORT |
UNREAL_BRIDGE_HOST |
| Unity | ws://localhost:9004/unity |
UNITY_BRIDGE_PORT |
UNITY_BRIDGE_HOST |
Ports default to 9001–9004 and host to localhost in each app's main.ts.
7.2 Common commands#
Every bridge registers these two commands regardless of engine. handshake
establishes mutual version identification; ping verifies liveness.
| Command | Request data | Response data |
|---|---|---|
handshake |
{ clientName, clientVersion } |
{ serverName, serverVersion, protocolVersion } |
ping |
{} |
{ timestamp } |
The bridge-core server emits connection, disconnection, command, and
error events.
7.3 Engine command sets#
The engine-specific commands registered by each bridge app are listed below. Implementation of each command lives in the corresponding engine adapter library.
| Engine | Command count | Commands |
|---|---|---|
| Blender | 6 | getSceneInfo, createObject, importAsset, exportAsset, setFrame, render |
| Godot | 9 | scene-tree access, node create/property/method, scene load, resource load, signal emit, GDScript execution, project settings |
| Unreal | 11 | world info, level load/unload, actor spawn/destroy/property, Blueprint function call, material parameter, Sequencer control, console command, screenshot |
| Unity | 14 | scene info / load / unload, GameObject create/destroy, prefab instantiate, transform set, component add / property set, animation play, animator parameter, physics force, raycast, message send |
The Unity, Unreal, Godot, and Blender command implementations live in
@bellona/unity, @bellona/unreal, @bellona/godot, and @bellona/blender
respectively.
7.4 Blender bridge session tracking#
bridge-blender is the only bridge that publishes cross-domain events. On
connection and disconnection it calls
BellonaEventPublisher.publishSessionStarted and publishSessionEnded (see
§9). The other bridges track sessions in the database but do not emit
cross-domain events.
8. Remote-Control Subsystem#
A browser-first remote-control layer for operating engine hosts, desktop applications, and headless browsers from a web operator console. The apps' package.json descriptions identify the gateway and host as "walking skeleton" services.
8.1 @bellona/remote-protocol#
Canonical protocol contracts for the entire remote-control subsystem. This library defines the type system and namespace structure that all three remote apps share.
Exports: BELLONA_REMOTE_PROTOCOL_PACKAGE_NAME,
BELLONA_REMOTE_PROTOCOL_VERSION (0.1.0),
BELLONA_REMOTE_PROTOCOL_SCHEMA_STATUS (version-negotiation), and
createBellonaRemoteProtocolDescriptor(). The library is partitioned into
contract modules: actor, audit, blender, browser, command, common,
device, desktop, dry-run, logging, namespaces, policy, result,
schema-registry, session, state, stream, unreal, version, plus
browser-compensating-actions and desktop-compensating-actions.
The REMOTE_COMMAND_NAMESPACE constant defines 13 command namespaces: device,
session, stream, agent, state, blender, unreal, browser,
desktop, file, process, approval, diagnostic.
8.2 @bellona/mcp-gateway#
Remote-control MCP gateway server and local stdio transport. Ships a
bellona-mcp-gateway binary (src/stdio-cli.js). Modules include
stdio-server, remote-control-tools, remote-control-resources,
auth-session, command-remediation, mcp-composition-rules, and an agent
control layer with the following modules: agent-capability-memory,
agent-autonomous-stop-criteria, agent-deep-integration-evals,
agent-dry-run-cost-time-estimator, agent-dry-run-impact-summary,
agent-dry-run-planners, agent-handoff-paths, agent-long-running-jobs,
agent-mutation-locking, agent-preflight-checks,
agent-tool-selection-policy, agent-visual-verification-policy.
8.3 Remote-control apps#
| App | Source highlights |
|---|---|
remote-gateway |
Device registry, session lifecycle, approval service, command dispatcher, pairing codes, host tokens, audit log, redaction, telemetry |
remote-host |
Adapter registry with Blender / Unreal / browser / desktop adapters, command executor, gateway connection, pairing client, identity store, macOS permissions |
control-room |
React/Vite operator UI: approval queue, command palette, device list, session timeline, stream preview, WebRTC loopback, mobile approval PWA, first-session tour |
The control-room is gated behind the VITE_BELLONA_CONTROL_ROOM_ENABLED
environment flag.
8.4 Phase 180 Roadmap Contract#
The remote-control subsystem is governed by the Phase 180 roadmap: the operating
checklist is TODOS/phase-180.md (180.C canonical sequential checklist), the
expanded requirements live in TODOS/phase-180-reference.md (180.R /
180.0–180.20, including the 180.19 acceptance criteria), and the audit of
known scope gaps is TODOS/phase-180-gaps.md. The implementation tracker
required by 180.C.01 lives at
docs/domains/bellona/extras/remote-control/implementation-tracker.md.
Planned target layout not yet present in the repo:
| Package | Role |
|---|---|
libs/bellona/remote-adapters |
Adapter interfaces for Blender, Unreal, browser, desktop, files, processes |
libs/bellona/mac-host-runtime |
macOS TCC permissions, process launch, window focus, capture, signing/updates |
libs/psyche/desktop-fallback |
Reusable screenshot/click/type/window fallback shared with Psyche Computer Use |
testing/bellona/remote-control |
Integration, e2e, fixture, and network-impairment test suites |
Binding protocol rules from Phase 180: command schemas live only in
libs/bellona/remote-protocol and are imported by gateway, host, MCP, adapters,
tests, and docs (single source of truth); Blender/Unreal/browser debug and
control ports remain localhost-only on the host; deep typed adapters must be
preferred over desktop fallback; and no privileged path (arbitrary shell,
arbitrary Blender Python, Unreal console, desktop control, or real browser
profiles) may ship before policy, approval, and audit primitives are complete.
9. Events#
9.1 Events Published#
@bellona/event-publisher exposes BellonaEventPublisher with eight typed
publish methods. The event-type string constants are defined in
@oshun/contracts (libs/contracts/src/events/bellona.ts).
The table below shows each event, its publish method, and the key fields in its contract Zod schema payload.
| Event | Publish method | Payload key fields (from contract Zod schema) |
|---|---|---|
bellona.session.started |
publishSessionStarted |
sessionId, projectId, userId, engine, engineVersion, workerId, connectionType, capabilities |
bellona.session.ended |
publishSessionEnded |
sessionId, projectId, userId, engine, durationMs, commandsExecuted, assetsTransferred, bytesTransferred, reason, errorMessage? |
bellona.build.started |
publishBuildStarted |
buildId, projectId, userId, engine, engineVersion, platform, configuration, features?, sourceCommit?, workerId |
bellona.build.progress |
publishBuildProgress |
buildId, stage, progress, message?, warnings, errors |
bellona.build.completed |
publishBuildCompleted |
buildId, projectId, userId, engine, platform, configuration, success, durationMs, artifacts[], metrics |
bellona.export.started |
publishExportStarted |
exportId, projectId, userId, targetFormat, assets[] |
bellona.export.ready |
publishExportReady |
exportId, projectId, userId, targetFormat, files[], totalSizeBytes, processingTimeMs, expiresAt |
bellona.asset.synced |
publishAssetSynced |
syncId, projectId, sessionId, engine, direction, assets[], totalSizeBytes, durationMs |
The publisher also exports payload types (BellonaSessionStartedPayload,
BellonaSessionEndedPayload, BellonaBuildStartedPayload,
BellonaBuildProgressPayload, BellonaBuildCompletedPayload,
BellonaExportStartedPayload, BellonaExportReadyPayload,
BellonaAssetSyncedPayload) and the GameEngine, BuildPlatform,
BuildStatus types, plus getBellonaEventPublisher,
createBellonaEventPublisher, resetBellonaEventPublisher.
9.2 Events Consumed#
@bellona/event-handlers defines BELLONA_SUBSCRIPTIONS — four cross-domain
subscriptions that drive Bellona's automated build reactions. Each handler
receives the event payload and enqueues the appropriate build or export job.
| Event | Source domain | Handler | Action |
|---|---|---|---|
hathor.world.published |
Hathor | handleHathorWorldPublished |
Enqueues a build for the world |
isis.asset.generated |
Isis | handleIsisAssetGenerated |
Enqueues a build for asset baking |
yemaya.build.requested |
Yemaya | handleYemayaBuildRequested |
Enqueues a build job |
yemaya.export.requested |
Yemaya | handleYemayaExportRequested |
Enqueues an export job |
setupBellonaEventHandlers accepts an eventBus, a consumerGroup, a
BuildQueueInterface, an ExportQueueInterface, an optional logger, and an
optional metrics config. Handler execution metrics are collected through
@oshun/metrics via withMetrics / HandlerStatsTracker.
9.3 Event Bus Transport#
The event bus is @oshun/event-bus, which is Redis-backed (it imports
ioredis). build-api/main.ts constructs the bus with
createEventBus({ redisUrl, sourceDomain: 'bellona', keyPrefix: 'oshun:events', persistence: true, eventTtl: 86400, ... }).
| Setting | Value |
|---|---|
| Transport | Redis |
| Source domain | bellona |
| Key prefix | oshun:events |
| Event TTL | 86400 s (24 hours) |
| Retry | Exponential, max 3 attempts, 1 s–30 s, multiplier 2 |
| Dead-letter | Enabled, 7-day retention, max 1000 entries |
| Consumer group | bellona-build-api (for the build-api subscriber) |
10. Asset Interchange (@bellona/interchange)#
The interchange library exposes a format conversion pipeline (import → validate
→ transform → export) under src/{gltf,fbx,usd,transform,validation}.
@bellona/interchange-models provides the shared data schemas.
10.1 AssetFormat union#
The AssetFormat type (interchange/src/types.ts) defines 13 3D-asset format
values. This is the complete list of formats the interchange pipeline can
process on the import side:
gltf, glb, usd, usda, usdc, usdz, fbx, obj, abc (Alembic),
ply, stl, dae (Collada), blend.
10.2 ImageFormat union#
The ImageFormat type defines 9 image format values used for texture
interchange:
png, jpg, jpeg, webp, exr, hdr, tga, bmp, tiff.
10.3 @bellona/asset-export#
A planning layer that sits on top of the interchange pipeline. Rather than executing conversions, it produces export plans and manifests that describe what conversions are needed and whether each target is ready or blocked.
Exports:
BELLONA_ASSET_EXPORT_FORMATS— the supported export target formats:usd,usda,usdc,usdz,gltf,glb,fbxBellonaAssetExportStatusunion —ready/needs-attention/blocked- Planning functions —
evaluateBellonaAssetExportTarget,evaluateBellonaAssetExportPlan,buildBellonaAssetExportManifest,createBellonaAssetExportTarget,createBellonaAssetExportPlan
Plan evaluation produces per-target readiness ratios, blocking/warning issue counts, and a checksum/package manifest.
11. Cross-Domain Integration (@bellona/integration)#
The integration library is the translation boundary between Oshun domain models and engine-native artifacts. It exports four factory functions, each producing a specialized consumer or compiler instance.
createHathorConsumer— imports lore content (worlds, quests, dialogue) from Hathor world-publication events, with a configurable default engine and output directory.createLoreCompiler— compiles lore content for a target engine at a configurable optimization level.createIsisConsumer— imports generated assets from Isis, optionally auto-converting them.createAssetConverter— converts raw assets to engine-native formats via the interchange pipeline.
12. CLI (apps/bellona/cli)#
A Commander.js CLI. The program name is bellona
(apps/bellona/cli/src/index.ts). Seven top-level commands are registered:
| Command | Source | Aliases | Purpose |
|---|---|---|---|
build |
commands/build.ts |
b (top-level), sub-aliases start/ls/get |
Submit, list, and inspect build jobs |
export |
commands/export.ts |
e (top-level), sub-aliases ls/get/rm |
Create and manage export packages |
sync |
commands/sync.ts |
sub-aliases bidirectional/ls |
Push / pull / bidirectional asset sync |
config |
commands/config.ts |
sub-aliases ls, profile subcommand |
Manage CLI configuration and profiles |
health |
commands/health.ts |
— | Check Build API and Render API health |
project |
commands/project.ts |
— | Manage engine project configurations |
detect |
commands/project.ts (detectCommand) |
— | Auto-detect engine projects in a directory |
The global --api-key option and --api-url resolution use the
BELLONA_API_KEY / BELLONA_API_URL / BELLONA_BUILD_API_URL environment
variables.
13. TypeScript SDK (@bellona/client)#
@bellona/client provides a typed client. The README shows
createBellonaClient({ baseUrl }) with namespaced operations (e.g.
client.exports.create, client.exports.onProgress,
client.exports.waitForCompletion).
14. C++ Native SDK (@bellona/sdk-cpp)#
libs/bellona/sdk-cpp contains C++ SDK sources (no package.json). It targets
native engine plugins and build-machine agents that cannot host a Node.js
runtime.
15. Configuration and Environment Variables#
15.1 Build API#
| Variable | Default | Description |
|---|---|---|
BELLONA_DATABASE_URL |
— | PostgreSQL connection URL |
REDIS_URL |
redis://localhost:6379 |
Redis URL (cache + queues + bus). When unset, build-api falls back to in-memory job queues. |
BUILD_CACHE_MEMORY_SIZE |
104857600 (100 MB) |
In-memory cache size in bytes |
BUILD_CACHE_MAX_SIZE |
10737418240 (10 GB) |
Maximum total cache size in bytes |
15.2 Render API#
| Variable | Default | Description |
|---|---|---|
REDIS_URL |
redis://localhost:6379 |
Redis connection URL |
15.3 Bridge Services#
| Variable | Default | Description |
|---|---|---|
BLENDER_BRIDGE_PORT |
9001 |
Blender bridge WebSocket port |
BLENDER_BRIDGE_HOST |
localhost |
Blender bridge host |
GODOT_BRIDGE_PORT |
9002 |
Godot bridge WebSocket port |
GODOT_BRIDGE_HOST |
localhost |
Godot bridge host |
UNREAL_BRIDGE_PORT |
9003 |
Unreal bridge WebSocket port |
UNREAL_BRIDGE_HOST |
localhost |
Unreal bridge host |
UNITY_BRIDGE_PORT |
9004 |
Unity bridge WebSocket port |
UNITY_BRIDGE_HOST |
localhost |
Unity bridge host |
15.4 CLI#
| Variable | Default | Description |
|---|---|---|
BELLONA_API_URL |
http://localhost:3020 |
CLI target API base URL |
BELLONA_BUILD_API_URL |
http://localhost:3020 |
Build API URL (used by health) |
BELLONA_RENDER_API_URL |
http://localhost:3021 |
Render API URL (used by health) |
BELLONA_API_KEY |
— | CLI API authentication key |
15.5 Control Room#
| Variable | Default | Description |
|---|---|---|
VITE_BELLONA_CONTROL_ROOM_ENABLED |
unset | Feature flag to enable the operator UI |
16. Integration Points#
16.1 Upstream Domains That Trigger Bellona#
The event-driven integration model means no upstream domain calls Bellona over HTTP. Instead, each domain publishes an event and Bellona's event handlers react asynchronously.
| Domain | Trigger event | Bellona response |
|---|---|---|
| Hathor | hathor.world.published |
Enqueues a world build |
| Isis | isis.asset.generated |
Enqueues an asset-baking build |
| Yemaya | yemaya.build.requested |
Enqueues a build job |
| Yemaya | yemaya.export.requested |
Enqueues an export job |
16.2 Shared Infrastructure Dependencies#
| Dependency | Usage |
|---|---|
@oshun/event-bus |
Redis-backed cross-domain event pub/sub |
@oshun/logging |
Structured logging across apps |
@oshun/cache |
Redis client / cache primitives |
@oshun/contracts |
Event-type constants and Zod payload schemas |
@oshun/metrics |
Event-handler metrics registry |
| PostgreSQL | Bellona schema database |
| Redis | Build/render cache, build/export job queues, event bus |
| MinIO / S3 | Artifact and export package storage |
17. V2 Reciprocal Tasks (Backlog)#
The following items are tracked in the Bellona backlog as reciprocal dependencies of the sister-monorepo V2 fighting-game project.
17.1 BellonaUnrealRuntime (planned)#
- Task ID:
BELLONA-UE-RUNTIME-V2-001 - Owner: Bellona Runtime Integrations
- ETA: 2026-06-30
Today the Unreal adapter ships an editor-only plugin at
libs/bellona/unreal/plugin/BellonaUnrealEditor/. The runtime-shipped companion
plugin BellonaUnrealRuntime is not yet implemented — no
BellonaUnrealRuntime directory exists under libs/bellona/unreal/plugin/.
When the runtime plugin is built it will live, like its editor sibling, under
Bellona ownership at libs/bellona/unreal/plugin/BellonaUnrealRuntime/. This is
the single source of truth for the plugin. V2 must not create
V2/ue/Plugins/BellonaUnrealRuntime/ as a parallel copy. The V2 monorepo
consumes the Bellona-owned plugin once it ships rather than forking a runtime
module of its own; a V2-side check-v2-bellona-runtime-gates.py CI check fails
the build if a BellonaUnrealRuntime plugin directory appears under
V2/ue/Plugins/.
Until the runtime plugin lands, the Editor-time BellonaUnrealEditor remains
available and it is the only Bellona Unreal plugin in either tree; all V2
author/cook workflows (including the frame-snap Live Link handoff in §17.2) run
through it. V2 runtime-dependent surfaces stay gated by the @oshun/config
feature flags ENABLE_V2_BELLONA_RUNTIME_HOT_RELOAD,
ENABLE_V2_BELLONA_RUNTIME_ASSET_IMPORT, and
ENABLE_V2_BELLONA_LIVE_COSMETIC_DELIVERY (all default false in
libs/shared/config/src/features.ts).
Planned scope: a runtime UE module (no editor-only dependencies) that ships in cooked V2 builds for runtime hot-reload of Bellona-cooked artifacts, ad-hoc runtime asset import on non-rollback surfaces, live cosmetic delivery, and provenance metadata handoff — each gated behind the corresponding feature flag above until the Bellona Runtime Integrations team marks the plugin production-ready.
17.2 Aja frame-snap Live Link#
- Task ID:
BELLONA-MOCAP-V2-FRAME-SNAP-001
This task is implemented in @bellona/mocap under src/frame-snap/. That
module defines:
- Constants
BELLONA_MOCAP_FRAME_SNAP_ROUTE(@aja -> @bellona/mocap -> @bellona/unreal),BELLONA_MOCAP_FRAME_SNAP_TARGET_FPS(60), andBELLONA_MOCAP_FRAME_SNAP_TOLERANCE_SECONDS(0.0005). - Types
BellonaFrameSnapClip,BellonaFrameSnapNotifySegmentKind,BellonaFrameSnapNotifySegmentInput,BellonaFrameSnapNotifySegment,BellonaFrameSnapExportRequest,BellonaFrameSnapLiveLinkManifest(withBellonaFrameSnapManifestClip,BellonaFrameSnapManifestFramePolicy,BellonaFrameSnapManifestLiveLink,BellonaFrameSnapManifestQualityGates), and theBellonaFrameSnapErrorclass. - Functions
createBellonaFrameSnapLiveLinkExport,normalizeBellonaNotifySegments,snapBellonaSecondsToFrame.
@bellona/mocap resamples Aja-retargeted skeleton clips to 60 Hz, assigns
integer frame numbers, normalizes notify segments to integer 60 Hz boundaries,
and rejects sub-frame segments. @bellona/unreal receives the editor-only Live
Link handoff for import/cook.
The contract route, written with the canonical arrow notation used by the V2
docs, is @aja → @bellona/mocap → @bellona/unreal. Every notify segment carries
alignment: 'integer-60hz-frame-boundaries', so the manifest's gameplay windows
land on deterministic integer frames. The V2 consumer of this manifest is
@v2/aja-bellona-livelink-export (Aja spec §11A.1).
Like the rest of the V2 Bellona surface, this path is author/cook-time only: the
manifest sets runtimeLiveLinkPluginRequired: false, the handoff is
editorOnlyHandoff, and runtime Live Link plugins remain disabled in
shipped V2 builds. Gameplay runs against the cooked, frame-snapped
AnimSequence, not a live Link stream — consistent with §17.1, where the
runtime plugin is gated until BellonaUnrealRuntime ships.
18. Acceptance Criteria#
The Bellona domain meets its specification when all of the following conditions hold. Each criterion maps directly to a testable behavior.
- The Prisma schema migrates cleanly via
prisma migrate dev/prisma migrate deploy, producing the 11 documented tables with the documented indexes and constraints. @bellona/build-apiinitialize()stands up the build cache, the Redis job queues (or the in-memory fallback whenREDIS_URLis unset), and the four cross-domain event subscriptions;getHealthStatus()reportshealthy.- The
build-workerpriority queue dequeues jobs by priority and dispatches eachJobTypeto its dedicated worker module. - Each of the four bridge apps starts a
bridge-coreWebSocket server on its documented port and registershandshake,ping, and the engine-specific command set (6 / 9 / 11 / 14 commands). bridge-blenderpublishesbellona.session.started/bellona.session.endedon connect / disconnect.@bellona/event-publisherpublishes the eightbellona.*events with payloads conforming to the@oshun/contractsZod schemas, over the Redis-backed event bus.@bellona/event-handlersconsumeshathor.world.published,isis.asset.generated,yemaya.build.requested, andyemaya.export.requested, enqueueing builds/exports.- The
bellonaCLI exposes the seven documented commands. - The interchange pipeline imports, validates, transforms, and exports the 13
AssetFormatvalues per its export-capability matrix.