Puffinsoft logo./

syntuxwiki

Usage

Getting started

Build your first generative UI webapp.

One component is all you need:

import { GeneratedUI } from 'getsyntux/client';

<GeneratedUI
  endpoint="/api/syntux"
  value={valueToDisplay}
  hint="UI should look like..."   
/>

If you are passing a large array to value, use the skeletonize property to avoid high token costs.

See the following examples to understand its capabilities.

Examples

Basic example

Generate a simple UI with a hint:

import { GeneratedUI } from 'getsyntux/client';

export default function Page() {
  const value = { username: 'John', email: 'john@gmail.com', age: 22 };

  return (
    <GeneratedUI
      endpoint="/api/syntux"
      value={value}
      hint="display as a profile card"
    />
  );
}
import { GeneratedUI } from 'getsyntux/client';
import { useLoaderData } from '@remix-run/react';

export async function loader() {
  return { username: 'John', email: 'john@gmail.com', age: 22 };
}

export default function Dashboard() {
  const value = useLoaderData<typeof loader>();
  return (
    <GeneratedUI
      endpoint="/api/syntux"
      value={value}
      hint="display as a profile card"
    />
  );
}
---
const value = { username: 'John', email: 'john@gmail.com', age: 22 };
---
<html>
  <body>
    <GeneratedUI
      client:load
      endpoint="/api/syntux"
      value={value}
      hint="display as a profile card"
    />
  </body>
</html>

Is the hint secret?

No. It is readable by the client.

Prompts you wish to be secret should be implemented at the endpoint.

Caching

Caching should be implemented on the controller side, then retrieved and passed to the client.

Use onGenerate to capture the schema.

In this example, we are using globalThis to store the cache in memory. This is only for demonstration! Use a real database in production.

const globalWithCache = globalThis as unknown as {
  syntuxCache: Map<number, string> | undefined;
};

export const cache = globalWithCache.syntuxCache ?? new Map<number, string>();  // user id → schema

if(process.env.NODE_ENV !== 'production'){
  globalWithCache.syntuxCache = cache;
}

export async function POST(request: Request){
  const userId = 10; 

  const handler = createSyntuxHandler({
    model: anthropic('claude-sonnet-4-5'),
    spec,
    onGenerate: (schema) => cache.set(userId, schema)
  });

  // custom logic here... (authentication)
    
  return handler(request);
}
const globalWithCache = globalThis as unknown as {
  syntuxCache: Map<number, string> | undefined;
};

export const cache = globalWithCache.syntuxCache ?? new Map<number, string>();  // user id → schema

if(process.env.NODE_ENV !== 'production'){
  globalWithCache.syntuxCache = cache;
}

export async function action({ request }: ActionFunctionArgs) {
  const userId = 10; 

  const handler = createSyntuxHandler({
    model: anthropic('claude-sonnet-4-5'),
    spec,
    onGenerate: (schema) => cache.set(userId, schema)
  });
    
  // custom logic here... (authentication)
    
  return handler(request);
}
const globalWithCache = globalThis as unknown as {
  syntuxCache: Map<number, string> | undefined;
};

export const cache = globalWithCache.syntuxCache ?? new Map<number, string>();  // user id → schema

if(process.env.NODE_ENV !== 'production'){
  globalWithCache.syntuxCache = cache;
}

export const POST: APIRoute = async ({ request }) => {
  const userId = 10; 

  const handler = createSyntuxHandler({
    model: anthropic('claude-sonnet-4-5'),
    spec,
    onGenerate: (schema) => cache.set(userId, schema)
  });
    
  // custom logic here... (authentication)
    
  return handler(request);
}

Then, provide the cached value to the cached property:

import { GeneratedUI } from 'getsyntux/client';
import { cache } from './api/syntux/route';

export default function Page() {
  const userId = 10;
  const value = { username: 'John', email: 'john@gmail.com', age: 22 };

  return (
    <GeneratedUI
      endpoint="/api/syntux"
      value={value}
      hint="UI should look like..."

      cached={cache.get(userId)}
    />
  );
}
import { GeneratedUI } from 'getsyntux/client';
import { useLoaderData } from '@remix-run/react';
import { cache } from './api.syntux';

export async function loader() {
  const userId = 10;
  return {
    cached: cache.get(userId),
    value: { username: 'John', email: 'john@gmail.com', age: 22 },
  };
}

export default function Dashboard() {
  const { cached, value } = useLoaderData<typeof loader>();

  return (
    <GeneratedUI
      endpoint="/api/syntux"
      value={value}
      hint="UI should look like..."

      cached={cached}
    />
  );
}
---
import { Dashboard } from '../components/Dashboard';
import { cache } from './api/syntux';

const userId = 10;
const value = { username: 'John', email: 'john@gmail.com', age: 22 };
---

<GeneratedUI
  client:load
  endpoint="/api/syntux"
  value={value}
  hint="UI should look like..."

  cached={cache.get(userId)}
/>

Custom components

Use custom React components, either your own or somebody else's (a UI library):

import { GeneratedUI } from 'getsyntux/client';
import { Card, Avatar } from '@/components/ui';

export default function Page() {
  const value = { username: 'John', email: 'john@gmail.com', avatar: '/john.png' };

  return (
    <GeneratedUI
      endpoint="/api/syntux"
      value={value}
      hint="use custom components when possible"

      components={[
        {
          name: 'Card',
          props: '{ title: string, body: string }',
          component: Card,
        },
        {
          name: 'Avatar',
          props: '{ src: string, alt: string }',
          component: Avatar,
          context: 'Displays a circular profile image.', /* optional */
        },
      ]}
    />
  );
}
import { GeneratedUI } from 'getsyntux/client';
import { Card, Avatar } from '~/components/ui';
import { useLoaderData } from '@remix-run/react';

export default function Dashboard() {
  const value = useLoaderData<typeof loader>();

  return (
    <GeneratedUI
      endpoint="/api/syntux"
      value={value}
      hint="use custom components when possible"
      
      components={[
        { name: 'Card', props: '{ title: string, body: string }', component: Card },
        { name: 'Avatar', props: '{ src: string, alt: string }', component: Avatar },
      ]}
    />
  );
}
---
const value = { username: 'John', email: 'john@gmail.com', avatar: '/john.png' };
---

<GeneratedUI
  client:load
  endpoint="/api/syntux"
  value={value}
  hint="use custom components when possible"

  components={[
    { name: 'Card', props: '{ title: string, body: string }', component: Card },
    { name: 'Avatar', props: '{ src: string, alt: string }', component: Avatar },
  ]}
/>

Make sure components are marked with "use client".

The components array can be automatically generated using the generate-defs CLI command.

Customize animation

By default, new elements fade in from below when mounted.

This motion cannot yet be customized. However, the duration and offset can, using the animate property:

<GeneratedUI
  model={anthropic("claude-sonnet-4-5")}
  value={valueToDisplay}
  animate={{
    offset: 10, // pixels
    duration: 100 // ms
  }}
/>

In order to disable the animation, set offset to 0 and/or duration to 0.

Animating custom components

By default, syntux is conservative when applying animations in order to not break the tree layout.

Animations are applied through the style property, via the opacity, transform, transition and willChange attributes.

The animation may not work for a custom component, but this can be fixed!

If the animation isn't displaying, that probably means your component doesn't respond to the style property. You need to include style as a property.

For instance:

export function CustomComponent({ ...rest }){ /* <-- rest takes care of style */
  return <div {...rest}>
    {/* original code here */}
  </div>
}

On this page