Atriux

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() — ergonomic getUserMedia wrapper.
  • 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 →