Write applications as precise sentences.
Laygent compiles a deliberately exact English language into React + TypeScript or HTML + CSS + JavaScript, plus Supabase schema migrations, authentication, storage policies, client operations, and Edge Functions. Every accepted phrase has one defined meaning.
The frozen v1 release
Laygent Language v1.0.0 is the immutable MVP grammar used for documentation, evaluation, and the next training-data phase. An incompatible compiler or grammar change requires a new language version; v1 is protected by an implementation hash and artifact manifest.
The mental model
A project is a tree. A page is the root. Containers hold named children. Leaf elements display text or accept input. Styles describe those elements. Interaction sentences connect user events to browser actions.
pricing_card is valid; pricing-card and 2nd_card are not.Sentence grammar
Export formats
Choose HTML / CSS / JS or React + TypeScript beside Export in Studio. Both use the same validated language, styles, and browser behaviors. The React ZIP includes React page components, TypeScript behavior modules, CSS, Vite configuration, and your original source.
npm install
npm run dev
npm run build
The production build is in dist/. Each page has its own HTML entry point. React creates the initial element tree, and the shared Laygent runtime manages subsequent state and DOM interactions; this version uses dynamic TypeScript types rather than converting each state into a React hook. Local assets must be copied into public/ at their referenced paths; remote assets and imports retain their URLs.
From the command line: python plain.py project.plain output --format react-ts. Omit --format for the original HTML export.
Each instruction occupies one line and ends with a period. The compact declaration is the normal writing form:
Create <type> <name> [displaying "text"] [containing children] [with properties].
Clauses appear in that order. Properties after with may be separated by commas, by a final and, or by both. All of these are equivalent: direction vertical, gap 4 pixels, direction vertical and gap 4 pixels, and direction vertical, and gap 4 pixels.
For input-like sentences, a repeated introducer such as with placeholder "Search" with background black is normalized too, although the single-with form remains preferred.
Create card profile_card containing profile_name and profile_role with padding 24 pixels, gap 8 pixels, background white, border radius 16 pixels, and shadow medium.
Create heading profile_name displaying "Ada Lovelace" with font size 24 pixels, and font weight 800.
Create text profile_role displaying "Systems designer" with text color gray.
Element library
| Type | Generated HTML | Purpose |
|---|---|---|
| page | <main> | A page root. Create one or more. |
| container | <div> | General layout grouping. |
| section | <section> | A meaningful region of a page. |
| navigation | <nav> | Navigation controls and links. |
| card | <article> | A self-contained content surface. |
| heading | <h1> | Prominent text. |
| text | <p> | Body copy, labels, metadata, or values. |
| button | <button> | Clickable browser action. |
| link | <a> | A destination link; requires a destination. |
| image | <img> | An image; requires source and description. |
| input | <input> | A single text field. |
| form | <form> | Groups inputs and can be bound to auth, database mutations, or Edge Functions. |
| label | <label> | An accessible label for a field. |
| textarea | <textarea> | Multi-line text input. |
| list | <ul> | A semantic list containing items. |
| item | <li> | A list item that may contain other elements. |
| divider | <hr> | A thematic visual divider. |
| select | <select> | A selection control containing options. |
| option | <option> | A selectable value inside a select. |
| icon | <img> | A local or remote icon; requires source and description. |
| video | <video> | Video media and nested source elements. |
| audio | <audio> | Audio media and nested source elements. |
| custom | Chosen tag | Any native or custom HTML tag via Create custom element. |
Layout properties
| Phrase | Meaning |
|---|---|
| viewport fill | Full width with at least the height of the viewport. Pages only. |
| direction vertical | horizontal | Stacks children using flexbox. |
| layout grid | Changes a container to CSS Grid. |
| grid columns 3 | Creates three equal grid columns. |
| width | height fill | Sets the dimension to 100%. |
| width | height content | Uses automatic content size. |
| width 320 pixels | 50 percent | Uses an exact or relative dimension. |
| minimum | maximum width | height <size> | Sets sizing boundaries. |
| gap 20 pixels | Space between children. |
| alignment start | center | end | stretch | Cross-axis child alignment. |
| distribution start | center | end | between | around | evenly | Main-axis child distribution. |
| wrap enabled | disabled | Controls flex wrapping. |
| overflow visible | hidden | auto | scroll | Controls overflow behavior. |
| position relative | absolute | fixed | sticky | Sets positioning mode. |
| top | right | bottom | left 0 pixels | Offsets a positioned element. Negative numbers are accepted. |
Appearance properties
| Phrase | Example or meaning |
|---|---|
| background <color> | background white |
| gradient <color> to <color> right | left | down | up | gradient navy to black down |
| text color <color> | Sets foreground color. |
| padding 24 pixels | Equal padding on every side. |
| horizontal | vertical padding 20 pixels | Axis-specific padding. |
| margin 20 pixels | auto | Outer spacing or horizontal centering. |
| border 1 pixels <color> | Solid border. |
| border radius 16 pixels | Rounded corners. |
| shadow none | small | medium | large | xlarge | Curated elevation levels. |
| opacity 80 percent | Value from 0 through 100. |
| backdrop blur 16 pixels | Blurs content behind an overlay. |
Colors
Use a six-digit hex value such as #111827, or one of: white, black, gray, light gray, dark gray, red, green, blue, yellow, orange, purple, slate, navy, indigo, cyan, teal, emerald, rose, pink, transparent.
Typography
Create heading title displaying "An exact title" with text color black, font size 48 pixels, font weight 800, line height 1.1, letter spacing -1 pixels, and text alignment center.
Available phrases: font size, font weight 400|500|600|700|800, numeric line height, pixel letter spacing, text alignment left|center|right, and text decoration none|underline.
Element attributes and forms
Create link guide_link displaying "Read the guide" with destination "#guide".
Create image cover with source "cover.jpg", and description "A dark sculptural chair".
Create input email with placeholder "Email address".
A link must have destination. An image must have both source and accessible description. An input may have a placeholder.
Create form contact_form containing email_label, email, message, and submit_button.
Create label email_label displaying "Email address".
email_label describes email.
Create input email with placeholder "you@example.com".
email input type is email.
email is required.
Create textarea message with placeholder "Your message".
message is required.
Create button submit_button displaying "Send".
submit_button submits form.
When contact_form is submitted, show confirmation.
Input types include text, email, number, password, date, checkbox, radio, range, color, file, URL, telephone, search, time, datetime-local, and hidden. Fields support required, disabled, read-only, multiple, field names, autocomplete, patterns, accepted file types, numeric boundaries, steps, and length boundaries. Native validation can drive explicit success and error elements.
Motion and hover states
Create button action displaying "Continue" with background indigo, text color white, padding 14 pixels, border radius 10 pixels, cursor pointer, transition normal, hover background purple, and hover lift 4 pixels.
Transitions are fast, normal, or slow. Hover supports background changes and upward lift. Entry animation presets are entry fade 400 milliseconds, entry rise 500 milliseconds, and entry scale 350 milliseconds. Elements also support scale, rotation, z-index, and aspect ratio.
Browser interactions
Behavior is deterministic. The source and target must be on the same page, except navigation, whose target is a page name.
modal starts hidden.
When open_button is clicked, show modal.
When close_button is clicked, hide modal.
When menu_button is clicked, toggle menu.
When settings_button is clicked, navigate to settings.
When Escape is pressed, hide modal.
State, bindings, and conditions
State gives the page memory while it is open. A state holds a number, Boolean, or text value. Bindings automatically redraw visible text after the state changes.
Create state count with value 0.
Create page counter containing count_value, add_button, remove_button, and empty_message.
Create heading count_value.
Create button add_button displaying "Add".
Create button remove_button displaying "Remove".
Create text empty_message displaying "The count is zero".
count_value displays state count.
When add_button is clicked, increase count by 1.
When remove_button is clicked, decrease count by 1.
Show empty_message when count equals 0.
Use set for direct assignment, increase and decrease for numeric state, and set query from its value on an input change. Conditions support equals and does not equal.
Reusable styling
Create card primary_card with padding 24 pixels, background white, border radius 16 pixels, and shadow medium.
Create card secondary_card.
secondary_card uses styles from primary_card.
The target receives the source element’s styles and hover rules. Properties explicitly written on the target override copied properties.
Responsive rules
Responsive instructions come after declarations and use a maximum screen width:
On screens below 900 pixels, layout direction is vertical.
On screens below 900 pixels, sidebar width is fill.
On screens below 760 pixels, cards grid columns is 1.
On screens below 760 pixels, cards gap is 12 pixels.
Responsive rules currently support direction, width, gap, and grid-column changes.
Multiple pages
Create multiple page roots in the same source. Each element belongs to exactly one page tree. Navigation compiles to the correct sibling page folder.
Create page home containing home_title and settings_button with viewport fill.
Create heading home_title displaying "Home".
Create button settings_button displaying "Settings".
When settings_button is clicked, navigate to settings.
Create page settings containing settings_title and home_button with viewport fill.
Create heading settings_title displaying "Settings".
Create button home_button displaying "Return home".
When home_button is clicked, navigate to home.
Advanced controlled composition
Advanced behavior remains compiled controlled English. Laygent models reusable classes, element states, keyframes, DOM actions, timers, persistence, and requests as explicit sentences. Unrestricted CSS and JavaScript blocks are rejected.
Custom semantic elements
Create custom element native_dialog as dialog.
native_dialog attribute "aria-modal" is "true".
native_dialog attribute "data-variant" is "luxury".
Any valid custom or native HTML tag can participate in containment, styling, text, attributes, and interactions. The element name still becomes its generated ID.
Arbitrary properties and attributes
hero CSS property "clip-path" is "polygon(0 0, 100% 0, 92% 100%, 0 100%)".
gallery CSS property "container-type" is "inline-size".
menu attribute "aria-label" is "Primary navigation".
Reusable styles and pseudo-states
Create style class selected.
selected property "outline" is "2px solid #4f46e5".
Apply style class selected to hero.
Create style rule hero_hover for hero when hovered.
hero_hover property "transform" is "translateY(-6px) scale(1.02)".
Design tokens, selectors, and media conditions
Create design token brand with value "#4f46e5".
hero property "background" uses token brand.
Create style rule list_items for direct children of product_list.
list_items property "padding" is "12px".
Create style rule first_item for child number 1 of product_list.
first_item property "font-weight" is "700".
Create style rule compact_panel for panel.
compact_panel property "padding" is "12px".
Use style rule compact_panel on screens below 700 pixels.
Named keyframe animation
Create animation reveal.
At 0 percent, reveal property "opacity" is "0".
At 0 percent, reveal property "transform" is "translateY(24px)".
At 100 percent, reveal property "opacity" is "1".
At 100 percent, reveal property "transform" is "translateY(0)".
hero plays reveal over 700 milliseconds once.
Controlled browser actions
When save_button is clicked, set status_text text to "Saved".
When menu_button is clicked, set menu attribute "aria-expanded" to "true".
When reset_button is clicked, remove menu attribute "aria-expanded".
When select_button is clicked, toggle style class selected on product_card.
Persist state theme in local storage.
On page dashboard, every 1000 milliseconds, increase elapsed by 1.
When load_button is clicked, request JSON from "/data.json" into results.
Collections and request lifecycle
Create collection products with values "Chair", "Lamp", "Table".
Render collection products inside product_list as list items.
loader starts hidden.
error_panel starts hidden.
When load_button is clicked, request JSON from "/products.json" into products while showing loader and show error_panel if it fails.
Style rules can target descendants, direct children, numbered children, before/after pseudo-elements, and parents containing another named element. Media conditions cover minimum and maximum width, dark mode, reduced motion, landscape, and print.
Parameterized components
Define component feature_card with parameters title and copy.
Create card root containing title_text and copy_text with padding 24 pixels.
Create heading title_text displaying "{{title}}".
Create text copy_text displaying "{{copy}}".
End component.
Create component feature_card as speed_feature with title "Fast", copy "Compiled locally".
Every component declares a root. Instances are expanded at compile time with isolated identifiers, then pass through the same validation as handwritten elements.
Filtering, sorting, and template loops
Create state query with value "".
Create collection products with values "Lamp", "Chair", "Table".
Create filtered collection matching from products containing state query.
Create sorted collection ordered from matching ascending.
Create container results containing product_template.
Create card product_template containing product_name.
Create text product_name.
product_name displays collection item.
Render collection ordered inside results using template product_template.
Drag, drop, pointers, and gestures
Make tile draggable within board.
Make children of task_list reorderable.
When tile is dropped on drop_zone, move it into the target.
When product_card is swiped left, show card_actions.
When product_card is long pressed, toggle context_menu.
Files, assets, icons, and lazy loading
Create icon logo_icon.
logo_icon source is "assets/logo.svg".
logo_icon description is "Company logo".
logo_icon loads lazily.
Create input upload.
upload input type is file.
upload accepts file types "image/*".
When upload changes, preview selected image in preview.
Import stylesheet from "https://cdn.example.com/icons.css".
Import JavaScript module from "./widgets.js".
Complete syntax index
This is the canonical inventory of sentence families accepted by the current compiler. Angle brackets describe a value you replace. A vertical bar means choose one option. Square brackets indicate an optional clause; do not type the brackets.
Project, declarations, and containment
Create <type> <name>.
Create <type> <name> displaying "<text>".
Create <type> <name> containing <child>, <child>, and <child>.
Create <type> <name> [displaying "<text>"] [containing <children>] with <property>, and <property>.
<parent> contains <child>, <child>, and <child>.
<textual-element> displays "<text>".
<page> fills the viewport.
<element> starts hidden.
Valid names match [A-Za-z][A-Za-z0-9_]*, are case-insensitive, and become lowercase HTML IDs. Valid types are page, container, section, navigation, card, heading, text, button, link, image, input, form, label, textarea, list, item, divider, select, option, icon, video, audio, and custom.
Dimensions and layout
<container> direction is vertical|horizontal.
<element> width is fill|content|<number> pixels|<number> percent.
<element> height is fill|content|<number> pixels|<number> percent.
<element> minimum width is <size>.
<element> maximum width is <size>.
<element> minimum height is <size>.
<element> maximum height is <size>.
<container> layout is grid.
<container> grid columns is <positive-integer>.
<container> gap is <number> pixels.
<container> alignment is start|center|end|stretch.
<container> distribution is start|center|end|between|around|evenly.
<container> wrap is enabled|disabled.
<element> overflow is visible|hidden|auto|scroll.
<element> position is relative|absolute|fixed|sticky.
<element> top|right|bottom|left is <signed-number> pixels.
<element> z index is <signed-integer>.
<element> aspect ratio is <number> by <number>.
<image> object fit is cover|contain|fill|none.
Appearance and typography
<element> background is <color>.
<element> gradient is <color> to <color> right|left|down|up.
<element> text color is <color>.
<element> padding is <number> pixels.
<element> horizontal padding is <number> pixels.
<element> vertical padding is <number> pixels.
<element> margin is <number> pixels|auto.
<element> border is <number> pixels <color>.
<element> border radius is <number> pixels.
<element> shadow is none|small|medium|large|xlarge.
<element> opacity is <0-100> percent.
<element> backdrop blur is <number> pixels.
<textual-element> font size is <number> pixels.
<textual-element> font weight is 400|500|600|700|800.
<textual-element> line height is <number>.
<textual-element> letter spacing is <signed-number> pixels.
<textual-element> text alignment is left|center|right.
<textual-element> text decoration is none|underline.
<element> cursor is pointer.
<element> scale is <number>.
<element> rotation is <signed-number> degrees.
Links, media, attributes, and native controls
<link> destination is "<url-or-path>".
<image|icon|video|audio> source is "<url-or-path>".
<image|icon> description is "<accessible-description>".
<input|textarea> placeholder is "<text>".
<input> input type is text|email|number|password|date|checkbox|radio|range|color|file|url|tel|search|time|datetime-local|hidden.
<label> describes <input-or-textarea>.
<option> option value is "<value>".
<input|textarea|select> field name is "<name>".
<input|textarea> autocomplete is "<browser-autocomplete-value>".
<input> pattern is "<regular-expression>".
<input> accepts file types "<accept-value>".
<element> attribute "<attribute-name>" is "<value>".
<element> is disabled.
<element> is read only.
<element> allows multiple values.
<option> is selected.
<video|audio> shows controls.
<video|audio> plays automatically.
<video|audio> loops.
The generic attribute sentence accepts standards-based attributes including ARIA and data-*. The compiler reserves id because the element name determines it.
Forms and validation
<input|textarea> is required.
<button> submits form.
<input|textarea> minimum is <number>.
<input|textarea> maximum is <number>.
<input|textarea> step is <number>.
<input|textarea> minimum length is <number>.
<input|textarea> maximum length is <number>.
When <form> is submitted, validate it and show <success> or show errors in <error>.
When <file-input> changes, preview selected image in <image>.
Preset and named animation
<element> transition is fast|normal|slow.
<element> hover background is <color>.
<element> hover lift is <number> pixels.
<element> enters with fade|rise|scale over <milliseconds> milliseconds.
Create animation <name>.
At <0-100> percent, <animation> property "<css-property>" is "<css-value>".
<element> plays <animation> over <milliseconds> milliseconds once|forever.
Responsive properties and media conditions
On screens below <pixels> pixels, <container> direction is vertical|horizontal.
On screens below <pixels> pixels, <element> width is <size>.
On screens below <pixels> pixels, <container> gap is <number> pixels.
On screens below <pixels> pixels, <container> grid columns is <integer>.
Use style rule <rule> on screens below <pixels> pixels.
Use style rule <rule> on screens above <pixels> pixels.
Use style rule <rule> when dark mode is preferred.
Use style rule <rule> when reduced motion is preferred.
Use style rule <rule> in landscape orientation.
Use style rule <rule> when printing.
Styles, selectors, design tokens, and CSS coverage
<element> uses styles from <element>.
<element> CSS property "<css-property>" is "<css-value>".
Create style class <name>.
Create style rule <name> for <element>.
Create style rule <name> for <element> when hovered|focused|active|disabled.
Create style rule <name> for descendants of <element>.
Create style rule <name> for direct children of <element>.
Create style rule <name> for child number <integer> of <element>.
Create style rule <name> for <element> before|after it.
Create style rule <name> for <element> when it contains <element>.
<style-rule> property "<css-property>" is "<css-value>".
Apply style class <class> to <element>.
Create design token <name> with value "<css-value>".
<element-or-rule> property "<css-property>" uses token <token>.
When <element> is clicked, set design token <token> to "<css-value>".
Generic CSS properties make the declaration vocabulary broad without accepting an unrestricted CSS block. Selector shapes remain controlled and validated.
Custom HTML and external resources
Create custom element <name> as <html-tag>.
Import stylesheet from "<url-or-path>".
Import JavaScript module from "<url-or-path>".
<image|icon|element> loads lazily.
Images, icons, fonts, stylesheets, modules, video, and audio may use local relative paths or remote URLs. Exported projects retain these references; the compiler does not download or embed them.
Scalar state, persistence, and visibility
Create state <name> with value <number>|true|false|"<text>".
<heading|text|button|label> displays state <state>.
Show <element> when <state> equals <value>.
Show <element> when <state> does not equal <value>.
Persist state <state> in local storage.
When <element> is clicked|submitted|changes, increase <state> by <number>.
When <element> is clicked|submitted|changes, decrease <state> by <number>.
When <element> is clicked|submitted|changes, set <state> to <value>.
When <input> changes, set <state> from its value.
On page <page>, every <milliseconds> milliseconds, increase|decrease <state> by <number>.
Collections, expressions, and rendering loops
Create collection <name> with values "<item>", "<item>".
Create filtered collection <name> from <collection> containing state <query-state>.
Create sorted collection <name> from <collection> ascending|descending.
Render collection <collection> inside <container> as text|list items.
Render collection <collection> inside <container> using template <element>.
<textual-element> displays collection item.
<textual-element> displays collection field <field>.
A template must already be inside its output container. The compiler captures it, clones it for each value, removes duplicated IDs, and fills marked item or field elements. JSON requests may replace a collection with an array of objects.
Events and element actions
When <element> is clicked|submitted|changes, show|hide|toggle <element>.
When <element> is clicked, navigate to <page>.
When Escape is pressed, hide <element>.
When <element> <event>, set <element> text to "<text>".
When <element> <event>, set <element> attribute "<name>" to "<value>".
When <element> <event>, remove <element> attribute "<name>".
When <element> <event>, add|remove|toggle style class <class> on <element>.
When <element> <event>, focus <element>.
When <element> <event>, scroll to <element>.
When <element> <event>, copy text from <element>.
When <element> <event> and state <state> equals|does not equal <value>, show|hide|toggle <element>.
When Enter|Escape|Space|ArrowUp|ArrowDown|ArrowLeft|ArrowRight is pressed on <element>, show|hide|toggle|focus <element>.
Where <event> appears, accepted phrases are is clicked, is submitted, changes, is focused, loses focus, is entered, and is left. Submitted events require a form; change events require an input or textarea.
Requests and lifecycle UI
When <element> <event>, request JSON from "<url>" into <state-or-collection>.
When <element> <event>, request JSON from "<url>" into <state-or-collection> while showing <loader> and show <error> if it fails.
Requests use browser fetch with GET, require a successful HTTP response, decode JSON, update state, and redraw bindings. Lifecycle form shows the loader during the request, hides the error before starting, and reveals it after failure.
Drag, drop, reordering, and gestures
Make <element> draggable.
Make <element> draggable within <container>.
Make children of <container> reorderable.
When <element> is dropped on <container>, move it into the target.
When <element> is swiped left|right|up|down, show|hide|toggle <element>.
When <element> is long pressed, show|hide|toggle <element>.
Pointer dragging uses pointer capture and optional boundary clamping. Drop zones and reordering use native drag events. A swipe requires approximately 45 pixels of movement; long press fires after approximately 550 milliseconds.
Parameterized components
Define component <component> [with parameters <parameter>, <parameter>].
<ordinary Laygent sentences creating an element named root>
End component.
Create component <component> as <instance> [with <parameter> "<value>", <parameter> "<value>"].
Use {{parameter}} inside component text and property strings. Each definition must create root. The root becomes the instance name; every other local element becomes instance_localname. All parameters must be supplied exactly once.
Multiple pages and generated files
One page:
output/index.html
output/styles.css
output/script.js only when behavior exists
Multiple pages:
output/<page>/index.html
output/<page>/styles.css
output/<page>/script.js only when behavior exists
Navigation between generated pages uses sibling page folders. Each page receives only its own element rules and interactions, plus global tokens, animations, style classes, and imported resources.
Explicitly rejected syntax
Begin custom CSS. ← rejected
Begin custom JavaScript. ← rejected
Laygent intentionally rejects unrestricted code blocks. Add missing capability as a controlled compiler primitive so it remains analyzable, validateable, and optimizable.
Explained examples
A responsive card row
Create page dashboard containing cards with viewport fill, background light gray, and padding 32 pixels.
Create section cards containing revenue and customers with layout grid, grid columns 2, and gap 20 pixels.
Create card revenue containing revenue_label and revenue_value with padding 24 pixels, gap 8 pixels, background white, border radius 16 pixels, shadow medium, transition normal, and hover lift 4 pixels.
Create text revenue_label displaying "Revenue" with text color gray.
Create heading revenue_value displaying "$84,240" with font size 32 pixels, and font weight 800.
Create card customers containing customers_label and customers_value with padding 24 pixels, gap 8 pixels, background white, border radius 16 pixels, and shadow medium.
Create text customers_label displaying "Customers" with text color gray.
Create heading customers_value displaying "2,429" with font size 32 pixels, and font weight 800.
On screens below 700 pixels, cards grid columns is 1.
The page owns the section, the section owns both cards, and each card owns its text. Grid creates the desktop row; one responsive sentence stacks it on smaller screens.
A functional modal
Create page product containing open_button and modal with viewport fill, alignment center, and distribution center.
Create button open_button displaying "View details" with background black, text color white, padding 14 pixels, border radius 10 pixels, and cursor pointer.
Create container modal containing modal_card with position fixed, top 0 pixels, right 0 pixels, bottom 0 pixels, left 0 pixels, background dark gray, alignment center, distribution center, and padding 24 pixels.
Create card modal_card containing modal_title, modal_copy, and close_button with width fill, maximum width 500 pixels, padding 28 pixels, gap 16 pixels, background white, border radius 16 pixels, and shadow xlarge.
Create heading modal_title displaying "Object details" with font size 28 pixels, and font weight 800.
Create text modal_copy displaying "A deterministic modal generated from controlled English." with text color gray.
Create button close_button displaying "Close" with background black, text color white, padding 12 pixels, border radius 10 pixels, and cursor pointer.
modal starts hidden.
When open_button is clicked, show modal.
When close_button is clicked, hide modal.
When Escape is pressed, hide modal.
Compiler rules and useful errors
- Every project needs at least one page.
- Every element name must be unique across the project.
- Every non-page element must have exactly one parent.
- A parent cannot contain itself or create a containment cycle.
- A non-container cannot contain children.
- An interaction cannot manipulate an element on another page.
- Unknown words, unsupported properties, missing periods, and invalid values produce a line-numbered error.
Full-stack architecture
Laygent does not create or own cloud accounts. It writes a conventional, portable source project. You create the Supabase and Vercel projects yourself, review the generated migration and policies, add environment values, and deploy from the exported folder.
Use Supabase backend.
This sentence activates backend export. It adds a migration, client integration, environment template, Supabase configuration, setup guide, and Vercel configuration. Backend sentences may appear anywhere at top level, but keeping them after the UI makes projects easier to read.
Project variables
The key icon in Studio opens the project Variables overlay. Laygent derives required values from the source. SUPABASE_URL and SUPABASE_PUBLISHABLE_KEY are managed automatically when Laygent creates or connects the Supabase project, so they never block export or publishing. You may still enter them for a manually configured standalone export. User-owned values such as secret PAYMENT_SERVICE_URL remain required and server-only.
Public configuration is remembered per project on the current device. Secret values remain in the active browser tab and are never synchronized into Laygent's project database. On export, public values are written to the git-ignored .env.local; Edge Function secrets are written to the git-ignored supabase/functions/.env. Corresponding .env.example files contain placeholders that are safe to commit.
Authentication
Use Supabase backend.
Enable email and password authentication.
Protect page dashboard with authentication.
After authentication navigate to dashboard.
Use form signup_form to sign up with email email_input and password password_input.
Use form login_form to sign in with email email_input and password password_input.
Use form reset_form to request password reset with email email_input.
When logout_button is clicked, sign out.
Each named form, input, button, and page must exist. Protected pages check the active Supabase session before remaining visible. Auth forms call the Supabase client directly. Configure site and redirect URLs in the Supabase dashboard after export.
Database schema and Row Level Security
Create database table projects.
projects has required text column title.
projects has text column description.
projects has boolean column published with default false.
projects belongs to authenticated user through owner_id.
Create index projects_owner_created on projects using owner_id, created_at.
Allow authenticated users to read, create, update, and delete their own rows in projects through owner_id.
Every generated public table has a UUID primary key plus created_at and updated_at timestamps. Supported field types are text, integer, number, boolean, uuid, timestamp, date, and json. A field may be required, unique, and may have a literal default.
comments has required text column body.
comments has integer column score with default 0.
comments references projects through project_id deleting cascade.
Allow anyone to read rows in published_articles.
Ownership creates a UUID foreign key to auth.users with auth.uid() as its default. Owner policies use auth.uid() for SELECT, INSERT, UPDATE, and DELETE. UPDATE receives both USING and WITH CHECK. Foreign-key and owner lookup columns should be indexed; the explicit index sentence makes that choice reviewable.
| Sentence | Generated effect |
|---|---|
| Create database table <table>. | PostgreSQL table, timestamps, UUID primary key, and RLS enabled. |
| <table> belongs to authenticated user through <column>. | Owner UUID linked to auth.users. |
| <table> references <table> through <column> deleting cascade|restrict|set null. | Foreign key with explicit deletion behavior. |
| Allow authenticated users to read, create, update, and delete their own rows... | Four owner-scoped RLS policies. |
| Allow anyone to read rows in <table>. | Public SELECT policy only. |
Queries and mutations
Create collection projects_data with values "".
Create state selected_id with value "".
Create data query project_list from projects selecting id, title, created_at.
project_list orders by created_at descending.
Load project_list on page dashboard into projects_data.
Use form project_form to insert into projects mapping title_input to title.
Use form edit_form to update projects using state selected_id as id mapping edit_title to title.
When delete_button is clicked, delete from projects using state selected_id as id.
A page load executes its named SELECT and writes the rows into a Laygent collection state. Form mappings read current element values. Inserts, updates, and deletes are still limited by RLS, regardless of what the browser requests. The compiler checks tables, columns, forms, fields, selector states, buttons, pages, and collections before export.
Supabase Storage
Create state uploaded_path with value "".
Create private storage bucket documents.
Allow authenticated users to read, upload, update, and delete their own files in documents.
When file_input changes, upload file to documents and store path in uploaded_path.
Owner files are stored below <user-id>/.... Generated storage.objects policies compare the first path segment with the authenticated user. A public bucket controls object URL visibility; database listing and mutations still use explicit policies.
APIs and Edge Functions
Create server function contact_request.
contact_request requires authentication.
contact_request accepts text field message_input.
contact_request returns JSON message "Received".
Use form contact_form to call server function contact_request.
The compiler creates supabase/functions/contact_request/index.ts, validates the POST body, handles CORS, optionally verifies the JWT, and wires the form to supabase.functions.invoke.
Create server function payment_bridge.
payment_bridge requires authentication.
payment_bridge accepts number field amount_input.
payment_bridge forwards request to URL from secret PAYMENT_SERVICE_URL.
Use form checkout_form to call server function payment_bridge.
A forwarded API URL is read from the Edge Function environment, never emitted into client code. Set it after export with supabase secrets set PAYMENT_SERVICE_URL=.... Generated forwarding is a secure starting boundary, not a substitute for domain-specific validation, idempotency, rate limits, or payment-provider signature verification.
Complete machine-writable full-stack example
Create page login containing login_form with viewport fill, alignment center, distribution center.
Create form login_form containing email_input, password_input, and login_button with direction vertical, gap 12 pixels.
Create input email_input with placeholder "Email".
Create input password_input with placeholder "Password".
password_input input type is password.
Create button login_button displaying "Sign in".
login_button submits form.
Create page dashboard containing project_form, file_input, and logout_button with padding 32 pixels, gap 16 pixels.
Create form project_form containing title_input and save_button with direction vertical, gap 12 pixels.
Create input title_input with placeholder "Project title".
Create button save_button displaying "Save".
save_button submits form.
Create input file_input with placeholder "Choose a file".
file_input input type is file.
Create button logout_button displaying "Sign out".
Create collection projects_data with values "".
Create state uploaded_path with value "".
Use Supabase backend.
Enable email and password authentication.
Use form login_form to sign in with email email_input and password password_input.
Protect page dashboard with authentication.
After authentication navigate to dashboard.
When logout_button is clicked, sign out.
Create database table projects.
projects has required text column title.
projects belongs to authenticated user through owner_id.
Create index projects_owner_created on projects using owner_id, created_at.
Allow authenticated users to read, create, update, and delete their own rows in projects through owner_id.
Create data query project_list from projects selecting id, title, created_at.
project_list orders by created_at descending.
Load project_list on page dashboard into projects_data.
Use form project_form to insert into projects mapping title_input to title.
Create private storage bucket project_files.
Allow authenticated users to read, upload, update, and delete their own files in project_files.
When file_input changes, upload file to project_files and store path in uploaded_path.
This is literal compiler input, not pseudocode. Use Connections to authorize GitHub, Supabase, and Vercel. Then use Publish to select or create the Supabase project, apply the generated migration and RLS/storage policies, upload Edge Function secrets, deploy Edge Functions, create the GitHub repository, synchronize Vercel environment variables, and start the Vercel deployment. Every external change remains inside accounts you authorize.
Preview and export
Run preview compiles the editor and displays every page as a tab. Generated interactions run inside the canvas, including modal behavior and page navigation.
Export project downloads laygent-project.zip. It contains your exact source and linked deployable code. When Supabase is enabled, it also contains migrations, RLS and storage policies, Edge Functions, environment templates, client integration, vercel.json, and BACKEND_SETUP.md. Laygent Publish retrieves the browser-safe Supabase URL and publishable key, injects them into the generated target, and creates the matching Vercel variables for Production, Preview, and Development. Server secrets are never embedded in browser files.
Publish performs the connected workflow without removing ZIP export. It asks for explicit confirmation because it creates external resources. Secret-filled local environment files are never committed to GitHub.
project.plain
BACKEND_SETUP.md
.env.example
vercel.json
supabase/
config.toml
migrations/0001_laygent_schema.sql
functions/<function>/index.ts
output/
backend.js
backend-config.js
home/
index.html
styles.css
script.js
settings/
index.html
styles.css
script.js
For React + TypeScript, backend client code is emitted as src/laygent-backend.ts and @supabase/supabase-js is included in package.json. Copy .env.example to .env.local, add the project URL and publishable key, and follow the generated setup guide. Never put a service-role key, database password, or third-party secret in browser environment variables.