Sklair is not a framework. It does not replace the DOM, ship a runtime, or redefine how browsers work.
Instead, Sklair operates entirely at build time, extending HTML with
components, compiler directives, deterministic optimisation, and sandboxed build hooks.
All of this while producing plain, standard HTML as output.
Define reusable HTML components that expand deterministically at build time. No runtime cost, no client-side abstraction - just clean output.
Guide compilation with explicit directives: ordering barriers, removal blocks, and classification hints that give you control without sacrificing automation. Directives are explicit, readable, and intentionally limited - Sklair avoids implicit magic.
Specific directives such as sklair:remove can be used to write HTML that works both
as raw HTML and as Sklair input.
Useful for previews, isolated component development, and editor tooling.
Sklair performs predictable, explainable optimisations -
especially in <head> ordering and deduplication -
without hidden heuristics.
Sklair supports pre- and post-build hooks
written in sandboxed Lua.
Hooks are ideal for data preparation, asset transformation,
and generating build-time artefacts - without introducing runtime complexity.
Hooks run in a restricted environment with a controlled filesystem API - no unrestricted OS access.
Hooks run sequentially, without background tasks or concurrency. Builds remain predictable and reproducible.
Perfect for compiling structured data into optimised assets that your site can consume directly.
Sklair does not inherently impose an application model.
Whether you're building a static site, a hybrid app, or a fully client-driven SPA,
Sklair prepares your HTML, data, and assets -
how you use JavaScript on top is entirely up to you.
preconnect, dns-prefetch)
Sklair extends HTML at build time.
Components expand, directives guide compilation, and the final output is
clean, standard HTML - with no runtime abstraction.
The examples below demonstrate how Sklair transforms structure while preserving intent.
Components are expanded deterministically at build time. The browser never sees component tags — only the final HTML.
Source
src/index.html
<body>
<SomeHeader></SomeHeader>
<Content></Content>
</body>
components/SomeHeader.html
<header>
<h1>Welcome to my site</h1>
</header>
Compiled output
<body>
<header>
<h1>Welcome to my site</h1>
</header>
<p>...</p>
</body>
Components may contain both <head> and <body> content.
Sklair merges, deduplicates, and reorders head nodes
according to browser loading semantics.
Source
src/index.html
<!DOCTYPE html>
<html>
<head>
<title>Hello world</title>
</head>
<body>
<!-- CommonHead is a component which also contributes its own <head> items -->
<!--
since components might be repeated, <head> injections are deduplicated
to ensure that the same items dont get injected multiple times
-->
<CommonHead></CommonHead>
<Content></Content>
</body>
</html>
components/CommonHead.html
<!DOCTYPE html>
<html>
<head>
<!--
the order here is purposefully very messed up and unconventional,
to show an example of sklair fixing this
-->
<link href="https://fonts.googleapis.com/css2?family=..." rel="stylesheet">
<script src="/assets/js/ThemeSync.js" defer></script>
<!-- sklair:ordering-barrier treat-as=script -->
<script src="https://cdn.tailwindcss.com"></script>
<script src="/assets/styles/tailwind.config.js"></script>
<link rel="stylesheet" href="/assets/styles/global.css">
<link rel="stylesheet" href="/assets/styles/themes.css">
<!-- sklair:ordering-barrier-end -->
<link rel="preconnect" href="https://wcdn.numelon.com">
<meta charset="UTF-8">
<meta name="theme-color" content="#ff4e4e">
<meta name="viewport" content="width=device-width, etc..." />
</head>
<body>
</body>
</html>
Compiled output
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="theme-color" content="#ff4e4e" />
<meta name="viewport" content="width=device-width, etc..." />
<link rel="preconnect" href="https://wcdn.numelon.com" />
<title>Hello world</title>
<link href="https://fonts.googleapis.com/css2?family=..."
rel="stylesheet" />
<script src="/assets/js/ThemeSync.js" defer=""></script>
<script src="https://cdn.tailwindcss.com"></script>
<script src="/assets/styles/tailwind.config.js"></script>
<link rel="stylesheet" href="/assets/styles/global.css" />
<link rel="stylesheet" href="/assets/styles/themes.css" />
<meta name="generator" content="https://sklair.numelon.com" />
</head>
<body>
<p>...</p>
</body>
</html>
The second example above shows how although the <head> of the
CommonHead component was unordered and semantically chaotic, the compiled output is
deterministically reordered according to browser loading semantics.
This is not a cosmetic change, albeit looking nicer is a plus. Modern browsers
stream-parse HTML as the bytes for it arrive, and many <head> elements (such as
meta charset, preconnects, stylesheets and
scripts) trigger side effects the moment
they are encountered. Their relative position therefore directly affects request scheduling,
render-blocking, and even URL resolution.
Sklair applies a heuristic head-ordering pass to ensure that these high-impact nodes are discovered
as early as
possible, improving page load behaviour without requiring authors to manually micromanage
this order themselves.
In some cases, the relative order of nodes must be preserved.
Sklair provides the sklair:ordering-barrier directive
to explicitly mark such regions.
<!-- sklair:ordering-barrier treat-as=script -->
<script src="https://cdn.tailwindcss.com"></script>
<script src="/assets/styles/tailwind.config.js"></script>
<!-- sklair:ordering-barrier-end -->
Ordering barriers allow Sklair to optimise aggressively while still respecting intentional sequencing - for example, ensuring that Tailwind configuration scripts load after the Tailwind runtime itself.