Widget Registry Reference
SDK API reference for the widget registry — the canonical source of truth for all field widget types.
Location
Package: @biloxistudios/studiobrain-sdk
Source: packages/sdk/src/templates/widget-registry.ts
Import: import { registerWidget, getWidget, ... } from '@biloxistudios/studiobrain-sdk'
Types
WidgetDefinition
interface WidgetDefinition {
/** Unique widget identifier (e.g., 'color-palette', 'entity-selector') */
id: string;
/** Human-readable label */
label: string;
/** Short description of what this widget does */
description: string;
/** Grouping category for UI organization */
category: WidgetCategory;
/** Where this widget comes from */
source: 'builtin' | 'plugin' | 'community';
/** The JSON Schema type of the value this widget produces */
value_type?: 'string' | 'number' | 'boolean' | 'array' | 'object';
/** Whether this widget accepts an options list (for select/radio/checkbox) */
accepts_options?: boolean;
/**
* Name patterns for inference. When inferWidgetFromName() sees a field name
* matching any of these patterns, it suggests this widget. Patterns are
* case-insensitive regex fragments tested against the field name.
*/
name_patterns?: string[];
}WidgetCategory
type WidgetCategory =
| 'text'
| 'number'
| 'selection'
| 'date'
| 'color'
| 'entity'
| 'array'
| 'media'
| 'document'
| 'spatial'
| 'layout'
| string; // extensible for pluginsThe string union member allows plugins to introduce custom categories without modifying the SDK.
Functions
registerWidget(widget)
Register a single widget definition. If a widget with the same id already exists, it is replaced.
function registerWidget(widget: WidgetDefinition): voidExample:
import { registerWidget } from '@biloxistudios/studiobrain-sdk';
registerWidget({
id: 'recipe-timer',
label: 'Recipe Timer',
description: 'Duration input with cooking presets',
category: 'number',
source: 'plugin',
value_type: 'number',
name_patterns: ['cook_time', 'prep_time', 'bake_time', 'timer'],
});registerWidgets(widgets)
Batch-register multiple widgets. Used by plugin loaders to register all widgets from a plugin manifest at once.
function registerWidgets(widgets: WidgetDefinition[]): voidExample:
import { registerWidgets } from '@biloxistudios/studiobrain-sdk';
// Called by the plugin loader after parsing plugin.json
registerWidgets([
{
id: 'music-key',
label: 'Musical Key',
description: 'Key signature selector with circle-of-fifths UI',
category: 'selection',
source: 'plugin',
value_type: 'string',
accepts_options: false,
name_patterns: ['key_signature', 'musical_key', 'song_key'],
},
{
id: 'bpm-input',
label: 'BPM Input',
description: 'Tempo input with tap-to-set and common presets',
category: 'number',
source: 'plugin',
value_type: 'number',
name_patterns: ['bpm', 'tempo'],
},
]);getWidget(id)
Look up a widget definition by ID. Returns undefined for unknown widgets.
Unknown widgets are valid — field_config.widget passes through verbatim. This function is for metadata lookup, not gatekeeping.
function getWidget(id: string): WidgetDefinition | undefinedgetWidgetValueType(id)
Get the value_type for a widget ID. Returns 'string' for unknown widgets.
function getWidgetValueType(id: string): stringThis is the function used by inferField() and templateToEntitySchema() to determine the JSON Schema type when a widget is resolved.
getAllWidgets()
Get all registered widgets (builtins + plugins). Returns a copy of the internal array.
function getAllWidgets(): WidgetDefinition[]getWidgetsByCategory()
Get all registered widgets grouped by their category value.
function getWidgetsByCategory(): Record<string, WidgetDefinition[]>inferWidgetFromName(fieldName)
Match a field name against all registered name_patterns. Returns the first matching widget, or undefined if no pattern matches.
function inferWidgetFromName(fieldName: string): WidgetDefinition | undefinedPatterns are compiled once on registration and cached. Each widget’s name_patterns array is joined with | into a single case-insensitive regex.
resetRegistry()
Reset the registry to builtins only. This is a test utility — do not call in production code.
function resetRegistry(): voidfield_config.widget Pass-Through
The registry does not restrict what widget IDs can appear in field_config.widget. Any string is valid:
field_config:
my_field:
widget: some-future-widget-that-doesnt-exist-yetWhen the frontend encounters an unknown widget ID, it falls back to rendering a text input. The registry is consulted only for:
- Value type inference —
getWidgetValueType()returns'string'for unknown IDs - Name pattern inference — only registered widgets participate in
inferWidgetFromName() - Layout Designer UI — the widget picker shows registered widgets with labels and categories
This design means templates can reference plugin widgets before the plugin is installed. The field simply renders as a text input until the plugin is loaded.
Integration with Other SDK Functions
templateToFormFields()
Located in src/templates/form-fields.ts. Converts template YAML into form field descriptors. Checks field_config.widget first, then falls back to the TYPE_MAP for the template field type. Does not call the widget registry directly — it trusts the widget string from field_config.
templateToEntitySchema()
Located in src/schemas/entity-schema.ts. Builds a full EntitySchema from a template. For each field:
- Calls
inferField(key, value)which internally callsinferWidgetFromName(key)from the registry - If
field_config[key].widgetexists, it overrides the inferredui_component
inferField()
Located in src/templates/field-inference.ts. Infers field type and UI widget from a field name and sample value. Priority:
- Array with string elements ->
multi-select - Boolean ->
boolean - Number -> check registry patterns, fallback to
number - String -> check registry patterns, length-based heuristic fallback
- Object -> check registry patterns, fallback to
textarea
Built-in Widget Table
The complete set of 48 built-in widgets with their registry metadata:
Text & Content (9)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
text | Text | string | — | — |
textarea | Textarea | string | — | — |
string | String | string | — | — |
rich-text | Rich Text | string | — | — |
code | Code | string | — | — |
read-only | Read Only | string | — | — |
url | URL | string | — | url, website, homepage, link |
email | string | — | email | |
slug | Slug | string | — | slug |
Numbers & Ranges (7)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
number | Number | number | — | — |
range | Range | number | — | — |
rating | Rating | number | — | rating, score, stars |
percentage-group | Percentage Group | object | — | — |
angle | Angle | number | — | angle, rotation, heading |
duration | Duration | number | — | duration, length, runtime |
year | Year | number | — | year, founded, established |
Selection (7)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
select | Select | string | yes | — |
multi-select | Multi Select | array | yes | — |
checkbox | Checkbox | boolean | — | — |
checkbox-group | Checkbox Group | array | yes | — |
radio-group | Radio Group | string | yes | — |
toggle | Toggle | boolean | — | — |
icon-picker | Icon Picker | string | — | icon |
Date & Time (5)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
date | Date | string | — | date, birthday, born |
datetime | Date & Time | string | — | — |
time | Time | string | — | — |
date-range | Date Range | object | — | date_range, period, timespan |
year | Year | number | — | year, founded, established |
Color (3)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
color-picker | Color Picker | string | — | color, colour |
color-palette | Color Palette | string | yes | — |
color-group | Color Group | object | — | colors, colour_scheme, palette |
Entity References (2)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
entity-selector | Entity Selector | string | — | faction, ally, enemy, parent, owner, creator |
ordered-entity-list | Ordered Entity List | array | — | — |
Arrays & Structures (7)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
tag-input | Tag Input | array | — | tags, keywords, labels |
textarea-array | Textarea Array | array | — | — |
object-array | Object Array | array | — | — |
nested-object | Nested Object | object | — | — |
key-value | Key-Value | object | — | metadata, properties, attributes |
ordered-list | Ordered List | array | — | — |
percentage-group | Percentage Group | object | — | — |
Media References (6)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
asset-ref | Asset Reference | string | — | image, avatar, portrait, thumbnail, asset |
image-ref | Image Reference | string | — | photo, picture, banner, cover |
audio-ref | Audio Reference | string | — | audio, sound, music, track |
video-ref | Video Reference | string | — | video, clip, footage |
model-3d-ref | 3D Model Reference | string | — | model_3d, mesh, fbx, gltf |
file-ref | File Reference | string | — | file, attachment, document |
Spatial (2)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
vector2 | Vector2 | object | — | position, coordinates, point |
vector3 | Vector3 | object | — | position_3d, location_3d |
Layout (1)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
heading | Heading | — | — | — |
Document (2)
| ID | Label | value_type | accepts_options | name_patterns |
|---|---|---|---|---|
nested-section | Nested Section | object | — | — |
doc-ref | Document Reference | string | — | document, doc, lore |
Related Documentation
- Widget System Architecture — resolution pipeline, extension model
- Field Widgets Reference — per-widget options, value formats, YAML examples
- Building Field Widgets — plugin development tutorial