A UI + logic pair
Luca UI is declarative — not a second general-purpose language. Luca Code owns logic in .lucc; UI descriptions live in .lucu, joined by a small one-way seam.
App:
id = "app"
state:
visits = 0
Text:
id = "greeting"
text = visits
Button:
id = "visit"
label = "Visit"
events:
tap = record_visit
Paired .lucc logic runs on the real interpreter, and results re-enter UI state only via set/flush — there is no automatic .lucc→state protocol in this Beta. The seam reuses only the public library (run / run_with_input, LucaError, value and type primitives).
Declarative and state-driven
Output derives from state and declared properties — components change through state and events, never through refs.
State and bindings
Batched stores, literal initials, bare identifiers resolved at output.
State is a Value-typed store with Luca Code semantics. state: blocks hold literal initial values only; set type-checks immediately and stages, flush commits at once with one notification per listener per changed key. Bare-identifier property values resolve against committed state — undeclared names and wrongly-typed locked values are Luca errors at the binding site. Nothing resolves an identifier to a component instance.
.lucc→state protocol await the design record. The block shapes above are the 1.0 Beta minimal assumption, not final design.
Events and lifecycle
Name routing in, lifecycle diffs and cancellation underneath.
events: blocks route event = handler names only. Dispatch validates the target id and the declared event, then returns the handler name — it never touches state and never returns a component reference. The runtime swaps trees with mount/unmount diffs, merges committed state, prunes listeners for removed components, and cancels component-scoped work when its component leaves the tree.