@penpair/web 0.1.1 → 0.1.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/README.md +12 -3
- package/docs/getting-started.md +1 -1
- package/docs/guide.md +1 -1
- package/docs/marwes-tokens.md +119 -0
- package/docs/releasing.md +3 -2
- package/package.json +4 -4
package/README.md
CHANGED
|
@@ -128,14 +128,22 @@ Everyone who works with the assistant does their own `npx @penpair/web connect`:
|
|
|
128
128
|
| [`@penpair/docker`](https://www.npmjs.com/package/@penpair/docker) | The same command, plus Penpot in Docker on your computer: `up`, `down`, `backup`, `restore`. Includes everything in the core | 0.1.1 |
|
|
129
129
|
| [`@penpair/core`](https://www.npmjs.com/package/@penpair/core) | The library and engine, with the skills. No command of its own; the two above are built on it | 0.1.1 |
|
|
130
130
|
| `penpair` | The short name for `@penpair/web`, so that `npx penpair setup` works | Waiting for npm to allow the name (it is blocked as too close to an unrelated package). Until then use `npx @penpair/web`. |
|
|
131
|
-
| `@penpair/marwes-ui` | The adapter for the Marwes UI component library
|
|
131
|
+
| [`@penpair/marwes-ui`](https://www.npmjs.com/package/@penpair/marwes-ui) | The adapter for the Marwes UI component library: Marwes tokens (and your theme) in Penpot, with drift checks | Tokens now; components planned. See below |
|
|
132
132
|
| `@penpair/reflection-check` | The link to Reflection's `reflection-check`, as its own package (today `penpair baselines` does it) | Planned |
|
|
133
133
|
|
|
134
134
|
You install **one** command package, `@penpair/web` or `@penpair/docker`; the core comes with it.
|
|
135
135
|
|
|
136
136
|
## Use it with Marwes
|
|
137
137
|
|
|
138
|
-
Using [Marwes UI](https://marwes.io), the themeable component library for React, Vue and Svelte? Connecting Marwes is the recommended setup: your Penpot file then speaks the same tokens
|
|
138
|
+
Using [Marwes UI](https://marwes.io), the themeable component library for React, Vue and Svelte? Connecting Marwes is the recommended setup: your Penpot file then speaks the same tokens as your code, so what is designed is what gets built.
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
npm i -D @penpair/marwes-ui
|
|
142
|
+
npx penpair marwes tokens snapshot --write # the expected tokens, from the installed Marwes and your own theme
|
|
143
|
+
npx penpair marwes tokens push --apply # Penpot gets them: Marwes sets, plus a small overlay of what your theme changes
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
The part that keeps it solid is drift: a Marwes upgrade, a theme edit or a hand edit in Penpot is found, not discovered later. `penpair marwes tokens check` runs offline in CI and fails when the committed snapshot no longer matches the installed Marwes; `diff` shows what Penpot lacks and how many shapes each changed token reaches. How it works and how to put it in CI: [Marwes tokens in Penpot, and keeping them true](https://github.com/niklas-westman/penpair/blob/main/docs/marwes-tokens.md). Marwes components in Penpot are not covered yet; they are built as your pages need them.
|
|
139
147
|
|
|
140
148
|
## Check each page with Reflection
|
|
141
149
|
|
|
@@ -184,7 +192,7 @@ If you were told to set penpair up, read [the setup skill](https://github.com/ni
|
|
|
184
192
|
- Run `npx @penpair/web doctor --json` to see where things stand; every failing check carries a `remedy`.
|
|
185
193
|
- Web is the default; use Docker only when the person asks for offline or local data.
|
|
186
194
|
- **The personal MCP key never goes through you.** The person pastes it themselves into `npx @penpair/web connect` (a hidden prompt), or pipes it from their clipboard.
|
|
187
|
-
- Done means `doctor` reports `ok: true` and "editor and plugin" connected. Then `npx @penpair/web skills install` gives you the rules for working in Penpot (`
|
|
195
|
+
- Done means `doctor` reports `ok: true` and "editor and plugin" connected. Then `npx @penpair/web skills install` gives you the rules for working in Penpot (`penpair-design`) and for judging a screen (`design-judgment`).
|
|
188
196
|
|
|
189
197
|
## Commands
|
|
190
198
|
|
|
@@ -211,6 +219,7 @@ If you were told to set penpair up, read [the setup skill](https://github.com/ni
|
|
|
211
219
|
|
|
212
220
|
- [Getting started](https://github.com/niklas-westman/penpair/blob/main/docs/getting-started.md): step by step, for designers and for whoever sets it up
|
|
213
221
|
- [Guide](https://github.com/niklas-westman/penpair/blob/main/docs/guide.md): extension points, instances, commands
|
|
222
|
+
- [Marwes tokens](https://github.com/niklas-westman/penpair/blob/main/docs/marwes-tokens.md): Marwes tokens in Penpot and drift checks
|
|
214
223
|
- [Compatibility](https://github.com/niklas-westman/penpair/blob/main/docs/compatibility.md): what was checked on which Penpot
|
|
215
224
|
- [Releasing](https://github.com/niklas-westman/penpair/blob/main/docs/releasing.md), [Changelog](https://github.com/niklas-westman/penpair/blob/main/CHANGELOG.md)
|
|
216
225
|
|
package/docs/getting-started.md
CHANGED
|
@@ -62,7 +62,7 @@ If you want to know what your Penpot offers before you start, `npx @penpair/web
|
|
|
62
62
|
```
|
|
63
63
|
npx @penpair/web skills install
|
|
64
64
|
```
|
|
65
|
-
This copies the rules the assistant follows (how to work safely in Penpot, and how to judge a screen) into `.skills/` and makes them visible to Codex and Claude Code. It prints a line for each to add to your `AGENTS.md`. Then fill in `.skills/
|
|
65
|
+
This copies the rules the assistant follows (how to work safely in Penpot, and how to judge a screen) into `.skills/` and makes them visible to Codex and Claude Code. It prints a line for each to add to your `AGENTS.md`. Then fill in `.skills/penpair-design/references/project-facts.md` (your file, never replaced): the Penpot file, the token sets, the names you use, who approves.
|
|
66
66
|
|
|
67
67
|
### Every day
|
|
68
68
|
Open the file in Penpot, choose **File, MCP Server, Connect**, keep the tab visible, and start working with the assistant.
|
package/docs/guide.md
CHANGED
|
@@ -6,7 +6,7 @@ The contract an adopting project works through. It grows with the code; each sec
|
|
|
6
6
|
| Point | A project supplies | First implementations |
|
|
7
7
|
| --- | --- | --- |
|
|
8
8
|
| Connection profile | endpoint, Penpot version, where the token comes from | local Docker, shared self-hosted, hosted |
|
|
9
|
-
| Library adapter | where tokens and components come from |
|
|
9
|
+
| Library adapter | where tokens and components come from; commands the adapter adds, listed under `adapters` in `penpair.config.json` (`defineAdapter` in `@penpair/core`) | `@penpair/marwes-ui` (tokens) |
|
|
10
10
|
| Snippet registry | named plugin snippets with inputs and a size check | tree, audit, tokens, archive |
|
|
11
11
|
| Verification provider | what "matches the design" means | `penpair baselines` (images and Reflection cases, below), a page-verify gate |
|
|
12
12
|
| Skill pack | rules the agent follows | the Penpot skill, design judgment |
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Marwes tokens in Penpot, and keeping them true
|
|
2
|
+
|
|
3
|
+
`@penpair/marwes-ui` puts the design tokens of [Marwes UI](https://marwes.io) (and your own theme on top of them) into your Penpot file, and keeps them from drifting away from the Marwes your app actually uses. The idea in one line: **the installed Marwes and your theme file are the truth; Penpot is made to match, and anything that stops matching is found.**
|
|
4
|
+
|
|
5
|
+
## How it fits together
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
installed Marwes ─┐
|
|
9
|
+
(@marwes-ui/core) ├──▶ expected tokens ──▶ committed snapshot ──▶ Penpot file
|
|
10
|
+
your theme file ─┘ (generated) design/…snapshot.json (sets and themes)
|
|
11
|
+
(acmeLight …) reviewed in git
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
- **Nothing is typed in twice.** The tokens are generated from the Marwes the app resolves and from the theme file the app imports (the same file and export), so what you design with is what the app renders.
|
|
15
|
+
- **Your choices stay visible.** Marwes's own values go in `Marwes · Core` and `Marwes · Dark`. What your theme changes goes in a small overlay set on top (`Acme · Light`, `Acme · Dark`), holding only the differences. A Marwes update moves the Marwes sets and never silently loses your choices, and the colours Marwes derives from yours (hover, pressed, disabled) follow automatically.
|
|
16
|
+
- **The snapshot is the record.** `design/marwes-tokens.snapshot.json` is generated, committed and reviewed like code. A Marwes bump shows up as a readable git diff of exactly which tokens changed.
|
|
17
|
+
|
|
18
|
+
## Setup
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm i -D @penpair/marwes-ui # next to @penpair/web (or @penpair/docker)
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
In `penpair.config.json`:
|
|
25
|
+
|
|
26
|
+
```json
|
|
27
|
+
{
|
|
28
|
+
"adapters": ["@penpair/marwes-ui"],
|
|
29
|
+
"marwes": {
|
|
30
|
+
"name": "Acme",
|
|
31
|
+
"project": "packages/app",
|
|
32
|
+
"themes": {
|
|
33
|
+
"light": { "module": "packages/app/src/theme.ts", "export": "acmeLight" },
|
|
34
|
+
"dark": { "module": "packages/app/src/theme.ts", "export": "acmeDark" }
|
|
35
|
+
},
|
|
36
|
+
"snapshot": "design/marwes-tokens.snapshot.json"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
| Setting | Meaning |
|
|
42
|
+
| --- | --- |
|
|
43
|
+
| `name` | Prefix for your overlay sets. Defaults to the instance name, capitalised. |
|
|
44
|
+
| `project` | The folder of the package that depends on Marwes (a workspace package in a monorepo). Default: the project root. |
|
|
45
|
+
| `themes` | Your own light and dark themes: a file and the name of its export (a Marwes `ThemeInput`; TypeScript is fine). Leave them out and only the Marwes sets are made. |
|
|
46
|
+
| `snapshot` | Where the committed snapshot lives. Default: `design/marwes-tokens.snapshot.json`. |
|
|
47
|
+
|
|
48
|
+
Then:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
penpair marwes tokens snapshot --write # generate the expectation and save it; commit the file
|
|
52
|
+
penpair marwes tokens push --apply # make Penpot match (look first without --apply)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## The commands
|
|
56
|
+
|
|
57
|
+
| Command | Needs Penpot | What it does |
|
|
58
|
+
| --- | --- | --- |
|
|
59
|
+
| `penpair marwes tokens snapshot [--write]` | no | Builds the expected tokens from the installed Marwes and your theme, and shows how they differ from the committed snapshot. `--write` saves it. |
|
|
60
|
+
| `penpair marwes tokens check [--json]` | no | Is the committed snapshot current? Exit 0 yes, 2 stale or missing, 1 broken (for example a half-finished Marwes upgrade). Made for CI. |
|
|
61
|
+
| `penpair marwes tokens diff [--json]` | yes | Penpot against the snapshot: what is missing, what differs, what was added by hand, and **how many shapes use each changed token**. |
|
|
62
|
+
| `penpair marwes tokens push [--apply] [--prune]` | yes | Brings Penpot to the snapshot. Looks first and prints the plan; `--apply` writes. |
|
|
63
|
+
| `penpair marwes tokens status` | optional | One screen: the installed Marwes packages, the snapshot, and Penpot. |
|
|
64
|
+
|
|
65
|
+
## What can drift, and what catches it
|
|
66
|
+
|
|
67
|
+
| What drifted | Caught by | Resolved by |
|
|
68
|
+
| --- | --- | --- |
|
|
69
|
+
| Marwes was upgraded (any token changed, added or removed) | `check` (offline, in CI): the snapshot is stale | `snapshot --write`, review the git diff, commit, then `push --apply` |
|
|
70
|
+
| Your theme file changed | `check`: the snapshot is stale | the same |
|
|
71
|
+
| Marwes packages are at different versions (a half-finished upgrade) | `check` fails with exit 1 | finish the upgrade; Marwes releases its packages together |
|
|
72
|
+
| **Marwes grew a kind of variable the adapter does not turn into a token** | `check`: the snapshot lists every variable it does not cover, so a new one changes it | review it, then extend the adapter or accept it by writing the snapshot |
|
|
73
|
+
| Someone edited a token in Penpot by hand | `diff`: shown as a difference, with what it reaches | `push --apply` puts it back (Marwes is authoritative) |
|
|
74
|
+
| Someone added a token to a Marwes set by hand | `diff`: "not in the expectation" | kept unless you push with `--prune` |
|
|
75
|
+
| A set was deleted or a theme changed in Penpot | `diff` | `push --apply` |
|
|
76
|
+
| The recorded Marwes version (in every token's description) is old | `diff` | `push --apply` updates it, so the file says which Marwes it came from |
|
|
77
|
+
|
|
78
|
+
## After a Marwes bump
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
pnpm up @marwes-ui/react # the app moves to the new Marwes
|
|
82
|
+
penpair marwes tokens check # fails: the snapshot is stale, and says what changed
|
|
83
|
+
penpair marwes tokens snapshot --write # regenerate; review `git diff design/` (the tokens that moved)
|
|
84
|
+
penpair marwes tokens diff # what Penpot lacks, and how many shapes each change reaches
|
|
85
|
+
penpair marwes tokens push --apply # bring Penpot along; it reads everything back to verify
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
`push` refuses to run while the snapshot is stale: the repository's record must lead, so a token never reaches Penpot that has not been through a commit. After the push, export your pages and let [Reflection](https://github.com/niklas-westman/reflection) show you what the new tokens changed visually.
|
|
89
|
+
|
|
90
|
+
## Keeping it from drifting in the first place
|
|
91
|
+
|
|
92
|
+
- **CI.** Add the check to the same pipeline that runs your tests: `penpair marwes tokens check`. It needs no Penpot and no key, so it runs anywhere. A pull request that bumps Marwes (by hand or by a dependency bot) or edits the theme without a new snapshot cannot merge.
|
|
93
|
+
- **A test, if you prefer.** The adapter exports the same check for your test runner:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
import { checkTokenSnapshot } from "@penpair/marwes-ui";
|
|
97
|
+
|
|
98
|
+
it("the Penpot token snapshot is current", async () => {
|
|
99
|
+
const check = await checkTokenSnapshot(process.cwd());
|
|
100
|
+
expect(check.problems).toEqual([]);
|
|
101
|
+
expect(check.current).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
- **Before designing.** `penpair marwes tokens status` takes a second and says whether the design file is on the Marwes the app uses.
|
|
106
|
+
|
|
107
|
+
## What `push` does and does not touch
|
|
108
|
+
|
|
109
|
+
- It manages only the sets the snapshot names (`Marwes · …` and your `Acme · Light/Dark`). Any other set in the file is yours and is never touched.
|
|
110
|
+
- It creates new sets inactive and builds the Light and Dark themes. If the file has **no active theme**, it activates Light so the tokens take part; a file that already has an active theme keeps its choice.
|
|
111
|
+
- Plain values are updated in place. Typography tokens are removed and added again, because Penpot stores a typography value assigned in place un-normalised.
|
|
112
|
+
- Tokens go in batches that stay under Penpot's request limit, and it stops at the first token Penpot rejects and says which.
|
|
113
|
+
- Afterwards it reads everything back: the file must match the snapshot, and **no shape may have moved or been rebound** (a fingerprint of every page's structure is compared before and after). Otherwise it says so and exits 1.
|
|
114
|
+
|
|
115
|
+
## What is covered, and what is not
|
|
116
|
+
|
|
117
|
+
Everything Marwes resolves for a theme becomes a token: colours, density sizes, the two radii, the three font families and the typography styles, plus the spacing scale. A variable that is not (today: `--mw-density-spacing-multiplier`, a multiplier) is listed in the snapshot's `unmapped` field and in `snapshot` output, so the gap is visible and a change to it is noticed.
|
|
118
|
+
|
|
119
|
+
Not covered yet: Marwes **components** in Penpot. Tokens come first; components are built as pages need them.
|
package/docs/releasing.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Releasing
|
|
2
2
|
|
|
3
|
-
All packages in this repository are released **together, at one version, even a package that did not change**: `@penpair/core`, `@penpair/web`, `@penpair/docker`, `penpair`, and anything added under `packages/` later. The root of the repository is a private workspace and is never published. The rule is enforced, not remembered:
|
|
3
|
+
All packages in this repository are released **together, at one version, even a package that did not change**: `@penpair/core`, `@penpair/web`, `@penpair/docker`, `@penpair/marwes-ui`, `penpair`, and anything added under `packages/` later. The root of the repository is a private workspace and is never published. The rule is enforced, not remembered:
|
|
4
4
|
|
|
5
5
|
| Guard | What it stops |
|
|
6
6
|
| --- | --- |
|
|
@@ -63,13 +63,14 @@ The release is then reported as `INCOMPLETE` (exit code 3) on purpose, and `pnpm
|
|
|
63
63
|
npm view @penpair/core version
|
|
64
64
|
npm view @penpair/web version
|
|
65
65
|
npm view @penpair/docker version
|
|
66
|
+
npm view @penpair/marwes-ui version
|
|
66
67
|
```
|
|
67
68
|
|
|
68
69
|
Then, in an empty folder, run `npx @penpair/web --version`, `npx @penpair/web setup --help` and `npx @penpair/docker --version` (and, once the short name is published, the same with `npx penpair`). Tag the release if you want one: `git tag v<version> && git push origin v<version>`.
|
|
69
70
|
|
|
70
71
|
## What each package ships
|
|
71
72
|
|
|
72
|
-
The core ships `dist`, `skills`, `LICENSE` and a short `README.md`. The web package ships `dist`, `docs`, `LICENSE` and the repository's `README.md` (copied in by `prepack`, git-ignored there). The Docker package
|
|
73
|
+
The core ships `dist`, `skills`, `LICENSE` and a short `README.md`. The web package ships `dist`, `docs`, `LICENSE` and the repository's `README.md` (copied in by `prepack`, git-ignored there). The Docker package and the Marwes adapter ship `dist`, `LICENSE` and `README.md`. The short name ships `bin`, `LICENSE` and `README.md`. Check with `npm pack --dry-run --ignore-scripts` in a package.
|
|
73
74
|
|
|
74
75
|
## After publishing
|
|
75
76
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@penpair/web",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "The penpair command for Penpot on the web (design.penpot.app or your team's own): guided setup, a safe write protocol, skills for AI agents. Includes everything in @penpair/core.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,8 +20,8 @@
|
|
|
20
20
|
"types": "./dist/index.d.ts",
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
|
-
"
|
|
24
|
-
"
|
|
23
|
+
"types": "./dist/index.d.ts",
|
|
24
|
+
"import": "./dist/index.js"
|
|
25
25
|
},
|
|
26
26
|
"./cli": "./dist/cli.js",
|
|
27
27
|
"./package.json": "./package.json"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"access": "public"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"@penpair/core": "0.1.
|
|
50
|
+
"@penpair/core": "0.1.2"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "tsc -p tsconfig.json",
|