@rubytech/create-maxy 1.0.878 → 1.0.880
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/package.json +1 -1
- package/payload/platform/plugins/cloudflare/PLUGIN.md +9 -0
- package/payload/platform/plugins/docs/references/platform.md +5 -1
- package/payload/platform/plugins/docs/references/plugins-guide.md +2 -2
- package/payload/platform/templates/agents/admin/IDENTITY.md +2 -0
- package/payload/premium-plugins/real-agency/BUNDLE.md +4 -2
- package/payload/premium-plugins/real-agency/plugins/brochures/PLUGIN.md +36 -0
- package/payload/premium-plugins/real-agency/plugins/brochures/commands/make-brochure.md +11 -0
- package/payload/premium-plugins/real-agency/plugins/brochures/skills/a4-print-documents/SKILL.md +288 -0
- package/payload/premium-plugins/real-agency/plugins/brochures/skills/brand-design/SKILL.md +185 -0
- package/payload/premium-plugins/real-agency/plugins/brochures/skills/make-brochure/SKILL.md +239 -0
- package/payload/premium-plugins/real-agency/plugins/brochures/skills/property-brochure/SKILL.md +306 -0
- package/payload/premium-plugins/real-agency/plugins/brochures/skills/property-brochure/references/template.html +1824 -0
- package/payload/premium-plugins/real-agency/plugins/brochures/skills/property-extract/SKILL.md +228 -0
- package/payload/server/chunk-2INJCOYG.js +1373 -0
- package/payload/server/chunk-DOIAYD3J.js +2282 -0
- package/payload/server/chunk-ICY65BIH.js +11364 -0
- package/payload/server/chunk-Q5J4NI6Q.js +660 -0
- package/payload/server/client-pool-JAM3QHGW.js +34 -0
- package/payload/server/cloudflare-task-tracker-HUTXJQXO.js +20 -0
- package/payload/server/maxy-edge.js +3 -3
- package/payload/server/public/assets/{Checkbox-CqsIsmEi.js → Checkbox-CeujDRv0.js} +1 -1
- package/payload/server/public/assets/{admin-CZlNLb9T.js → admin-CCEuBnaK.js} +4 -4
- package/payload/server/public/assets/data-LYciLZK9.js +1 -0
- package/payload/server/public/assets/graph-C-SKAbGX.js +1 -0
- package/payload/server/public/assets/{graph-labels-D0qUVHtZ.js → graph-labels-Co03qEv5.js} +1 -1
- package/payload/server/public/assets/jsx-runtime-BcZkJOEw.css +1 -0
- package/payload/server/public/assets/{page-CnyySOZF.js → page-C4E0CWHe.js} +1 -1
- package/payload/server/public/assets/{page-DcK36vDf.js → page-DGLz4ozf.js} +1 -1
- package/payload/server/public/assets/{public-SXA00FTv.js → public-rILg7e8-.js} +1 -1
- package/payload/server/public/assets/{useVoiceRecorder-DcByEBLy.js → useVoiceRecorder-D3Upd7Q3.js} +1 -1
- package/payload/server/public/data.html +5 -5
- package/payload/server/public/graph.html +6 -6
- package/payload/server/public/index.html +8 -8
- package/payload/server/public/public.html +5 -5
- package/payload/server/server.js +55 -11
- package/payload/server/public/assets/data-CH-nQ7oX.js +0 -1
- package/payload/server/public/assets/graph-mpWDe4rf.js +0 -1
- package/payload/server/public/assets/jsx-runtime-Cy_HdZWV.css +0 -1
- /package/payload/server/public/assets/{jsx-runtime-BEjEWeaF.js → jsx-runtime-BWYXu1CT.js} +0 -0
package/package.json
CHANGED
|
@@ -53,6 +53,15 @@ The agent loads these references on demand via `plugin-read` as the conversation
|
|
|
53
53
|
|
|
54
54
|
VNC surfacing is post-navigation, never on form submit. Two sites call `useDeviceUrlActions().onShowVnc()` and both fire only after a successful CDP nav: `DeviceUrlBlock` (tool-output URL clicks) and `ActionLogPanel.handleOauthRespawn` (the "Re-open on Pi browser" button rendered when an OAuth URL appears in the action log). The form (`cloudflare-setup-form`) must NOT call `onShowVnc()` on POST resolve — pre-warming the fullscreen overlay before the OAuth URL is on the brand chromium hides the form, the ActionLogPanel, and the very button operators must click. The `[browser-viewer] event=mount surface="overlay"` line must appear within 5 s of `[device-url:click] navigateResult=ok`, never before.
|
|
55
55
|
|
|
56
|
+
### Error envelope contract
|
|
57
|
+
|
|
58
|
+
Every `POST /api/admin/cloudflare/setup` failure returns a `CloudflareSetupError` carrying — in addition to `field`, `message`, `output`, `correlationId`, `streamLogPath` — two structured fields the form relays into the chat as a fenced JSON block:
|
|
59
|
+
|
|
60
|
+
- `inputsAlreadyHeld: { admin?: string; public?: string; apex?: string }` — the FQDNs the route composed from the submit body before `err()` fired. Pre-validation failures emit `{}` so absence is itself deterministic.
|
|
61
|
+
- `discoveryResults: { tunnels: { id; name }[]; domains: string[] }` — the last-known snapshot from the process-lifetime `discoveryCache` Map that `GET /tunnels` and `GET /domains` write to on success.
|
|
62
|
+
|
|
63
|
+
The chat relay appends both as a fenced ```` ```json ```` block under "Held by deterministic tools (do not re-solicit)". The admin agent's reply quotes those values back rather than re-soliciting; the rule lives in IDENTITY.md § "Post-deterministic-error reply contract" and `.docs/agents.md` § "Intent Gate — post-deterministic-error reply contract". The shared `TunnelEntry` shape lives in [`platform/ui/app/lib/cloudflare-setup-types.ts`](../../ui/app/lib/cloudflare-setup-types.ts).
|
|
64
|
+
|
|
56
65
|
## Identity model
|
|
57
66
|
|
|
58
67
|
- **Product identity** (Maxy vs Real Agent) — known from `brand.json` (`productName`, `configDir`).
|
|
@@ -84,7 +84,11 @@ If the browser drops the SSE connection mid-upgrade (typical during the maxy res
|
|
|
84
84
|
|
|
85
85
|
**Mid-turn stream-drop banners.** If a chat turn ends abruptly the bubble shows one of two messages depending on what actually happened. You see "Server is restarting — reconnect will happen automatically." only when the app server itself emits the restart signal — typically during a Software Update or a Cloudflare setup that re-launches the brand service. You see "Lost connection — retrying." when your browser's connection to the Pi dropped mid-stream while the server was still up — typically a flaky Wi-Fi moment or the tunnel hiccupping. Either way the chat resumes once the connection is back; the previously-rendered messages stay on screen so you don't lose context.
|
|
86
86
|
|
|
87
|
-
**Cloudflare setup flow.** Same pattern — POST to `/api/admin/cloudflare/setup` launches a `cloudflare-setup` action that runs `~/setup-tunnel.sh <brand> <port> <hostname...>`. When the script emits the OAuth consent URL on stdout, the log panel surfaces an **"Authorise in Cloudflare"** button; clicking it opens the consent page in a new tab. After you approve, the script's callback receives `cert.pem` and the setup continues through `tunnel create`/`route`/`run`. On devices where a VNC Chromium is also running, the script can drive the click via CDP automatically (same button remains a harmless safety net).
|
|
87
|
+
**Cloudflare setup flow.** Same pattern — POST to `/api/admin/cloudflare/setup` launches a `cloudflare-setup` action that runs `~/setup-tunnel.sh <brand> <port> <hostname...>`. When the script emits the OAuth consent URL on stdout, the log panel surfaces an **"Authorise in Cloudflare"** button; clicking it opens the consent page in a new tab. After you approve, the script's callback receives `cert.pem` and the setup continues through `tunnel create`/`route`/`run`. On devices where a VNC Chromium is also running, the script can drive the click via CDP automatically (same button remains a harmless safety net). Setup failures return a `CloudflareSetupError` carrying `inputsAlreadyHeld:{admin,public,apex}` and `discoveryResults:{tunnels,domains}` (from the process-lifetime discovery cache `/tunnels` and `/domains` populate on success); the form appends both fields as a fenced JSON block to the chat-relay body so the agent's next reply quotes held values verbatim rather than re-soliciting hostnames.
|
|
88
|
+
|
|
89
|
+
**Active-chat stream-log click telemetry.** Clicking "Stream log" in the active chat fetches the URL inline (`/api/admin/logs?type=stream&conversationId=…&download=1`), emits a `[stream-log-click] status=<c> bytes=<n> conversationId=<tail>` line in `server.log` via the `/api/_client-error` event pipe, and downloads the same response. Operator-grep `[stream-log-click] status=404` for client/server identity mismatches.
|
|
90
|
+
|
|
91
|
+
**Bundle-mtime session prelude.** Each admin session boot stamps `[boot] bundleMtime=<iso> conversationId=<tail>` in `server.log` next to `[plugins] MCP servers for session:`; the same value is injected into the admin system prompt as `<deployment>bundleMtime=…</deployment>` so the agent can compare deploy time against any earlier `phase=error` in the conversation and re-invoke the deterministic path when the bundle post-dates the failure.
|
|
88
92
|
|
|
89
93
|
**Sudo password** is prompted once per upgrade. The admin server pipes it to `sudo -S -v` to validate + cache, then forwards it to the action unit via `systemd-run --setenv=SUDO_PASSWORD` so the installer's in-unit `sudo -S` reads it directly — per-TTY sudoers configurations where the user-level cache does not cover a fresh systemd-run unit still work. The password is never written to any log, SSE frame, or persisted file.
|
|
90
94
|
|
|
@@ -76,12 +76,12 @@ Premium plugins are one-off purchases that grant permanent ownership. They are n
|
|
|
76
76
|
| Plugin | Type | What it does | Public agent |
|
|
77
77
|
|--------|------|-------------|-------------|
|
|
78
78
|
| `teaching` | Skills | Interactive tutoring, lesson planning, and study pack generation from your knowledge base | Yes — all 3 skills serve students and parents |
|
|
79
|
-
| `real-agency` | Bundle (
|
|
79
|
+
| `real-agency` | Bundle (11 sub-plugins) | UK estate agency skills — sales, listings, vendor management, buyer management, lead generation, coaching, business operations, onboarding, teaching, Loop CRM, and property brochures. 3 specialist roles (negotiator, valuer, compliance) | 5 sub-plugins (estate-sales, buyers, estate-coaching, estate-teaching, estate-onboarding) |
|
|
80
80
|
| `writer-craft` | Skills + Agent | Manuscript review and writing craft — story architecture, reader engagement, prose craft, editorial practice, and multi-level review | No — writing craft serves the author |
|
|
81
81
|
|
|
82
82
|
**How it works:** When you purchase a premium plugin, it's delivered to your {{productName}} via conversation. Tell {{productName}} "Enable the teaching plugin" and it handles the rest. Premium plugins are yours permanently — they survive updates and reinstalls.
|
|
83
83
|
|
|
84
|
-
Some premium plugins are **bundles** — a single purchase that delivers multiple sub-plugins, each independently activatable. For example, Real Agency delivers
|
|
84
|
+
Some premium plugins are **bundles** — a single purchase that delivers multiple sub-plugins, each independently activatable. For example, Real Agency delivers 11 sub-plugins covering different aspects of estate agency work. You can enable all of them or just the ones you need (e.g., "Enable estate-sales" for just the sales skills). Enabling or disabling individual sub-plugins does not affect the others.
|
|
85
85
|
|
|
86
86
|
**Public agent embedding:** Premium plugins marked as public-eligible have their full content (skills and reference knowledge) embedded in public agent prompts. This means a public agent for a Real Agency member can handle buyer enquiries, book viewings, deliver coaching content, and onboard new applicants — all powered by the premium plugin's domain knowledge. Plugins marked admin-only (listings, vendors, leads, business) are only available to the account owner's admin agent.
|
|
87
87
|
|
|
@@ -89,6 +89,8 @@ Do not retry the same tool against the same target within a turn. A second ident
|
|
|
89
89
|
|
|
90
90
|
When a tool returns a structured failure whose error content begins with an UPPERCASE_ERROR_CODE (for example `WEBFETCH_CANNOT_READ_JS_SPA`), the runtime has already determined that retrying the same tool will fail and that a substitute would launder uncertainty. Read the error's plain-English explanation, then write one or two sentences to the owner that name (a) what failed, (b) the reason in their language, and (c) the concrete actions they can take to unblock — typically pasting text or sending a screenshot. Do not silently dispatch a substitute (Playwright, research-assistant, memory-search) to continue the original instruction; that hides the failure and the owner loses the ability to judge whether the substitute's output answers their question. A verbal instruction in the current conversation is not consent — only an explicit standing policy recorded in account configuration counts, and no such mechanism exists today. Until one exists, every structured tool failure becomes a question for the owner. Wait for direction before resuming.
|
|
91
91
|
|
|
92
|
+
**Post-deterministic-error reply contract — never re-solicit held values.** When a Cloudflare form failure surfaces in the chat relay, the trailing fenced `json` block labelled "Held by deterministic tools (do not re-solicit)" is the route's structured payload. It carries `inputsAlreadyHeld` (the FQDNs already submitted: `admin`, `public`, `apex`) and `discoveryResults` (the discovery snapshot the route was holding: `tunnels`, `domains`). The next reply structurally consumes this payload — restate the held values verbatim, name the literal error, and decide between two actions: (a) if the `<deployment>` block's `bundleMtime` post-dates this failure's timestamp, the deterministic path has been redeployed with a fix — re-invoke the same path immediately; (b) otherwise surface the literal error plus the next deterministic step from the relevant SKILL (`setup-tunnel.sh`, `reset-tunnel.sh`, `dashboard-guide.md`). Asking the operator for a hostname, tunnel name, or apex that already appears in `inputsAlreadyHeld` or `discoveryResults` is a doctrine violation — the structured payload is the answer set; the deterministic path holds the values; the chat relay is for restatement, not re-entry.
|
|
93
|
+
|
|
92
94
|
## Cypher schema
|
|
93
95
|
|
|
94
96
|
Your system prompt contains a `# SCHEMA (Neo4j graph, canonical reference)` block listing every label and relationship type your graph actually contains. Before authoring any cypher against the memory graph, consult that block. Never invent an edge or label name that is not in it — the plausible-sounding names you half-remember from other systems (`HAS_MESSAGE`, `IN_CONVERSATION`, `CONTAINS_MESSAGE`) do not exist here; Messages attach to Conversations via `:PART_OF`, not any other edge.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: real-agency
|
|
3
|
-
description: "UK estate agency skills + Loop CRM integration —
|
|
3
|
+
description: "UK estate agency skills + Loop CRM integration — 11 sub-plugins covering sales, listings, vendor management, buyer management, lead generation, coaching, business operations, onboarding, teaching, Loop CRM, and property brochures. 3 specialist roles (negotiator, valuer, compliance). 32 skills + 22 MCP tools."
|
|
4
4
|
plugins:
|
|
5
5
|
- estate-sales
|
|
6
6
|
- listings
|
|
@@ -12,11 +12,12 @@ plugins:
|
|
|
12
12
|
- estate-onboarding
|
|
13
13
|
- estate-teaching
|
|
14
14
|
- loop
|
|
15
|
+
- brochures
|
|
15
16
|
---
|
|
16
17
|
|
|
17
18
|
# Real Agency
|
|
18
19
|
|
|
19
|
-
Premium plugin bundle for UK estate agency professionals. Purchasing this bundle grants access to all
|
|
20
|
+
Premium plugin bundle for UK estate agency professionals. Purchasing this bundle grants access to all 11 sub-plugins, each independently activatable via `enabledPlugins`. The bundle also delivers three specialist roles — negotiator, valuer, and compliance — that embed domain knowledge from the sub-plugins and operate autonomously with Loop CRM tools.
|
|
20
21
|
|
|
21
22
|
## Specialist Roles
|
|
22
23
|
|
|
@@ -40,3 +41,4 @@ Premium plugin bundle for UK estate agency professionals. Purchasing this bundle
|
|
|
40
41
|
| `estate-onboarding` | 1 | — | First-run member onboarding |
|
|
41
42
|
| `estate-teaching` | 1 | — | Structured education module browsing and delivery |
|
|
42
43
|
| `loop` | — | 22 | Loop CRM integration — properties, people, viewings, feedback, team, marketing, customer preferences, supplier |
|
|
44
|
+
| `brochures` | 5 | — | Property brochure pipeline — brand extract, property extract, A4 layout, print constraints |
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brochures
|
|
3
|
+
description: "End-to-end pipeline for producing print-ready A4 estate-agent property brochures, with a single-entry orchestrator that skips upstream steps whose outputs already exist: extract brand from the agent's website, extract property assets from the listing URL, lay out the brochure, and satisfy print constraints for pixel-perfect PDF."
|
|
4
|
+
tools: []
|
|
5
|
+
metadata: {"platform":{"optional":true,"embed":["admin"]}}
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Real Agency — Brochures
|
|
9
|
+
|
|
10
|
+
End-to-end estate-agent brochure pipeline. From an agent website URL and a property listing URL, the skills produce a print-ready A4 PDF brochure plus the live HTML used to author it. The pipeline is idempotent: each upstream step is skipped when its output already exists on disk for the requested source.
|
|
11
|
+
|
|
12
|
+
## When to Activate
|
|
13
|
+
|
|
14
|
+
The user wants to produce a property brochure — either end-to-end from a listing URL, or from pre-staged photos and a brand pack.
|
|
15
|
+
|
|
16
|
+
## Skills
|
|
17
|
+
|
|
18
|
+
| Skill | Purpose |
|
|
19
|
+
|-------|---------|
|
|
20
|
+
| `make-brochure` | Single-entry orchestrator — brand → property → A4 brochure, skipping upstream steps whose outputs already exist |
|
|
21
|
+
| `brand-design` | Extract brand identity from an agent website URL into a brand pack (DESIGN.md, light/dark logos, description.md) |
|
|
22
|
+
| `property-extract` | Stage property assets from a listing URL (photos, floorplans, EPC, structured metadata) |
|
|
23
|
+
| `property-brochure` | Lay out an A4 brochure from a brand pack + property assets (HTML + per-page print snapshots + recompressed PDF) |
|
|
24
|
+
| `a4-print-documents` | Print constraints for A4 HTML documents — glassmorphism survival, page margins, full-bleed, whitespace discipline |
|
|
25
|
+
|
|
26
|
+
## Commands
|
|
27
|
+
|
|
28
|
+
`/make-brochure <agent-url-or-brand-dir> <listing-url-or-assets-dir>` — run the full pipeline.
|
|
29
|
+
|
|
30
|
+
## Tools Used
|
|
31
|
+
|
|
32
|
+
No MCP server. Skills operate via existing platform tools (Bash, Read, Write, Edit, Glob, Grep, WebFetch) plus the Playwright MCP plugin for headless rendering, screenshot capture, and print-to-PDF. The image encoder is `cwebp` (libwebp); the PDF recompressor is Ghostscript (`gs`).
|
|
33
|
+
|
|
34
|
+
## References
|
|
35
|
+
|
|
36
|
+
Each skill loads its own reference files on demand. The brochure folio template lives at `skills/property-brochure/references/template.html`.
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: End-to-end estate-agent brochure pipeline (brand → property → A4 PDF). Pass an agent URL and a listing URL.
|
|
3
|
+
argument-hint: <agent-url-or-brand-dir> <listing-url-or-assets-dir>
|
|
4
|
+
allowed-tools: Bash, Read, Write, Edit, Glob, Grep, WebFetch, Skill
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
Run the `make-brochure` skill end-to-end on the inputs below. Skip any upstream step whose output already exists on disk.
|
|
8
|
+
|
|
9
|
+
Inputs: $ARGUMENTS
|
|
10
|
+
|
|
11
|
+
Invoke the `make-brochure` skill (from this plugin) and follow its routing rules: `brand-design` → `property-extract` → `property-brochure` → `a4-print-documents`. Stop at the print-ready PDF and report its path.
|
package/payload/premium-plugins/real-agency/plugins/brochures/skills/a4-print-documents/SKILL.md
ADDED
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: a4-print-documents
|
|
3
|
+
description: Constraints for producing A4 HTML documents intended for PDF download via browser print. Use when creating or modifying any HTML document that will be printed to PDF, uses A4 page dimensions, or contains glassmorphism/backdrop-filter effects that must survive print. Triggers include "one-pager", "A4", "print to PDF", "download PDF", "market analysis", "executive document", or any HTML document with a print button.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# A4 Print-Ready HTML Documents
|
|
7
|
+
|
|
8
|
+
Constraints derived from two corrected reference documents: `biosymm/output/biosymm-one-pager.html` (single A4 page) and `gpu-derivatives/output/gpu-derivatives-brochure.html` (multi-page flowing brochure). Every rule exists because violating it caused a visible problem.
|
|
9
|
+
|
|
10
|
+
## Cover glassmorphism panels must span the full page width
|
|
11
|
+
|
|
12
|
+
When the cover uses a glassmorphism panel for the title block (eyebrow, wordmark, gold rule, tagline, contact strip), make it a horizontal **full-width band** anchored to the page edges — not a floating card with side margins. Full-width bands read as architectural marquees that match A4 proportions; floating cards look like UI tooltips superimposed on a photo.
|
|
13
|
+
|
|
14
|
+
```css
|
|
15
|
+
.cover-glass {
|
|
16
|
+
position: absolute;
|
|
17
|
+
left: 0; right: 0; bottom: 0;
|
|
18
|
+
height: 88mm; /* lock the height so content cannot overflow */
|
|
19
|
+
padding: 12mm 22mm; /* generous side padding gives the title breathing room */
|
|
20
|
+
background: rgba(20, 20, 20, 0.30);
|
|
21
|
+
backdrop-filter: blur(22px) saturate(135%);
|
|
22
|
+
-webkit-backdrop-filter: blur(22px) saturate(135%);
|
|
23
|
+
border-top: 1px solid rgba(255, 255, 255, 0.18);
|
|
24
|
+
overflow: hidden;
|
|
25
|
+
z-index: 3;
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
**Critical structural rule — the band must be a direct child of the cover element**, not nested inside a padded wrapper. If you nest it inside a wrapper that has `padding: 18mm 18mm 16mm` and `position: absolute; inset: 0`, the absolutely-positioned band's `bottom: 0` will not actually anchor to the page edge in every browser's print engine, and content overflows below the page. Place the title block as a sibling of `.cover-photo` and `.cover-veil`, directly inside `.cover`:
|
|
30
|
+
|
|
31
|
+
```html
|
|
32
|
+
<section class="page cover">
|
|
33
|
+
<img class="cover-print-img" src="cover-print.png" alt="">
|
|
34
|
+
<div class="cover-photo"></div>
|
|
35
|
+
<div class="cover-veil"></div>
|
|
36
|
+
<div class="cover-top">…logo + locale…</div> <!-- absolute, top-anchored -->
|
|
37
|
+
<div class="cover-glass">…title block…</div> <!-- absolute, bottom-anchored -->
|
|
38
|
+
</section>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Lock the band height** with an explicit `height` (e.g. `88mm`) and `overflow: hidden`. Don't rely on `height: auto` with `bottom: 0` — content overflow caused by font-loading races, wrapping changes, or hidden flex constraints will silently push text below the page edge in the screenshot capture, even if `overflow: hidden` is on the page itself. Locking the height plus tight content control is how you guarantee the band looks identical on screen and in print.
|
|
42
|
+
|
|
43
|
+
**Keep the band's content compact.** Inside the band: an eyebrow, the title (≤ 56pt), a gold rule (≤ 22mm), and the tagline (≤ 14pt with `max-width: 165mm`). Resist the urge to add a contact-strip footer inside the band — the logo at the top of the cover is sufficient branding, and key facts live on the next page. A busy band crowds the title; a clean band lets the wordmark do its job.
|
|
44
|
+
|
|
45
|
+
## Glassmorphism does not survive print
|
|
46
|
+
|
|
47
|
+
`backdrop-filter: blur()`, CSS glassmorphism, and layered transparency effects render as flat, transparent boxes in browser print/PDF output. This is a browser limitation, not a CSS error.
|
|
48
|
+
|
|
49
|
+
**Required pattern:** Every section using glassmorphism needs a pre-rendered PNG fallback that is hidden on screen and shown only in print.
|
|
50
|
+
|
|
51
|
+
```css
|
|
52
|
+
.cover-print-img { display: none; }
|
|
53
|
+
|
|
54
|
+
@media print {
|
|
55
|
+
.cover > *:not(.cover-print-img) { display: none !important; }
|
|
56
|
+
.cover-print-img {
|
|
57
|
+
display: block !important;
|
|
58
|
+
position: absolute;
|
|
59
|
+
inset: 0;
|
|
60
|
+
width: 100%;
|
|
61
|
+
height: 100%;
|
|
62
|
+
object-fit: cover;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
```html
|
|
68
|
+
<div class="cover">
|
|
69
|
+
<img class="cover-print-img" src="cover-print.png" alt="">
|
|
70
|
+
<!-- live glassmorphism content follows -->
|
|
71
|
+
</div>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
This pattern applies to every full-bleed glassmorphism section (cover pages, back pages). The GPU derivatives brochure uses it for both `.cover` and `.backpage`.
|
|
75
|
+
|
|
76
|
+
### Capturing the print image
|
|
77
|
+
|
|
78
|
+
Each glassmorphism section needs its **own** screenshot — you cannot reuse a print image from a different document or a differently-sized section.
|
|
79
|
+
|
|
80
|
+
**Capture process** (using Playwright or equivalent browser automation):
|
|
81
|
+
|
|
82
|
+
1. Serve the HTML over HTTP (e.g. `python3 -m http.server`) — `file://` protocol is blocked by Playwright.
|
|
83
|
+
2. Set the viewport to match the element's rendered size. Measure the element with `boundingBox()` first, then resize the viewport to `Math.ceil(width) + 1` by `Math.ceil(height) + 1` to eliminate scrollbars.
|
|
84
|
+
3. Hide UI chrome (download buttons, navigation overlays) **and** set `document.body.style.overflow = 'hidden'` to suppress any body-level scrollbars.
|
|
85
|
+
4. Screenshot the specific element (e.g. `.cover`, `.backpage`) using `locator.screenshot()` — not a full-page or viewport screenshot.
|
|
86
|
+
5. Save the PNG alongside the HTML in the same output directory, named for the section it replaces (e.g. `cover-print.png`, `backpage-print.png`).
|
|
87
|
+
6. Restore hidden elements and overflow after capture.
|
|
88
|
+
7. Reference this image in the `<img>` element's `src`.
|
|
89
|
+
8. Visually verify the saved PNG by reading it — confirm no scrollbars, no UI chrome, correct dimensions.
|
|
90
|
+
|
|
91
|
+
## Page margins, page numbers, and running footers
|
|
92
|
+
|
|
93
|
+
Use `@page` margin boxes for page numbers and running footers — not `position: fixed` elements. This is the pattern used in the GPU derivatives brochure and is the most reliable cross-browser approach.
|
|
94
|
+
|
|
95
|
+
```css
|
|
96
|
+
@page {
|
|
97
|
+
margin: 0.6in 0.7in 0.8in;
|
|
98
|
+
@bottom-center {
|
|
99
|
+
content: counter(page);
|
|
100
|
+
font-family: 'Playfair Display', Georgia, serif;
|
|
101
|
+
font-size: 9pt;
|
|
102
|
+
color: #8A8A84;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* Cover page: zero margins, no page number */
|
|
107
|
+
@page :first {
|
|
108
|
+
margin: 0;
|
|
109
|
+
@bottom-center { content: none; }
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/* Named page for full-bleed back page */
|
|
113
|
+
@page backpage-full {
|
|
114
|
+
margin: 0;
|
|
115
|
+
@bottom-center { content: none; }
|
|
116
|
+
}
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Then in `@media print`, the cover needs NO `page:` property — `@page :first` handles it. Only the backpage needs the named page assignment:
|
|
120
|
+
|
|
121
|
+
```css
|
|
122
|
+
@media print {
|
|
123
|
+
.cover {
|
|
124
|
+
width: auto; margin: 0; box-shadow: none; /* reset screen-only properties */
|
|
125
|
+
min-height: 0;
|
|
126
|
+
height: 100vh;
|
|
127
|
+
page-break-after: always;
|
|
128
|
+
position: relative;
|
|
129
|
+
overflow: hidden;
|
|
130
|
+
}
|
|
131
|
+
.backpage {
|
|
132
|
+
width: auto; margin: 0; box-shadow: none; /* reset screen-only properties */
|
|
133
|
+
min-height: 0;
|
|
134
|
+
height: 100vh;
|
|
135
|
+
page-break-before: always;
|
|
136
|
+
position: relative;
|
|
137
|
+
overflow: hidden;
|
|
138
|
+
page: backpage-full;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
**Key details:**
|
|
144
|
+
- `@page :first` zeros the margins for the cover — no named page needed on the cover element. This is the pattern from the GPU derivatives reference and it works.
|
|
145
|
+
- Named pages are only needed for non-first full-bleed pages (backpage).
|
|
146
|
+
- `counter(page)` gives automatic page numbering with no JavaScript.
|
|
147
|
+
- No `position: fixed` hacks are needed for repeating headers/footers.
|
|
148
|
+
- If the screen CSS uses `width: 210mm; margin: 20px auto; box-shadow: ...` on the cover/backpage (for the card-on-grey-background look), the print CSS MUST explicitly reset these: `width: auto; margin: 0; box-shadow: none;`. Screen-only layout properties leak into print if not reset. Do NOT use `width: 100vw` or `margin: 0 !important` — just `width: auto; margin: 0`.
|
|
149
|
+
- The print image uses `position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;` — this is what the GPU derivatives reference uses and it works.
|
|
150
|
+
|
|
151
|
+
## A4 layout — continuous flow, not fixed-height boxes
|
|
152
|
+
|
|
153
|
+
Forcing each section into a fixed `height: 297mm` div creates large whitespace gaps when content doesn't fill a full page.
|
|
154
|
+
|
|
155
|
+
**Correct approach:**
|
|
156
|
+
|
|
157
|
+
- **Cover page:** `min-height: 100vh` on screen; `height: 100vh; page-break-after: always;` in print.
|
|
158
|
+
- **Content:** Flows naturally. The `@page` margins handle spacing. No fixed-height containers.
|
|
159
|
+
- Use `page-break-inside: avoid` on logical units (cards, tables, callouts, stat groups, timeline items, competitor cards, pullquotes).
|
|
160
|
+
- Use `page-break-before: always` on major section dividers (part breaks).
|
|
161
|
+
- Use `page-break-after: avoid` on headings and section numbers so they don't strand at the bottom of a page.
|
|
162
|
+
- Set `orphans: 3; widows: 3;` on paragraphs to prevent single-line stragglers.
|
|
163
|
+
|
|
164
|
+
## No page may end with significant whitespace
|
|
165
|
+
|
|
166
|
+
Every A4 page must have its content fill the page intentionally — to the bottom margin or close to it. Large blocks of empty space at the bottom of a page are an editorial failure: they make a brochure feel underweight and signal that the layout was never finished. Print buyers read whitespace as "the agency couldn't be bothered."
|
|
167
|
+
|
|
168
|
+
**The rule:** if a page has visible empty space below the last content block that's larger than ~25mm (≈ 10% of A4 height), do one of three things — never ship it as-is.
|
|
169
|
+
|
|
170
|
+
1. **Resize the existing content to fill.** Make image grids stretch to the available height (`grid-auto-rows: 1fr` plus `flex: 1; min-height: 0` on the grid container). Make figures/charts `flex: 1; min-height: 0; object-fit: contain`. Pull text to a larger size if the column is narrow. The page's outer container should be `display: flex; flex-direction: column` so children can grow.
|
|
171
|
+
|
|
172
|
+
2. **Add more content of the same kind.** A photo gallery on a property brochure should fill — if you have 8 images and the grid stops at 60% of the page, add 3 more images and extend the grid to 5 rows. Reach back to the source media for unused assets before resorting to filler.
|
|
173
|
+
|
|
174
|
+
3. **Add a different kind of supporting content** — a sidebar with stats and copy beside a wide-aspect image, a closing callout band at the bottom of an otherwise text-heavy page, a distances/highlights block beside an EPC chart, a room schedule next to a floorplan. The added content must be substantively useful, not decorative noise.
|
|
175
|
+
|
|
176
|
+
**Diagnostic patterns** that produce whitespace and how to fix them:
|
|
177
|
+
|
|
178
|
+
| Pattern | Why it leaves space | Fix |
|
|
179
|
+
|---|---|---|
|
|
180
|
+
| `object-fit: contain` on a wide-aspect image inside a tall pane | Image fits to width, leaves vertical empty space above and below | Either pair the image with a meta-column sidebar (image + descriptive text in 2-col grid) or stack the image with a content block beneath |
|
|
181
|
+
| Grid with `grid-auto-rows: 36mm` (fixed) | Grid only takes its computed natural height, ignoring page height | Use `grid-auto-rows: 1fr` and put the grid in a `flex: 1` container so rows stretch to fill |
|
|
182
|
+
| Body content with no explicit flex | Content sizes to its natural height, leaving the bottom of the page empty | Make the page a flex column (`display: flex; flex-direction: column`) and give the last (or main) block `flex: 1; min-height: 0` |
|
|
183
|
+
| Two-column layout where one column is much shorter | Short column leaves whitespace below it | Either `align-items: stretch` (so the short column gets a meta-block at the bottom) or split the layout into a 3-band design where a third row covers the gap |
|
|
184
|
+
|
|
185
|
+
**Verify by reading the rendered PDF page-by-page.** `pdfinfo` reporting "10 pages, A4" is not verification. Open each page visually, look at the bottom 30%, and confirm content reaches it. The skill's emphasis on "Visually verify the saved PNG by reading it" applies equally to every PDF page, not just the cover.
|
|
186
|
+
|
|
187
|
+
## Dark backgrounds are stripped in print
|
|
188
|
+
|
|
189
|
+
Browsers strip background colours by default when printing.
|
|
190
|
+
|
|
191
|
+
**Required:** Add both properties to every dark element in `@media print`:
|
|
192
|
+
|
|
193
|
+
```css
|
|
194
|
+
@media print {
|
|
195
|
+
.dark-element {
|
|
196
|
+
-webkit-print-color-adjust: exact;
|
|
197
|
+
print-color-adjust: exact;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Stripping glassmorphism from content areas
|
|
203
|
+
|
|
204
|
+
In multi-page documents, strip `backdrop-filter` from content sections (where it won't render correctly anyway) while preserving it on cover/backpage elements that are replaced with print images:
|
|
205
|
+
|
|
206
|
+
```css
|
|
207
|
+
@media print {
|
|
208
|
+
/* Strip glass from content */
|
|
209
|
+
.content *, .content *::before, .content *::after {
|
|
210
|
+
backdrop-filter: none !important;
|
|
211
|
+
-webkit-backdrop-filter: none !important;
|
|
212
|
+
border-radius: 0 !important;
|
|
213
|
+
box-shadow: none !important;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
## Document structure pattern
|
|
219
|
+
|
|
220
|
+
Multi-page documents follow this structure:
|
|
221
|
+
|
|
222
|
+
1. **Cover** — full-bleed, glassmorphism, with print image fallback. Uses `@page :first { margin: 0; }` — NO named page on the element. `page-break-after: always`.
|
|
223
|
+
2. **Table of contents** (optional) — `page-break-after: always` to start content on a fresh page.
|
|
224
|
+
3. **Content sections** — flowing, with part dividers using `page-break-before: always`.
|
|
225
|
+
4. **Back page** — full-bleed CTA/contact page. **Not** an inline footer div — a separate top-level element outside `.body-wrap` with its own named page, print image fallback, and `page-break-before: always`.
|
|
226
|
+
|
|
227
|
+
**The back page is mandatory for multi-page documents.** An inline CTA footer (a `div` inside flowing content) ends up floating mid-page with whitespace below it. The back page pattern guarantees a clean final page.
|
|
228
|
+
|
|
229
|
+
```css
|
|
230
|
+
@page backpage-full {
|
|
231
|
+
margin: 0;
|
|
232
|
+
@bottom-center { content: none; }
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
@media print {
|
|
236
|
+
.backpage {
|
|
237
|
+
page: backpage-full;
|
|
238
|
+
min-height: 0; height: 100vh;
|
|
239
|
+
page-break-before: always;
|
|
240
|
+
position: relative; overflow: hidden;
|
|
241
|
+
}
|
|
242
|
+
.backpage > *:not(.backpage-print-img) { display: none !important; }
|
|
243
|
+
.backpage-print-img {
|
|
244
|
+
display: block !important;
|
|
245
|
+
position: absolute;
|
|
246
|
+
inset: 0;
|
|
247
|
+
width: 100%; height: 100%;
|
|
248
|
+
object-fit: cover;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
```html
|
|
254
|
+
<!-- Outside .body-wrap, after it closes -->
|
|
255
|
+
<div class="backpage">
|
|
256
|
+
<img class="backpage-print-img" src="backpage-print.png" alt="" style="display:none;">
|
|
257
|
+
<!-- live backpage content (bg, text, contact info) -->
|
|
258
|
+
</div>
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
The backpage print image is captured via the same Playwright process as the cover — element-level screenshot with UI chrome hidden.
|
|
262
|
+
|
|
263
|
+
## Single-page documents
|
|
264
|
+
|
|
265
|
+
For single A4 documents (like the BioSymm one-pager), use fixed dimensions:
|
|
266
|
+
|
|
267
|
+
```css
|
|
268
|
+
.page {
|
|
269
|
+
width: 210mm;
|
|
270
|
+
min-height: 297mm;
|
|
271
|
+
margin: 0 auto;
|
|
272
|
+
overflow: hidden;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
@page { size: A4; margin: 0; }
|
|
276
|
+
|
|
277
|
+
@media print {
|
|
278
|
+
.page {
|
|
279
|
+
width: 210mm;
|
|
280
|
+
height: 297mm;
|
|
281
|
+
page-break-after: always;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Document background for multi-page screen viewing
|
|
287
|
+
|
|
288
|
+
Multi-page documents use a neutral body background (e.g. `body { background: var(--background); }`) on screen. In `@media print`, reset to `body { background: white; }`.
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: brand-design
|
|
3
|
+
description: Use when a website URL needs to be turned into a brand-design package — a directory containing a tokenized DESIGN.md, light and dark logo files sourced from the site, and a description.md with company copy plus registered company details. Trigger phrases include "extract brand from <url>", "build a brand pack from <site>", "tokenize <site> design", "scrape brand assets", or any request that names a live URL and asks for design tokens, logos, and company description together.
|
|
4
|
+
allowed-tools:
|
|
5
|
+
- Bash
|
|
6
|
+
- Read
|
|
7
|
+
- Write
|
|
8
|
+
- Edit
|
|
9
|
+
- Glob
|
|
10
|
+
- Grep
|
|
11
|
+
- WebFetch
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# brand-design
|
|
15
|
+
|
|
16
|
+
Turn one publicly-accessible website URL into a self-contained brand-design directory that downstream design, marketing, and document-generation skills can consume without re-visiting the source site.
|
|
17
|
+
|
|
18
|
+
The reference output this skill targets is `/Users/neo/estate-agents/beacons/` — read that directory once before generating to anchor the standard. (The neighbouring `/Users/neo/estate-agents/muvin/` is structurally identical; either may be inspected.)
|
|
19
|
+
|
|
20
|
+
## Outcome contract
|
|
21
|
+
|
|
22
|
+
The skill is **complete** when the target directory contains exactly these four artifacts at its root:
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
<output-dir>/
|
|
26
|
+
DESIGN.md # tokenized design system, observed values
|
|
27
|
+
<slug>-logo-light.png # logo as it renders on a light surface
|
|
28
|
+
<slug>-logo-dark.png # logo as it renders on a dark surface
|
|
29
|
+
description.md # company copy + official registration details
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
`<slug>` is the lowercase, hyphen-separated brand name (e.g. `beacons`, not `beaconsrealestate.co.uk`). The slug is reused as the directory name unless the caller specifies otherwise — that is, the brand workspace is `<output-dir>/<slug>/` and these four files live at its root.
|
|
33
|
+
|
|
34
|
+
A sibling `properties/` directory may also be present at `<output-dir>/properties/` — it belongs to `property-extract` and **must not** be touched by this skill. Working files this skill creates (screenshots, intermediate JSON, snapshot dumps) must be cleaned up before reporting completion. The four artifacts above are the deliverable; nothing else this skill writes is "scratch" that survives.
|
|
35
|
+
|
|
36
|
+
## Inputs
|
|
37
|
+
|
|
38
|
+
Required: a URL. If only a brand name is given, decline and ask for the URL — there is no reliable way to disambiguate brand without the source of truth.
|
|
39
|
+
|
|
40
|
+
Optional: an output directory path. Default: `./<slug>/` in the caller's current working directory.
|
|
41
|
+
|
|
42
|
+
## Scope boundaries
|
|
43
|
+
|
|
44
|
+
| In scope | Out of scope |
|
|
45
|
+
|---|---|
|
|
46
|
+
| Public HTML/CSS sites renderable in a headless browser | Login-gated sites, paywalled content |
|
|
47
|
+
| Brand colour, type, spacing, motion, radius, shadow, layout tokens | Editorial/component-level patterns (defer to `design-systems:component-spec`) |
|
|
48
|
+
| Header logo, footer logo, favicon | Photography, iconography sets, illustrations |
|
|
49
|
+
| Company copy from Home + About + Footer + Contact pages | Blog content, case studies, full marketing copy library |
|
|
50
|
+
| UK Companies House-style registration details when present in the footer or `/legal`, `/terms`, `/privacy`, `/imprint` | Hunting for company details outside the site (no Companies House lookups, no LinkedIn) |
|
|
51
|
+
| Light + dark logos as the site itself ships them | Generating brand variants the brand has not authored — but a recoloured fallback is permitted with explicit provenance, see **Logo authenticity** |
|
|
52
|
+
|
|
53
|
+
If the site is JS-only and the headless browser cannot render it, stop and report `STATUS: BLOCKED` with the symptom — do not synthesise tokens from a blank page.
|
|
54
|
+
|
|
55
|
+
## Artifact contracts
|
|
56
|
+
|
|
57
|
+
### `DESIGN.md`
|
|
58
|
+
|
|
59
|
+
A three-tier (primitive → semantic → component) token spec produced from **observed computed styles**, not from CSS source guesses. Every value in tier 1 must be backed by a measurement at a real viewport.
|
|
60
|
+
|
|
61
|
+
The contract for this file is owned by `design-systems:tokenize`. Invoke that skill against the target URL and write its output to `<output-dir>/DESIGN.md`. Do not re-derive tokens here.
|
|
62
|
+
|
|
63
|
+
What the file must contain regardless of who generated it:
|
|
64
|
+
|
|
65
|
+
- A header noting the source URL and the date the tokens were captured.
|
|
66
|
+
- Inventory & method paragraph stating viewports inspected and how counts were obtained.
|
|
67
|
+
- Tier 1 primitives for: colour, alpha/scrim, typography (family, weights, size scale at desktop **and** mobile, line-height, letter-spacing), spacing, radius, shadow, motion, layout, breakpoints. Each row carries the observed count or `(proposed)` if the value is being introduced rather than extracted.
|
|
68
|
+
- Tier 2 semantic role mappings (text, surface, action, border, typography roles, spacing roles, motion roles).
|
|
69
|
+
- Tier 3 component tokens for at least: primary button, text input, card, hero, footer, header, banded section.
|
|
70
|
+
- A **Theme Mapping** section with the as-built theme **and** a proposed dark-theme block. Mark the dark theme as proposed if the site does not ship one.
|
|
71
|
+
- A **Divergences** block calling out every place the captured value disagrees with prior assumed/inherited token docs (if any) — wording: "Prior assumption / Actual live behaviour".
|
|
72
|
+
- A migration guide: ordered find/replace from raw values to tokens, plus behaviours-to-correct table.
|
|
73
|
+
|
|
74
|
+
The naming convention is `--ds-{category}-{property}-{variant}-{state}` unless the site already ships a brand-prefixed convention, in which case adopt the existing prefix and note it.
|
|
75
|
+
|
|
76
|
+
### `<slug>-logo-light.png` and `<slug>-logo-dark.png`
|
|
77
|
+
|
|
78
|
+
Two PNGs of the wordmark/lockup as the brand uses it. Naming is literal: lowercase slug, hyphenated, `-logo-light.png` / `-logo-dark.png`.
|
|
79
|
+
|
|
80
|
+
Acceptance criteria:
|
|
81
|
+
|
|
82
|
+
- File format: PNG with alpha. Even if the source is SVG, also write a rasterised PNG at 2× the rendered header height for downstream document-generation skills that don't accept SVG.
|
|
83
|
+
- The light logo renders cleanly on a white-to-paper-50 surface; the dark logo renders cleanly on an ink/black surface.
|
|
84
|
+
- No surrounding chrome. The crop is the logo itself plus the brand's intended whitespace — not a slice of the navigation bar.
|
|
85
|
+
- Aspect ratio matches the source. Do not stretch.
|
|
86
|
+
|
|
87
|
+
#### Logo authenticity
|
|
88
|
+
|
|
89
|
+
Provenance must be honest. The two acceptable origins, in priority order:
|
|
90
|
+
|
|
91
|
+
1. **Authored** — the brand ships two distinct logo files (one for light surfaces, one for dark). Use both verbatim from their `<img src>` URLs (or inline SVG, rasterised). This is the only origin that may be silently saved.
|
|
92
|
+
2. **Recoloured derivative** — the brand ships only one logo. The second file is generated by recolouring (typically inverting fill from `--ds-color-ink-900` to `--ds-color-paper-0`, or vice versa). When this happens:
|
|
93
|
+
- Append a single line at the bottom of `description.md` under a `## Asset notes` heading: `<slug>-logo-dark.png is a recoloured derivative — the source site ships one logo only.` (Or `-light.png`, whichever was synthesised.)
|
|
94
|
+
- Do not invent shape changes, glows, or stroke variants. Only fill colour may be inverted.
|
|
95
|
+
|
|
96
|
+
A photographic crop of the logo from a screenshot is **not** acceptable — the result has anti-aliased edges against a non-transparent background. Always pull the asset from `<img src>` / `<svg>` and rasterise on a transparent canvas.
|
|
97
|
+
|
|
98
|
+
### `description.md`
|
|
99
|
+
|
|
100
|
+
Plain Markdown, no frontmatter. The structure mirrors the reference at `/Users/neo/estate-agents/beacons/description.md`:
|
|
101
|
+
|
|
102
|
+
1. Brand name on its own line.
|
|
103
|
+
2. The brand's own tagline / one-liner from the homepage hero.
|
|
104
|
+
3. Vision / "about us" paragraph(s) verbatim from the homepage and About page. Keep paragraph breaks. Do not paraphrase.
|
|
105
|
+
4. Service-area or coverage paragraph if the brand has one (common for property, legal, healthcare, trades).
|
|
106
|
+
5. A short list of value-prop bullets if the homepage uses them (e.g. "Personal Service / Transparent Communication / …"). Keep them as a flat list, one per line, no bullet character.
|
|
107
|
+
6. The closing call-to-action paragraph from the homepage or contact page.
|
|
108
|
+
7. Brand name again as a divider.
|
|
109
|
+
8. **Official details block** — extracted from the footer, terms, privacy, or imprint page. Each on its own line, label first:
|
|
110
|
+
- `Registered Office: …`
|
|
111
|
+
- `Registered Company Number: …` (UK) or `Company Registration Number: …` (other)
|
|
112
|
+
- `VAT Registration Number: …` (if shown)
|
|
113
|
+
- Any regulator-issued numbers shown publicly (FCA, ICO, RICS, ARLA, Bar Council, etc.)
|
|
114
|
+
9. The source URL on the final line.
|
|
115
|
+
|
|
116
|
+
Capture rules:
|
|
117
|
+
|
|
118
|
+
- **Verbatim** — preserve the brand's punctuation, capitalisation, and Oxford comma habits. This file is the source of truth for downstream brochures, decks, and emails; paraphrasing introduces drift.
|
|
119
|
+
- If a section is missing from the site, omit it. Do not invent placeholders.
|
|
120
|
+
- If the company is non-UK, replace UK-specific labels with the local equivalents (`Handelsregister`, `SIRET`, `EIN`, `ABN`, etc.) — but only if those labels appear on the site.
|
|
121
|
+
- Do not include phone numbers, email addresses, or contact form URLs unless they appear in the official-details footer block. Marketing contact details belong in a separate brand asset, not this file.
|
|
122
|
+
|
|
123
|
+
## How tokens, logos, and copy fit together
|
|
124
|
+
|
|
125
|
+
These three artifacts are not independent — they cross-reference:
|
|
126
|
+
|
|
127
|
+
- `description.md`'s "Asset notes" line records when `*-light.png` or `*-dark.png` was synthesised rather than authored.
|
|
128
|
+
- `DESIGN.md`'s ink and paper primitives are the colours used to fill any synthesised dark logo. The recolour is not a free choice — it ties to `--ds-color-paper-0` for light-on-dark and `--ds-color-ink-900` for dark-on-light.
|
|
129
|
+
- `DESIGN.md`'s `--ds-color-action-primary-bg` is usually the same accent that appears in the brand's logo. A mismatch is a useful sanity check — if they disagree, re-inspect the logo source.
|
|
130
|
+
|
|
131
|
+
After all three artifacts are written, do a final consistency pass: open each file and confirm the cross-references are consistent.
|
|
132
|
+
|
|
133
|
+
## Process — high level
|
|
134
|
+
|
|
135
|
+
The skill orchestrates three smaller capabilities and a final assembly. Each is a **what**, not a **how**:
|
|
136
|
+
|
|
137
|
+
1. **Tokenize.** Drive `design-systems:tokenize` (or its equivalent) against the URL at desktop (1440×900) and mobile (500×700) viewports. Output → `DESIGN.md`.
|
|
138
|
+
2. **Extract logos.** From a rendered page, locate the brand-mark element in the header (light surface) and the footer (dark surface). Pull each via its source URL or inline SVG markup. Rasterise SVG to PNG with a transparent background. If only one origin exists, generate the other as a recoloured derivative and record the provenance.
|
|
139
|
+
3. **Capture copy.** Visit the homepage, About page, and footer/legal page. Extract the sections enumerated in the `description.md` contract above. Preserve verbatim text.
|
|
140
|
+
4. **Assemble.** Write the four artifacts to `<output-dir>/`. Run the cross-reference consistency pass. Delete any working files.
|
|
141
|
+
|
|
142
|
+
The skill does **not** prescribe which browser tool to use. Where multiple are available (gstack `browse`, Chrome DevTools MCP, Playwright MCP), pick whichever is already wired in the current environment. Token capture in particular benefits from Chrome DevTools because computed styles and `@media` rules are first-class there.
|
|
143
|
+
|
|
144
|
+
## Reference standard
|
|
145
|
+
|
|
146
|
+
Before producing output, read these files to anchor the format:
|
|
147
|
+
|
|
148
|
+
- `/Users/neo/estate-agents/beacons/DESIGN.md` — the depth and format expected of the token spec.
|
|
149
|
+
- `/Users/neo/estate-agents/beacons/description.md` — the voice and structure expected of the company description.
|
|
150
|
+
- `/Users/neo/estate-agents/beacons/beacons-logo-light.png`, `…-dark.png` — the visual standard for logo crops.
|
|
151
|
+
|
|
152
|
+
A delivered package that diverges substantially in structure from the reference is wrong, even if the content is accurate.
|
|
153
|
+
|
|
154
|
+
## Common mistakes
|
|
155
|
+
|
|
156
|
+
| Mistake | Why it's wrong |
|
|
157
|
+
|---|---|
|
|
158
|
+
| Saving a screenshot crop instead of pulling `<img src>` | Crops carry the surrounding background colour as anti-aliased noise. The PNG must be transparent on the logo's negative space. |
|
|
159
|
+
| Synthesising a dark logo silently | Downstream consumers will treat a derivative as authoritative. Provenance is mandatory. |
|
|
160
|
+
| Paraphrasing the homepage hero into "punchier" copy | `description.md` is the source of truth for the brand's voice. The brand's words, not yours. |
|
|
161
|
+
| Inventing token values that the site doesn't use | Token tier 1 is **observed**. `(proposed)` is for tier-2/3 values that fill an obvious gap, not for guesses about what the brand wants. |
|
|
162
|
+
| Including blog posts or case studies in `description.md` | The file is identity, not editorial. |
|
|
163
|
+
| Naming files after the domain (`beaconsrealestate-logo.png`) | Slug is the brand name, not the FQDN. |
|
|
164
|
+
| Skipping the mobile viewport during token capture | Type scale and section padding both differ at mobile. A desktop-only tokenization is incomplete. |
|
|
165
|
+
| Generating the dark theme block in `DESIGN.md` from imagination | If the site is light-only, the dark theme is an **inversion derived from the primitives**, marked "proposed", not a parallel design system. |
|
|
166
|
+
| Embedding the company description inside `DESIGN.md` | The artifacts are separable on purpose. Each file has one job. |
|
|
167
|
+
|
|
168
|
+
## Completion criteria
|
|
169
|
+
|
|
170
|
+
Report `DONE` only after:
|
|
171
|
+
|
|
172
|
+
- All four files exist at the expected paths and only those files.
|
|
173
|
+
- `DESIGN.md` references the source URL and capture date in its first paragraph.
|
|
174
|
+
- Both logo PNGs render correctly on their target surfaces (a quick eyeball at 64px height is sufficient — no chrome, no surrounding nav).
|
|
175
|
+
- `description.md` contains, at minimum, the brand name, the homepage hero copy, and any registration numbers visible on the site.
|
|
176
|
+
- If a recoloured logo was synthesised, the `## Asset notes` line is present in `description.md`.
|
|
177
|
+
- Working files (HTML dumps, snapshot JSON, intermediate screenshots) are removed.
|
|
178
|
+
|
|
179
|
+
If any of those are not true, report `DONE_WITH_CONCERNS` and list each gap.
|
|
180
|
+
|
|
181
|
+
## When NOT to use this skill
|
|
182
|
+
|
|
183
|
+
- The user wants a **proposed** brand identity for a product that doesn't have a site yet → use `brand-pack` or `design-consultation` instead. Those generate; this one extracts.
|
|
184
|
+
- The user wants a fresh DESIGN.md only → call `design-systems:tokenize` directly; the wrapper here is overkill.
|
|
185
|
+
- The user wants a full visual audit, hover states, and component inventory → `plan-design-review` or `design-review` go deeper than this skill is scoped for.
|