Visual Designer

Build applications, not mockups. The Delphi model, modernized.

Drag widgets onto the canvas. Wire event handlers. Add layout rules. Preview interactively. Export as a working React app. The distance from design to production is zero.


Widget palette

Pre-built UI components you drag onto the canvas. Each has typed inputs, events, and outputs.

WidgetInputsEventsOutputs
Buttonlabel, color, disabledclickisPressed, isHovered
TextInputvalue, placeholderchange, focus, blurtext, isFocused
Slidermin, max, value, stepchangevalue
Checkboxchecked, labelchangechecked
Dropdownoptions, selectedchangeselectedValue
Listitems, templateselectselectedItem
Paneltitle, collapsibletoggleisOpen
Imagesrc, fitloadnaturalWidth, naturalHeight

Widgets are components — same system as custom components. The built-in palette is a starting point, not a limit.


Three levels of logic

Level 1: Property toggle

No code. Click a button → toggle a panel's visibility. Wire it in the properties panel.

Level 2: Formula action

One expression. Click a button → set slider.value = 0. Reactive evaluation handles the rest.

Level 3: Script block

Full code. Click a button → fetch data from an API, parse it, update the UI.

const response = await fetch(api.url);
const data = await response.json();
dataTable.items = data.results;
loadingSpinner.visible = false;

Start at level 1. Graduate to level 3 when you need it. The system doesn't force a choice.


Layout system

Beyond absolute positioning — responsive containers that adapt to content and screen size.

Flex layout

Container (direction: row, gap: 12, align: center)
├── Avatar
├── Name
└── Badge

Grid layout

Container (columns: "1fr 2fr 1fr", rows: "auto")
├── Sidebar
├── Content
└── Panel

Absolute

Pixel-perfect placement. The default. Switch to flex or grid per container.

Formula-driven dimensions:

ContentPanel.width = $parent.width * 0.7
Sidebar.width = $parent.width - ContentPanel.width - 24


Preview mode

A dedicated mode that hides all editor chrome and runs your application interactively.

What happens:

  • Handles, selection outlines, gizmos disappear
  • Event handlers execute on user interaction
  • Reactive formulas evaluate
  • Layout rules apply
  • Cursor changes on interactive widgets

What doesn't happen:

  • No editing — canvas is locked
  • No tool switching
  • No property panel (unless you built one as a component)

Open in a separate window for side-by-side editing and preview.


The Delphi model, modernized

Visual Basic and Delphi proved that dragging components onto a canvas and wiring properties is the fastest way to build applications. That model died because the web won.

Formo brings it back — for the web.

Classic RADFormo
TButton on a FormButton component on canvas
TTimer (non-visual)Timer non-visual component
TDatabaseApiConnection non-visual component
Object InspectorProperties panel with formulas
OnClick event handlerClick event with code editor
Compiled .exeExported React app

Same speed. Modern output. Browser-native.


User journey

1. Draw shapes on canvas ← design tool
2. Add keyframe animation ← motion tool
3. Write formulas: x = mouse.x ← interactive tool
4. Group elements into Components ← building blocks
5. Wire components with formulas ← application logic
6. Export as React app ← production code

Each step is independently useful. Stop at step 1 — you have a design tool. Stop at step 3 — you have an interactive prototype. Go to step 6 — you have working software.


title: "Interactive slider"
description: "A slider widget that controls a shape's rotation"
nodes:
  - type: RECT, name: "Track", x: 200, y: 350, w: 200, h: 6, fill: "#BDC3C7", cornerRadius: 3
  - type: ELLIPSE, name: "Thumb", x: 200, y: 350, w: 20, h: 20, fill: "#3498DB"
  - type: RECT, name: "Box", x: 200, y: 180, w: 80, h: 80, fill: "#E74C3C"
formulas:
  - node: "Thumb", prop: "x", value: "clamp(mouse.x, 100, 300)"
  - node: "Box", prop: "rotation", value: "(Thumb.x - 100) / 200 * 360"
tools_visible: [select, play]
ui_visible: [properties, formulas]

ComponentsExportFormulas

Join the Beta →

Дальше →The Editor