the normal swiftui loop is powerful, but it is not light. every meaningful change wants a compiler, a signer, a target device, and a deploy step. studio has a different job: it needs to let a phone hold the sketch, the preview, and the iteration loop at the same time.
wren runtime sits between source text and native swiftui. it does not try to replace xcode, swift, or the app store pipeline. it gives studio a smaller runtime lane for prototypes, templates, and generated app surfaces.
parse once, render many times
wren starts with swift source and builds a program model from it. the runtime uses swift's parser stack where it can, folds operator sequences, collects declarations, and decides what should be rendered: a view struct, a main() function, or top-level script output.
let parsed = Parser.parse(source: source)
let folded = try OperatorTable.standardOperators.foldAll(parsed)
let program = try WrenProgram(source: source)
that program model is deliberately narrow. studio does not need every possible swift feature for the first preview pass. it needs enough of the language to express useful swiftui screens, plus clear errors when a sketch asks for something outside the runtime.
runtime values carry the sketch
once source becomes a program, wren evaluates it through runtime values. strings, numbers, colors, arrays, closures, bindings, and view values can move through the interpreter without pretending they are fully compiled swift types.
enum RuntimeValue {
case string(String)
case number(Double)
case closure(RuntimeClosure)
case view(AnyView)
case native(Any)
}
that type-erased layer is what lets studio keep the prototype fluid. the source can describe intent, while the runtime decides which pieces can become native swiftui immediately.
swiftui stays native
the important trick is that wren does not draw a fake ui. when interpreted code asks for Text, VStack, Button, List, navigation, shapes, or secondthumb components, the bridge maps those calls into real swiftui views.
case "VStack":
let children = try childViews(from: args, interpreter: interpreter)
return .view(
AnyView(VStack { childGroup(children) })
)
that keeps the preview honest. layout, typography, gestures, and platform behavior come from swiftui itself, while studio controls the faster edit-run loop around it.
state survives the refresh
a prototype stops feeling live if every button press resets the world. wren runtime keeps state boxes keyed by structural identity and bumps a generation counter when interpreted state changes. the host view observes that counter and re-renders the interpreted tree.
@Published private(set) var generation = 0
private var stateStore: [String: WrenStateBox] = [:]
func stateDidChange() {
guard !isRendering else { return }
generation += 1
}
that is the core of the feeling: source changes compile into a fresh program, but interaction state can persist across normal render passes. buttons, toggles, timers, and bindings can behave like a real app surface instead of a static mockup.
why studio needs this
studio is built for fast product thinking on-device. wren runtime gives it three useful constraints:
- the prototype can be swiftui-shaped without requiring a full xcode deploy for every edit.
- the preview can use native platform views instead of screenshots or a custom renderer.
- the runtime can expose only the pieces studio supports, which keeps generated code easier to explain and repair.
wren is the runtime. studio is the product. the split matters because studio can keep getting more capable without turning the runtime into a full compiler, and wren can stay focused on the narrow path that makes rapid swiftui prototyping feel good.
the result is not magic. it is a carefully scoped interpreter, a swiftui bridge, and a host view that knows when to rebuild. together, those pieces let studio turn a sketch into something you can tap quickly enough that the next idea is still fresh.