Developer ReferenceComponent Blocks Reference

Component Blocks Reference

Reusable UI widgets for the StudioBrain Layout Designer.

Overview

Component blocks are self-contained UI widgets that can be placed in layout sections alongside form fields. They are managed through the Component Block Registry (src/lib/component-block-registry.ts) and rendered by ComponentBlockRenderer.

The Layout Designer provides a drag-and-drop palette where admins can place blocks into entity layouts. Blocks support both edit and view modes, and each block can declare configurable settings via a config_schema.

For the full Layout System architecture, see the Architecture page.

Built-in Blocks

entity-assets

PropertyValue
Categorymedia
Modesedit, view
Sourcebuiltin

Full asset browser with upload, primary image selection, and asset role management.

Config Options:

  • title (string, default: “Assets”) — Section heading
  • showUpload (boolean, default: true) — Show upload controls

entity-timeline

PropertyValue
Categorydisplay
Modesedit, view
Sourcebuiltin

Interactive timeline panel for entity events and milestones with auto-populate capability.

Config Options: None


production-status

PropertyValue
Categoryworkflow
Modesedit, view
Sourcebuiltin

Production pipeline status editor showing general/game/TV status with inline save.

Config Options: None (uses entity’s production_status field directly)


markdown-content

PropertyValue
Categorydisplay
Modesview
Sourcebuiltin

Rendered markdown body content using the MarkdownRenderer component.

Config Options: None


primary-image

PropertyValue
Categorymedia
Modesview
Sourcebuiltin

Hero/primary image display with placeholder fallback when no image is set.

Config Options:

  • max_height (select, default: “500px”) — Maximum display height: Small (200px), Medium (300px), Large (500px), X-Large (700px), No Limit
  • object_fit (select, default: “cover”) — Fit mode: Cover (crop to fill), Contain (show all), Fill (stretch)
  • rounded (select, default: “lg”) — Border radius: None, Medium, Large, Extra Large, Circle

entity-chat

PropertyValue
Categoryinteraction
Modesview
Sourcebuiltin

AI-assisted chat panel for entity editing and brainstorming.

Config Options: None


entity-relationships

PropertyValue
Categorydisplay
Modesview
Sourcebuiltin

Automatically scans common relationship fields and renders them as grouped link cards. Scanned fields include: relationships, allies, enemies, members, key_personnel, associated_brands, subsidiaries, parent_company, primary_npcs, controlled_territories.

Config Options:

  • showAddButton (boolean, default: false) — Show add relationship button

entity-workflow-trigger

PropertyValue
Categoryworkflow
Modesedit
Sourcebuiltin

Trigger ComfyUI AI generation workflows for the current entity.

Config Options: None


static-content

PropertyValue
Categorydisplay
Modesedit, view
Sourcebuiltin

Add static text, markdown notes, headers, separators, or info/warning boxes to the layout.

Config Options:

  • content_type (select, default: “text”) — Content type: Plain Text, Markdown, Header, Separator / Divider, Info Box, Warning Box
  • content (textarea, default: "") — The content to display
  • heading_level (select, default: “h3”) — Heading level for header type: H2 (Large), H3 (Medium), H4 (Small)

Plugin Blocks

Third-party plugins can register blocks via their plugin.json manifest. These render as sandboxed iframes via PluginBlockIframe. The component ID format for plugin blocks is:

plugin:{pluginId}:{panelId}

For example: plugin:my-analytics:network-graph

Plugin blocks automatically appear in the Layout Designer palette under the “plugin” category. See Plugin Development for details on declaring plugin panels.

Creating a Custom Block

Step 1: Create the Component

// src/components/blocks/MyCustomBlock.tsx
interface MyCustomBlockProps {
  config?: Record<string, any>;
  entityType: string;
  entityId: string;
  data: any;
  mode: 'edit' | 'view';
}
 
export default function MyCustomBlock({ config, data, mode }: MyCustomBlockProps) {
  return <div>{/* Block UI */}</div>;
}

Step 2: Register in ComponentBlockRenderer

// src/components/ComponentBlockRenderer.tsx
case 'my-custom-block':
  return <MyCustomBlock config={config} entityType={entityType} entityId={entityId} data={data} mode={mode} />;

Step 3: Add to Registry

// src/lib/component-block-registry.ts -- add to BUILTIN_BLOCKS array
{
  id: 'my-custom-block',
  label: 'My Custom Block',
  description: 'Does something useful',
  icon: 'Sparkles',
  category: 'display',
  source: 'builtin',
  default_config: {},
  config_schema: {
    title: { type: 'string', label: 'Title', default: 'Default Title' },
    showExtra: { type: 'boolean', label: 'Show Extra', default: false },
  },
  modes: ['edit', 'view'],
}

The block will automatically appear in the Layout Designer palette under its category.

Config Schema

Blocks can declare a config_schema for designer-editable settings. The BlockConfigPanel renders this dynamically.

Supported Field Types

TypeRenders AsExample
stringText inputtype: 'string', label: 'Title', default: 'Assets'
numberNumber inputtype: 'number', label: 'Max Items', default: 10
booleanToggle checkboxtype: 'boolean', label: 'Show Upload', default: true
selectDropdowntype: 'select', label: 'Visibility', default: 'team' with options array
textareaMulti-line texttype: 'textarea', label: 'Content', default: ''

Select Options Format

{
  type: 'select',
  label: 'Max Height',
  default: '500px',
  options: [
    { value: '200px', label: 'Small (200px)' },
    { value: '500px', label: 'Large (500px)' },
    { value: 'none', label: 'No Limit' },
  ],
}

Block Definition Interface

interface ComponentBlockDefinition {
  id: string;                   // Unique block ID
  label: string;                // Display name in palette
  description: string;          // Tooltip description
  icon: string;                 // Lucide icon name
  category: 'display' | 'media' | 'interaction' | 'workflow' | 'plugin';
  source: 'builtin' | string;  // 'builtin' or plugin ID
  default_config?: Record<string, any>;
  config_schema?: Record<string, {
    type: string;
    label: string;
    default?: any;
    options?: Array<{ value: string; label: string }>;
  }>;
  modes?: ('edit' | 'view')[];
}

Rendering

ComponentBlockRenderer receives these props:

interface ComponentBlockRendererProps {
  componentId: string;        // Block ID or "plugin:{id}:{panel}"
  config?: Record<string, any>;
  entityType: string;
  entityId: string;
  data: any;
  mode?: 'edit' | 'view';
}

It uses React.lazy for code-splitting large components (EntityAssets, EntityChatPanel) and dispatches to the correct block based on componentId. Unknown blocks show a warning fallback. Plugin blocks (matching plugin:*:*) are routed to PluginBlockIframe.

Registry API

The registry provides utility functions for working with blocks:

import { getAllBlocks, getBlockById, getBlocksByCategory } from '@/lib/component-block-registry';
 
// Get all blocks (built-in + plugin)
const blocks = getAllBlocks(pluginPanels);
 
// Look up a specific block
const block = getBlockById('entity-assets');
 
// Group blocks by category for palette display
const grouped = getBlocksByCategory(pluginPanels);
// { display: [...], media: [...], workflow: [...], plugin: [...] }

Key Files

AreaPath
Registrysrc/lib/component-block-registry.ts
Renderersrc/components/ComponentBlockRenderer.tsx
Block typessrc/types/layout.ts
Plugin iframesrc/components/blocks/PluginBlockIframe.tsx
Primary imagesrc/components/blocks/PrimaryImageBlock.tsx
Relationshipssrc/components/blocks/RelationshipsBlock.tsx
Read-only fieldssrc/components/blocks/ReadOnlyFieldRenderer.tsx
Designer palettesrc/components/LayoutDesigner/ComponentBlockPalette.tsx
Config panelsrc/components/LayoutDesigner/BlockConfigPanel.tsx