diff --git a/editor/README.md b/editor/README.md
deleted file mode 100644
index 600d266..0000000
--- a/editor/README.md
+++ /dev/null
@@ -1,97 +0,0 @@
-# Editor Tooling
-
-Editor support for Deserve, including syntax highlighting for Deserve View Engine (DVE) templates.
-
-## Table of Contents
-
-- [DVE (Deserve View Engine)](#dve-deserve-view-engine)
-- [Example: Use DVE in Deserve](#example-use-dve-in-deserve)
- - [Project Structure](#project-structure)
- - [1) Add Templates](#1-add-templates)
- - [2) Configure Router](#2-configure-router)
- - [3) Render in a Route](#3-render-in-a-route)
-- [Syntax Highlighting (Cursor / VS Code / Trae)](#syntax-highlighting-cursor--vs-code--trae)
-
-## DVE (Deserve View Engine)
-
-DVE is Deserve's built-in view engine for rendering `.dve` templates.
-
-## Example: Use DVE in Deserve
-
-### Project Structure
-
-```
-.
-├── main.ts
-├── routes/
-│ └── index.ts
-└── views/
- ├── index.dve
- └── partials/
- └── header.dve
-```
-
-### 1) Add Templates
-
-Create `views/index.dve`:
-
-```txt
-{{> partials/header.dve}}
-Hello {{ user?.name ?? 'Guest' }}.
-```
-
-Create `views/partials/header.dve`:
-
-```txt
-
Welcome
-```
-
-### 2) Configure Router
-
-Enable DVE by setting `viewsDir` when the router is created.
-
-```ts
-import { Router } from '@neabyte/deserve'
-
-const router = new Router({
- routesDir: './routes',
- viewsDir: './views'
-})
-
-await router.serve(8000)
-```
-
-### 3) Render in a Route
-
-Create `routes/index.ts`:
-
-```ts
-import type { Context } from '@neabyte/deserve'
-
-export async function GET(ctx: Context) {
- return await ctx.render('index', { user: { name: 'Nea' } })
-}
-```
-
-Run the server and open `http://localhost:8000` to see the rendered page.
-
-## Syntax Highlighting (Cursor / VS Code / Trae)
-
-Deserve ships a local DVE extension package at `editor/dve/dve-language-0.1.0.vsix`.
-
-Install it with an editor CLI:
-
-```bash
-# Trae
-trae --install-extension ./dve/dve-language-0.1.0.vsix --force
-
-# VS Code
-code --install-extension ./dve/dve-language-0.1.0.vsix --force
-
-# Cursor
-cursor --install-extension ./dve/dve-language-0.1.0.vsix --force
-```
-
-After installing, reload the editor window and open any `.dve` file, where HTML stays the base syntax with the embedded DVE tags highlighted on top.
-
-- **DVE syntax reference**: See [`editor/dve/README.md`](dve/README.md)
diff --git a/editor/dve/README.md b/editor/dve/README.md
deleted file mode 100644
index 9b0bd66..0000000
--- a/editor/dve/README.md
+++ /dev/null
@@ -1,250 +0,0 @@
-# DVE Grammar
-
-A short, friendly tour of the Deserve `.dve` template syntax that reads from top to bottom, so the first open of a `.dve` file feels easy instead of intimidating.
-
-- **Editor tooling overview**: See [`editor/README.md`](../README.md)
-
-## Table of Contents
-
-- [Install Local VSIX](#install-local-vsix)
-- [Start Here](#start-here)
-- [Variables](#variables)
-- [Raw Output (Unescaped)](#raw-output-unescaped)
-- [Include](#include)
-- [If / Else](#if--else)
-- [Each](#each)
-- [Each Metadata](#each-metadata)
-- [Expressions](#expressions)
-- [Operator Reference](#operator-reference)
-- [Snippets](#snippets)
-- [Advanced Examples](#advanced-examples)
-- [What DVE Does Not Do](#what-dve-does-not-do)
-- [Editor Scope Mapping](#editor-scope-mapping)
-
-## Install Local VSIX
-
-This folder ships a prebuilt VSIX package, so nothing needs to be built first:
-
-```txt
-dve-language-0.1.0.vsix
-```
-
-Install it from this directory with an editor CLI:
-
-```bash
-# VS Code
-code --install-extension ./dve-language-0.1.0.vsix --force
-
-# Cursor
-cursor --install-extension ./dve-language-0.1.0.vsix --force
-
-# Trae
-trae --install-extension ./dve-language-0.1.0.vsix --force
-```
-
-Reload the editor after installing, and since DVE builds on HTML syntax the `.dve` files keep full HTML highlighting with the template tags layered on top.
-
-## Start Here
-
-The whole language comes down to two tags, and once those land the rest is just small variations.
-
-A `{{ ... }}` tag **shows a value** while a `{{#... }} ... {{/... }}` tag wraps a **block** like an if or a loop, and everything further down builds on those two shapes.
-
-```txt
-Hello {{ user?.name ?? 'Guest' }}.
-{{#if user?.isAdmin}}ADMIN{{else}}USER{{/if}}
-```
-
-## Variables
-
-A value wrapped in double braces is printed onto the page, and DVE escapes HTML by default so user input can never sneak in markup or open an injection hole.
-
-```txt
-Hello {{ name }}.
-```
-
-## Raw Output (Unescaped)
-
-Triple braces print the value as-is with no escaping, which is meant only for HTML that is already known to be safe.
-
-```txt
-{{{ trustedHtml }}}
-```
-
-## Include
-
-A repeated piece of markup can live in its own file and get pulled in with an include, where the path is resolved relative to the configured `viewsDir`.
-
-```txt
-{{> partials/header.dve}}
-```
-
-## If / Else
-
-An `#if` block renders its body only when the condition is truthy and an optional `else` covers the other case, and every `#if` must be closed with a matching `/if` or DVE reports the block as unclosed.
-
-```txt
-{{#if ok}}YES{{else}}NO{{/if}}
-```
-
-## Each
-
-An `#each` block walks an array and `as` names the current item, and leaving the name out falls back to `item`.
-
-```txt
-{{#each items as item}}{{ item }},{{/each}}
-```
-
-## Each Metadata
-
-Inside an `#each` block four helpers are available for free, so the loop position never has to be tracked by hand:
-
-- `@index` — current position, starting at 0
-- `@first` — true on the first item
-- `@last` — true on the last item
-- `@length` — total number of items
-
-```txt
-{{#each items as item}}({{ @index }}/{{ @length }} {{#if @first}}F{{else}}-{{/if}}{{#if @last}}L{{else}}-{{/if}}={{ item }});{{/each}}
-```
-
-## Expressions
-
-Any `{{ ... }}` tag accepts a small JavaScript-like expression, so a value can be read, given a fallback, compared, or run through a little math all in one place.
-
-```txt
-Hello {{ user?.name ?? 'Guest' }}.
-Total {{ price * quantity }}
-{{#if age >= 18}}Adult{{else}}Minor{{/if}}
-```
-
-A few behaviours worth knowing:
-
-- A dotted path like `user.profile.name` reads nested values, and missing data along the way resolves to `undefined`
-- Both `.` and `?.` return `undefined` when the object is missing, so a deep lookup never throws
-- Strings use `"double"` or `'single'` quotes and understand the `\n`, `\t`, `\r` escapes
-- Numbers can be decimals or exponents like `2.5` or `1e3`
-
-## Operator Reference
-
-Everything DVE understands, lowest precedence at the top down to highest at the bottom, and anything not on this list is rejected by the parser on purpose.
-
-| Group | Operators | Example |
-| -------------- | --------------------------------------------------- | -------------------------- |
-| Ternary | `? :` | `{{ ok ? 'yes' : 'no' }}` |
-| Nullish | `??` | `{{ name ?? 'Guest' }}` |
-| Logical OR | `\|\|` | `{{ a \|\| b }}` |
-| Logical AND | `&&` | `{{ a && b }}` |
-| Equality | `===` `!==` `==` `!=` | `{{ role === 'admin' }}` |
-| Relational | `>` `<` `>=` `<=` | `{{ age >= 18 }}` |
-| Additive | `+` `-` | `{{ a + b }}` |
-| Multiplicative | `*` `/` `%` | `{{ total % 2 }}` |
-| Unary | `!` `+` `-` | `{{ !done }}` |
-| Member | `.` `?.` | `{{ user?.profile.name }}` |
-| Grouping | `( )` | `{{ (a + b) * c }}` |
-| Literals | numbers, strings, `true` `false` `null` `undefined` | `{{ 1 + 2 * 3 }}` |
-
-## Snippets
-
-Type a prefix and press Tab to drop in the syntax that is easiest to forget.
-
-| Prefix | Inserts |
-| ---------- | ------------------------------------- |
-| `dve` | `{{ value }}` |
-| `dveraw` | `{{{ html }}}` |
-| `dveinc` | `{{> partials/header.dve }}` |
-| `dveif` | `{{#if}} ... {{else}} ... {{/if}}` |
-| `dveifn` | multi-line `{{#if}}` block |
-| `dveeach` | `{{#each items as item}}` block |
-| `dveeachm` | `#each` block with `@index`/`@length` |
-| `dvetern` | `{{ cond ? yes : no }}` |
-| `dvedef` | `{{ value ?? 'fallback' }}` |
-| `dveopt` | `{{ user?.name ?? 'Guest' }}` |
-| `dvecmt` | `` |
-
-## Advanced Examples
-
-### Layout + Partial Composition
-
-`views/layout.dve`:
-
-```txt
-
-
- {{> partials/header.dve}}
-
- {{{ bodyHtml }}}
-
- {{> partials/footer.dve}}
-
-
-```
-
-`views/partials/header.dve`:
-
-```txt
-
- {{ title ?? 'Untitled' }}
- {{#if user?.name}}Hello {{ user.name }}.
{{else}}Hello Guest.
{{/if}}
-
-```
-
-### Lists With Conditional Blocks
-
-```txt
-{{#if items?.length ?? 0}}
-
- {{#each items as item}}
- -
- {{#if item?.isPinned}}[PIN] {{/if}}
- ({{ @index + 1 }}/{{ @length }}) {{ item?.label ?? 'No label' }}
-
- {{/each}}
-
-{{else}}
- No items.
-{{/if}}
-```
-
-### Nested Each (Matrix-Style)
-
-```txt
-
- {{#each rows as row}}
-
- {{#each row as cell}}
- | {{ cell }} |
- {{/each}}
-
- {{/each}}
-
-```
-
-## What DVE Does Not Do
-
-DVE stays small on purpose so a template can never run arbitrary code, and these limits are the safety boundary rather than missing features:
-
-- No function or method calls
-- No array indexing like `items[0]`
-- No assignment or variable declarations
-- No regular expressions or arbitrary JavaScript
-
-Two guardrails also stop runaway templates, where include nesting is capped at 64 levels deep and a single `#each` is capped at 100,000 iterations, and crossing either one raises a clear error instead of hanging.
-
-Anything that needs real logic belongs in the route handler, where the finished value gets computed and then passed into the template.
-
-## Editor Scope Mapping
-
-| Syntax | Scope |
-| ---------------------------------- | ------------------------------------------------------- |
-| `{{` `}}` `{{{` `}}}` | `meta.tag.output.dve` / `meta.tag.raw.dve` |
-| `#if` `#each` `else` `/if` `/each` | `keyword.control.dve` |
-| `>` (include) | `keyword.control.include.dve` |
-| `as` (in #each) | `keyword.operator.as.dve` |
-| Include path | `string.unquoted.path.dve` |
-| `true` `false` `null` `undefined` | `constant.language.dve` |
-| Numbers (incl. `1e3`) | `constant.numeric.dve` |
-| `"..."` `'...'` | `string.quoted.double.dve` / `string.quoted.single.dve` |
-| Operators `?.` `===` `??` etc. | `keyword.operator.dve` |
-| Identifiers / variables | `variable.other.dve` |
-| Item name in #each | `variable.parameter.dve` |
diff --git a/editor/dve/dve-language-0.1.0.vsix b/editor/dve/dve-language-0.1.0.vsix
deleted file mode 100644
index a729a0d..0000000
Binary files a/editor/dve/dve-language-0.1.0.vsix and /dev/null differ
diff --git a/editor/dve/language-configuration.json b/editor/dve/language-configuration.json
deleted file mode 100644
index ae56a0e..0000000
--- a/editor/dve/language-configuration.json
+++ /dev/null
@@ -1,19 +0,0 @@
-{
- "comments": {},
- "brackets": [
- ["{{", "}}"],
- ["{{{", "}}}"]
- ],
- "autoClosingPairs": [
- { "open": "{{", "close": "}}" },
- { "open": "{{{", "close": "}}}" },
- { "open": "\"", "close": "\"", "notIn": ["string"] },
- { "open": "'", "close": "'", "notIn": ["string"] }
- ],
- "surroundingPairs": [
- ["{{", "}}"],
- ["{{{", "}}}"],
- ["\"", "\""],
- ["'", "'"]
- ]
-}
diff --git a/editor/dve/package.json b/editor/dve/package.json
deleted file mode 100644
index 1bcaa23..0000000
--- a/editor/dve/package.json
+++ /dev/null
@@ -1,45 +0,0 @@
-{
- "name": "dve-language",
- "displayName": "DVE Template Language",
- "description": "Syntax highlighting for Deserve (.dve) templates",
- "version": "0.1.0",
- "publisher": "neabyte",
- "engines": {
- "vscode": "^1.74.0"
- },
- "categories": [
- "Programming Languages"
- ],
- "contributes": {
- "languages": [
- {
- "id": "dve",
- "aliases": [
- "DVE",
- "dve"
- ],
- "extensions": [
- ".dve"
- ],
- "configuration": "./language-configuration.json"
- }
- ],
- "snippets": [
- {
- "language": "dve",
- "path": "./snippets/dve.code-snippets"
- }
- ],
- "grammars": [
- {
- "language": "dve",
- "scopeName": "text.html.dve",
- "path": "./syntaxes/dve.tmLanguage.json",
- "embeddedLanguages": {
- "meta.embedded.line.dve": "dve",
- "meta.embedded.block.dve": "dve"
- }
- }
- ]
- }
-}
diff --git a/editor/dve/snippets/dve.code-snippets b/editor/dve/snippets/dve.code-snippets
deleted file mode 100644
index 44899f3..0000000
--- a/editor/dve/snippets/dve.code-snippets
+++ /dev/null
@@ -1,61 +0,0 @@
-{
- "DVE: Tag": {
- "prefix": "dve",
- "body": ["{{ ${1:value} }}"],
- "description": "Insert DVE tag: {{ value }}"
- },
- "DVE: Raw Tag": {
- "prefix": "dveraw",
- "body": ["{{{ ${1:html} }}}"],
- "description": "Insert DVE raw tag: {{{ html }}}"
- },
- "DVE: Include": {
- "prefix": "dveinc",
- "body": ["{{> ${1:partials/header.dve} }}"],
- "description": "Insert DVE include: {{> path }}"
- },
- "DVE: If / Else": {
- "prefix": "dveif",
- "body": ["{{#if ${1:condition}}}${2:then}{{else}}${3:else}{{/if}}"],
- "description": "Insert DVE if/else block"
- },
- "DVE: If": {
- "prefix": "dveifn",
- "body": ["{{#if ${1:condition}}}", " ${2:then}", "{{/if}}"],
- "description": "Insert DVE if block (multi-line)"
- },
- "DVE: Each": {
- "prefix": "dveeach",
- "body": ["{{#each ${1:items} as ${2:item}}}", " ${3:{{ item }}}", "{{/each}}"],
- "description": "Insert DVE each block"
- },
- "DVE: Each (With Meta)": {
- "prefix": "dveeachm",
- "body": [
- "{{#each ${1:items} as ${2:item}}}",
- " ({{ @index }}/{{ @length }}) ${3:{{ item }}}",
- "{{/each}}"
- ],
- "description": "Insert DVE each block with @index/@length"
- },
- "DVE: Ternary": {
- "prefix": "dvetern",
- "body": ["{{ ${1:condition} ? ${2:yes} : ${3:no} }}"],
- "description": "Insert DVE ternary: {{ cond ? yes : no }}"
- },
- "DVE: Default (Nullish)": {
- "prefix": "dvedef",
- "body": ["{{ ${1:value} ?? ${2:'fallback'} }}"],
- "description": "Insert DVE nullish default: {{ value ?? 'fallback' }}"
- },
- "DVE: Optional Chain": {
- "prefix": "dveopt",
- "body": ["{{ ${1:user}?.${2:name} ?? ${3:'Guest'} }}"],
- "description": "Insert DVE optional chain: {{ user?.name ?? 'Guest' }}"
- },
- "DVE: Comment (HTML)": {
- "prefix": "dvecmt",
- "body": [""],
- "description": "Insert HTML comment inside template"
- }
-}
diff --git a/editor/dve/syntaxes/dve.tmLanguage.json b/editor/dve/syntaxes/dve.tmLanguage.json
deleted file mode 100644
index ac7e8db..0000000
--- a/editor/dve/syntaxes/dve.tmLanguage.json
+++ /dev/null
@@ -1,141 +0,0 @@
-{
- "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
- "name": "DVE",
- "scopeName": "text.html.dve",
- "fileTypes": ["dve"],
- "patterns": [{ "include": "#dve-tags" }, { "include": "text.html.basic" }],
- "repository": {
- "dve-tags": {
- "patterns": [
- { "include": "#dve-raw-tag" },
- { "include": "#dve-include-tag" },
- { "include": "#dve-block-tag" },
- { "include": "#dve-output-tag" }
- ]
- },
- "dve-raw-tag": {
- "begin": "\\{\\{\\{",
- "beginCaptures": {
- "0": { "name": "punctuation.section.embedded.begin.dve" }
- },
- "end": "\\}\\}\\}",
- "endCaptures": {
- "0": { "name": "punctuation.section.embedded.end.dve" }
- },
- "name": "meta.embedded.line.dve meta.tag.raw.dve",
- "contentName": "meta.expression.dve",
- "patterns": [{ "include": "#expression" }]
- },
- "dve-include-tag": {
- "begin": "\\{\\{\\s*(>)",
- "beginCaptures": {
- "0": { "name": "punctuation.section.embedded.begin.dve" },
- "1": { "name": "keyword.control.include.dve" }
- },
- "end": "\\}\\}",
- "endCaptures": {
- "0": { "name": "punctuation.section.embedded.end.dve" }
- },
- "name": "meta.embedded.line.dve meta.tag.include.dve",
- "patterns": [{ "include": "#path" }]
- },
- "dve-block-tag": {
- "begin": "\\{\\{\\s*(#if|#each|else|/if|/each)\\b",
- "beginCaptures": {
- "0": { "name": "punctuation.section.embedded.begin.dve" },
- "1": { "name": "keyword.control.dve" }
- },
- "end": "\\}\\}",
- "endCaptures": {
- "0": { "name": "punctuation.section.embedded.end.dve" }
- },
- "name": "meta.embedded.block.dve meta.tag.block.dve",
- "patterns": [
- {
- "match": "\\b(as)\\s+([a-zA-Z_$][a-zA-Z0-9_$]*)",
- "captures": {
- "1": { "name": "keyword.operator.as.dve" },
- "2": { "name": "variable.parameter.dve" }
- }
- },
- { "include": "#expression" }
- ]
- },
- "dve-output-tag": {
- "begin": "\\{\\{",
- "beginCaptures": {
- "0": { "name": "punctuation.section.embedded.begin.dve" }
- },
- "end": "\\}\\}",
- "endCaptures": {
- "0": { "name": "punctuation.section.embedded.end.dve" }
- },
- "name": "meta.embedded.line.dve meta.tag.output.dve",
- "contentName": "meta.expression.dve",
- "patterns": [{ "include": "#expression" }]
- },
- "expression": {
- "patterns": [
- { "include": "#string-double" },
- { "include": "#string-single" },
- { "include": "#number" },
- { "include": "#literal" },
- { "include": "#operator" },
- { "include": "#identifier" }
- ]
- },
- "path": {
- "match": "[@a-zA-Z0-9_$./\\\\-]+\\.dve|[@a-zA-Z_$][a-zA-Z0-9_$.]*",
- "name": "string.unquoted.path.dve"
- },
- "string-double": {
- "begin": "\"",
- "end": "\"",
- "name": "string.quoted.double.dve",
- "patterns": [
- {
- "match": "\\\\.",
- "name": "constant.character.escape.dve"
- }
- ]
- },
- "string-single": {
- "begin": "'",
- "end": "'",
- "name": "string.quoted.single.dve",
- "patterns": [
- {
- "match": "\\\\.",
- "name": "constant.character.escape.dve"
- }
- ]
- },
- "number": {
- "match": "\\b[0-9]+(\\.[0-9]+)?([eE][+-]?[0-9]+)?\\b",
- "name": "constant.numeric.dve"
- },
- "literal": {
- "match": "\\b(true|false|null|undefined)\\b",
- "name": "constant.language.dve"
- },
- "operator": {
- "match": "\\?\\.|===|!==|==|!=|&&|\\|\\||\\?\\?|>=|<=|[?.!:()+\\-*/%<>]",
- "name": "keyword.operator.dve"
- },
- "identifier": {
- "match": "\\b([a-zA-Z_$@][a-zA-Z0-9_$]*)\\b",
- "name": "variable.other.dve"
- }
- },
- "injections": {
- "L:text.html.dve - (meta.embedded.line.dve | meta.embedded.block.dve)": {
- "patterns": [{ "include": "#dve-tags" }]
- },
- "L:text.html.basic": {
- "patterns": [{ "include": "#dve-tags" }]
- },
- "L:string.quoted.double.html, L:string.quoted.single.html": {
- "patterns": [{ "include": "#dve-tags" }]
- }
- }
-}