# WEB Compiler Reference For LLM Agents

This document is a compact but comprehensive reference for generating valid WEB source for the current compiler implementation.

Use this when you need to:

- write `.web` source
- predict what `compiler.js` will emit
- understand which constructs affect HTML vs CSS
- use compile-time JavaScript safely
- avoid features the compiler does not support

This is an implementation-oriented reference, not a marketing overview.

## 1. Fast Mental Model

WEB has three practical entry points:

- legacy script mode: `layout.web` -> `index.html`, `styles.css`
- CLI mode: `home.web` -> `home.html`, `home.css`
- CLI scaffold mode: `web init [directory]` creates `index.web`, `web-lang-agents.md`, and then compiles to `index.html` plus `index.css` in the chosen project directory

Run:

```bash
node compiler.js
web init
web init .
web init website
web home.web
web home
web .
web ./code/*
```

The compiler pipeline is:

1. tokenize source
2. parse into a small AST
3. build a variable table
4. build a type symbol table
5. build the HTML document model
6. build the CSS style model
7. emit `index.html`
8. emit `styles.css`

Generated HTML shell:

- `<!DOCTYPE html>`
- `<html lang="en">`
- `<meta charset="UTF-8" />`
- `<meta name="viewport" content="width=device-width, initial-scale=1.0" />`
- fixed `<title>WEB Output</title>`
- fixed stylesheet link to `styles.css`
- top-level `::head` entries are rendered before `</head>`
- all rendered WEB nodes are inserted inside `<body>`
- top-level `::script` blocks are rendered near the end of `<body>`

Key idea:

- one optional top-level `define { ... }` block owns variables, type declarations, and style inheritance
- normal WEB blocks describe DOM structure and CSS
- top-level `html { ... }` and `* { ... }` describe global CSS selectors only
- `::attrs { ... }` adds real HTML attributes to normal WEB nodes
- `::head { ... }` adds literal `meta` and `link` tags to `<head>` without entering the CSS pipeline
- `::script { ... }` adds literal `<script></script>` tags without entering the CSS pipeline
- `derivedName extends baseName;` declarations still describe CSS inheritance only, and they only appear inside `define { ... }`
- `styles { ... }`, `::pseudo`, and `::media` describe CSS only
- `::keyframes` describes global animation blocks only
- `js\`...\`` runs at compile time, never in the browser

If you remember only one rule, remember this:

- HTML structure comes from normal DOM-scope paths
- CSS comes from property assignments plus style scopes, pseudo blocks, media blocks, and raw CSS

## 2. Minimal Working Shape

This is the simplest useful WEB file shape:

```web
define {
  @pageWidth = "960px";
  Main pageMain;
  Heading heroTitle;
  Paragraph heroCopy;
  Button heroButton;
}

pageMain {
  width = @pageWidth;
  display = "grid";
  gap = "16px";

  heroTitle {
    textContent = "Hello";
  }

  heroCopy {
    textContent = "WEB compiles to HTML and CSS.";
  }

  heroButton {
    textContent = "Launch";
    padding = "12px 18px";
  }
}
```

## 3. Top-Level Rule Order

The compiler is strict about what may appear at the top of the file.

Recommended order:

1. one optional `define { ... }` block
2. optional top-level global selector blocks with `html { ... }` or `* { ... }`
3. rules and blocks
4. optional top-level `::head` blocks
5. optional top-level `::script` blocks
6. top-level `::keyframes` may appear with other top-level rules, but never inside a block

Hard constraints:

- variables must be declared inside `define { ... }`
- type declarations must be declared inside `define { ... }`
- style inheritance declarations must be declared inside `define { ... }`
- `define { ... }` may appear at most once
- `define { ... }` must appear before rules
- variables cannot use `js\`...\``
- `html { ... }` and `* { ... }` are reserved for global CSS selector blocks
- `::head` must be top-level
- `::script` must be top-level
- `::keyframes` must be top-level

## 4. Core Syntax

### 4.1 `define { ... }`

Syntax:

```web
define {
  @space = "1rem";
  Button actionButton;
  actionButton heroButton;
  heroButton extends actionButton;
}
```

What belongs inside `define`:

- variable declarations
- type declarations
- style inheritance declarations

What does not belong inside `define`:

- DOM rules
- CSS property assignments
- `styles { ... }`
- `::pseudo`
- `::media`
- `::attrs`
- `::head`
- `::script`
- `::keyframes`

### 4.2 Type declarations

Syntax:

```web
BaseType NewType;
```

Examples:

```web
Button actionButton;
actionButton heroButton;
Heading2 sectionHeading;
Article featureCard;
```

What this does:

- creates a named type alias
- allows semantic inheritance
- affects HTML tag inference

What this does not do:

- it does not automatically share CSS properties
- use `storeCard extends card;` for CSS inheritance
- it does not create output by itself

Type declarations must live inside the top-level `define { ... }` block.

### 4.3 Style inheritance

Syntax:

```web
derivedName extends baseName;
```

Example:

```web
define {
  Article card;
  card storeCard;
  storeCard extends card;
}
```

What this does:

- copies CSS from `card` into `storeCard`
- keeps HTML tag inference separate from CSS reuse
- supports transitive inheritance such as `featuredStoreCard extends storeCard;`

What this does not do:

- it does not change HTML tag inference by itself
- it does not create output by itself

Important behavior:

- style inheritance is CSS-only
- explicit derived styles override inherited base styles
- closer ancestors override farther ancestors
- circular style inheritance is not allowed
- inheritance applies to normal rules, descendant rules, style scopes, pseudo blocks, media blocks, and `raw`

If you want the derived name to share both:

- the same semantic HTML tag
- and the same CSS

combine type inheritance and style inheritance:

```web
define {
  Article card;
  card storeCard;
  storeCard extends card;
}
```

Style inheritance declarations must live inside the top-level `define { ... }` block.

### 4.4 `::head`

Use `::head { ... }` when you want WEB to emit literal `meta` and `link` tags inside the document head.

Syntax:

```web
::head {
  meta {
    name = "description";
    content = "Landing page built in WEB.";
  }

  link {
    rel = "help";
    href = "compiler.md";
    type = "text/markdown";
  }
}
```

Behavior:

- `::head` is top-level only
- it creates HTML only, not CSS
- it only supports `meta { ... }` and `link { ... }` entries
- each `meta` or `link` entry supports direct HTML attribute assignments only
- attribute names are written in camelCase and compile to kebab-case
- rendered head entries are inserted before `</head>`

### 4.5 `::script`

Use `::script { ... }` when you want WEB to emit a literal script tag.

Syntax:

```web
::script {
  src = "/assets/app.js";
  defer = "true";

  code {
    function helloWorld () {
      alert("hello world");
    }
  }
}
```

Behavior:

- `::script` is top-level only
- it creates HTML only, not CSS
- it supports direct HTML attribute assignments
- it supports one optional `code { ... }` block
- the `code { ... }` body is copied as raw script text
- rendered script tags are inserted near the end of `<body>`

Attribute notes:

- `defer = true;` emits a bare boolean attribute
- `defer = "true";` emits `defer="true"`
- camelCase names compile to kebab-case, so `dataMode` becomes `data-mode`

### 4.6 Global selector blocks

WEB has two special global CSS blocks:

```web
* {
  boxSizing = "border-box";
}

html {
  background = "#101522";
  color = "#f7f6ff";
}
```

Behavior:

- these compile directly to `*` and `html` CSS selectors
- they are CSS-only and never create DOM nodes
- they must appear at the top level
- they are also allowed inside a top-level `::media`
- nested `html { ... }` or `* { ... }` inside an element scope is invalid

These are not normal WEB nodes. They bypass tag inference and the document model.

### 4.7 Variables

Syntax:

```web
define {
  @name = value;
}
```

Examples:

```web
@pageWidth = "min(1120px, calc(100vw - 48px))";
@panelRadius = "24px";
@borderRule = "1px solid rgba(0, 0, 0, 0.08)";
```

Rules:

- variable names must start with `@`
- variables must be declared inside `define { ... }`
- variables may reference other variables
- variables may not use `js\`...\``

### 4.8 Dot notation

Syntax:

```web
pageMain.heroSection.heroTitle.textContent = "Hello";
pageMain.heroSection.padding = "24px";
```

Meaning:

- the path before the final segment identifies a node
- the final segment is the property name

### 4.9 Nested blocks

Syntax:

```web
pageMain {
  heroSection {
    heroTitle {
      textContent = "Hello";
    }
  }
}
```

Equivalent to dot notation:

```web
pageMain.heroSection.heroTitle.textContent = "Hello";
```

### 4.10 Dotted block scopes

Also valid:

```web
pageMain.heroSection {
  heroTitle {
    textContent = "Hello";
  }
}
```

### 4.11 Bare identifiers are not valid rules

This is invalid:

```web
pageMain
```

After a path, the parser expects either:

- `=` for an assignment
- `{` for a block

## 5. HTML Structure Model

WEB does not let you write literal HTML tags in normal source. It creates HTML by rebuilding a tree from rule paths.

Example:

```web
pageMain.heroSection.heroTitle.textContent = "Hello";
pageMain.heroSection.heroButton.textContent = "Launch";
```

This produces a DOM tree like:

- `pageMain`
- `heroSection` inside `pageMain`
- `heroTitle` inside `heroSection`
- `heroButton` inside `heroSection`

Important:

- each unique path maps to one element
- later assignments update the same node
- path identity matters more than declaration order

## 6. HTML Tag Inference

The compiler resolves each node name through the type symbol table, then infers an HTML tag from the resolved base type.

### 6.1 Declared names

Example:

```web
Button heroButton;
```

`heroButton` resolves to base type `Button`, so it renders as `<button>`.

### 6.2 Undeclared names

Undeclared names are allowed.

Example:

```web
pageCanvas {
  width = "100%";
}
```

This still renders, because the compiler treats unknown names as external or built-in types and then runs tag inference on the name itself.

Examples:

- `pageCanvas` -> `<div>`
- `heroSection` -> `<section>`
- `siteHeader` -> `<header>`
- `primaryButton` -> `<button>`

If nothing matches, the fallback is:

- `<div>`

### 6.3 Built-in tag inference

Supported mappings include:

- `Heading`, `Heading1`, `H1` -> `<h1>`
- `Heading2`, `H2` -> `<h2>`
- `Heading3`, `H3` -> `<h3>`
- `Heading4`, `H4` -> `<h4>`
- `Heading5`, `H5` -> `<h5>`
- `Heading6`, `H6` -> `<h6>`
- `Button` -> `<button>`
- `Paragraph`, `Text` -> `<p>`
- `Span` -> `<span>`
- `Section` -> `<section>`
- `Main` -> `<main>`
- `Header` -> `<header>`
- `Footer` -> `<footer>`
- `Nav`, `Navigation` -> `<nav>`
- `Article` -> `<article>`
- `Aside` -> `<aside>`
- `Figure` -> `<figure>`
- `FigureCaption`, `FigCaption` -> `<figcaption>`
- `Link`, `Anchor` -> `<a>`
- `Picture` -> `<picture>`
- `Source` -> `<source>`
- `Image`, `Img` -> `<img>`
- `Video` -> `<video>`
- `Audio` -> `<audio>`
- `Form` -> `<form>`
- `Label` -> `<label>`
- `Dialog` -> `<dialog>`
- `Details` -> `<details>`
- `Summary` -> `<summary>`
- `Input` -> `<input>`
- `TextArea` -> `<textarea>`
- `Select` -> `<select>`
- `Option` -> `<option>`
- `List`, `UnorderedList`, `BulletList` -> `<ul>`
- `OrderedList`, `NumberedList` -> `<ol>`
- `ListItem` -> `<li>`
- `Table` -> `<table>`
- `TableHead` -> `<thead>`
- `TableBody` -> `<tbody>`
- `TableFoot` -> `<tfoot>`
- `TableRow` -> `<tr>`
- `TableHeaderCell` -> `<th>`
- `TableCell` -> `<td>`
- `Code` -> `<code>`
- `Pre`, `Preformatted` -> `<pre>`
- `Strong` -> `<strong>`
- `Em`, `Emphasis` -> `<em>`
- `LineBreak`, `Br` -> `<br>`

## 7. Reserved Properties

WEB has three special property names in normal DOM scopes:

- `textContent`
- `innerHTML`
- `raw`

Everything else is treated as a CSS property.

### 7.1 `textContent`

- inserts escaped text into the node
- safe for plain content

Example:

```web
heroCopy.textContent = "Safe plain text";
```

### 7.2 `innerHTML`

- inserts raw HTML into the node
- may also accept structured fragments returned from `js\`...\``

Example:

```web
heroCopy.innerHTML = "Read the <strong>docs</strong>.";
```

### 7.3 `::attrs`

Use `::attrs { ... }` when you want real HTML attributes on a normal WEB node.

Example:

```web
docsLink {
  textContent = "Docs";

  ::attrs {
    href = "/docs";
    target = "_blank";
    rel = "noreferrer";
    ariaLabel = "Open docs";
    dataTrack = "docs";
  }
}
```

Behavior:

- `::attrs` must be nested directly inside an element scope
- it is not allowed inside `styles { ... }`, pseudo blocks, or media blocks
- it only supports direct attribute assignments
- attribute names are written in camelCase and compile to kebab-case
- `disabled = true;` emits a bare boolean attribute
- `open = true;` is useful for `Dialog` and `Details`
- `false`, `null`, and `undefined` omit the attribute
- `class` and `style` are not allowed in `::attrs`

### 7.4 `raw`

- inserts raw CSS associated with the current selector
- meant as an escape hatch

Example:

```web
heroButton.raw = `
  transition: transform 0.2s ease;
  &:hover {
    transform: translateY(-1px);
  }
`;
```

## 8. CSS Property Model

Any non-reserved property assignment becomes CSS.

Example:

```web
heroSection {
  display = "grid";
  gap = "18px";
  backgroundColor = "#101522";
}
```

Compiles to CSS similar to:

```css
.heroSection {
  display: grid;
  gap: 18px;
  background-color: #101522;
}
```

Rules:

- write CSS properties in camelCase
- compiler converts them to kebab-case
- later assignments to the same property on the same rule win

## 9. Value Types

WEB accepts these value kinds:

- quoted strings: `"grid"`
- plain template literals: `` `some text` ``
- numbers: `1`, `0.95`, `-8`
- percentages: `50%`
- bare identifiers: `none`, `auto`, `inherit`
- variable references: `@pageWidth`
- JavaScript injections: `` js`...` ``

Examples:

```web
heroSection.display = grid;
heroSection.opacity = 0.95;
heroSection.width = 100%;
heroSection.border = @borderRule;
heroSection.fontFamily = `"Helvetica Neue", Arial, sans-serif`;
```

Notes:

- plain template literals are just string-like values, not executed JavaScript
- object-like values are only possible through `js\`...\``

## 9.1 Comments

WEB source supports:

- line comments with `//`
- block comments with `/* ... */`

## 10. Selector Generation

WEB turns paths into descendant class selectors.

Example:

```web
pageMain.heroSection.heroButton.background = "#2d5cff";
```

Compiles to:

```css
.pageMain .heroSection .heroButton {
  background: #2d5cff;
}
```

The generated HTML also uses the node name as the element class.

Example:

- node name `heroButton`
- generated HTML class `class="heroButton"`

## 11. `styles { ... }` Scope

`styles { ... }` creates CSS selectors without creating HTML nodes.

Use it when:

- `innerHTML = js\`...\`` returns class names that need styling
- you want descendant CSS rules only

Example:

```web
featureGrid {
  innerHTML = js`
    return node("Article", "featureCard", {
      children: [
        node("Heading3", "featureTitle", { textContent: "Readable" }),
      ],
    });
  `;

  styles {
    featureCard {
      padding = "20px";
      borderRadius = "20px";
    }

    featureTitle {
      color = "#1e2852";
    }
  }
}
```

Rules:

- `styles { ... }` affects CSS only
- it does not create DOM nodes
- `textContent` is not allowed inside `styles`
- `innerHTML` is not allowed inside `styles`
- `raw` is allowed inside `styles`
- pseudo blocks are allowed inside `styles`

## 12. Pseudo System

WEB uses a unified `::...` syntax for:

- pseudo-classes
- pseudo-elements
- `::attrs`
- media queries
- keyframes

### 12.1 Pseudo selector blocks

Example:

```web
buttonCard {
  background = "blue";

  ::hover {
    background = "red";
  }
}
```

Compiles to:

```css
.buttonCard {
  background: blue;
}

.buttonCard:hover {
  background: red;
}
```

### 12.2 Mapping rules

The compiler normalizes pseudo names like this:

- pseudo-classes use a single CSS colon
- pseudo-elements use a double CSS colon
- camelCase is converted to kebab-case

Examples:

- `::hover` -> `:hover`
- `::focusWithin` -> `:focus-within`
- `::nthChild(2n + 1)` -> `:nth-child(2n + 1)`
- `::before` -> `::before`
- `::firstLetter` -> `::first-letter`

### 12.3 Nested pseudo descendants

Pseudo blocks attach to the scope where they are declared.

Example:

```web
card {
  badge {
    opacity = 0.4;
  }

  ::hover {
    badge {
      opacity = 1;
    }
  }
}
```

Compiles conceptually to:

```css
.card .badge {
  opacity: 0.4;
}

.card:hover .badge {
  opacity: 1;
}
```

### 12.4 Placement rule

Pseudo selector blocks must be nested inside:

- an element scope
- or a `styles { ... }` scope

This is invalid:

```web
::hover {
  background = "red";
}
```

## 13. `::keyframes`

`::keyframes` creates top-level animation blocks.

Example:

```web
card {
  animation = "slideIn 0.4s ease";
}

::keyframes slideIn {
  from {
    opacity = 0;
    transform = "translateY(18px)";
  }

  50% {
    opacity = 1;
  }

  to {
    opacity = 1;
    transform = "translateY(0)";
  }
}
```

Rules:

- must be top-level
- must not be inside elements
- must not be inside `styles { ... }`
- stages may only be `from`, `to`, or percentages like `50%`
- keyframe stages accept CSS property assignments only
- `textContent`, `innerHTML`, and `raw` are not allowed inside keyframe stages

## 14. `::media`

`::media (...)` creates CSS media query scopes.

### 14.1 Nested media

```web
card {
  padding = "20px";

  ::media (max-width: 700px) {
    padding = "14px";
  }
}
```

### 14.2 Top-level media

```web
::media (max-width: 700px) {
  pageMain {
    gap = "18px";
  }
}
```

### 14.3 Combined media and pseudo

```web
buttonCard {
  ::media (max-width: 700px) {
    ::hover {
      background = "#2d5cff";
    }
  }
}
```

Rules:

- write the media condition in normal CSS syntax
- `::media` can contain selector blocks, style scopes, pseudo blocks, properties, and `raw`
- `textContent` and `innerHTML` are not allowed inside media scopes
- type declarations and variables are not allowed inside media scopes

## 15. Raw CSS Escape Hatch

Use `raw` only when WEB syntax is not expressive enough.

Supported raw behaviors:

- normal declarations
- nested selectors with `&`
- nested selectors beginning with `:` or `[` attach to the parent selector
- at-rules such as `@supports`
- passthrough at-rules such as `@keyframes`, `@font-face`, `@property`, `@counter-style`, `@page`

Example:

```web
heroButton.raw = `
  transition: transform 0.25s ease;
  &:hover {
    transform: translateY(-2px);
  }
  @supports (backdrop-filter: blur(12px)) {
    backdrop-filter: blur(12px);
  }
`;
```

Guideline:

- prefer normal properties first
- then `styles { ... }`
- then `::pseudo`
- then `::media`
- use `raw` last

## 16. Compile-Time JavaScript

`js\`...\`` executes at compile time inside Node via `vm`.

It is never emitted as browser JavaScript.

Timeout:

- 1 second

Error behavior:

- runtime errors become inline text
- syntax errors become inline text
- timeouts become inline text
- JS failure does not crash compilation

### 16.1 Result resolution order

The compiler resolves a JS block in this order:

1. explicit `return`
2. output collected through `emit(value)`
3. the last top-level declared variable in the JS source
4. empty string

Example:

```web
heroCopy.textContent = js`
  emit("Hello ");
  emit("world");
`;
```

### 16.2 How results are converted

For normal string-like contexts:

- strings stay strings
- numbers become strings
- booleans become strings
- plain objects are JSON-stringified if possible
- `null` and `undefined` become empty strings

For `innerHTML = js\`...\``:

- structured fragment values are preserved and rendered as HTML

For `textContent = js\`...\``:

- fragment values are not preserved as structure
- errors become escaped text

## 17. JavaScript Injection API

The compile-time JS sandbox exposes these helpers:

- `emit(value)`
- `node(typeName, className?, options?)`
- `el(...)` as an alias for `node(...)`
- `fragment(children)`
- `text(value)`
- `html(value)`

The sandbox also exposes a muted `console`:

- `console.log`
- `console.info`
- `console.warn`
- `console.error`

These do nothing.

### 17.1 `emit(value)`

Appends text to an internal output buffer.

Rules:

- `emit(undefined)` and `emit(null)` do not append text
- returns the current accumulated buffer
- only matters if no explicit `return` overrides it

### 17.2 `node(typeName, className?, options?)`

Creates a structured fragment node.

Example:

```web
cards.innerHTML = js`
  return node("Article", "featureCard", {
    children: [
      node("Heading3", "featureTitle", { textContent: "Fast" }),
      node("Paragraph", "featureCopy", { textContent: "Generated in a loop." }),
    ],
  });
`;
```

Rules:

- `typeName` must be a non-empty string
- `className` may be a string, array, or omitted
- `options` must be an object when provided
- `typeName` goes through the same HTML tag inference as normal WEB nodes

### 17.3 `node(...)` options

Supported options:

- `className`
- `textContent`
- `innerHTML`
- `children`
- `style`
- `attributes`

Details:

- `textContent` becomes escaped text
- `innerHTML` is inserted raw
- `children` may be a single child, an array, or nested arrays
- `style` may be a string or an object
- `attributes` must be an object

### 17.4 `style` option

Examples:

```js
style: "padding: 20px; color: #123;"
```

```js
style: {
  padding: "20px",
  backgroundColor: "#eef2ff",
}
```

Behavior:

- object keys are converted from camelCase to kebab-case
- falsey values `undefined`, `null`, and `false` are omitted
- resulting styles are emitted inline on the fragment node

### 17.5 `attributes` option

Example:

```js
attributes: {
  href: "/docs",
  target: "_blank",
  disabled: true,
}
```

Behavior:

- `undefined`, `null`, and `false` omit the attribute
- `true` emits a bare boolean attribute
- all other values are stringified and escaped

Important:

- normal WEB blocks support real HTML attributes through `::attrs { ... }`
- use JS fragment `attributes` when the node itself is being generated inside `js\`...\``

### 17.6 `fragment(children)`

Groups children without adding a wrapper element.

### 17.7 `text(value)`

Creates an escaped text node.

### 17.8 `html(value)`

Creates a raw HTML fragment node.

Use this sparingly.

## 18. Void Elements

Void tags cannot contain content or children.

Relevant built-ins include:

- `Image` / `Img`
- `Input`
- `LineBreak` / `Br`
- `Source`

This rule applies both to:

- normal WEB nodes
- JS fragment nodes

## 19. What Creates HTML vs What Creates CSS

This distinction is critical for agents.

### Creates HTML and CSS

- normal assignments in DOM scopes
- nested blocks under normal element scopes

### Creates HTML only

- `::attrs { ... }`
- `::head { ... }`
- `::script { ... }`

### Creates CSS only

- top-level `html { ... }` and `* { ... }`
- style inheritance declarations inside `define { ... }` such as `storeCard extends card;`
- `styles { ... }`
- `::hover`, `::before`, other pseudo blocks
- `::media (...)`
- `::keyframes`
- `raw`

### Creates compile-time generated HTML

- `innerHTML = js\`...\`` when the JS returns strings or structured fragments

## 20. Common Agent Mistakes

Avoid these:

### Mistake 1: treating normal properties as HTML attributes

This does not set a real anchor `href`:

```web
docsLink.href = "/docs";
```

It becomes CSS:

```css
.docsLink {
  href: /docs;
}
```

Use `::attrs { ... }` on normal WEB nodes:

```web
docsLink {
  ::attrs {
    href = "/docs";
  }
}
```

Use JS fragment `attributes` only when the node is created inside `js\`...\``.

### Mistake 2: putting variables after rules

Invalid:

```web
pageMain.width = "100%";
define {
  @pageWidth = "960px";
}
```

### Mistake 3: putting `::keyframes` inside a block

Invalid:

```web
card {
  ::keyframes fadeIn {
    from {
      opacity = 0;
    }
  }
}
```

### Mistake 4: using `textContent` inside `styles`

Invalid:

```web
heroSection {
  styles {
    title {
      textContent = "Hello";
    }
  }
}
```

### Mistake 5: confusing type inheritance with style inheritance

This is false today.

Type inheritance affects:

- tag resolution
- semantic naming

It does not affect CSS sharing.

Use this for semantic inheritance:

```web
card storeCard;
```

Use this for CSS inheritance:

```web
storeCard extends card;
```

Use both if you want both.

Type declarations alone do not affect:

- CSS property inheritance inside the compiler

### Mistake 6: overusing declarations that are not needed

If a node name already infers the right tag, you may omit the declaration.

Example:

- `heroSection` already infers `<section>`
- `siteHeader` already infers `<header>`
- `pageCanvas` falls back to `<div>`

## 21. Recommended Authoring Strategy For Agents

When generating new WEB code:

1. declare only the types that improve semantics or clarity
2. use undeclared names freely for wrapper `<div>`s
3. prefer nested blocks for readability
4. put variables, type declarations, and style inheritance inside one `define { ... }` block
5. use variables for repeated primitive values
6. use normal property assignments before raw CSS
7. use `::attrs { ... }` for real HTML attributes on normal WEB nodes
8. use `styles { ... }` for classes created by JS fragments
9. use `::pseudo` and `::media` before `raw`
10. use `js\`...\`` only when loops, conditionals, or fragment generation are genuinely needed

## 22. Canonical Authoring Template

```web
define {
  @pageWidth = "min(1120px, calc(100vw - 48px))";
  @panelRadius = "24px";
  @borderRule = "1px solid rgba(0, 0, 0, 0.08)";

  Main pageMain;
  Article card;
  card storeCard;
  storeCard extends card;
  Heading heroTitle;
  Paragraph heroCopy;
  Button heroButton;
}

pageMain {
  width = @pageWidth;
  display = "grid";
  gap = "24px";

  heroSection {
    padding = "32px";
    border = @borderRule;
    borderRadius = @panelRadius;

    heroLink {
      textContent = "Docs";

      ::attrs {
        href = "/docs";
        target = "_blank";
      }
    }

    heroTitle {
      textContent = "Build with WEB";
    }

    heroCopy {
      textContent = "One source file, compiled to HTML and CSS.";
    }

    heroButton {
      textContent = "Launch";

      ::hover {
        transform = "translateY(-1px)";
      }
    }
  }

  featureGrid {
    innerHTML = js`
      const items = ["Readable", "Composable", "Static"];
      return items.map((label) =>
        node("Article", "featureCard", {
          children: [
            node("Heading3", "featureTitle", { textContent: label }),
          ],
        })
      );
    `;

    styles {
      featureCard {
        padding = "20px";
        border = @borderRule;
      }
    }
  }
}

::media (max-width: 700px) {
  pageMain {
    gap = "16px";
  }
}
```

## 23. Summary

WEB is a path-based declarative language with:

- optional semantic type declarations
- one optional top-level `define { ... }` prelude
- variables inside `define`
- CSS inheritance declarations with `extends` inside `define`
- nested or dotted rule syntax
- real HTML attributes through `::attrs`
- literal head tags through top-level `::head`
- literal script tags through top-level `::script`
- CSS property generation
- CSS-only `styles { ... }` scopes
- first-class `::pseudo`
- top-level `::keyframes`
- first-class `::media`
- compile-time `js` with a small fragment API
- `raw` as a last-resort CSS escape hatch

The most important operational truth for agents is:

- normal scopes create DOM
- `::attrs` adds HTML attributes to DOM nodes
- `::head` adds literal meta/link tags to the document head
- `::script` adds literal script tags to the HTML output
- style scopes and pseudo/media scopes create CSS
- JS runs only at compile time
- JS fragment `attributes` is only needed when the node itself is generated inside `js\`...\``
