Write less. Build faster. No imports. Pure magic.
<Counter>
<state count={0} />
<button onClick={() => state.count.value++}>
Count: {state.count.value}
</button>
</Counter>
Built-in SpeckAgent class for Claude integration. Build AI-powered apps in minutes, not hours.
const agent = new SpeckAgent({ purpose: '...' });
Components auto-discover each other. Just use <MyComponent /> anywhere.
Powered by Preact Signals. Only what changes re-renders. No virtual DOM diffing.
Client-side routing with dynamic params. No extra packages needed.
<async>, <then>, <catch>, <loading> — handle promises declaratively.
Flexible composition with named slots and prop spreading. Build reusable components.
$ npm create speck-app my-app $ cd my-app
# Edit .env
VITE_ANTHROPIC_API_KEY=sk-ant-...
$ npm run dev ✓ Vite server running at http://localhost:5174 ✓ Compiler watching for changes ✓ AI Agent proxy ready
<Counter>
<state count={0} />
<script>
const increment = () => state.count.value++;
const decrement = () => state.count.value--;
</script>
<div>
<h2>Count: {state.count.value}</h2>
<button onClick={decrement}>-</button>
<button onClick={increment}>+</button>
</div>
</Counter>
Declare state with <state> tags. Access values with .value. Updates are fine-grained — only what changes re-renders.
<Welcome>
<state isLoggedIn={false} />
<if condition={state.isLoggedIn.value}>
<p>Welcome back!</p>
<Dashboard />
</if>
<if condition={!state.isLoggedIn.value}>
<p>Please log in.</p>
<LoginForm />
</if>
</Welcome>
Use <if condition={...}> for conditional rendering. Clean, readable, no ternary soup.
<UserList>
<state users={[
{ id: 1, name: "Alice" },
{ id: 2, name: "Bob" }
]} />
<ul>
<loop of={state.users.value} let={user}>
<li>{user.name}</li>
</loop>
</ul>
</UserList>
Iterate with <loop of={array} let={item}>. No .map() callbacks needed.
<App>
<Router>
<route path="/">
<HomePage />
</route>
<route path="/user/:id" let={params}>
<UserProfile userId={params.id} />
</route>
</Router>
</App>
Client-side routing with dynamic params. No react-router needed. Just <Router> and <route>.
<DataLoader>
<async promise={fetch('/api/data').then(r => r.json())}>
<loading>
<p>Loading...</p>
</loading>
<then let={data}>
<p>Got: {data.name}</p>
</then>
<catch let={error}>
<p>Error: {error.message}</p>
</catch>
</async>
</DataLoader>
Handle promises with <async>. Built-in loading, success, and error states. No useEffect gymnastics.
<AskClaude>
<state message={""} />
<state response={""} />
<state loading={false} />
<input value={state.message.value} />
<button onClick={async () => {
state.loading.value = true;
const agent = new SpeckAgent({
purpose: 'You are helpful.',
model: 'claude-sonnet-4-20250514'
});
const result = await agent.send(state.message.value);
state.response.value = result.content;
state.loading.value = false;
}}>
{state.loading.value ? 'Thinking...' : 'Ask'}
</button>
<p>{state.response.value}</p>
</AskClaude>
Built-in SpeckAgent class for Claude integration. Add AI chat to your app in minutes. Streaming support included.
import { useState } from 'react';
import Button from './Button';
import Header from './Header';
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<Header />
<p>Count: {count}</p>
<Button onClick={() => setCount(c => c + 1)}>
Increment
</Button>
</div>
);
}
<Counter>
<state count={0} />
<div>
<Header />
<p>Count: {state.count.value}</p>
<Button onClick={() => state.count.value++}>
Increment
</Button>
</div>
</Counter>
Join the future of web development. AI-native. Zero imports. Pure magic.