MPA-first · TypeScript-native · DOM-direct

Build for the web.
Stay close to it.

Maya turns TypeScript pages into static HTML, then brings them alive with signals that update the exact DOM nodes you intended—no virtual DOM, hydration, or app server in the way.

Try the live Signal demo
100% TypeScript UI0 virtual DOM3 app targets
TypeScript inDOM alive
01page.tsm.Html(…)
build
02Brahmastatic output
mount
03Real DOMexact updates
STATIC SHELL

No virtual tree between your code and the interface.

A smaller conceptual stack for

STATIC-FIRSTSIGNAL-POWEREDCOMPONENT-DRIVENEDGE-READY

The browser platform,
written in TypeScript.

Maya’s templating syntax is TypeScript that reads like HTML. There is no JSX dialect or SCSS layer to learn before you can make a useful interface.

ONE LANGUAGE

A page is just a typed expression.

Markup, behavior, and composition stay together in TypeScript. Native element factories keep the shape familiar while the compiler keeps it honest.

Explore Maya syntax →
page.ts
import { m } from "@cyftec/maya";
import { signal, tmpl } from "@cyftec/maya/signal";

const count = signal(0);

export default m.Button({
  onclick: () => count.value++,
  children: tmpl`Count: ${count}`,
});

Real pages.
Real DOM.

Maya is MPA-first. Brahma writes static pages, Maya mounts the real DOM, and signals keep the parts that need to move precisely reactive.

MULTI-PAGE BY DEFAULT

Files become pages—not routes in disguise.

A Maya app resembles the durable HTML–CSS–JS web: independent static documents with page-local JavaScript and no client router required.

MPA map3 routes · 0 routers
dev/page.ts/index.html
dev/docs/page.ts/docs/index.html
dev/about.page.ts/about.html
static pagesreactive islands

COMPONENTS + DOM

Compose freely. Reach the node directly.

Component-driven architecture does not put the browser behind a framework escape hatch. Element getters resolve to actual DOM nodes.

direct-dom.ts
const panel = m.Article({
  children: "Native DOM node",
});

m.Button({
  onclick: () =>
    panel().toggleAttribute("data-open"),
  children: "Toggle panel",
});

CONTROL COMPONENTS

Say If, For, and Switch when that is what you mean.

Built-in control components replace noisy conditional markup. Use them for clarity—or use ordinary TypeScript whenever it fits better.

state
Iftruthy / falsy
Forkeyed lists
Switchnamed cases

Readable control flow is part of the element tree.

Change the data.
Only the right node moves.

Signals are small reactive data units that notify the computations that read them. Maya uses those effects to surgically update a text node, child position, or attribute—not re-render an entire component tree.

interactive playgroundno virtual DOM

TRY IT NOW

Make the DOM move.Tap the bright button and watch the highlighted values update instantly.
source12
exact text node ×224
<main> <aside>untouched</aside> <output>24</output></main>

Convenient at author-time.
Careful at run-time.

Maya keeps its low-level promises visible: browser attributes remain typed, keyed nodes keep their identity, and removed subtrees release their reactive work.

TYPED BROWSER CONTRACTS

Autocomplete for the platform—not an invented prop API.

Tag-specific attribute grammars guide valid values in TypeScript. Runtime sanitizers also reject dangerous href schemes and unsafe inline style expressions.

typed-elements.ts
m.Input({
  type: "email",
  required: true,
});

m.Button({ type: "submit" });
m.Link({ rel: "stylesheet" });

// runtime URL/style sanitizers
m.A({ href: trustedUrl });

KEYED BY IDENTITY

Move the list without throwing its nodes away.

Give m.For an itemKey and Maya preserves matching element getters through shuffles and updates, while per-item signals carry the changed data.

before
#a · Alpha
#b · Beta
#c · Gamma
shuffle
after
#c · Gamma
#a · Alpha
#b · Beta

same nodes · new positions

LIFECYCLE-AWARE

Reactive work ends when its DOM leaves.

When onunmount is used, Maya observes removed subtrees, calls lifecycle listeners from the deepest child upward, and disposes the signal effects attached to those elements.

<section> <card> <button /> </card></section>
onunmountcleanup completelistener calledeffects disposed

MutationObserver walks removed subtrees deepest-first.

Brahma handles the journey.
Karma keeps the map.

Create, continuously develop, build, and publish Maya apps from one dedicated CLI—with project behavior gathered into one typed configuration file.

BRAHMA CLI

From empty folder to publishable app.

Spawn a project, install its declared dependencies, run a watched staging server, and emit minified production files.

Open Brahma docs →
terminal
$ brahma create hello-maya
✓ web scaffold created

$ cd hello-maya && brahma install
✓ dependencies synchronized from karma.ts

$ brahma stage
→ watching dev/ at localhost:3000

$ brahma publish
✓ static production build ready

WEB · PWA · EXT

Choose the shell. Keep the same mental model.

Brahma creates web, PWA, or Chrome extension scaffolds. Manifests stay in TypeScript, so platform fields come with autocomplete and type checking.

Webstatic MPA
PWAtyped manifest
ExtensionManifest V3
one TypeScript toolchain

KARMA.TS

The configuration center, not another config pile.

Build paths, serve behavior, dependencies, Git ignores, and editor settings live together in one project-level TypeScript file.

karma.ts
export const karma = {
  brahma: {
    build: { publishDir: "docs" },
    serve: { port: 3000 },
  },
  maya: {
    appType: "web",
    dependencies: { "@cyftec/maya": "latest" },
  },
};

Ship the app.
Skip the app server.

Brahma emits static HTML, CSS, and page-local JavaScript before deployment. Your fully reactive interface can live on a CDN, object storage, or GitHub Pages—without a cloud compute machine running it.

See the production workflow →
BUILDBrahma publishHTML · CSS · JS
CDNedge-ready
GHPages-ready
S3static-ready

$0 app server required

2.04× React throughput

A direct path pays off.

In the Maya Benchmark’s 10,000-row keyed mutation test, Maya’s exact-node updates deliver 188,000 DOM operations per second.

Open the full benchmarkMaya Benchmark v1 · Chromium 140 · Apple M3 Pro · median of 50 runs. Exact result set used by the linked benchmark site.
DOM operations / secondhigher is better
Maya
188k
Svelte
151k
Vue
119k
React
92k
Angular
74k
050k100k150k200k

START CLOSE TO THE PLATFORM

Build something that feels
like the web—because it is.