Runtime SDK
@atriux/runtime is the closed React-hook surface that generate-mode projects can use to talk to the platform. Identity, persistence, theme tokens, chat-driven data entry. Anything not in this SDK is unreachable from sandboxed creator code.
Why a closed SDK
Generate-mode code runs inside <iframe sandbox="allow-scripts"> — no allow-same-origin. Browser-enforced isolation. From inside the iframe, fetches to atriux.tech/api/* are CORS-blocked (the iframe has a null origin). The only way creator code can "reach" the platform is via postMessage to the parent window, which the runtime SDK handles for you.
That gives Atriux a strong guarantee: anything creator code can do, it does through the runtime SDK. We control that surface; we know exactly what creators can do.
How to use it
The build agent emits files under App.tsx (the entry point) plus optional helpers. Inside any of them, you can import:
import {
useUser,
useTheme,
useProjectData,
setProjectData,
useDataAgent,
} from "@atriux/runtime";react and react-dom are also available. Anything else fails to compile.
Hook reference
useUser()
Returns the current viewer's identity, or null while init is in flight (typically < 100ms after iframe load).
const user = useUser();
// { id: string, name: string, email: string, avatar: string | null } | null
if (!user) return <div>Loading…</div>;
return <p>Hi, {user.name}.</p>;Privacy: only public fields are exposed (no PII beyond the user's display name + email + avatar URL). Don't log user.email to console or include it in error reports.
useTheme()
Read-only access to the platform's design tokens. Use for <canvas> / <svg> rendering that can't use Tailwind classes.
const theme = useTheme();
// { bg, ink, accent, card, border } | null
ctx.fillStyle = theme?.accent ?? "#b45309";
ctx.fillRect(0, 0, 100, 100);useProjectData(key, defaultValue)
Per-(project, user) persistent key/value store. Replaces localStorage— sandboxed iframes can't access parent localStorage, so all generate-mode persistence flows through this hook.
const [count, setCount] = useProjectData("count", 0);
return (
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
);On first render returns the default value, then asynchronously fetches the stored value and re-renders. Calling the setter writes to the server immediately and updates local state optimistically.
Caps:
- 200 keys per (project, user)
- 64KB serialized JSON per value
- 1MB total blob
setProjectData(key, value)
Imperative setter. Same semantics as useProjectData's setter, usable outside React components (event handlers in vanilla code).
await setProjectData("lastSeen", new Date().toISOString());useDataAgent()
Chat-driven data entry — the same data agent ChatBlock uses, exposed as a hook so generate-mode projects can render their own chat UI alongside custom dashboards.
const chat = useDataAgent();
// { messages, sending, error, send, refresh }
return (
<div>
{chat.messages.map((m, i) => (
<p key={i}>{(m.content as any).text}</p>
))}
<input
onKeyDown={(e) => {
if (e.key === "Enter") {
chat.send(e.currentTarget.value);
e.currentTarget.value = "";
}
}}
/>
</div>
);Always prefer useDataAgent over a formfor data input. The platform's interaction model is conversational end-to-end; a form on a generate-mode project would feel out of place next to chat-based projects elsewhere on the dashboard.
The postMessage protocol
Internally, the SDK uses two message types between iframe and parent:
- Init handshake. The iframe posts
{ type: "atriux-ready" }on load; the parent replies with{ type: "atriux-init", payload: { slug, user, theme } }. - RPC. The iframe posts
{ type: "atriux-rpc", id, action, args }; the parent forwards to a server route, then replies with{ type: "atriux-rpc-response", id, result|error }.
Allowed actions are an explicit allowlist. Currently: data:get, data:set, chat:send, chat:history. Anything else gets a forbidden_action error.
What's NOT in the SDK (yet)
Future hooks land as patterns emerge across multiple projects. Currently planned:
useCredits()+chargeCredits(n, reason)— let creator code charge end users for premium actions inside the project.requestAgent({ prompt, schema })— Atriux-mediated Claude call so generate-mode projects can do AI things without holding API keys.useCamera()— ergonomicgetUserMediawrapper.useFile()— per-project blob store for uploads/downloads.
SDK versioning
The SDK is bundled into each project's compiled output at finish_generate_project time. SDK version is locked per-project — when we ship a new SDK, existing projects keep their old version (frozen in their compiled bundle). Only NEW builds (or re-saved old ones) pick up the change.
This means SDK upgrades are non-breaking by design: we never invalidate a creator's working project. The trade-off is that older projects miss out on new hooks until they're re-saved.
Next: Earnings model →