# Limits of version 0

- **Status:** current on 2026-11-06, for version 0.
- **Related documents:** [language spec](https://surface.solenovis.com/docs/language.md), [component reference](https://surface.solenovis.com/docs/components.md), [Surface Layout Spec](https://surface.solenovis.com/docs/layout.md), [differences between the web and the native targets](https://surface.solenovis.com/docs/targets.md)

The specs describe the language that Surface will have. The compiler of version 0 does not have all of it yet. This page lists each gap and each limit of version 0 on one page. The specs mark the same gaps with "Not in version 0".

Two private enums of two child components can have the same name in one file. `tone={.warm}` works for both. A longer expression, such as `tone={a ? .warm : .cold}`, finds only the first enum. Use another name, or export the enum.

---

## 1. Features that are compile errors

The compiler rejects these features with an error. The message of most errors ends with "is not supported in version 0".

| Feature | Spec | What to do in version 0 |
|---|---|---|
| `Canvas` and `PlatformView` | 9.6, component reference 4.16, ADR-0089 | Version 1 does not have them. For a drawing, use a `Drawing` with shapes (component reference 4.11). |
| `transform`, `fill-rule="evenodd"`, gradients, `text` and `use` in an SVG file of an icon | component reference 4.12 | Convert the file first, for example with `svgo` and its `convertTransform` plugin. |
| A user component, text or a block element in a `Drawing` | component reference 4.11 | Put the shapes into the `Drawing` itself, and text above it in a `Stack`. |
| A utility that is not paint on a shape or a `Group`, for example `rotate-45` on a `Circle` | component reference 4.11, ADR-0120 | A shape has no box, so the native targets cannot apply these utilities. Change the coordinates of the shape, or put the transform on the `Drawing`. |
| More than 31 props and states in a component, 30 in a component with `#fill`, or more than 31 effects | 7.4, 7.5 | The web target keeps the dirty bits in 32-bit integers, so each target has this limit. A `motion` counts as a state (ADR-0104), and `Window` counts as a state in a component that reads it (ADR-0106). Move a group of values into a record, or a part of the markup into a component. |
| A record or an enum that holds a value of its own type outside a `List` or a `Map` | 4.6 | A native build gives each field a fixed size. Use `children: List<Node>` in place of `next: Node?`. |
| A `fixed` element without a place on both axes | layout spec 5.7, ADR-0106 | A browser keeps the place in the flow, and a native target has no such place. Add `top-` or `bottom-`, and `inset-s-`, `inset-e-`, `left-` or `right-`, or `inset-`. |
| A box utility, a computed value, a variant form or an event on a `Span` | component reference 4.4a, ADR-0111 | A `Span` takes only the utilities of text, and `hover:` and `dark:` with them. Put a part with padding, a border or a transform outside the `Text`, for example in a `Row`. |
| A name with `__` | 3.1, ADR-0115 | The compiler makes its own names with `__`. A JSON key with `__`, for example `__typename`, cannot be a field, and `Json.decode` ignores it. |

---

## 2. Features that behave differently in version 0

| Feature | Spec | What version 0 does |
|---|---|---|
| A `fallback` block that sends events | 13.3 | Not in version 0: a `fallback` block has only the functions of the module. |
| The theme while the app runs | layout spec 2.1 | `Theme.setMode` chooses a variant of the theme (ADR-0072, ADR-0103), and `Theme.setToken` changes a color or a length (ADR-0082, ADR-0130). The title bar of a native window follows the system. |
| Animation | layout spec 5.10, ADR-0104 | `transition` cannot animate a filter. |
| A spring in Safari before 17.2 | layout spec 5.10, ADR-0104 | That browser has no `linear()`. A spring in a rule uses a `cubic-bezier` of a similar shape, and a move uses `ease-out`. The enter of a `Transition` with a spring plays no animation. |
| An app in a view of a host | ADR-0041 | `surf build --target desktop --embed` works on macOS only. |
| An `Image` on the native targets | component reference 4.5 | Windows shows the first frame of an animated WebP. The cache is in memory only. A picture needs room in a texture of 4096 × 4096 device px: a larger one does not paint fully. A picture above 2^26 pixels does not paint, also after its scale (ADR-0109). |
| Text in other languages | ADR-0066 | Chinese and Japanese lines break, Arabic and Hebrew paragraphs take their direction, and `dir` and `lang` work on all targets. Vertical text is not done. The selection of a mixed line is one rectangle. |
| Italic text on the native targets | ADR-0068, ADR-0131 | The system font and the monospaced system font use the italic face of the platform. A variable font uses its axis. Another font gets a slant of 14 degrees. A theme cannot name a second file for italic. |
| An error boundary | language spec 9.5 | `#try` has no retry. It catches the mount and the updates of its body, not event handlers, effects or tasks. A page from a server has no test of it yet. |
| A missing asset | component reference 4.5 | The compiler checks a path in quotes. A computed path has no check: on the native targets, the image then paints nothing. |

---

## 3. Checks that version 0 does not do

| Check | Spec | What version 0 does |
|---|---|---|
| A utility that has no effect on its element, for example `gap-1` on a `Text` or `text-20` on an `Image` | layout spec 12 | The compiler checks the name and the value of each utility, but not the element. `surf lint` finds the common cases (rule `no-effect`). Its list of rules is short, so it can miss a case. |

---

## 4. Targets

| Target | State |
|---|---|
| Web | Works, also with server rendering and hydration (SurfWave). |
| macOS | Works. |
| Linux | Works on Wayland. `--x11` adds an X11 window with fewer features (ADR-0088). |
| Windows | Works on x86_64. CI builds the aarch64 binary and checks its size, but no test runs on an ARM device yet (W10). A `surf` from a checkout builds the binary with `rust-lld` and no Visual Studio (ADR-0136). CI runs the TodoMVC source and the mail client on Windows. `surf package` writes a signed MSIX package (ADR-0141). A release of `surf` for Windows and a signature for the public are not done ([windows.md](https://git.solenovis.com/henning.liemant/surface/src/branch/main/docs/plan/windows.md)). |
| iOS and Android | Not done. |

The web and the native targets have small differences. [A separate page](https://surface.solenovis.com/docs/targets.md) lists them.

---

## 5. A server

| Limit | What to do in version 0 |
|---|---|
| A server has no Rust crates, so it has no database client | Put the database behind an API, and set `API_ORIGIN`. |
| A server is a binary with a port | No serverless host and no Workers. Use a container or a machine. |
| A press before the script runs | It does nothing. A link and a form work with no script. |
| A server has no TLS | Put a proxy in front of it, and set `ORIGIN`. See [security](https://surface.solenovis.com/docs/security.md). |
| A server has no `https:` client | `Http` on the server takes `http:` only. Keep the API in your own network. |
| A server does not read a body in chunks | The answer is status 501. A proxy must send a length. |
| A server has no limit for each client | Let the proxy limit the rate and the connections of each client. |
| `href` and `action` take four schemes | A relative URL, `http`, `https`, `mailto` and `tel`. The element gets no attribute for another scheme (ADR-0109). |

---

## 6. Tools

| Limit | What to do in version 0 |
|---|---|
| The releases of `surf` cover Linux x86-64 and macOS arm64 | On another system, build `surf` from a checkout. This needs Rust 1.99 or later. |
| The Linux release of `surf` comes from Debian 12, so it needs glibc 2.36 or later | On an older system, build `surf` from a checkout. The apps that `surf` builds keep the minimum of the target matrix (PLAN.md section 12.3). |
| The first native build needs the network, and a native build needs a linker | Run `surf doctor`. It names the package of the linker. ADR-0101 gives the reason. |
| The host of `--embed` is a Rust crate, so it has its own Rust install | Only this case needs Rust. An app and its extern modules use the private toolchain. |
| `surf test` runs the native layout, not the CSS of the web | Test the web output with Playwright against a build. |
| A test that calls an extern module needs a host function or a `fallback` block | Give the module a `fallback` block. |
| A package has `.surf` files and extern files only | The app keeps the assets and the theme. |
| There is no central registry of packages | A git address or a path names a package. |
| `surf dev` answers only `127.0.0.1`, `localhost` and `[::1]` on its own port (ADR-0109) | To try a page on another device, serve a build with another server. |
| The inspector only shows values (ADR-0105) | It cannot change a state. A derived value shows only after the app computed it. The paths under `/__inspector/` belong to the inspector, so an app with routes cannot use them. |
| `surf mcp --http` has no TLS, no sign-in and no limit for each client (ADR-0107) | Put a reverse proxy in front of it. The proxy gives TLS and the rate limit of each client. |

---

## 7. Decided for version 1, not built yet

On 2026-11-04, the project owner decided section 13 of the layout spec and section 18 of the language spec (ADR-0124 to ADR-0135). On 2026-11-05, the project owner answered the open questions for version 1 (ADR-0104, ADR-0109, ADR-0113, ADR-0124, ADR-0126, ADR-0134 and ADR-0139 to ADR-0141). On the same day, the project owner decided the motion of version 1 (ADR-0150 to ADR-0154). On the same day, ADR-0155 to ADR-0159 gave the media of P6.25. The specs describe these features, but the compiler of version 0 does not have them yet. Version 0 gives a compile error for the new syntax, or it does what the last column says.

| Feature | Spec | What to do in version 0 |
|---|---|---|
| The other fixes of the native differences | ADR-0131 | `docs/native-differences.md` lists each row with the plan "1.0". |
| A module constant gets its value at its first read, with one value for the process on a server | language spec 7.3, ADR-0131 | The web computes it at the load, and a server has one value for each thread. |
| The base path for a picture of `src/assets` on a page below the root of an app with routes | wave spec 5, ADR-0139 | A path such as `assets/logo.png` reads its file relative to the address of the page. Show such a picture only on the root page, or give it a full URL. |
| The base path for a `Link`, a form and an `Http` request of a web app with no routes | wave spec 5, ADR-0139 | Only the script and the stylesheet get the base path. Write the prefix into each address that starts with `/`. |
| The split of a `Span` into parts, the underline and the line through of the parts of a split text, and a computed `opacity-` on a split text on the web | layout spec 5.10, ADR-0153 | Split the whole `Text`. Give the opacity with a fixed `opacity-` or with an animation. |
| The hidden pointer, and the Tab key and the accessibility tree only in the video and its bar, in the full screen of a `Video` | component reference 4.5d, ADR-0156, decision 29 | The video and its bar cover the window. A native window goes into the full screen mode of the system. |
| The full screen mode of the window of the X11 fallback of Linux | component reference 4.5d, ADR-0156, decision 27 | The video and its bar cover the window. The window keeps its size. |
| The pause of a video that `autoplay` started while no part of it is in the window | component reference 4.5b, ADR-0158, decision 4 | Give the `Video` `bind:paused`, and pause it in `on:visible`. |
| `object-` utilities on a `Video` with `controls` | component reference 4.5b, 4.5d | The bar has the style of the element, and its video fits with `object-contain`. |
| The `Track` elements of a block in the menu of the captions | component reference 4.5d, ADR-0157, decision 9 | Write each `Track` outside a block. |
| The tags `<i>` and `<u>` of a text cue on the native targets | component reference 4.5c, ADR-0157, decision 5 | The text shows without the italic and the underline. `<b>` works. |
| `indent-` (`text-indent`) on the native targets | layout spec 5.9, 12, ADR-0160 | The web indents the first line. The native targets have no indent. Put the first word of the text into a `Span` with a margin, or use a `Row`. |

Function types in extern modules come after version 1 (ADR-0133). Percentages in `calc()` and subgrid also come after version 1 (ADR-0125, ADR-0126).
