Widgetly
Describe a widget in plain English, get a real interactive iOS widget
You describe a widget. A model returns a JSON widget spec. One universal SwiftUI renderer draws it as a real, interactive home-screen widget.
No code generation, ever
That constraint is the whole design. The obvious version of this product has an AI write Swift, which you then have to compile, sign, and ship through the App Store — which means it isn’t a product, it’s a tutorial.
Instead the spec is pure data: elements, variables, actions, tokens, and budgets, validated
with Zod at the API boundary. The same SpecRenderer that draws the preview inside the app
is the one compiled into the WidgetKit extension, so anything the AI designs is something the
extension can already draw. Nothing new ever needs to be built to support a new widget.
┌─────────────┐ prompt ┌──────────────────┐ Zod-validated spec
│ iOS app │ ──────────► │ POST /api/generate│ ─────────────┐
│ (chat UI) │ ◄────────── │ Vercel AI SDK │ │
└──────┬──────┘ spec └──────────────────┘ │
│ saves spec + variable values │
▼ │
┌─────────────────────┐ read ┌──────────────────────┐ │
│ App Group container │ ◄──────────── │ WidgetKit extension │ │
│ specs.json + state │ │ SAME SpecRenderer │◄┘
└─────────────────────┘ App Intents │ Button(intent:) taps │
▲──────────────────────────┴──────────────────────┘
Interactive, not decorative
The widgets respond to taps through App Intents — Button(intent:) writes back into the
shared App Group container, and the widget reloads with new state. A counter counts. A
checklist checks. That’s the difference between a widget and a screenshot pinned to your home
screen.
The spec is the contract
Everything lives or dies on the schema, so it’s the documented artefact: element types, variable binding, action semantics, the token set, and hard budgets on element count and nesting depth. Budgets matter more than they sound — WidgetKit has real memory ceilings, and a model with no limits will happily design something that gets killed on render.