Skip to content

Commit 4dd1240

Browse files
authored
docs: add npm-first quickstart
docs: add npm-first quickstart
2 parents dc995d4 + a2c6221 commit 4dd1240

3 files changed

Lines changed: 237 additions & 7 deletions

File tree

README.md

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,19 @@ It is not production-ready yet. The goal right now is to keep the foundation sma
3939
Intent is available as experimental alpha packages on npm:
4040

4141
```sh
42-
pnpm add @intent-framework/core@alpha @intent-framework/dom@alpha @intent-framework/router@alpha @intent-framework/testing@alpha
42+
pnpm add @intent-framework/core@0.1.0-alpha.1 @intent-framework/dom@0.1.0-alpha.1 @intent-framework/router@0.1.0-alpha.1 @intent-framework/testing@0.1.0-alpha.1
4343
```
4444

4545
```sh
46-
npm install @intent-framework/core@alpha @intent-framework/dom@alpha @intent-framework/router@alpha @intent-framework/testing@alpha
46+
npm install @intent-framework/core@0.1.0-alpha.1 @intent-framework/dom@0.1.0-alpha.1 @intent-framework/router@0.1.0-alpha.1 @intent-framework/testing@0.1.0-alpha.1
4747
```
4848

49+
The quickstart pins the current alpha version so examples match the published APIs.
50+
4951
```txt
52+
Current alpha: v0.1.0-alpha.1
5053
First public alpha: v0.1.0-alpha.0
51-
GitHub Release: https://github.com/intent-framework/intent/releases/tag/v0.1.0-alpha.0
54+
GitHub Releases: https://github.com/intent-framework/intent/releases
5255
```
5356

5457
Published packages:
@@ -64,6 +67,10 @@ Published packages:
6467

6568
This is experimental alpha software. APIs are subject to change. Not recommended for production use.
6669

70+
## Quickstart
71+
72+
See [docs/Quickstart.md](docs/Quickstart.md) for a step-by-step guide — install, define a screen, render it, test it, and inspect the semantic graph.
73+
6774
## Why Intent exists
6875

6976
Modern app code often scatters product meaning across UI components, route files, data hooks, form handlers, test selectors, and backend endpoints.

docs/MVP-Checkpoint.md

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
## Date
44

5-
2026-06-25
5+
2026-06-26
66

77
## Current status
88

@@ -27,6 +27,7 @@ It now has:
2727

2828
## What is proven
2929

30+
- An npm-first quickstart guides new developers through install, definition, rendering, testing, and graph inspection.
3031
- Screens can be authored semantically.
3132
- DOM can materialize the graph without being the source of truth.
3233
- Actions can be independently executable.
@@ -134,6 +135,7 @@ Do not jump into these without a very specific narrow PR:
134135

135136
## Recommended next moves
136137

137-
1. Add a tiny diagnostics/dev-inspection page or command that prints `inspectScreen()` output for demo screens without `MutationObserver`.
138-
2. Improve resource semantics documentation: runtime-scoped resources, reload, stale, invalidation, context.
139-
3. Add one or two graph diagnostics that catch real authoring mistakes before adding any new package.
138+
1. Add a canonical example app that new developers can clone and run after the quickstart.
139+
2. Add a tiny diagnostics/dev-inspection page or command that prints `inspectScreen()` output for demo screens without `MutationObserver`.
140+
3. Improve resource semantics documentation: runtime-scoped resources, reload, stale, invalidation, context.
141+
4. Add one or two graph diagnostics that catch real authoring mistakes before adding any new package.

docs/Quickstart.md

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
# Intent Quickstart
2+
3+
**Product intent is the program.**
4+
5+
This guide shows the fastest path from zero to a semantic screen using published alpha packages.
6+
7+
## 1. Install
8+
9+
```sh
10+
pnpm add @intent-framework/core@0.1.0-alpha.1 @intent-framework/dom@0.1.0-alpha.1 @intent-framework/testing@0.1.0-alpha.1
11+
```
12+
13+
Or with npm:
14+
15+
```sh
16+
npm install @intent-framework/core@0.1.0-alpha.1 @intent-framework/dom@0.1.0-alpha.1 @intent-framework/testing@0.1.0-alpha.1
17+
```
18+
19+
The quickstart pins `0.1.0-alpha.1` so the examples match the APIs shown below.
20+
21+
You also need `typescript` and `vitest` for type checking and tests.
22+
23+
The router (`@intent-framework/router`) and server (`@intent-framework/server`) are separate — the quickstart stays screen-first.
24+
25+
## 2. Define a screen
26+
27+
Create a file that describes what the screen means, not what it looks like:
28+
29+
```ts
30+
import { screen } from "@intent-framework/core"
31+
32+
export const InviteMember = screen("InviteMember", $ => {
33+
const email = $.state.text("email")
34+
35+
const emailAsk = $.ask("Email", email)
36+
.required("Email is required")
37+
.validate(value => value.includes("@"), "Enter a valid email")
38+
39+
const invite = $.act("Invite member")
40+
.primary()
41+
.when(emailAsk.valid, "Enter a valid email first")
42+
.does(() => {
43+
console.log("invite", email.value)
44+
})
45+
46+
$.surface("main").contains(emailAsk, invite)
47+
})
48+
```
49+
50+
This describes:
51+
52+
- A screen named `InviteMember`
53+
- A text state named `email`
54+
- An ask labelled `Email` that is required and validated
55+
- A primary action labelled `Invite member` that is blocked until the email is valid
56+
- A surface named `main` that groups the ask and action
57+
58+
State, validation, actions, and surfaces are semantic nodes — not yet DOM.
59+
60+
## 3. Render with DOM
61+
62+
The DOM renderer materializes the screen into real HTML. No JSX required.
63+
64+
```ts
65+
import { renderDom } from "@intent-framework/dom"
66+
import { InviteMember } from "./InviteMember.js"
67+
68+
const root = document.getElementById("root")!
69+
renderDom(InviteMember, { target: root })
70+
```
71+
72+
This produces:
73+
74+
```html
75+
<main>
76+
<form method="POST" novalidate>
77+
<div class="ask-group">
78+
<label for="ask_email">Email</label>
79+
<input id="ask_email" name="ask_email" type="text" required />
80+
</div>
81+
<button id="act_invite_member" type="button" class="primary" disabled>
82+
Invite member
83+
</button>
84+
<output id="feedback-output" aria-live="polite"></output>
85+
</form>
86+
</main>
87+
```
88+
89+
- Labels, inputs, buttons, and live regions are real DOM.
90+
- The submit button is initially disabled because the email is empty.
91+
- Typing a valid email enables the button reactively.
92+
- Pressing Enter triggers the default action when unambiguous.
93+
94+
The DOM renderer also accepts services and an option to show the screen name as an `<h1>`:
95+
96+
```ts
97+
renderDom(InviteMember, {
98+
target: root,
99+
showScreenName: true,
100+
})
101+
```
102+
103+
## 4. Test semantically
104+
105+
The testing package lets you assert product behavior without touching the DOM:
106+
107+
```ts
108+
import { test, expect } from "vitest"
109+
import { testScreen } from "@intent-framework/testing"
110+
import { InviteMember } from "./InviteMember.js"
111+
112+
test("invite is blocked until email is valid", async () => {
113+
await testScreen(InviteMember, async app => {
114+
await app.act("Invite member").toBeBlockedBy("Enter a valid email first")
115+
116+
await app.answer("Email", "ada@example.com")
117+
118+
await app.act("Invite member").toBeEnabled()
119+
})
120+
})
121+
122+
test("invite feedback shows after execution", async () => {
123+
await testScreen(InviteMember, async app => {
124+
await app.answer("Email", "ada@example.com")
125+
await app.act("Invite member").run()
126+
// Action status is available via feedback()
127+
})
128+
})
129+
```
130+
131+
The harness:
132+
133+
- Creates a runtime for the screen
134+
- Answers asks by setting state directly
135+
- Checks action enabled/blocked state via semantic conditions
136+
- Executes actions through the runtime context
137+
138+
No DOM, no selectors, no waiting for renders. Tests speak product language.
139+
140+
## 5. Inspect the semantic graph
141+
142+
`inspectScreen()` returns a snapshot of the screen's semantic nodes, their states, and diagnostics:
143+
144+
```ts
145+
import { inspectScreen } from "@intent-framework/core"
146+
import { InviteMember } from "./InviteMember.js"
147+
148+
const graph = inspectScreen(InviteMember)
149+
console.log(JSON.stringify(graph, null, 2))
150+
```
151+
152+
Example output:
153+
154+
```json
155+
{
156+
"name": "InviteMember",
157+
"semanticId": "screen:invite-member",
158+
"asks": [
159+
{
160+
"id": "ask_email",
161+
"semanticId": "ask:email",
162+
"label": "Email",
163+
"kind": "text",
164+
"required": true,
165+
"valid": false,
166+
"error": "Email is required"
167+
}
168+
],
169+
"acts": [
170+
{
171+
"id": "act_invite_member",
172+
"semanticId": "action:invite-member",
173+
"label": "Invite member",
174+
"primary": true,
175+
"enabled": false,
176+
"blockedReasons": ["Enter a valid email first"]
177+
}
178+
],
179+
"surfaces": [
180+
{
181+
"id": "surface_main",
182+
"semanticId": "surface:main",
183+
"name": "main",
184+
"itemCount": 2
185+
}
186+
],
187+
"diagnostics": []
188+
}
189+
```
190+
191+
Every node carries a stable, deterministic `semanticId`:
192+
193+
| Node | semanticId |
194+
|------|------------|
195+
| Screen | `screen:invite-member` |
196+
| Ask | `ask:email` |
197+
| Action | `action:invite-member` |
198+
| Surface | `surface:main` |
199+
200+
Diagnostics catch common authoring mistakes — multiple primary actions, secret asks that are not private, nodes not included in any surface.
201+
202+
## 6. What just happened?
203+
204+
You defined a screen in product terms — not as components, markup, or CSS classes.
205+
206+
- **The screen describes product intent.** It says: there is an email to collect, an invite action to offer, and a rule that the invite is blocked until the email is valid.
207+
- **The DOM renderer materialized** that intent into real, inspectable HTML with labels, inputs, disabled states, and live regions — automatically.
208+
- **The testing harness validated** that the action is blocked for the right reason and becomes enabled when the ask is satisfied — without touching the DOM.
209+
- **`inspectScreen()` exposed the graph** for diagnostics and future tooling (DevTools, analytics, code generation).
210+
211+
This is the pattern:
212+
213+
```txt
214+
Screen intent → Semantic graph → Materialized output (DOM, tests, diagnostics)
215+
```
216+
217+
Intent does not replace components for everything. It replaces components as the source of truth for product behavior.
218+
219+
---
220+
221+
**Next steps:** See the [web demo](../examples/web-basic) for a full team invite flow with routing, resources, and diagnostics. Read the [Specification](Specification.md) for the architecture. Check the [MVP Checkpoint](MVP-Checkpoint.md) for current boundaries.

0 commit comments

Comments
 (0)