Skip to content

UI layer for Atscript

Atscript UI

Your types render themselves.

Forms, smart tables and multi-step HTTP flows — declared once in .as, rendered everywhere. No render boilerplate, no manual wiring, no schema drift.

<AsForm /><AsTable /><AsWfForm />
Atscript UI
01 · Forms

Forms that write themselves.

Labels, placeholders, field types and validation live on the model. Mount <AsForm> and you get a fully wired form — submit handler, per-field errors, structured arrays, nested objects.

Quick StartForms Overview
contact.as
atscript
@meta.label 'Contact'
@ui.submit.text 'Send'
export interface ContactForm {
  @meta.label 'Name'
  @ui.placeholder 'Jane Doe'
  @meta.required
  name: string

  @meta.label 'Email'
  @ui.placeholder 'jane@example.com'
  email: string.email

  @meta.label 'Message'
  @ui.type 'textarea'
  message: string
}
Contact
02 · Tables

Tables that filter, sort, paginate, scale.

Server-driven queries, full-text search, sorting, pagination, virtualised scrolling, column resize and reorder — wired up automatically from the same annotated type your DB uses.

Tables OverviewQuery Function
products.as
atscript
@meta.label 'Products'
@db.table 'products'
export interface ProductsTable {
  @meta.id
  id: number

  @meta.label 'Name'
  @db.index.fulltext 'search_idx'
  @ui.table.width '16em'
  name: string

  @meta.label 'Price'
  @db.amount.currency 'USD'
  @ui.table.width '8em'
  price: number.decimal

  @meta.label 'Status'
  status: 'active' | 'draft' | 'archived'

  @meta.label 'Updated'
  updatedAt: number.timestamp.updated
}
App.vue
vue
<AsTableRoot url="/api/products" v-slot="{ state }">
  <AsTable />
</AsTableRoot>
Status
active
NamePrice StatusUpdated
Mechanical keyboard$129.00active2d ago
Trackball mouse$59.99active3d ago
Aluminium stand$42.00active2w ago
Braided USB-C cable$14.50draft1w ago
03 · Workflows

Multi-step flows the server owns.

Login + MFA. Sign-up + verify. Invite + register. Long, branching journeys over plain HTTP — the server decides what comes next, the client just renders whatever it gets back.

Workflows OverviewHello World
login.workflow.ts
typescript
@Controller()
export class LoginFlow {
  @Workflow("auth/login")
  @WorkflowSchema([{ id: "creds" }, { id: "mfa" }])
  flow() {}

  @Step("creds")
  async creds(@FormInput input?: LoginForm) {
    if (!input) return requireInput(LoginForm);
    return { user: await authenticate(input) };
  }

  @Step("mfa")
  async mfa(@FormInput input?: MfaForm, @WfState user) {
    if (user.mfaEnabled && !input) return requireInput(MfaForm);
    return { finished: true, redirect: "/dashboard" };
  }
}
App.vue
vue
<AsWfForm path="/api/wf" name="auth/login" @finished="goHome" />
Credentials
2MFA code
3Dashboard
server decides next
Step 2 · Verify
04 · Theme

One theme. Every pixel.

Override vunor's palette, radius, fingertip heights, or icons once — every form input, table cell, dialog and step indicator inherits it. No per-component restyles.

primary
success
warning
danger
neutral
radius4 · 8 · 14
fingertipxs · s · m
SaveCancelMore
Theme & PaletteIconsas-* Shortcuts
05 · AI agent skill

Your AI already speaks it.

One command teaches Claude Code, Cursor, Windsurf, and Codex the entire UI stack — <AsForm>, <AsTable>, <AsWfForm>, theming, and the framework-agnostic core.

  • @ui.* annotations & field resolver
  • <AsForm> · <AsTable> · <AsWfForm>
  • moost-wf server workflows & presets
  • UnoCSS preset, vunor theming, icons
Companions
Learn about AI agent skills

Released under the MIT License.