Skip to main content

Field System

Fields define the inputs and outputs of operators, providing both data validation and UI hints for the node editor interface.

Field Fundamentals

Fields serve dual purposes:

  1. Data Schema: Validate and type-check data using Zod schemas
  2. UI Hints: Tell the interface how to render input controls
// Example field definition
const numberField = new NumberField(50, {
min: 0,
max: 100,
step: 1,
})

Core Field Types

Primitive Fields

NumberField

new NumberField(50, {
min: 0, // Minimum value
max: 100, // Maximum value
step: 1, // Increment step
})

BooleanField

new BooleanField(true)

ColorField

new ColorField('#ff0000', {
accessor: true, // Allow this field to connect to Accessor functions
transform: hexToColor // Convert to a [R, G, B] tuple array for Deck
})

Geometric Fields

PointField

new Point2DField([-74.0, 40.7], {
returnType: 'tuple', // [lng, lat] or 'object' for { lng, lat }
})

Vec2Field

new Vec2Field([0, 0], {
returnType: 'object', // { x, y } or 'tuple' for [x, y]
})

Data Fields

DataField

For open-ended data structures:

new DataField([]) // Any array or object

CompoundPropsField

For specific object schemas:

new CompoundPropsField({
view: z.object({
name: z.string(),
value: z.number()
})
})

Advanced Fields

CodeField

For JavaScript code input:

new CodeField('return data.length', {
language: 'javascript'
})

Also accepts SQL.

Field Options

Common Options

{
optional: true, // Allow undefined values
accessor: true, // Mark as accessor function
transform: (val) => val // Transform function
}

Validation

Fields use Zod schemas for runtime validation:

// Custom validation
new StringField('user@example.com', {
schema: z.string().email(), // Email validation
})

Field Connections

Creating Connections

// Connect output of nodeA to input of nodeB using fully qualified paths
nodeB.fields.input.addConnection('/container/nodeA', nodeA.fields.output)

Connection Rules

  • Type Compatibility: Output type must match input type
  • Single Input: Each input can have only one connection
  • Multiple Outputs: Outputs can connect to multiple inputs
  • No Cycles: Connections cannot create circular dependencies

Connection Validation

// Check if connection is valid
const canConnect = nodeA.fields.output.canConnectTo(nodeB.fields.input)

Custom Fields

Create custom field types by extending base classes:

export class CustomField extends Field<z.ZodString> {
createSchema(options: CustomFieldOptions) {
return z.string().min(options.minLength || 0)
}

static component = 'CustomFieldComponent' // UI component name
}

UI Components

Register custom UI components:

// In field-components.tsx

const CustomFieldComponent = ({ id, field, disabled }) => (
<input
value={field.value}
onChange={e => onChange(e.target.value)}
className="custom-input"
/>
)
export const inputComponents = {
CustomField: CustomFieldComponent
}

Best Practices

Field Design

  • Use descriptive names and labels
  • Provide sensible default values
  • Set appropriate validation constraints
  • Include helpful placeholder text

Type Safety

  • Leverage Zod schemas for validation
  • Use TypeScript for compile-time checking
  • Handle validation errors gracefully
  • Provide clear error messages

Performance

  • Avoid expensive validation in hot paths
  • Use memoization for complex transformations
  • Batch updates when possible
  • Minimize unnecessary re-renders

User Experience

  • Group related fields logically
  • Use appropriate input types for data
  • Provide visual feedback for validation
  • Support keyboard navigation