> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tinykit.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# No API Key Required

> Generate apps with Claude, ChatGPT, or any LLM—no API costs

If you're already paying for Claude Pro, ChatGPT Plus, or another LLM subscription, you can generate tinykit apps directly in those chat interfaces and import them—no API key needed.

## How It Works

1. **Prompt your LLM** with the template below
2. **Copy the JSON** response
3. **Import** on the app creation screen or History tab

***

## Snapshot Format

tinykit uses a simple JSON format:

```json theme={null}
{
  "description": "My App",
  "frontend_code": "<script>\n  // Svelte 5 code\n</script>\n\n<div>\n  <!-- HTML -->\n</div>\n\n<style>\n  /* CSS */\n</style>",
  "design": [
    {
      "id": "1",
      "name": "Primary Color",
      "css_var": "--color-primary",
      "value": "#3b82f6",
      "type": "color",
      "description": "Main brand color"
    }
  ],
  "content": [
    {
      "id": "1",
      "name": "Site Title",
      "key": "site_title",
      "value": "My App",
      "type": "text",
      "description": "Displayed in the header"
    }
  ],
  "collections": [
    {
      "name": "todos",
      "schema": [
        { "name": "title", "type": "text" },
        { "name": "completed", "type": "boolean" }
      ],
      "records": [
        { "id": "1", "title": "Example task", "completed": false }
      ]
    }
  ]
}
```

Only `frontend_code` is required. The rest are optional.

***

## Prompt Template

Copy this into Claude, ChatGPT, or your preferred LLM:

````markdown theme={null}
Create a tinykit app: [DESCRIBE YOUR APP HERE]

Output valid JSON with this exact structure:

```json
{
  "description": "App name",
  "frontend_code": "SVELTE_5_COMPONENT_HERE",
  "design": [],
  "content": [],
  "collections": []
}
```

## Architecture

- Single Svelte 5 file with standard CSS in <style>
- NO Tailwind/utility classes - use semantic class names (.card, .button, .header)
- Data via `import data from '$data'` with realtime subscriptions
- Content via `import content from '$content'` for editable text
- Design via CSS variables (--kebab-case) with fallbacks
- External data via `import { proxy } from '$tinykit'`

## Svelte 5 Runes (REQUIRED)

```javascript
let count = $state(0)                                      // reactive state
let doubled = $derived(count * 2)                          // simple expressions ONLY
let filtered = $derived.by(() => items.filter(x => x.done)) // use .by() for callbacks/filters
$effect(() => { /* side effects, return cleanup fn */ })
```

- Events: `onclick={fn}` (NOT on:click). Call e.preventDefault() in handler.
- Props: `let { x } = $props()` (NOT export let)
- Bindings: `bind:value` works in Svelte 5

## Data API

```javascript
import data from '$data'

// Subscribe for realtime updates (returns unsubscribe fn)
$effect(() => data.todos.subscribe(items => { todos = items; loading = false }))

// CRUD - realtime auto-updates UI
await data.todos.create({ title: 'New' })
await data.todos.update(id, { done: true })
await data.todos.delete(id)
```

## Proxy API (for external data)

```javascript
import { proxy } from '$tinykit'

const data = await proxy.json('https://api.example.com/data')  // JSON
const rss = await proxy.text('https://hnrss.org/frontpage')    // text/RSS/XML
<audio src={proxy.url('https://example.com/audio.mp3')} />     // media URLs
```

## Responsive Layout

- Mobile-first: base styles for small screens, media queries for larger
- Stack layouts vertically by default, horizontal on wider screens
- Use relative units (%, rem, fr) not fixed px widths
- Touch-friendly: buttons/links min 44px tap target

```css
.container { padding: 1rem; }
.grid { display: flex; flex-direction: column; gap: 1rem; }

@media (min-width: 768px) {
  .container { padding: 2rem; }
  .grid { flex-direction: row; }
}
```

## Design Fields

Use CSS vars with fallbacks in code:
```css
.card { background: var(--card-background, #ffffff); }
```

Types: "color", "font", "radius", "shadow", "size", "text"
Name descriptively: "Card Background" not "Primary Color"

## Content Fields

Reference in code as content.field_key:
```svelte
<h1>{content.hero_title}</h1>
```

Types: "text", "textarea", "number", "boolean", "json"
Extract ALL user-facing text: titles, buttons, placeholders, empty states.

## Collections (Database)

- schema: array of {name, type} where type is "text", "number", "boolean", "date", "email", or "url"
- records: sample data (optional)

## Common Mistakes (AVOID)

- `$derived(items.filter(...))` → use `$derived.by(() => items.filter(...))` for callbacks
- `result.sort()` in $derived → use `[...result].sort()` (sort mutates, copy first)
- Missing return in $effect → `$effect(() => { return data.x.subscribe(...) })` for cleanup
- `on:click` → use `onclick` (Svelte 5)
- `export let x` → use `let { x } = $props()` (Svelte 5)
- No loading state → always `let loading = $state(true)`, set false in subscribe callback
- Missing fallback → `var(--x, #default)` not `var(--x)`

## UX Polish

- Use `transition:fade={{ duration: 100 }}` for dialogs, modals, and list items
- Import: `import { fade } from 'svelte/transition'`

## JSON Output Rules

- Escape newlines as \n and quotes as \" in frontend_code
- Output ONLY the JSON, no explanation
````

***

## Importing

### New App

1. Go to the app creation screen
2. Click **Import from JSON**
3. Paste or upload your JSON

### Existing App

1. Open the History tab (`Cmd+6`)
2. Click the upload button (↑)
3. Select your `.json` file

***

## Tips

<AccordionGroup>
  <Accordion title="JSON escaping issues">
    The most common problem is improper escaping in `frontend_code`. Newlines must be `\n` and quotes must be `\"`. If your LLM outputs code blocks inside the JSON, ask it to:

    ```
    Output the frontend_code as a properly escaped JSON string,
    not as a code block. Use \n for newlines and \" for quotes.
    ```
  </Accordion>

  <Accordion title="Validate before importing">
    Paste your JSON into [jsonlint.com](https://jsonlint.com) before importing. Common issues:

    * Trailing commas after last array/object item
    * Unescaped quotes in strings
    * Missing closing brackets
  </Accordion>
</AccordionGroup>
