Dala (dala v0.0.13)

Copy Markdown View Source

Dala — BEAM-on-device dalaile framework for Elixir.

OTP runs on the device. Screens are GenServers. The UI is rendered by Compose (Android) and SwiftUI (iOS) via a thin NIF. No server required.

Quick start

defmodule MyApp.HomeScreen do
  use Dala.Screen

  def mount(_params, _session, socket) do
    {:ok, Dala.Socket.assign(socket, :title, "Hello, Dala!")}
  end

  def render(assigns) do
    %{
      type:  :column,
      props: %{padding: :space_md},
      children: [
        %{type: :text, props: %{text: assigns.title, text_size: :xl}, children: []}
      ]
    }
  end
end

Plugin Architecture

Dala is designed as a runtime-extensible UI host where everything is just schema + commands + native capabilities. This is the same fundamental direction used by React Native Fabric, Flutter Engine, SwiftUI internals, Jetpack Compose runtime, VSCode extension host, and browser DOM.

Core Philosophy

Dala core knows almost nothing. Plugins self-describe themselves through:

  • Schema - component metadata (props, events, capabilities)
  • Commands - binary protocol for communication
  • Native capabilities - platform-specific rendering

Architecture

Dala itself only knows:

ThingResponsibility
TreeUI node graph
Diff engineupdates
Binary transportcommands
Schedulerasync/state
Registryplugin lookup
Layout protocolsizing/constraints
Event bridgeevent routing

Everything else — video, maps, charts, camera, ML view, custom renderer, AR, Metal canvas — becomes plugins.

Plugin Example

defmodule MyApp.VideoPlugin do
  use Dala.Plugin

  component "video" do
    prop "source", :string
    prop "autoplay", :bool
    prop "controls", :bool
    prop "volume", :f32

    event "progress"
    event "ended"

    native "ios", "DalaVideoView"
    native "android", "com.dala.video.VideoView"

    capability :gestures
    capability :accessibility
    capability :animation
  end
end

This is NOT UI code. This is metadata. Core Dala automatically generates:

  • Protocol encoders/decoders
  • Validators
  • Documentation
  • Registry entries

Generic Node Model

Everything becomes a generic node:

%Dala.Node{
  type: "video",
  props: %{source: "...", autoplay: true},
  children: []
}

Dala core NEVER special-cases video, maps, or charts. The same generic lifecycle applies to all plugins:

  • create/2
  • update/2
  • layout/2
  • event/3
  • dispose/1

Universal Command Stream

Dala core emits only generic operations:

  • CREATE_NODE
  • UPDATE_PROP
  • REMOVE_NODE
  • EMIT_EVENT
  • RUN_ANIMATION

Plugins interpret semantics. Core stays tiny.

Versioned Schema ABI

Plugins MUST declare versions for compatibility:

schema_version "1.0.0"
protocol_version 3
native_api_version "2.0.0"

Otherwise ecosystem explodes later.

Host/Runtime Separation

Plugins should NEVER directly access BEAM internals, scheduler state, or raw protocol sockets. Instead:

Plugin
   
Host API
   
Dala Runtime

Exactly like browser extensions.

Schema-First Architecture

Designing around schema-first (not widget-first, not native-view-first, not protocol-first) unlocks:

  • Tooling and validation
  • Code generation
  • Compatibility guarantees
  • Visual editors
  • Plugin ecosystems
  • AI-generated UIs
  • Hot reload
  • Documentation

Modules

  • Dala.App — app entry point and navigation declaration
  • Dala.Screen — screen behaviour and GenServer wrapper
  • Dala.Socket — assigns and navigation API
  • Dala.Theme — design token system
  • Dala.Renderer — component tree serialisation
  • Dala.Test — live device inspection and testing helpers
  • Dala.Preview (dev only) — preview UI in browser without device
  • Dala.Plugin — plugin system (schema, protocol, manifest)
  • Dala.Plugin.Registry — plugin lookup and capability negotiation

See the Getting Started guide to create your first app. See Architecture & Prior Art for how Dala compares to LiveView Native, Elixir Desktop, React Native, Flutter, and native development.

Summary

Functions

assign(socket, kw)

See Dala.Socket.assign/2.

assign(socket, key, value)

See Dala.Socket.assign/3.