Repository navigation
0.52.0 - Atomic Dawn
This is a transformative release introducing the renewed Atomic Modules system, a zero-bundle, zero-compiler approach to embedding server-defined modules directly into the browser.
Modules are now delivered just-in-time, only when referenced inside <Script> blocks. No bundling, no imports, no dead code.
Added
- feat:
createModule(...)API, define modules using a dedicated factory:
export const { Module } = createModule({ css });- feat:
createScript(...)now accepts amodulesmap:
export const { Script } = createScript({
atomic: true,
css,
modules: {
modal: Modal,
audio: AudioPlayer,
},
});- feat: Atomic utils (
$) now receive typed access to the modules you register:
<Script>
{({ el, $ }) => {
$.modal.open({ frag: '/about' });
$.audio.play('intro');
}}
</Script>- feat: Just-In-Time Module Delivery, Modules referenced via
$.<name>inside a script block will be automatically detected and included in the client payload only if they aren't already present.
Improved
- feat: Smarter ScriptEngine - Function bodies are now parsed for
$.<module>references. Missing modules are auto-registered and included in SSR output if not yet on the frontend. - feat: Flexible Module Design - Modules are now plain functions — no JSX, no wrappers, no need to render anything:
export function Modal () {
return Module({
name: 'modal',
mod: ({ mod, $ }) => {
... // Do logic here (eg define functions, create dom nodes if necessary)
/* The return result will be registered on Atomic Utils */
return {
open: () => ...,
close: () => ...
};
},
});
}- dx: Full Typing Pipeline - Your module return types flow into the
$util with no manual typing, making authoring expressive and predictable.
Breaking
Moduleis no longer part ofcreateScript(...)return, you must now usecreateModule(...)to get access to theModulefactory.Moduleis no longer a JSX element. The new API:
import {Module} from "~/script";
export function Modal () {
...
return Module({
name: "modal",
data: {cls},
mod: ({data, $}) => {
...
return {
... // Your methods that you want to expose to $.modal.X
};
},
});
}Why Atomic Modules?
Scripts are often the connective tissue between your UI and logic, but traditionally require bundlers, import graphs, or manual registration.
Atomic Modules remove that constraint. They're:
- Declared server-side
- Registered as functions
- Used on-demand
- Delivered just-in-time
This gives you fully reactive, client-accessible logic with no bundling or compilers. Just fragments and function literals.
✅ Use case: Modal, Audio, Notifications, Haptics, Services, Shared Methods, etc.
📦 Examples
Define a Module
// Modal.ts
export const Modal = Module({
name: 'modal',
mod: ({ $ }) => {
let root: HTMLDivElement | null = null;
function open(frag: DocumentFragment) {
root = $.create('div', { children: [frag] });
document.body.appendChild(root);
}
function close() {
if (root) root.remove();
root = null;
}
return {
open: async ({frag}:{frag:string}) => {
if (root) root.remove();
const res = await $.fetch<DocumentFragment>(frag);
if (res.ok && res.content) open(res.content);
},
close,
};
},
});Register It
// script.ts
import { createScript, createModule } from '@trifrost/core';
import { type Env } from './types';
import { css } from './css';
import { Modal } from './components/modules/Modal';
export const { Module } = createModule<Env>({css});
const config = {
atomic: true,
css,
modules: {
modal: Modal,
... // Other modules
},
} as const;
export const { Script, script } = createScript<typeof config, Env>(config);Access It in Markup:
// Within a component
<button type="button" className={css.use('linkButton')}>
What's this?
<Script>
{({ el, $ }) => {
// Note $.modal.open, this is fully typed
$.on(el, 'click', () => $.modal.open(...));
}}
</Script>
</button>AudioPlayer Example:
// Atomic module declaration
export function AudioPlayer () {
return Module({
name: 'audio',
mod: () => ({
play: (track: string) => { new Audio(`/sounds/${track}.mp3`).play(); },
fx: (key: string) => { /* play fx */ },
}),
});
}// Script usage
<Script>
{({ $, el }) => $.on(el, 'click', () => $.audio.fx('click'))}
</Script>No imports. No runtime shimming. No bundlers. Just logic — shipped atomically.
Need a broader example? Check out the Atomic Arcade Source or play it live
This is the final major release before TriFrost v1.0.
It lays the groundwork for the Atomic Ecosystem, where modules are treated as first-class, isolated, reactive, typed fragments of behavior.
TriFrost remains committed to:
- Zero-runtime boilerplate
- Full type inference
- Fine-grained delivery
- Build system independence
Welcome to Atomic Dawn, where logic fragments are first-class, and delivery is intelligent by default.
As always, stay frosty ❄️.