@open-aippt/cli 1.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +38 -0
- package/dist/cli.js +311 -0
- package/package.json +56 -0
- package/template/.agents/skills/apply-comments/SKILL.md +83 -0
- package/template/.agents/skills/create-slide/SKILL.md +91 -0
- package/template/.agents/skills/create-theme/SKILL.md +250 -0
- package/template/.agents/skills/current-slide/SKILL.md +110 -0
- package/template/.agents/skills/slide-authoring/SKILL.md +625 -0
- package/template/AGENTS.md +32 -0
- package/template/README.md +64 -0
- package/template/assets/.gitkeep +0 -0
- package/template/netlify.toml +4 -0
- package/template/open-aippt.config.ts +5 -0
- package/template/package.json +22 -0
- package/template/slides/.folders.json +4 -0
- package/template/slides/getting-started/assets/claude.svg +1 -0
- package/template/slides/getting-started/assets/cloudflare.svg +1 -0
- package/template/slides/getting-started/assets/gemini.svg +1 -0
- package/template/slides/getting-started/assets/openai.svg +1 -0
- package/template/slides/getting-started/assets/opencode.svg +7 -0
- package/template/slides/getting-started/assets/vercel.svg +1 -0
- package/template/slides/getting-started/assets/zeabur.svg +5 -0
- package/template/slides/getting-started/index.tsx +3406 -0
- package/template/themes/.gitkeep +0 -0
- package/template/tsconfig.json +17 -0
- package/template/vercel.json +3 -0
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: create-theme
|
|
3
|
+
description: Use this skill when the user wants to create, draft, author, or extract a slide theme in this open-aippt repo. Triggers on phrases like "create a theme", "make a theme called X", "extract a theme from <slide>", "build a theme from these images". Produces two paired files under `themes/` — `<id>.md` (palette, typography, layout, fixed Title/Footer components, motion) and `<id>.demo.tsx` (a runnable demo slide that the dev-UI Themes panel previews). Do NOT use for editing real slides — only for authoring the theme bundle.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Create a slide theme
|
|
7
|
+
|
|
8
|
+
This skill produces a **theme bundle** under `themes/`: two paired files that together describe a reusable visual identity.
|
|
9
|
+
|
|
10
|
+
1. `themes/<id>.md` — agent-facing documentation: palette, typography, layout, fixed Title/Footer/Eyebrow components, motion. This is what `create-slide` reads when an author picks the theme.
|
|
11
|
+
2. `themes/<id>.demo.tsx` — a runnable mini-slide (a normal slide module: `export default Page[]`) that demonstrates the theme on 2–3 pages. The dev UI's **Themes panel** loads this file and renders it as the theme's live preview.
|
|
12
|
+
|
|
13
|
+
Both files share the same stem so the runtime can pair them automatically.
|
|
14
|
+
|
|
15
|
+
A theme is **distinct from a slide's `design` const**. The theme markdown is authoring-time aesthetic direction (copied into a real slide's source by `create-slide`). The demo `.tsx` is a self-contained preview, not a real slide — it does not appear in the slides list. A per-slide `const design: DesignSystem = { … }` (declared at the top of `slides/<id>/index.tsx`) is the runtime tokens object the user can tweak from the Design panel. The markdown commits the *direction*; the per-slide `design` const makes the slide *tweakable*; the demo `.tsx` makes the theme *previewable*.
|
|
16
|
+
|
|
17
|
+
You only write files under `themes/<id>.md` and `themes/<id>.demo.tsx`. Never modify real slides or other configuration. The canvas / type-scale defaults that themes can override live in the **`slide-authoring`** skill — read it before writing the theme so your overrides are stated explicitly.
|
|
18
|
+
|
|
19
|
+
## Step 1 — Identify the input source
|
|
20
|
+
|
|
21
|
+
A theme can be derived from any combination of three input shapes:
|
|
22
|
+
|
|
23
|
+
- **Image references** — paths or URLs to slide screenshots, mood-board images, brand assets.
|
|
24
|
+
- **Free-text description** — prose describing the desired palette, fonts, feel.
|
|
25
|
+
- **An existing slide** — `slides/<id>/index.tsx` whose visual identity should be lifted out into a reusable theme.
|
|
26
|
+
|
|
27
|
+
If the user's original message already specifies the inputs unambiguously, skip the question and proceed. Otherwise call `AskUserQuestion` (multi-select) so they can pick one or more sources, and ask follow-ups (paths, slide id, prose) only as needed.
|
|
28
|
+
|
|
29
|
+
## Step 2 — Gather raw inputs
|
|
30
|
+
|
|
31
|
+
- **Images**: read each path with the `Read` tool (it accepts images). Note dominant colors as hex, type weight/style, layout rhythm, decorative motifs, and any recurring chrome (header bar, footer line, page numbers).
|
|
32
|
+
- **Text**: extract explicit tokens (hex codes, font names, motion verbs) and implicit tone words ("editorial", "playful", "brutalist"). Resolve vague language into concrete decisions before writing.
|
|
33
|
+
- **Existing slide**: read `slides/<id>/index.tsx` and pull:
|
|
34
|
+
- The `palette` object → Palette section.
|
|
35
|
+
- Font constants and any `font-size` patterns → Typography section.
|
|
36
|
+
- Padding / alignment patterns → Layout section.
|
|
37
|
+
- Recurring components (TrafficLights, Eyebrow, Footer-style helpers, WindowShell, …) → Fixed components section.
|
|
38
|
+
- `@keyframes` blocks and the shared `styles` string → Motion section.
|
|
39
|
+
- The aesthetic feel implied by the design → Aesthetic paragraph.
|
|
40
|
+
|
|
41
|
+
When inputs disagree (e.g. images use blue but the description says green), ask the user which to honor.
|
|
42
|
+
|
|
43
|
+
## Step 3 — Pick a theme id
|
|
44
|
+
|
|
45
|
+
Use **kebab-case**, short, descriptive. Examples: `editorial-noir`, `brutalist-mono`, `pastel-soft`, `dev-terminal`. Check `themes/` to avoid collisions.
|
|
46
|
+
|
|
47
|
+
## Step 4 — Write `themes/<id>.md`
|
|
48
|
+
|
|
49
|
+
Produce a file with this exact section order. Section bodies adapt to the theme; the headings stay consistent across all themes.
|
|
50
|
+
|
|
51
|
+
````markdown
|
|
52
|
+
---
|
|
53
|
+
name: <Human title, e.g. "Editorial Noir">
|
|
54
|
+
description: <one-line elevator pitch>
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
# <Theme name>
|
|
58
|
+
|
|
59
|
+
## Palette
|
|
60
|
+
|
|
61
|
+
| Role | Value | Notes |
|
|
62
|
+
| ------ | --------- | ------------------------------ |
|
|
63
|
+
| bg | `#0f172a` | page background |
|
|
64
|
+
| text | `#f8fafc` | primary copy |
|
|
65
|
+
| accent | `#fbbf24` | callouts, eyebrow, key numbers |
|
|
66
|
+
| muted | `#94a3b8` | secondary copy, dividers |
|
|
67
|
+
| ... | ... | extend as the theme requires |
|
|
68
|
+
|
|
69
|
+
## Typography
|
|
70
|
+
|
|
71
|
+
- Display font: `<stack>` — weight 800–900 for headlines.
|
|
72
|
+
- Body font: `<stack>` — weight 400–500.
|
|
73
|
+
- Type-scale overrides (only list what differs from `slide-authoring` defaults):
|
|
74
|
+
- Hero title: 180 px (default 140–200 ✓)
|
|
75
|
+
- Body text: 36 px
|
|
76
|
+
|
|
77
|
+
## Layout
|
|
78
|
+
|
|
79
|
+
- Content padding: 120 px from canvas edges (1920 × 1080).
|
|
80
|
+
- Alignment: left-aligned, single column.
|
|
81
|
+
- Grid notes: optional 12-column overlay at 80 px gutter for content pages.
|
|
82
|
+
|
|
83
|
+
## Fixed components
|
|
84
|
+
|
|
85
|
+
These are paste-ready. Copy them verbatim into a slide that uses this theme.
|
|
86
|
+
|
|
87
|
+
### Title
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
const Title = ({ children }: { children: React.ReactNode }) => (
|
|
91
|
+
<h1
|
|
92
|
+
style={{
|
|
93
|
+
fontSize: 140,
|
|
94
|
+
fontWeight: 900,
|
|
95
|
+
lineHeight: 1.05,
|
|
96
|
+
letterSpacing: '-0.02em',
|
|
97
|
+
margin: 0,
|
|
98
|
+
color: '#f8fafc',
|
|
99
|
+
}}
|
|
100
|
+
>
|
|
101
|
+
{children}
|
|
102
|
+
</h1>
|
|
103
|
+
);
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Footer
|
|
107
|
+
|
|
108
|
+
Pull the page number from `useSlidePageNumber()` — never hardcode `pageNum` / `total` props.
|
|
109
|
+
|
|
110
|
+
```tsx
|
|
111
|
+
import { useSlidePageNumber } from '@open-aippt/core';
|
|
112
|
+
|
|
113
|
+
const Footer = () => {
|
|
114
|
+
const { current, total } = useSlidePageNumber();
|
|
115
|
+
return (
|
|
116
|
+
<div
|
|
117
|
+
style={{
|
|
118
|
+
position: 'absolute',
|
|
119
|
+
left: 120,
|
|
120
|
+
right: 120,
|
|
121
|
+
bottom: 60,
|
|
122
|
+
display: 'flex',
|
|
123
|
+
justifyContent: 'space-between',
|
|
124
|
+
fontSize: 24,
|
|
125
|
+
color: '#94a3b8',
|
|
126
|
+
}}
|
|
127
|
+
>
|
|
128
|
+
<span>EDITORIAL NOIR · 2026</span>
|
|
129
|
+
<span>{current} / {total}</span>
|
|
130
|
+
</div>
|
|
131
|
+
);
|
|
132
|
+
};
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Eyebrow / accents (optional)
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
const Eyebrow = ({ children }: { children: React.ReactNode }) => (
|
|
139
|
+
<div style={{ fontSize: 26, letterSpacing: '0.2em', color: '#fbbf24' }}>
|
|
140
|
+
{children}
|
|
141
|
+
</div>
|
|
142
|
+
);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## Motion
|
|
146
|
+
|
|
147
|
+
- Philosophy: static / subtle / rich — pick one and explain in one sentence.
|
|
148
|
+
- Reusable keyframes (paste-ready, only if the philosophy is subtle or rich):
|
|
149
|
+
|
|
150
|
+
```css
|
|
151
|
+
@keyframes fadeUp {
|
|
152
|
+
from { opacity: 0; transform: translateY(24px); }
|
|
153
|
+
to { opacity: 1; transform: translateY(0); }
|
|
154
|
+
}
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Aesthetic
|
|
158
|
+
|
|
159
|
+
One paragraph. What it feels like, the references it draws on, what to avoid (e.g. "no rounded corners; no gradients; no decorative emoji"). Commit to a single direction — minimal, maximalist, editorial, retro, brutalist, soft/pastel, neon, paper/print.
|
|
160
|
+
|
|
161
|
+
## Example usage
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
const Cover: Page = () => (
|
|
165
|
+
<div style={{ width: '100%', height: '100%', background: '#0f172a', color: '#f8fafc', padding: 120, display: 'flex', flexDirection: 'column', justifyContent: 'center' }}>
|
|
166
|
+
<Eyebrow>CHAPTER 01</Eyebrow>
|
|
167
|
+
<Title>The Big Idea</Title>
|
|
168
|
+
<p style={{ fontSize: 36, color: '#94a3b8', maxWidth: 1200, marginTop: 32 }}>
|
|
169
|
+
A short subtitle that explains what this slide is about.
|
|
170
|
+
</p>
|
|
171
|
+
<Footer />
|
|
172
|
+
</div>
|
|
173
|
+
);
|
|
174
|
+
```
|
|
175
|
+
````
|
|
176
|
+
|
|
177
|
+
## Step 4b — Write `themes/<id>.demo.tsx`
|
|
178
|
+
|
|
179
|
+
The demo is a normal slide module — same shape as `slides/<id>/index.tsx`, just sitting under `themes/` so the runtime knows it's preview-only. The dev-UI Themes panel imports it and renders it inside `SlideCanvas` (1920×1080).
|
|
180
|
+
|
|
181
|
+
Contract:
|
|
182
|
+
|
|
183
|
+
- `import { type Page, useSlidePageNumber } from '@open-aippt/core';`
|
|
184
|
+
- Inline the **same** `Title`, `Footer`, `Eyebrow` components defined in the theme markdown — verbatim, no abstractions, no imports from elsewhere. The demo and the markdown must stay in lockstep so what the user sees in the panel matches what `create-slide` will paste into a real slide.
|
|
185
|
+
- Export 2–3 `Page` components and a default array. Aim for: a Cover (Eyebrow + Title + subtitle), one Content page exercising body type + accent, and a Closer or "End" card. The "Example usage" block at the bottom of the markdown is a good starting point — extend it.
|
|
186
|
+
- If the theme has runtime-tweakable tokens worth surfacing in the Design panel later, also `export const design: DesignSystem = {...}`.
|
|
187
|
+
- No external assets, no `import` from `@/`, no slides-only helpers (e.g. `WindowShell` from a real slide). Demo files must be self-contained.
|
|
188
|
+
|
|
189
|
+
Skeleton:
|
|
190
|
+
|
|
191
|
+
```tsx
|
|
192
|
+
import { type Page, useSlidePageNumber } from '@open-aippt/core';
|
|
193
|
+
|
|
194
|
+
const Title = ({ children }: { children: React.ReactNode }) => (
|
|
195
|
+
// …same JSX as in themes/<id>.md
|
|
196
|
+
);
|
|
197
|
+
const Footer = () => {
|
|
198
|
+
const { current, total } = useSlidePageNumber();
|
|
199
|
+
// …
|
|
200
|
+
};
|
|
201
|
+
const Eyebrow = ({ children }: { children: React.ReactNode }) => (
|
|
202
|
+
// …
|
|
203
|
+
);
|
|
204
|
+
|
|
205
|
+
const Cover: Page = () => (
|
|
206
|
+
// …
|
|
207
|
+
);
|
|
208
|
+
const Content: Page = () => (
|
|
209
|
+
// …
|
|
210
|
+
);
|
|
211
|
+
const Closer: Page = () => (
|
|
212
|
+
// …
|
|
213
|
+
);
|
|
214
|
+
|
|
215
|
+
export default [Cover, Content, Closer];
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Step 5 — Self-review
|
|
219
|
+
|
|
220
|
+
Run this checklist before finishing:
|
|
221
|
+
|
|
222
|
+
- [ ] Palette covers `bg` / `text` / `accent` / `muted` at minimum, all as hex.
|
|
223
|
+
- [ ] Type scale specifies hero, heading, body, caption sizes (or explicitly defers to `slide-authoring` defaults).
|
|
224
|
+
- [ ] At least Title and Footer are defined as paste-ready React with concrete inline styles.
|
|
225
|
+
- [ ] Motion section commits to one of static / subtle / rich.
|
|
226
|
+
- [ ] Aesthetic paragraph names a single coherent direction.
|
|
227
|
+
- [ ] Both files written: `themes/<id>.md` and `themes/<id>.demo.tsx`. No slide changes, no config changes.
|
|
228
|
+
- [ ] Demo `.tsx` exports 2–3 pages and inlines the same Title/Footer/Eyebrow components defined in the markdown.
|
|
229
|
+
- [ ] Demo opens cleanly in the **Themes** panel of the dev UI — re-checked by you only by reading the file (do not start a server).
|
|
230
|
+
|
|
231
|
+
## Step 6 — Hand off
|
|
232
|
+
|
|
233
|
+
Tell the user:
|
|
234
|
+
|
|
235
|
+
- The theme id and the two file paths (`themes/<id>.md` + `themes/<id>.demo.tsx`).
|
|
236
|
+
- That the demo will appear in the dev UI's **Themes** panel as a live card and detail view (HMR — no restart needed).
|
|
237
|
+
- That `/create-slide` will list the theme as a picker option on its next run.
|
|
238
|
+
- A one-line summary of the look (palette + aesthetic).
|
|
239
|
+
|
|
240
|
+
Do not run the dev server. Do not modify real slides — even to demonstrate the theme; the demo `.tsx` is the demonstration.
|
|
241
|
+
|
|
242
|
+
## Anti-patterns
|
|
243
|
+
|
|
244
|
+
- ❌ Writing executable code in `themes/<id>.md` outside the labeled component snippets — the markdown is documentation.
|
|
245
|
+
- ❌ Producing only the markdown without the demo, or only the demo without the markdown. A theme is the **bundle** — both files, every time.
|
|
246
|
+
- ❌ Treating `themes/<id>.demo.tsx` as a real slide. It is preview-only and lives outside the slides list; never put it under `slides/`.
|
|
247
|
+
- ❌ Importing from `@/` or any slide-specific helper inside the demo. The demo is self-contained.
|
|
248
|
+
- ❌ Inventing palette / fonts when the user supplied images or an existing slide. Extract, don't fabricate.
|
|
249
|
+
- ❌ Editing `slides/`, `packages/`, `package.json`, or `open-aippt.config.ts`.
|
|
250
|
+
- ❌ Skipping the Fixed components section. Title and Footer are the most common reuse target — they must be paste-ready.
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: current-slide
|
|
3
|
+
description: Resolve which slide, page, and (optionally) selected element the user is currently viewing in the open-aippt dev server. Consult this whenever the user references "this page", "this slide", "this element", "the slide I'm on", "the current page", or any deictic reference to slide content without naming it. Re-read `node_modules/.open-aippt/current.json` at the start of every such turn — the user navigates between turns, so a value you read earlier in the conversation is almost certainly stale.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Where is the user right now?
|
|
7
|
+
|
|
8
|
+
When the user says "fix this page", "tweak this heading", or "the slide I'm looking at", they almost never name the slide id, page number, or element — they mean wherever they are in the dev viewer. Before asking "which slide?" or "which element?", check the file the dev server writes on every navigation and inspector pick.
|
|
9
|
+
|
|
10
|
+
## Re-read on every deictic turn — never reuse a prior read
|
|
11
|
+
|
|
12
|
+
`current.json` is a live cursor, not a fact about the conversation. The user moves between slides, pages, and elements freely between your turns — including while you were doing other work. **Read the file fresh at the start of every new turn that uses a deictic reference**, even if:
|
|
13
|
+
|
|
14
|
+
- you already read it earlier in this same conversation,
|
|
15
|
+
- you just finished editing the slide it pointed to,
|
|
16
|
+
- the user's new message sounds like a continuation ("now make it bigger", "also fix this one", "keep going").
|
|
17
|
+
|
|
18
|
+
A "continue editing" follow-up is exactly the case where the user has likely just navigated to a different slide or picked a different element. Trusting your last read here will silently edit the wrong file. Re-read, compare `slideId` / `pageIndex` / `selection` against what you used last time, and act on the new values.
|
|
19
|
+
|
|
20
|
+
## How to read it
|
|
21
|
+
|
|
22
|
+
```
|
|
23
|
+
node_modules/.open-aippt/current.json
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
Path is relative to the project root (the user's `cwd`, the directory that contains `slides/` and `package.json`). Use the `Read` tool. The file is JSON.
|
|
27
|
+
|
|
28
|
+
## What you get
|
|
29
|
+
|
|
30
|
+
```json
|
|
31
|
+
{
|
|
32
|
+
"slideId": "q2-roadmap",
|
|
33
|
+
"pageIndex": 2,
|
|
34
|
+
"pageNumber": 3,
|
|
35
|
+
"totalPages": 8,
|
|
36
|
+
"slideTitle": "Q2 Roadmap",
|
|
37
|
+
"view": "slides",
|
|
38
|
+
"pagePath": "slides/q2-roadmap/index.tsx",
|
|
39
|
+
"selection": {
|
|
40
|
+
"line": 42,
|
|
41
|
+
"column": 6,
|
|
42
|
+
"tagName": "h1",
|
|
43
|
+
"text": "Q2 Roadmap"
|
|
44
|
+
},
|
|
45
|
+
"updatedAt": "2026-05-09T14:32:11.123Z"
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
- `slideId` — folder name under `slides/`. Use as-is for any `/__slides/<id>/...` API or as the URL segment.
|
|
50
|
+
- `pageIndex` — 0-based, for use with the page array in `index.tsx` (`export default [Cover, Body, ...]`).
|
|
51
|
+
- `pageNumber` — 1-based, for use in messages to the user ("page 3 of 8") and for the URL `?p=N`.
|
|
52
|
+
- `pagePath` — relative path to the slide source. Hand straight to `Read` / `Edit`.
|
|
53
|
+
- `view` — `"slides"` (canvas view) or `"assets"` (asset manager). If `"assets"`, the user is browsing files for that slide rather than viewing a page.
|
|
54
|
+
- `selection` — `null` if nothing is selected. Otherwise, the JSX element the user picked in the inspector overlay:
|
|
55
|
+
- `line` (1-indexed) and `column` (0-indexed) point to the JSX opening tag inside `pagePath`. This is the canonical handle — match against the source line, not the rendered DOM.
|
|
56
|
+
- `tagName` is the rendered DOM tag, lowercased (`"h1"`, `"div"`, `"img"`).
|
|
57
|
+
- `text` is a trimmed text snippet (≤120 chars) from the element's `textContent`, useful as a sanity check that you're looking at the right node.
|
|
58
|
+
- Selection auto-clears whenever the user navigates to a different slide or page.
|
|
59
|
+
- `updatedAt` — ISO timestamp of the last navigation or selection change. Use it to detect staleness.
|
|
60
|
+
|
|
61
|
+
## When to use this
|
|
62
|
+
|
|
63
|
+
- The user references the current slide/page deictically: "this", "here", "the page I'm on", "the slide I'm looking at", "what I'm working on".
|
|
64
|
+
- The user references a specific element: "this heading", "this image", "the button I just clicked", "tighten this", "change the color of this". If `selection` is non-null, that's the element they mean.
|
|
65
|
+
- Before asking "which slide?" or "which element?" as a clarifying question — check this file first.
|
|
66
|
+
- Before guessing from `git log`, recently-edited files, or the most recent slide folder.
|
|
67
|
+
|
|
68
|
+
## When NOT to use this
|
|
69
|
+
|
|
70
|
+
- The user names a slide explicitly ("edit `q2-roadmap`") — use that name directly.
|
|
71
|
+
- The `apply-comments` workflow already finds the right file via `@slide-comment` markers; it doesn't need this skill.
|
|
72
|
+
- For listing or discovering slides — read `slides/` directly.
|
|
73
|
+
|
|
74
|
+
## Staleness — verify before acting
|
|
75
|
+
|
|
76
|
+
`updatedAt` is the last time the user navigated. Treat it like a cache:
|
|
77
|
+
|
|
78
|
+
- **Fresh (under ~5 minutes old)**: trust it. Open `pagePath`, do the work.
|
|
79
|
+
- **Older than ~5 minutes, or older than your last interaction with the user**: confirm with the user before editing. The dev server may not be running; the user may have switched contexts.
|
|
80
|
+
- **Hours/days old**: ignore it. Ask the user which slide they mean.
|
|
81
|
+
|
|
82
|
+
A *newer* `updatedAt` than the one you saw last turn is the normal signal that the user has moved — switch to the new `slideId` / `pageIndex` / `selection` without asking.
|
|
83
|
+
|
|
84
|
+
## When the file is missing
|
|
85
|
+
|
|
86
|
+
- The dev server hasn't been opened on a slide yet, or has never run.
|
|
87
|
+
- Don't create the file or guess. Ask the user which slide they mean, or suggest they open the slide in the dev server first.
|
|
88
|
+
|
|
89
|
+
## Example — page-level reference
|
|
90
|
+
|
|
91
|
+
User: "tighten the spacing on this page"
|
|
92
|
+
|
|
93
|
+
1. Read `node_modules/.open-aippt/current.json`.
|
|
94
|
+
2. Check `updatedAt` is recent.
|
|
95
|
+
3. Read `pagePath` (e.g. `slides/q2-roadmap/index.tsx`).
|
|
96
|
+
4. Identify the page at `pageIndex` in the default-exported array.
|
|
97
|
+
5. Consult the `slide-authoring` skill for spacing rules, then edit that page in place.
|
|
98
|
+
|
|
99
|
+
If `current.json` is missing or stale, ask: "Which slide and page should I tighten? The dev server hasn't published a current page recently."
|
|
100
|
+
|
|
101
|
+
## Example — element-level reference
|
|
102
|
+
|
|
103
|
+
User: "make this bigger"
|
|
104
|
+
|
|
105
|
+
1. Read `node_modules/.open-aippt/current.json`.
|
|
106
|
+
2. If `selection` is non-null, the user means that element. Read `pagePath`, jump to `selection.line`, and find the JSX opening tag near that line/column. Confirm with the snippet in `selection.text` and the `tagName`.
|
|
107
|
+
3. Consult `slide-authoring` for type-scale and layout rules before editing.
|
|
108
|
+
4. Edit the JSX node in place.
|
|
109
|
+
|
|
110
|
+
If `selection` is null, fall back to the page-level flow above — and consider asking "which element?" since the user used a deictic but hasn't picked one in the inspector.
|