@se-studio/skills 1.0.1

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/package.json +25 -0
  3. package/skills/contentful-cms-alt-text-audit/SKILL.md +60 -0
  4. package/skills/contentful-cms-cms-guidelines/README.md +166 -0
  5. package/skills/contentful-cms-cms-guidelines/colour-hint-prompt.md +77 -0
  6. package/skills/contentful-cms-cms-guidelines/evaluation-prompt.md +84 -0
  7. package/skills/contentful-cms-cms-guidelines/generate-component-guidelines.md +126 -0
  8. package/skills/contentful-cms-cms-guidelines/generation-prompt.md +231 -0
  9. package/skills/contentful-cms-cms-guidelines/html-component-authoring.md +401 -0
  10. package/skills/contentful-cms-cms-guidelines/validation-prompt.md +170 -0
  11. package/skills/contentful-cms-cms-guidelines/variant-loop.md +189 -0
  12. package/skills/contentful-cms-cms-guidelines/variant-proposal-prompt.md +131 -0
  13. package/skills/contentful-cms-core/SKILL.md +793 -0
  14. package/skills/contentful-cms-generate-all-guidelines/SKILL.md +313 -0
  15. package/skills/contentful-cms-generate-cms-guidelines/SKILL.md +313 -0
  16. package/skills/contentful-cms-image-guide/SKILL.md +240 -0
  17. package/skills/contentful-cms-navigation/SKILL.md +23 -0
  18. package/skills/contentful-cms-rich-text/SKILL.md +96 -0
  19. package/skills/contentful-cms-schema-org/SKILL.md +74 -0
  20. package/skills/contentful-cms-screenshots/SKILL.md +46 -0
  21. package/skills/contentful-cms-seo-descriptions/SKILL.md +54 -0
  22. package/skills/contentful-cms-templates/SKILL.md +21 -0
  23. package/skills/contentful-cms-update-cms-guidelines/SKILL.md +348 -0
  24. package/skills/performance-audit/SKILL.md +344 -0
  25. package/skills/se-marketing-sites-cms-routes-and-appshared/SKILL.md +99 -0
  26. package/skills/se-marketing-sites-create-collection/SKILL.md +295 -0
  27. package/skills/se-marketing-sites-create-component/SKILL.md +250 -0
  28. package/skills/se-marketing-sites-create-page/SKILL.md +183 -0
  29. package/skills/se-marketing-sites-curate-showcase-mocks/SKILL.md +344 -0
  30. package/skills/se-marketing-sites-handling-media/SKILL.md +195 -0
  31. package/skills/se-marketing-sites-lib-cms-structure/SKILL.md +83 -0
  32. package/skills/se-marketing-sites-register-cms-features/SKILL.md +95 -0
  33. package/skills/se-marketing-sites-styling-system/SKILL.md +122 -0
  34. package/skills/site-workflows-brand-context-builder/SKILL.md +98 -0
@@ -0,0 +1,183 @@
1
+ ---
2
+ name: create-page-route
3
+ description: Guide for creating new Next.js App Router pages and dynamic routes in the SE Core Product framework. Use when creating CMS-driven pages, adding route segments, or setting up routing.
4
+ license: Private
5
+ metadata:
6
+ author: se-core-product
7
+ version: "2.0.0"
8
+ ---
9
+
10
+ # Creating Pages and Routes
11
+
12
+ This guide explains how to create new pages and handle routing in the SE Core Product Next.js framework. The system uses Next.js App Router with Contentful-driven dynamic routing.
13
+
14
+ Reference apps: **example-se2026**, **example-brightline**, **example-om1**.
15
+
16
+ ## Page Architecture
17
+
18
+ ### 1. (cms-routes) Route Group
19
+
20
+ All CMS-driven pages live under `src/app/(cms-routes)/`. The layout enables dynamic params:
21
+
22
+ ```tsx
23
+ // layout.tsx
24
+ export const dynamicParams = true;
25
+
26
+ export default function CmsRoutesLayout({ children }: { children: React.ReactNode }) {
27
+ return children;
28
+ }
29
+ ```
30
+
31
+ ### 2. Route Structure
32
+
33
+ | Path | File | Purpose |
34
+ |------|------|---------|
35
+ | `/` | `page.ts` | Home (slug: `index`) |
36
+ | `/{slug}/` | `[level1]/page.ts` | Single-level page |
37
+ | `/{slug1}/{slug2}/...` | `[level1]/[...slugs]/page.ts` | Multi-level pages |
38
+ | `/articles/` | `articles/page.ts` | Articles index (uses ARTICLES_BASE from constants) |
39
+ | `/articles/{type}/` | `articles/[articleType]/page.ts` | Article type index |
40
+ | `/articles/{type}/{tag}/` | `articles/[articleType]/[tag]/page.ts` | Article type + tag index |
41
+ | `/articles/{type}/{tag}/{article}/` | `articles/[articleType]/[tag]/[...slugs]/page.ts` | Individual article |
42
+ | `/tags/`, `/tags/{tag}/` | `tags/` | Tag index (if enabled) |
43
+ | `/people/`, `/people/{person}/` | `people/` | People (if enabled) |
44
+
45
+ Base paths (e.g. `/articles` vs `/learning-hub`) come from `@/lib/constants`.
46
+
47
+ ### 3. appShared Pattern
48
+
49
+ Route files are thin wrappers. Data-fetching and rendering logic lives in `src/appShared/`:
50
+
51
+ - `pageShared.tsx` – `generatePage`, `generatePageMetadata`
52
+ - `articleShared.tsx` – articles
53
+ - `articleTypeShared.tsx`, `articleTypesIndexShared.tsx`, `articleTypeTagShared.tsx` – article indices
54
+ - `customTypeShared.tsx` – custom types
55
+ - `personShared.tsx`, `tagShared.tsx`, `tagsIndexShared.tsx`, `teamIndexShared.tsx`
56
+
57
+ ## Route Page Template
58
+
59
+ Each route page extracts params and delegates to the appropriate appShared function:
60
+
61
+ ```typescript
62
+ import type { ResolvingMetadata } from 'next';
63
+ import { generatePage, generatePageMetadata } from '@/appShared/pageShared';
64
+
65
+ export function generateStaticParams() {
66
+ return [];
67
+ }
68
+
69
+ async function extractDetails(props: PageProps<'/[level1]'>) {
70
+ const params = await props.params;
71
+ const { level1 } = params;
72
+ return { slug: level1, path: `/${level1}/` };
73
+ }
74
+
75
+ export async function generateMetadata(props: PageProps<'/[level1]'>, parent: ResolvingMetadata) {
76
+ const { slug, path } = await extractDetails(props);
77
+ return generatePageMetadata(slug, path, true, parent);
78
+ }
79
+
80
+ export default async function (props: PageProps<'/[level1]'>) {
81
+ const { slug, path } = await extractDetails(props);
82
+ return generatePage(slug, path, true);
83
+ }
84
+ ```
85
+
86
+ For the home page (`/`), use slug `'index'` and path `'/'` directly.
87
+
88
+ ## CmsContent Usage
89
+
90
+ The appShared modules render content with:
91
+
92
+ ```tsx
93
+ <CmsContent
94
+ contents={page.contents}
95
+ rendererConfig={projectRendererConfig}
96
+ pageContext={{ page }}
97
+ />
98
+ ```
99
+
100
+ - `contents` – array of page/article contents (not the full page object)
101
+ - `rendererConfig` – from `@/lib/cms-server`
102
+ - `pageContext` – provides page/article/customType to child components
103
+
104
+ For route files that only need `converterContext` or `buildInformation` (e.g. `generateStaticParams`, sitemap, path computation), import from `@/lib/converter-context` when that module exists, so you don't pull in cms-server.
105
+
106
+ ## Creating a Specialized Route
107
+
108
+ For a route that behaves differently from standard CMS pages (e.g. search, dashboard):
109
+
110
+ 1. Create the route under `(cms-routes)` or a separate route group.
111
+ 2. Either create a new appShared module (if the pattern is reusable) or implement inline.
112
+ 3. Use `getPageWithErrors`, `getArticleWithErrors`, etc. from `@/lib/cms-server`.
113
+ 4. Use `projectRendererConfig` from `@/lib/cms-server`.
114
+ 5. Render with `CmsContent` using `contents`, `rendererConfig`, and `pageContext`.
115
+
116
+ ## Custom Layouts
117
+
118
+ If a route needs a different layout (e.g. no header/footer), create `layout.tsx` in that route directory.
119
+
120
+ ## Troubleshooting
121
+
122
+ - **404 on new route**: Re-run the dev server or build after adding a dynamic route segment.
123
+ - **Static params missing**: Dynamic routes use `generateStaticParams() { return []; }` for on-demand rendering.
124
+ - **Preview mode**: Handled by `draftOnly` in `@/lib/server-config`; appShared modules use it automatically.
125
+
126
+ ## A/B Test Variant Route (`page-test`)
127
+
128
+ When A/B testing is enabled, variant pages are served through a `/page-test/[...slugs]` route that the middleware rewrites to. This route **must** use `generatePageTestMetadata` (not `generatePageMetadata`) so that `robots`/`indexed` comes from the **canonical/control** page — variant entries are intentionally `indexed: false` in Contentful.
129
+
130
+ If the slug is not a known variant in `testsByPath`, **return 404** (`notFound()`): there is no control page to merge, and `/page-test/…` is only valid for configured tests.
131
+
132
+ ```typescript
133
+ import { findCanonicalPath } from '@se-studio/ab-testing';
134
+ import type { ResolvingMetadata } from 'next';
135
+ import { notFound } from 'next/navigation';
136
+ import { testsByPath } from '@/generated/abTests';
137
+ import { generatePage, generatePageTestMetadata } from '@/lib/route-handlers';
138
+ import { getPageRouteConfig } from '@/lib/routeConfig';
139
+
140
+ /** Variant slug must appear in testsByPath; otherwise this route is not valid. */
141
+ function requireCanonicalPath(slug: string): string {
142
+ const canonicalPath = findCanonicalPath(testsByPath, slug);
143
+ if (!canonicalPath) {
144
+ notFound();
145
+ }
146
+ return canonicalPath;
147
+ }
148
+
149
+ export function generateStaticParams() {
150
+ return [];
151
+ }
152
+
153
+ async function extractDetails(props: PageProps<'/page-test/[...slugs]'>) {
154
+ const params = await props.params;
155
+ const slug = params.slugs.join('/');
156
+ return { slug, path: `/page-test/${slug}/` };
157
+ }
158
+
159
+ export async function generateMetadata(
160
+ props: PageProps<'/page-test/[...slugs]'>,
161
+ parent: ResolvingMetadata,
162
+ ) {
163
+ const { slug } = await extractDetails(props);
164
+ const canonicalPath = requireCanonicalPath(slug);
165
+ const canonicalSlug = canonicalPath.replace(/^\/|\/$/g, '') || slug;
166
+ // Use generatePageTestMetadata: merges variant title/description with
167
+ // canonical page's indexed flag so robots directives are always correct.
168
+ return generatePageTestMetadata(slug, canonicalSlug, canonicalPath, getPageRouteConfig(canonicalSlug), parent);
169
+ }
170
+
171
+ export default async function (props: PageProps<'/page-test/[...slugs]'>) {
172
+ const { slug, path } = await extractDetails(props);
173
+ requireCanonicalPath(slug);
174
+ return generatePage(slug, path, getPageRouteConfig(slug));
175
+ }
176
+ ```
177
+
178
+ Also export `generatePageTestMetadata` from the app's `src/lib/route-handlers.ts` destructuring alongside `generatePageMetadata`.
179
+
180
+ ## See Also
181
+
182
+ - **cms-routes-and-appshared** – Full route structure and appShared pattern
183
+ - **lib-cms-structure** – lib directory layout and cms-server usage
@@ -0,0 +1,344 @@
1
+ ---
2
+ name: curate-showcase-mocks
3
+ description: Extracts real component/collection data from Contentful and curates the best examples into showcase-mocks.json, making the CMS showcase display realistic content instead of generic placeholder text.
4
+ license: Private
5
+ metadata:
6
+ author: se-core-product
7
+ version: "2.1.0"
8
+ ---
9
+
10
+ # Curate Showcase Mocks
11
+
12
+ This skill refreshes the CMS showcase with realistic content from the live Contentful space.
13
+ It uses a **two-phase CLI pipeline** — extraction followed by LLM-driven curation — to produce
14
+ `src/generated/showcase-mocks.json`, which the showcase loads at runtime.
15
+
16
+ It is **Step 2** of **`update-cms-guidelines`** mode **`fresh`** (after the clean slate). Realistic mocks and `accepted-variants` files are **required** before bulk screenshot capture in **generate-all-guidelines**.
17
+
18
+ ## When to use
19
+
20
+ Run this skill when:
21
+ - A new app has been populated in Contentful and the showcase still shows placeholder text
22
+ - The CMS content has been significantly updated and the showcase looks stale
23
+ - New component or collection types have been added and need good mock data
24
+ - You are doing a **full CMS guidelines regeneration** and need fresh showcase data before Phase 1 / 1b screenshots
25
+
26
+ ## Prerequisites
27
+
28
+ - The app's `.env.local` must contain `CONTENTFUL_SPACE_ID`, `CONTENTFUL_ACCESS_TOKEN`, and `CONTENTFUL_ENVIRONMENT_NAME`
29
+ - An LLM API key in `.env.local`: `OPENAI_API_KEY` (preferred) or `ANTHROPIC_API_KEY`
30
+ - Optional: `CONTENTFUL_PREVIEW_ACCESS_TOKEN` to also include draft/unpublished entries
31
+ - For monorepo apps: all packages must be built (`pnpm build` from repo root)
32
+ - The app must be fully set up (see **First-time setup** below if not yet done)
33
+
34
+ ## First-time setup (new apps)
35
+
36
+ Before running this skill on a new app, four one-time changes are required.
37
+
38
+ ### 1 — Add scripts to `package.json`
39
+
40
+ **Monorepo app** (uses local packages via relative paths):
41
+
42
+ ```json
43
+ "generate-showcase": "node ../../packages/project-build/dist/generate-showcase-data.js",
44
+ "generate-showcase-mocks": "node ../../packages/project-build/dist/generate-showcase-mocks.js"
45
+ ```
46
+
47
+ **External/standalone project** (uses npm-installed packages):
48
+
49
+ ```json
50
+ "generate-showcase": "node node_modules/@se-studio/project-build/dist/generate-showcase-data.js",
51
+ "generate-showcase-mocks": "node node_modules/@se-studio/project-build/dist/generate-showcase-mocks.js"
52
+ ```
53
+
54
+ Alternatively for external projects, use the installed binaries directly (available on PATH after install):
55
+
56
+ ```bash
57
+ generate-showcase-data # runs in-place from the project root
58
+ generate-showcase-mocks
59
+ ```
60
+
61
+ ### 2 — Gitignore the generated files
62
+
63
+ In the app's `.gitignore`, add:
64
+
65
+ ```
66
+ # Generated showcase files (large, regenerable — curated mocks committed separately)
67
+ src/generated/showcase-examples.json
68
+ src/generated/showcase-mocks-draft.json
69
+ src/generated/cms-discovery/accepted-variants/
70
+ ```
71
+
72
+ ### 3 — Wire the render pages to use curated mocks
73
+
74
+ Both `src/app/(cms-dev)/cms/showcase/render/page.tsx` and `render-all/page.tsx` need to import
75
+ `mergeShowcaseMocks` and the curated mocks file.
76
+
77
+ **`render/page.tsx`** — change from:
78
+
79
+ ```tsx
80
+ import { DEFAULT_SHOWCASE_CONTROL_STATE, ShowcaseRenderPage } from '@se-studio/core-ui';
81
+ // ... other imports ...
82
+
83
+ export default async function Page(...) {
84
+ return (
85
+ <ShowcaseRenderPage
86
+ componentMockMap={componentMockMap}
87
+ collectionMockMap={collectionMockMap}
88
+ collectionCardMockMap={collectionCardMockMap}
89
+ ...
90
+ />
91
+ );
92
+ }
93
+ ```
94
+
95
+ to:
96
+
97
+ ```tsx
98
+ import { DEFAULT_SHOWCASE_CONTROL_STATE, ShowcaseRenderPage, mergeShowcaseMocks } from '@se-studio/core-ui';
99
+ // ... other imports ...
100
+ import curatedMocks from '@/generated/showcase-mocks.json';
101
+
102
+ const { componentMockMap: mergedComponentMocks, collectionMockMap: mergedCollectionMocks, collectionCardMockMap: mergedCardMocks } =
103
+ mergeShowcaseMocks(curatedMocks, { componentMockMap, collectionMockMap, collectionCardMockMap });
104
+
105
+ export default async function Page(...) {
106
+ return (
107
+ <ShowcaseRenderPage
108
+ componentMockMap={mergedComponentMocks}
109
+ collectionMockMap={mergedCollectionMocks}
110
+ collectionCardMockMap={mergedCardMocks}
111
+ ...
112
+ />
113
+ );
114
+ }
115
+ ```
116
+
117
+ Apply the same pattern to **`render-all/page.tsx`**.
118
+
119
+ ### 4 — Create an empty `showcase-mocks.json` stub
120
+
121
+ Create `src/generated/showcase-mocks.json` so the import compiles before curated data exists:
122
+
123
+ ```json
124
+ {
125
+ "curatedAt": "2026-01-01T00:00:00.000Z",
126
+ "components": {},
127
+ "collections": {}
128
+ }
129
+ ```
130
+
131
+ Once these four steps are done, proceed with the steps below.
132
+
133
+ ---
134
+
135
+ ## Pipeline Overview
136
+
137
+ The workflow is now a **three-step pipeline**:
138
+
139
+ ```
140
+ Step 1: generate-showcase-data → showcase-examples.json (all CMS data, sorted by completeness)
141
+ Step 2: generate-showcase-mocks → showcase-mocks-draft.json (LLM selects best + proposes variants)
142
+ Step 3: AI review (this skill) → showcase-mocks.json (final curated mocks, committed)
143
+ ```
144
+
145
+ Steps 1 and 2 are automated CLI commands. Step 3 is where you (the AI) review the draft,
146
+ adjust anything the LLM got wrong, handle layout variants, and write the final committed file.
147
+
148
+ ---
149
+
150
+ ## Steps
151
+
152
+ ### Step 1 — Run the extraction script
153
+
154
+ Run the CLI to fetch all component/collection entries from Contentful:
155
+
156
+ **Monorepo:**
157
+ ```bash
158
+ pnpm --filter {appName} generate-showcase
159
+ ```
160
+
161
+ **External project (from project root):**
162
+ ```bash
163
+ node node_modules/@se-studio/project-build/dist/generate-showcase-data.js
164
+ ```
165
+
166
+ **Optional flags:**
167
+ - `--include-drafts` — also fetches draft/unpublished entries via the Preview API (requires `CONTENTFUL_PREVIEW_ACCESS_TOKEN`)
168
+ - `--all-types` — fetches all entry content types without a filter (instead of fetching component and collection separately)
169
+
170
+ This writes `src/generated/showcase-examples.json` — every example grouped by type, sorted by
171
+ `fieldCompleteness` descending. This file is gitignored.
172
+
173
+ ### Step 2 — Run the LLM curation script
174
+
175
+ **Monorepo:**
176
+ ```bash
177
+ pnpm --filter {appName} generate-showcase-mocks
178
+ ```
179
+
180
+ **External project:**
181
+ ```bash
182
+ node node_modules/@se-studio/project-build/dist/generate-showcase-mocks.js
183
+ ```
184
+
185
+ This reads `showcase-examples.json`, calls the LLM (OpenAI or Anthropic — auto-detected from
186
+ `.env.local`), and produces:
187
+ - `src/generated/showcase-mocks-draft.json` — best mock per type + proposed variant param sets
188
+ - `src/generated/cms-discovery/accepted-variants/{components|collections|externals}/<slug>.json` — per-type variant files (in mode subdir)
189
+
190
+ **Optional flags:**
191
+ - `--model <model>` — override the LLM model (e.g. `--model gpt-4o`)
192
+ - `--types <Type1,Type2>` — limit to specific type names (comma-separated, useful for re-running single types)
193
+
194
+ ### Step 3 — Read the draft and registrations
195
+
196
+ Read these files:
197
+
198
+ 1. `src/generated/showcase-mocks-draft.json` — the LLM's selected mocks + variant proposals
199
+ 2. `src/lib/registrations.ts` — the app's component/collection registrations
200
+
201
+ From the registrations file, collect:
202
+ - The full list of registered component type names
203
+ - The full list of registered collection type names
204
+ - Any registrations with `showcaseExclude: true` — these types must be skipped entirely
205
+
206
+ Check the draft against the registrations: are there registered types missing from the draft?
207
+ If so, check `showcase-examples.json` directly to find examples for those types.
208
+
209
+ ### Step 4 — Review and refine mocks
210
+
211
+ For each type in the draft:
212
+
213
+ **Validate the LLM selection:**
214
+ - Confirm the selected mock has a real heading (not a test entry)
215
+ - Confirm it has a working visual URL (if the field exists)
216
+ - Confirm the mock fields are complete and reflect real brand content
217
+
218
+ **Add layout variants not in the CMS:**
219
+ Some types have meaningful variants that may not exist as separate CMS entries — a flipped
220
+ layout, a narrow/wide version, or a no-visual state. These can be represented by adjusting
221
+ the base mock with URL param overrides. Review each type's variant proposals from the LLM
222
+ (in `showcase-mocks-draft.json`) and add any important ones that are missing:
223
+
224
+ - For a Hero with a left-layout variant: add a variant with `{ "showcaseParams": { "flip": "true" } }` or similar
225
+ - For a content block with a narrow option: `{ "showcaseParams": { "width": "narrow" } }`
226
+ - Adjust the LLM's proposed params to match the actual param names used in the component's showcase controls
227
+
228
+ **For collections — curating cards:**
229
+ - Select ALL cards from the best example (do not cap — use the real count)
230
+ - If fewer than 4 cards, check the next-best example for additional cards
231
+ - Cards with no heading and no body are useless — skip them
232
+
233
+ ### Step 5 — Write showcase-mocks.json
234
+
235
+ Write the curated data to `src/generated/showcase-mocks.json`. This file IS committed to git.
236
+
237
+ Use the LLM draft as the starting point and apply your corrections from Step 4.
238
+
239
+ **Format:**
240
+
241
+ ```json
242
+ {
243
+ "curatedAt": "2026-02-28T14:00:00.000Z",
244
+ "components": {
245
+ "Hero": {
246
+ "heading": "Mental health care for kids and teens. Parenting support for you.",
247
+ "preHeading": "Brightline",
248
+ "body": { "json": { "nodeType": "document", "content": [...] } },
249
+ "visual": { "width": 1200, "height": 800, "url": "https://images.ctfassets.net/..." },
250
+ "backgroundColour": "Off White"
251
+ }
252
+ },
253
+ "collections": {
254
+ "FAQ": {
255
+ "mock": { "heading": "Top FAQs" },
256
+ "cards": [
257
+ { "heading": "Who is Brightline?", "body": { "json": { ... } } }
258
+ ]
259
+ }
260
+ }
261
+ }
262
+ ```
263
+
264
+ **Rules for the output:**
265
+ - Set `curatedAt` to the current ISO timestamp
266
+ - Only include types that have real CMS data
267
+ - For component mocks: include only fields present in the source data
268
+ - For collection mocks: always include `mock` and `cards`
269
+ - Rich Text body fields must be `{ "json": <Document> }` — copy as-is
270
+ - Visual fields must include `width`, `height`, AND `url` — never strip `url`
271
+ - Include `widthPercent` when present on media/externalVideo entries
272
+ - Include `otherMedia` when present — copy the full array including `url` and `widthPercent`
273
+ - Do NOT invent or modify content — use the real data from the examples file
274
+ - Include `backgroundColour` and `textColour` where the source has them
275
+ - For cards: include ALL fields present in source, including `backgroundColour`, `textColour`, `links`
276
+
277
+ ### Step 6 — Verify
278
+
279
+ After writing, briefly confirm:
280
+ - The file is valid JSON
281
+ - Component and collection counts look reasonable (non-zero)
282
+ - Key types (Hero, main collections) have entries
283
+ - Visual fields include `url` properties
284
+
285
+ ---
286
+
287
+ ## Output files
288
+
289
+ | File | Location | Committed |
290
+ |------|----------|-----------|
291
+ | `showcase-examples.json` | `src/generated/showcase-examples.json` | No (gitignored) |
292
+ | `showcase-mocks-draft.json` | `src/generated/showcase-mocks-draft.json` | No (gitignored) |
293
+ | `accepted-variants/` | `src/generated/cms-discovery/accepted-variants/{components\|collections\|externals}/` | No (gitignored) |
294
+ | `showcase-mocks.json` | `src/generated/showcase-mocks.json` | Yes |
295
+
296
+ ---
297
+
298
+ ## How the showcase uses this
299
+
300
+ The showcase uses a **two-layer model**:
301
+
302
+ 1. **Base: mock data** — `showcase-mocks.json` is merged over inline registration mocks via
303
+ `mergeShowcaseMocks()` from `@se-studio/core-ui`. Curated data takes precedence; types without
304
+ curated data fall back to their inline `mock:` in the registration.
305
+
306
+ 2. **Patch: URL params** — Any control field in the URL (e.g. `?backgroundColour=Navy`) overrides
307
+ the mock. The control bar encodes only values that differ from the mock baseline.
308
+
309
+ `?clean=true` skips mock data entirely and uses the default showcase control state only.
310
+
311
+ ---
312
+
313
+ ## External project setup
314
+
315
+ ### Installing skills
316
+
317
+ For standalone projects not in the monorepo, install SE Studio skills via the `skills` CLI:
318
+
319
+ ```bash
320
+ npx skills add @se-studio/skills
321
+ ```
322
+
323
+ This installs all SE Studio agent skills (including this one) into the project's agent skill
324
+ directories (e.g. `.claude/skills/` for Claude Code).
325
+
326
+ ### Auto-sync on package update
327
+
328
+ Add `@se-studio/skills` as a devDependency and a `postinstall` script so skills reinstall
329
+ whenever `pnpm install` is run:
330
+
331
+ ```json
332
+ "devDependencies": {
333
+ "@se-studio/skills": "^1.0.0"
334
+ },
335
+ "scripts": {
336
+ "postinstall": "npx skills update -y"
337
+ }
338
+ ```
339
+
340
+ ### Script paths
341
+
342
+ The CLI scripts are available as installed binaries after `npm install @se-studio/project-build`.
343
+ Both `generate-showcase-data` and `generate-showcase-mocks` read `.env.local` from `process.cwd()`,
344
+ so run them from the project root.