@zenuml/core 3.47.9 → 3.48.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.
- package/dist/cli/zenuml.mjs +13529 -0
- package/dist/cli/zenuml.mjs.map +1 -0
- package/dist/cloud-icons-eHuugVSv.js.map +1 -0
- package/dist/zenuml.esm.mjs +2153 -2156
- package/dist/zenuml.esm.mjs.map +1 -0
- package/dist/zenuml.js +82 -82
- package/dist/zenuml.js.map +1 -0
- package/package.json +18 -5
- package/.agents/skills/babysit-pr/SKILL.md +0 -223
- package/.agents/skills/babysit-pr/agents/openai.yaml +0 -7
- package/.agents/skills/dia-scoring/SKILL.md +0 -139
- package/.agents/skills/dia-scoring/agents/openai.yaml +0 -7
- package/.agents/skills/dia-scoring/references/selectors-and-keys.md +0 -253
- package/.agents/skills/land-pr/SKILL.md +0 -120
- package/.agents/skills/propagate-core-release/SKILL.md +0 -205
- package/.agents/skills/propagate-core-release/agents/openai.yaml +0 -7
- package/.agents/skills/propagate-core-release/references/downstreams.md +0 -42
- package/.agents/skills/ship-branch/SKILL.md +0 -105
- package/.agents/skills/submit-branch/SKILL.md +0 -76
- package/.agents/skills/validate-branch/SKILL.md +0 -72
- package/.claude/commands/README.md +0 -162
- package/.claude/commands/analyze.md +0 -101
- package/.claude/commands/clarify.md +0 -158
- package/.claude/commands/code-review.md +0 -322
- package/.claude/commands/constitution.md +0 -73
- package/.claude/commands/create-docs.md +0 -309
- package/.claude/commands/full-context.md +0 -121
- package/.claude/commands/gemini-consult.md +0 -164
- package/.claude/commands/handoff.md +0 -146
- package/.claude/commands/implement.md +0 -56
- package/.claude/commands/plan.md +0 -43
- package/.claude/commands/refactor.md +0 -188
- package/.claude/commands/specify.md +0 -21
- package/.claude/commands/tasks.md +0 -62
- package/.claude/commands/update-docs.md +0 -314
- package/.claude/hooks/README.md +0 -270
- package/.claude/hooks/config/sensitive-patterns.json +0 -86
- package/.claude/hooks/gemini-context-injector.sh +0 -129
- package/.claude/hooks/mcp-security-scan.sh +0 -147
- package/.claude/hooks/notify.sh +0 -103
- package/.claude/hooks/setup/hook-setup.md +0 -96
- package/.claude/hooks/setup/settings.json.template +0 -63
- package/.claude/hooks/sounds/complete.wav +0 -0
- package/.claude/hooks/sounds/input-needed.wav +0 -0
- package/.claude/hooks/subagent-context-injector.sh +0 -65
- package/.claude/skills/babysit-pr/SKILL.md +0 -223
- package/.claude/skills/babysit-pr/agents/openai.yaml +0 -7
- package/.claude/skills/dia-scoring/SKILL.md +0 -139
- package/.claude/skills/dia-scoring/agents/openai.yaml +0 -7
- package/.claude/skills/dia-scoring/references/selectors-and-keys.md +0 -253
- package/.claude/skills/emoji-eval/SKILL.md +0 -187
- package/.claude/skills/land-pr/SKILL.md +0 -120
- package/.claude/skills/propagate-core-release/SKILL.md +0 -205
- package/.claude/skills/propagate-core-release/agents/openai.yaml +0 -7
- package/.claude/skills/propagate-core-release/references/downstreams.md +0 -42
- package/.claude/skills/ship-branch/SKILL.md +0 -105
- package/.claude/skills/submit-branch/SKILL.md +0 -76
- package/.claude/skills/validate-branch/SKILL.md +0 -72
- package/.claude/skills/zenuml-ux-research/SKILL.md +0 -183
- package/.claude/skills/zenuml-ux-research/references/assertion-catalog.md +0 -261
- package/.claude/skills/zenuml-ux-research/references/best-practices-overview.md +0 -56
- package/.claude/skills/zenuml-ux-research/references/report-template.md +0 -89
- package/.claude/skills/zenuml-ux-research/references/scenarios/edit-message-label.md +0 -37
- package/.claude/skills/zenuml-ux-research/references/scenarios/insert-message.md +0 -36
- package/.claude/skills/zenuml-ux-research/references/scenarios/insert-participant.md +0 -31
- package/.claude/skills/zenuml-ux-research/references/scenarios/rename-participant.md +0 -33
- package/.claude/skills/zenuml-ux-research/references/scenarios/undo-insert.md +0 -35
- package/.devcontainer/devcontainer.json +0 -21
- package/.dockerignore +0 -19
- package/.eslintrc.js +0 -39
- package/.git-blame-ignore-revs +0 -6
- package/.kiro/hooks/README.md +0 -38
- package/.kiro/hooks/session-sound-notification.js +0 -44
- package/.kiro/hooks/session-sound-notification.json +0 -23
- package/.mcp.json.example +0 -17
- package/.nvmrc +0 -1
- package/.prettierignore +0 -4
- package/.prettierrc +0 -1
- package/.specify/memory/constitution.md +0 -33
- package/.specify/scripts/bash/check-prerequisites.sh +0 -166
- package/.specify/scripts/bash/common.sh +0 -113
- package/.specify/scripts/bash/create-new-feature.sh +0 -97
- package/.specify/scripts/bash/setup-plan.sh +0 -60
- package/.specify/scripts/bash/update-agent-context.sh +0 -728
- package/.specify/templates/agent-file-template.md +0 -23
- package/.specify/templates/plan-template.md +0 -219
- package/.specify/templates/spec-template.md +0 -116
- package/.specify/templates/tasks-template.md +0 -127
- package/.storybook/main.ts +0 -25
- package/.storybook/preview.ts +0 -29
- package/.watchmanconfig +0 -3
- package/AGENTS.md +0 -26
- package/CLAUDE.md +0 -124
- package/DEPLOYMENT.md +0 -62
- package/Dockerfile +0 -36
- package/IMPLEMENTATION_PLAN.md +0 -163
- package/Integration/vanilla-js/index.html +0 -42
- package/MCP-ASSISTANT-RULES.md +0 -85
- package/README_CN.md +0 -15
- package/TUTORIAL.md +0 -116
- package/antlr/antlr-4.11.1-complete.jar +0 -0
- package/bun.lock +0 -1544
- package/bunfig.toml +0 -52
- package/docs/UNICODE_SUPPORT.md +0 -179
- package/docs/ai-context/deployment-infrastructure.md +0 -21
- package/docs/ai-context/docs-overview.md +0 -89
- package/docs/ai-context/handoff.md +0 -174
- package/docs/ai-context/project-structure.md +0 -160
- package/docs/ai-context/system-integration.md +0 -21
- package/docs/asciidoc/contributor.adoc +0 -54
- package/docs/asciidoc/create-my-own-theme.adoc +0 -149
- package/docs/asciidoc/images/creation-component.png +0 -0
- package/docs/asciidoc/images/creation-rtl.png +0 -0
- package/docs/asciidoc/images/message-arrow-rtl.png +0 -0
- package/docs/asciidoc/images/occurrence.png +0 -0
- package/docs/asciidoc/images/return-message-conflict.png +0 -0
- package/docs/asciidoc/images/shift-up-half-the-height.png +0 -0
- package/docs/asciidoc/images/three-layer-info-arch.png +0 -0
- package/docs/asciidoc/images/vertical-alignment.svg +0 -1
- package/docs/asciidoc/images/vertically-aligning.png +0 -0
- package/docs/asciidoc/index.adoc +0 -277
- package/docs/asciidoc/theme-debug-web-app.png +0 -0
- package/docs/asciidoc/tutorial.adoc +0 -22
- package/docs/asciidoc/user-css.png +0 -0
- package/docs/async-vs-sync-parser-rules.md +0 -81
- package/docs/divider-parser-allow-spaces.md +0 -38
- package/docs/highlighting-messages.md +0 -52
- package/docs/images/editor-sample.png +0 -0
- package/docs/inherited-vs-provided-from.md +0 -64
- package/docs/parser/Assignment.md +0 -8
- package/docs/parser/PARSER_IMPROVEMENTS_CC.md +0 -425
- package/docs/parser/grammar_review_gemini.md +0 -116
- package/docs/participants-function.md +0 -25
- package/docs/responsive-participant-margin.md +0 -52
- package/docs/starter.md +0 -9
- package/docs/superpowers/plans/2026-03-27-e2e-test-reorg.md +0 -698
- package/docs/superpowers/plans/2026-03-30-emoji-support.md +0 -1220
- package/docs/superpowers/plans/2026-03-30-self-correcting-scoring.md +0 -206
- package/docs/superpowers/plans/2026-04-15-keyboard-editing-on-diagram.md +0 -1992
- package/docs/superpowers/plans/2026-04-15-zenuml-ux-research-skill.md +0 -1452
- package/docs/ux-research/.gitkeep +0 -0
- package/docs/ux-research/2026-04-15-rename-participant.md +0 -156
- package/docs/ux-research/2026-04-18-insert-participant.md +0 -151
- package/docs/width-translate-and-offsets.md +0 -62
- package/docs/xss.md +0 -59
- package/e2e/data/compare-cases.js +0 -1090
- package/e2e/data/diff-algorithm.js +0 -199
- package/e2e/fixtures/create-message.html +0 -26
- package/e2e/fixtures/editable-label.html +0 -35
- package/e2e/fixtures/editable-span.html +0 -122
- package/e2e/fixtures/empty-diagram.html +0 -23
- package/e2e/fixtures/fixture.html +0 -31
- package/e2e/fixtures/insert-participant.html +0 -23
- package/e2e/fixtures/reorder-cross-fragment.html +0 -31
- package/e2e/fixtures/reorder-fragment.html +0 -29
- package/e2e/fixtures/reorder-message.html +0 -27
- package/e2e/fixtures/svg-test.html +0 -21
- package/e2e/fixtures/type-switch.html +0 -29
- package/e2e/tools/canonical-history.html +0 -908
- package/e2e/tools/compare-case.html +0 -371
- package/e2e/tools/compare.html +0 -35
- package/e2e/tools/native-diff-ext/background.js +0 -60
- package/e2e/tools/native-diff-ext/bridge.js +0 -26
- package/e2e/tools/native-diff-ext/content.js +0 -194
- package/e2e/tools/svg-preview.html +0 -56
- package/embed.html +0 -193
- package/eslint.config.mjs +0 -35
- package/firebase-debug.log +0 -108
- package/iframe-container-demo/diagram.html +0 -124
- package/iframe-container-demo/host.html +0 -817
- package/index.html +0 -771
- package/mermaid-zenuml-async-spa-auth.png +0 -0
- package/mermaid-zenuml-async-spa-auth.snapshot.md +0 -96
- package/newsletter/unicode-support-announcement.md +0 -134
- package/playground/creation.html +0 -53
- package/playground/message.html +0 -63
- package/playwright.config.ts +0 -40
- package/renderer.html +0 -366
- package/scripts/analyze-compare-case/collect-data.mjs +0 -1134
- package/scripts/analyze-compare-case/config.mjs +0 -102
- package/scripts/analyze-compare-case/geometry.mjs +0 -101
- package/scripts/analyze-compare-case/native-diff.mjs +0 -224
- package/scripts/analyze-compare-case/output.mjs +0 -74
- package/scripts/analyze-compare-case/panel-diff.mjs +0 -114
- package/scripts/analyze-compare-case/report.mjs +0 -162
- package/scripts/analyze-compare-case/residual-scopes.mjs +0 -347
- package/scripts/analyze-compare-case/scoring.mjs +0 -829
- package/scripts/analyze-compare-case.mjs +0 -149
- package/scripts/bump-version.js +0 -117
- package/scripts/snapshot-dual.js +0 -173
- package/scripts/update-snapshots.js +0 -70
- package/skills/dia-scoring/SKILL.md +0 -129
- package/skills/dia-scoring/agents/openai.yaml +0 -7
- package/skills/dia-scoring/references/selectors-and-keys.md +0 -253
- package/tailwind.config.js +0 -126
- package/test-compression.html +0 -274
- package/test-mermaid-zenuml.html +0 -57
- package/test-setup.ts +0 -124
- package/test-url-params.html +0 -192
- package/tsconfig.app.json +0 -31
- package/tsconfig.node.json +0 -24
- package/tsconfig.test.json +0 -9
- package/vite.config.lib.ts +0 -93
- package/vite.config.ts +0 -84
- package/wrangler.toml +0 -18
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: submit-branch
|
|
3
|
-
description: Push the current branch and create or reuse a PR on mermaid-js/zenuml-core. Use when the user says "submit", "create PR", "push and PR", "open a pull request", "submit branch", or wants to publish their work as a PR without merging. Does not fix CI or merge — those are separate skills.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Submit Branch
|
|
7
|
-
|
|
8
|
-
Publish the current branch as a pull request on `mermaid-js/zenuml-core`. Reuses an existing PR if one already exists for this branch.
|
|
9
|
-
|
|
10
|
-
## Preconditions
|
|
11
|
-
|
|
12
|
-
The worktree must be in a committable state:
|
|
13
|
-
|
|
14
|
-
- **Clean worktree** — nothing to commit, just push. This is the ideal case.
|
|
15
|
-
- **Scoped changes** — all modified files relate to the current work. Stage and commit them.
|
|
16
|
-
- **Mixed/unrelated changes** — modified files include unrelated work. **Stop and ask the user** which files to include. Never auto-commit a mixed worktree.
|
|
17
|
-
|
|
18
|
-
To check: `git status` and review the file list. If in doubt, ask.
|
|
19
|
-
|
|
20
|
-
## Steps
|
|
21
|
-
|
|
22
|
-
### 1. Check worktree state
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
git status
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
If dirty, evaluate whether changes are scoped (all related to the branch's purpose) or mixed. If mixed, stop and ask.
|
|
29
|
-
|
|
30
|
-
If scoped, stage the relevant files and commit with a descriptive message. Follow the repo's commit conventions (one-line message, Co-Authored-By trailer).
|
|
31
|
-
|
|
32
|
-
### 2. Push
|
|
33
|
-
|
|
34
|
-
```bash
|
|
35
|
-
git push -u origin <branch-name>
|
|
36
|
-
```
|
|
37
|
-
|
|
38
|
-
Use regular push — never force-push. If push fails due to upstream changes, report the conflict and stop.
|
|
39
|
-
|
|
40
|
-
### 3. Create or reuse PR
|
|
41
|
-
|
|
42
|
-
Check if a PR already exists:
|
|
43
|
-
|
|
44
|
-
```bash
|
|
45
|
-
gh pr view --json number,title,url 2>/dev/null
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
If a PR exists, report its URL and stop — nothing more to do.
|
|
49
|
-
|
|
50
|
-
If no PR exists, create one:
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
gh pr create --title "<concise title>" --body "$(cat <<'EOF'
|
|
54
|
-
## Summary
|
|
55
|
-
<bullet points>
|
|
56
|
-
|
|
57
|
-
## Test plan
|
|
58
|
-
<what was tested>
|
|
59
|
-
EOF
|
|
60
|
-
)"
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
The PR targets `main` on `mermaid-js/zenuml-core`.
|
|
64
|
-
|
|
65
|
-
## Output
|
|
66
|
-
|
|
67
|
-
Report:
|
|
68
|
-
|
|
69
|
-
- **SUBMITTED** — PR number, URL, and branch name
|
|
70
|
-
- **FAILED** — what went wrong (dirty worktree, push conflict, gh error)
|
|
71
|
-
|
|
72
|
-
## Does NOT
|
|
73
|
-
|
|
74
|
-
- Run tests or lint (use `/validate-branch` for that)
|
|
75
|
-
- Fix CI failures (use `/babysit-pr` for that)
|
|
76
|
-
- Merge the PR (use `/land-pr` for that)
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: validate-branch
|
|
3
|
-
description: Run local validation checks on the current branch before shipping. Use when the user says "validate", "check branch", "am I good", "run tests", "preflight", "is this ready", or wants to verify their branch passes all checks before pushing or creating a PR. Also use as a precondition check before invoking submit-branch or ship-branch.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Validate Branch
|
|
7
|
-
|
|
8
|
-
Verify the current branch passes all local checks. This is the "am I good?" skill — run it anytime before shipping, or just to check your work.
|
|
9
|
-
|
|
10
|
-
## Why this order matters
|
|
11
|
-
|
|
12
|
-
Checks run fastest-first so you get feedback quickly. Lint catches syntax issues in seconds. Unit tests catch logic errors in a few seconds. Playwright E2E is slowest (~1-2 min) and catches integration regressions. No point waiting for E2E if lint fails.
|
|
13
|
-
|
|
14
|
-
## Steps
|
|
15
|
-
|
|
16
|
-
Run from the `zenuml-core` directory. Stop on first failure.
|
|
17
|
-
|
|
18
|
-
### 1. Lint
|
|
19
|
-
|
|
20
|
-
```bash
|
|
21
|
-
bun eslint
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
If lint fails, report the errors and stop. These are usually quick fixes.
|
|
25
|
-
|
|
26
|
-
### 2. Unit tests
|
|
27
|
-
|
|
28
|
-
```bash
|
|
29
|
-
bun run test
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
Do NOT use `bun test` — it picks up Playwright files and gives false failures. If tests fail, report the failing test names and stop.
|
|
33
|
-
|
|
34
|
-
### 3. Playwright E2E
|
|
35
|
-
|
|
36
|
-
Before running Playwright, make sure port `8080` is either free or owned by a dev server started from **this repo**. `playwright.config.ts` uses `reuseExistingServer`, so an unrelated Vite server on `8080` will cause false results.
|
|
37
|
-
|
|
38
|
-
```bash
|
|
39
|
-
PORT="${PORT:-8080}"
|
|
40
|
-
THIS_REPO="$(pwd -P)"
|
|
41
|
-
LISTENER_PID="$(lsof -tiTCP:${PORT} -sTCP:LISTEN 2>/dev/null | head -n1 || true)"
|
|
42
|
-
|
|
43
|
-
if [ -n "$LISTENER_PID" ]; then
|
|
44
|
-
LISTENER_CMD="$(ps -p "$LISTENER_PID" -o command=)"
|
|
45
|
-
if [[ "$LISTENER_CMD" != *"$THIS_REPO"* ]]; then
|
|
46
|
-
echo "Port ${PORT} is owned by another repo; killing PID ${LISTENER_PID}"
|
|
47
|
-
kill "$LISTENER_PID"
|
|
48
|
-
fi
|
|
49
|
-
fi
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
If you killed a different repo's server, do **not** start Vite manually. `bun pw` will launch the correct dev server from this folder via Playwright's `webServer` config.
|
|
53
|
-
|
|
54
|
-
```bash
|
|
55
|
-
bun pw
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
If snapshot tests fail, check whether the changes are intentional (rendering code changed) or unexpected. Report which snapshots failed.
|
|
59
|
-
|
|
60
|
-
## Output
|
|
61
|
-
|
|
62
|
-
Report one of:
|
|
63
|
-
|
|
64
|
-
- **PASS** — all 3 checks passed, branch is ready
|
|
65
|
-
- **FAIL** — which check failed, the error output, and a one-line suggestion
|
|
66
|
-
|
|
67
|
-
## Gotchas
|
|
68
|
-
|
|
69
|
-
- `bun run test` not `bun test` — critical difference, the latter runs E2E too
|
|
70
|
-
- Playwright needs browsers installed (`bun pw:install` if missing)
|
|
71
|
-
- Before `bun pw`, verify any existing `8080` listener belongs to this repo; otherwise kill it and let Playwright start the right server
|
|
72
|
-
- HTML Playwright snapshot failures are a hard stop — never update HTML snapshots without understanding why they changed
|
|
@@ -1,183 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: zenuml-ux-research
|
|
3
|
-
description: Audit one ZenUML user interaction scenario at a time (e.g., inserting a message, renaming a participant) against diagramming-tool best practices. Uses claude-in-chrome to walk through the flow in a live browser and writes a gap-only markdown report to docs/ux-research/. Use when the user says "audit ux of", "zenuml ux research", "analyze interaction for zenuml", "run ux research on", or "/zenuml-ux-research". Produces a research report, not an audit pass/fail matrix.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# ZenUML UX Research
|
|
7
|
-
|
|
8
|
-
This skill audits a single ZenUML interaction scenario against diagramming-tool best practices and writes a gap-only markdown report. It is a research tool, not an audit or regression tool. Run it interactively, read the report, and act on it by hand. Never wire it into CI.
|
|
9
|
-
|
|
10
|
-
## When to invoke
|
|
11
|
-
|
|
12
|
-
- User asks "audit ux of X", "zenuml ux research", "analyze interaction for X".
|
|
13
|
-
- User runs `/zenuml-ux-research <scenario-id>` or `/zenuml-ux-research "free-text goal"`.
|
|
14
|
-
- User asks for a specific gap analysis in the ZenUML editor experience.
|
|
15
|
-
|
|
16
|
-
Do NOT invoke this skill for pixel-level comparison (that is `dia-scoring`), parser behavior, or build/deploy tasks.
|
|
17
|
-
|
|
18
|
-
## Invocation parameters
|
|
19
|
-
|
|
20
|
-
- **Scenario identifier (positional):** either a catalog ID like `insert-message` or a free-text goal like `"audit how users insert a message between A and B"`.
|
|
21
|
-
- **`--url <url>` (optional):** target URL. Default `http://localhost:4000`. Can point to a deployed staging URL.
|
|
22
|
-
- **`--allow-prod` (optional):** required for any URL that is not `localhost`, `127.0.0.1`, or a known staging subdomain. The skill is read-only against the target, but this flag forces the human to confirm they know they're pointing at a real-users environment.
|
|
23
|
-
|
|
24
|
-
## Dependencies
|
|
25
|
-
|
|
26
|
-
- `claude-in-chrome` MCP tools (for walkthrough). If these are not yet loaded in the session, the skill must instruct the user to load them via `ToolSearch` and stop; the walkthrough cannot run in text-only mode.
|
|
27
|
-
- `ZenUML dev server or a reachable URL` (default `http://localhost:4000`).
|
|
28
|
-
- `Read` / `Grep` tools (for static source analysis of `zenuml-core/src/`).
|
|
29
|
-
- `WebSearch` / `WebFetch` tools (for targeted best-practice lookups; optional).
|
|
30
|
-
|
|
31
|
-
## Files this skill uses at runtime
|
|
32
|
-
|
|
33
|
-
- `references/scenarios/<scenario-id>.md` — loaded at Phase A.
|
|
34
|
-
- `references/assertion-catalog.md` — loaded at Phase B.
|
|
35
|
-
- `references/best-practices-overview.md` — loaded at Phase B for narrative framing.
|
|
36
|
-
- `references/report-template.md` — loaded at Phase F.
|
|
37
|
-
|
|
38
|
-
## Report output
|
|
39
|
-
|
|
40
|
-
- Written to `zenuml-core/docs/ux-research/YYYY-MM-DD-<scenario-id>.md`.
|
|
41
|
-
- Create the directory if it doesn't exist (`mkdir -p`).
|
|
42
|
-
- On filename collision, append `-2`, `-3`, etc. Never overwrite.
|
|
43
|
-
- Never commit the report automatically — the human decides.
|
|
44
|
-
|
|
45
|
-
## Workflow
|
|
46
|
-
|
|
47
|
-
### Phase A — Scenario resolution
|
|
48
|
-
|
|
49
|
-
1. Determine whether the invocation is a catalog ID or free-text.
|
|
50
|
-
2. **Catalog ID:**
|
|
51
|
-
- Check that `references/scenarios/<id>.md` exists.
|
|
52
|
-
- If not, list all available scenario filenames (glob `references/scenarios/*.md`) and stop.
|
|
53
|
-
- Load the file. Verify it has front matter with `id` and `title`, plus headings for `User intent`, `Starting DSL`, `Target DSL`, `Relevant assertion categories`. If any are missing, print which field is missing from which file and stop.
|
|
54
|
-
3. **Free-text:**
|
|
55
|
-
- Synthesize a scenario record with the same fields (id, title, user intent, starting DSL, target DSL, relevant categories).
|
|
56
|
-
- Present the synthesized record to the user and wait for explicit confirmation.
|
|
57
|
-
- Do NOT proceed on an unconfirmed synthesized scenario.
|
|
58
|
-
4. Check `--url` reachability with a quick HTTP GET.
|
|
59
|
-
- If unreachable and the URL is local: print the exact fix command (`cd /Users/penxia/ai-personal/zenuml-core && bun run dev`) and stop.
|
|
60
|
-
- If unreachable and the URL is remote: print the HTTP status and stop.
|
|
61
|
-
- If reachable and the URL is non-local but does NOT have `--allow-prod`: warn and stop. Non-local URLs that look like known staging patterns (e.g., contain `staging`, `preview`, `github.io` for the gh-pages build) may proceed with a one-line warning but no hard stop.
|
|
62
|
-
5. Confirm `claude-in-chrome` tools are loaded. If not: instruct the user to load them via `ToolSearch` with query `"select:mcp__claude-in-chrome__tabs_context_mcp,mcp__claude-in-chrome__tabs_create_mcp,mcp__claude-in-chrome__navigate,mcp__claude-in-chrome__find,mcp__claude-in-chrome__computer,mcp__claude-in-chrome__read_page,mcp__claude-in-chrome__read_console_messages,mcp__claude-in-chrome__javascript_tool"` and stop.
|
|
63
|
-
|
|
64
|
-
### Phase B — Hypothesis formation
|
|
65
|
-
|
|
66
|
-
1. Read the scenario's User intent.
|
|
67
|
-
2. Read `references/best-practices-overview.md` for narrative framing.
|
|
68
|
-
3. Scan `references/assertion-catalog.md` for rules whose category is in the scenario's Relevant assertion categories list. Treat these as **priors** — starting points for what you expect to see — not as a checklist.
|
|
69
|
-
4. Form a short list of expectations in working memory. Example for `rename-participant`: "I expect Enter on selected participant to enter edit mode (KBD-03). I expect caret at end (EDT-02). I expect Escape to cancel (KBD-04). I expect undo granularity to be at the label level (UND-02)."
|
|
70
|
-
5. **Hypotheses are NOT limited to the catalog.** Form open-ended expectations based on general best practices and common sense. If the scenario suggests territory the catalog is silent on, run **1–3** targeted `WebSearch` queries (e.g., "how does tldraw handle arrow-key navigation between shapes"). Keep the budget tight.
|
|
71
|
-
|
|
72
|
-
### Phase C — Browser walkthrough
|
|
73
|
-
|
|
74
|
-
1. `mcp__claude-in-chrome__tabs_context_mcp` → get current tab state (do not reuse existing tabs from prior sessions).
|
|
75
|
-
2. `mcp__claude-in-chrome__tabs_create_mcp` → open a new tab.
|
|
76
|
-
3. `mcp__claude-in-chrome__navigate` → navigate to the `--url`.
|
|
77
|
-
4. Wait for the page to load. `mcp__claude-in-chrome__read_console_messages` at each interaction to catch runtime errors.
|
|
78
|
-
5. **Seed the starting state** by interacting with the DSL editor pane to type the scenario's Starting DSL. This is setup, not walkthrough — failures here are infrastructure errors.
|
|
79
|
-
- If Starting DSL is empty, no seeding is needed.
|
|
80
|
-
- If seeding itself fails (e.g., the DSL editor is unreachable), stop, report "could not seed starting state via DSL editor" as a walkthrough-blocker, and do NOT write a report. This is worse than a gap — it's a dead environment.
|
|
81
|
-
6. **Attempt to reach Target DSL via the most discoverable path a new user would try first.** Record each step:
|
|
82
|
-
- What was attempted (e.g., "clicked canvas area to the right of participant B")
|
|
83
|
-
- What happened (e.g., "no visible change; console warning: `[zenuml] unknown click target`")
|
|
84
|
-
- Whether it advanced toward Target DSL
|
|
85
|
-
7. If the first path fails or hits friction, try 1–2 alternative paths (toolbar, keyboard shortcut, DSL edit). Record each.
|
|
86
|
-
8. **Capture screenshots only at decision moments**, not every step — keeps reports readable. Use `mcp__claude-in-chrome__computer` for screenshots if the tool is available.
|
|
87
|
-
9. **Hard stop after 3 failed attempts on the same step.** Record "could not perform step X after 3 attempts" and move on or stop. Do NOT loop.
|
|
88
|
-
|
|
89
|
-
### Phase D — Gap detection
|
|
90
|
-
|
|
91
|
-
1. For each observation, compare against the corresponding hypothesis.
|
|
92
|
-
2. **If observation matches hypothesis: drop it. Do not record. Silence is correct.**
|
|
93
|
-
3. **If observation diverges from hypothesis: record a gap.** Each gap has:
|
|
94
|
-
- Headline (short, e.g., "Enter on selected participant does nothing")
|
|
95
|
-
- Observed (verbatim)
|
|
96
|
-
- Expected (from hypothesis)
|
|
97
|
-
- Catalog ID (scan `references/assertion-catalog.md` for a rule whose `Applies when` and `Check` match; cite that ID. If no rule matches, label the gap `novel — candidate for new rule`.)
|
|
98
|
-
- Exemplars (from the catalog if cited, else from web search)
|
|
99
|
-
- Rationale
|
|
100
|
-
- Severity (`low`, `med`, `high`) — use the catalog rule's severity if cited, else judge based on impact
|
|
101
|
-
4. Novel gaps are flagged but NOT auto-written to the catalog. The human reviews them and folds them in manually later.
|
|
102
|
-
|
|
103
|
-
### Phase E — Targeted static source analysis
|
|
104
|
-
|
|
105
|
-
For each gap, use `Grep` on `/Users/penxia/ai-personal/zenuml-core/src/` to find the relevant code path:
|
|
106
|
-
|
|
107
|
-
- For keyboard interactions: grep for the key name (`'Enter'`, `'Escape'`) and keydown listeners.
|
|
108
|
-
- For selection state: grep for `select`, `Selection`, `aria-selected`, and the Jotai atoms.
|
|
109
|
-
- For inline editing: grep for `contenteditable`, `input`, component names like `Participant`, `Message`.
|
|
110
|
-
- For undo/redo: grep for `undo`, `history`, `Jotai` atoms that track history state.
|
|
111
|
-
|
|
112
|
-
Attach `file:line` pointers to each gap. If no handler is found, write `"no code path found — this is a missing implementation, not a misrouted one."` Often the most useful finding.
|
|
113
|
-
|
|
114
|
-
### Phase F — Report writing
|
|
115
|
-
|
|
116
|
-
1. Load `references/report-template.md`.
|
|
117
|
-
2. Fill in all `{{placeholder}}` fields.
|
|
118
|
-
3. Determine the output path:
|
|
119
|
-
- Today's date in `YYYY-MM-DD` format.
|
|
120
|
-
- Filename: `YYYY-MM-DD-<scenario-id>.md`.
|
|
121
|
-
- Full path: `/Users/penxia/ai-personal/zenuml-core/docs/ux-research/YYYY-MM-DD-<scenario-id>.md`.
|
|
122
|
-
4. Create `docs/ux-research/` if it doesn't exist.
|
|
123
|
-
5. If the filename already exists for today, append `-2`, `-3`, etc.
|
|
124
|
-
6. Write the file.
|
|
125
|
-
7. If gap count is zero, render the zero-gap form (omit Gaps and Playwright snippet sections, collapse the walkthrough to a one-line "No gaps observed on <sha>").
|
|
126
|
-
|
|
127
|
-
### Phase G — Hand-off
|
|
128
|
-
|
|
129
|
-
1. Print the report path.
|
|
130
|
-
2. Print a one-line summary: `"Found N gaps (X high, Y med, Z low). Report at <path>."`
|
|
131
|
-
3. Stop. Do NOT:
|
|
132
|
-
- auto-commit the report
|
|
133
|
-
- auto-fix any gap
|
|
134
|
-
- open a PR
|
|
135
|
-
- notify anyone
|
|
136
|
-
- run additional scenarios
|
|
137
|
-
|
|
138
|
-
## Error handling
|
|
139
|
-
|
|
140
|
-
**Invocation-time (fail fast, clear instructions):**
|
|
141
|
-
|
|
142
|
-
- Scenario ID not found → list `references/scenarios/*.md` filenames, stop.
|
|
143
|
-
- Free-text goal too ambiguous (e.g., can't infer starting or target DSL) → ask one clarifying question, re-confirm, only proceed on confirmation.
|
|
144
|
-
- Scenario file malformed → print file path and missing field, stop.
|
|
145
|
-
- `claude-in-chrome` tools not loaded → instruct user to load via ToolSearch (query shown above), stop.
|
|
146
|
-
- URL unreachable → print fix command, stop.
|
|
147
|
-
- Non-local URL without `--allow-prod` → warn and stop.
|
|
148
|
-
|
|
149
|
-
**Walkthrough-time (observe and record, do not panic):**
|
|
150
|
-
|
|
151
|
-
- Target state unreachable after 2–3 paths → this is itself a high-severity gap. Write a report with "scenario target is unreachable via discovered interaction paths" as the primary finding.
|
|
152
|
-
- Console error mid-walkthrough → captured, included in the walkthrough step, does not halt unless the app becomes unresponsive.
|
|
153
|
-
- Browser crash → stop, print observations so far, do NOT write a partial report.
|
|
154
|
-
- Screenshot failure → skipped, walkthrough step still recorded with `screenshot: failed`.
|
|
155
|
-
- Same step fails 3 times → stop retrying, record "could not perform step X", move on or stop.
|
|
156
|
-
|
|
157
|
-
**Analysis-time (degrade gracefully):**
|
|
158
|
-
|
|
159
|
-
- Static analysis finds no handler → say so explicitly.
|
|
160
|
-
- Web search returns nothing → fall back to catalog and common sense.
|
|
161
|
-
- Catalog has no matching rule → label gap `novel`, flag as growth candidate.
|
|
162
|
-
|
|
163
|
-
**Output-time:**
|
|
164
|
-
|
|
165
|
-
- `docs/ux-research/` does not exist → create it.
|
|
166
|
-
- Filename collision → append `-2`, `-3`, etc.
|
|
167
|
-
- Git SHA capture fails → write `unknown` in metadata. Do not abort.
|
|
168
|
-
|
|
169
|
-
## What this skill does NOT do
|
|
170
|
-
|
|
171
|
-
- Retry failed walkthrough paths indefinitely.
|
|
172
|
-
- Auto-fix any gap.
|
|
173
|
-
- Commit the report, open a PR, notify anyone.
|
|
174
|
-
- Run multiple scenarios in one invocation.
|
|
175
|
-
- Run Playwright — only emits a snippet for the human to use.
|
|
176
|
-
- Touch production deploy state.
|
|
177
|
-
|
|
178
|
-
## Extending the skill
|
|
179
|
-
|
|
180
|
-
- **New scenario:** drop a new file into `references/scenarios/`, matching the format of existing scenarios. The skill discovers it automatically.
|
|
181
|
-
- **New assertion rule:** append it to `references/assertion-catalog.md` with the next sequential ID in its category. Never renumber existing rules.
|
|
182
|
-
- **Catalog growth from novel gaps:** when a run flags a `novel` gap, the human reviews and, if appropriate, adds a new rule to the catalog by hand.
|
|
183
|
-
- **Calibration drift:** any substantial change to this SKILL.md should be followed by re-running both calibration scenarios (see the plan document).
|
|
@@ -1,261 +0,0 @@
|
|
|
1
|
-
# ZenUML UX Assertion Catalog
|
|
2
|
-
|
|
3
|
-
Atomic, testable best-practice rules for diagramming-tool interactions. Each rule has a stable ID that may be cited in gap reports. The catalog is a **reference library and hypothesis primer**, not a checklist — the skill does NOT grind through all rules on every run.
|
|
4
|
-
|
|
5
|
-
## Catalog structure
|
|
6
|
-
|
|
7
|
-
Each rule has:
|
|
8
|
-
|
|
9
|
-
- **ID** — stable, citable (e.g., `KBD-03`). Category prefix + two-digit number. Never renumber.
|
|
10
|
-
- **Rule** — one sentence describing the expected behavior.
|
|
11
|
-
- **Exemplars** — 2–3 tools where the rule is observed.
|
|
12
|
-
- **Rationale** — why the rule matters.
|
|
13
|
-
- **Applies when** — precondition that must hold for the rule to be meaningful.
|
|
14
|
-
- **Check** — concrete, observable outcome the skill can verify (optional for subjective rules).
|
|
15
|
-
- **Severity** — `low`, `med`, `high`.
|
|
16
|
-
|
|
17
|
-
New rules are appended; IDs are never reused.
|
|
18
|
-
|
|
19
|
-
---
|
|
20
|
-
|
|
21
|
-
## SEL — Selection model
|
|
22
|
-
|
|
23
|
-
### SEL-01
|
|
24
|
-
**Rule:** Clicking an item on the canvas selects it exclusively, deselecting anything else that was selected.
|
|
25
|
-
**Exemplars:** Figma, tldraw, draw.io.
|
|
26
|
-
**Rationale:** The standard single-select model users expect from any canvas editor; anything else forces the user to explicitly clear prior selection.
|
|
27
|
-
**Applies when:** The canvas has at least one selectable item and the user clicks it with a single unmodified click.
|
|
28
|
-
**Check:** Before click: zero or more items selected. After click: only the clicked item is selected.
|
|
29
|
-
**Severity:** high
|
|
30
|
-
|
|
31
|
-
### SEL-02
|
|
32
|
-
**Rule:** Clicking empty canvas area deselects all items.
|
|
33
|
-
**Exemplars:** Figma, tldraw, Excalidraw.
|
|
34
|
-
**Rationale:** Gives the user an always-available "get out of selection" gesture that does not require keyboard.
|
|
35
|
-
**Applies when:** At least one item is selected and the user clicks an area of the canvas with no item under the cursor.
|
|
36
|
-
**Check:** After click: zero items selected.
|
|
37
|
-
**Severity:** med
|
|
38
|
-
|
|
39
|
-
### SEL-03
|
|
40
|
-
**Rule:** Selected items have a visible, persistent selection indicator (outline, highlight, or handles).
|
|
41
|
-
**Exemplars:** Figma (blue outline), tldraw (dashed outline), draw.io (handles).
|
|
42
|
-
**Rationale:** Without visual feedback, selection state is invisible and any subsequent keyboard action feels random.
|
|
43
|
-
**Applies when:** One or more items are selected.
|
|
44
|
-
**Check:** The selected item's bounding box has a visually distinct marker compared to its non-selected state.
|
|
45
|
-
**Severity:** high
|
|
46
|
-
|
|
47
|
-
### SEL-04
|
|
48
|
-
**Rule:** Selection state is exposed to assistive technologies via `aria-selected` or equivalent.
|
|
49
|
-
**Exemplars:** VS Code editor, GitHub file tree.
|
|
50
|
-
**Rationale:** Screen-reader users need programmatic access to selection. Day 1 this rule is observational (the skill notes whether the attribute is present); it is not a hard fail.
|
|
51
|
-
**Applies when:** One or more items are selected.
|
|
52
|
-
**Check:** Inspect DOM for `aria-selected="true"` on the selected element or its representative.
|
|
53
|
-
**Severity:** low
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
## KBD — Keyboard interaction
|
|
58
|
-
|
|
59
|
-
### KBD-01
|
|
60
|
-
**Rule:** Tab moves focus INTO the diagram composite widget from the surrounding page; Shift+Tab moves focus OUT.
|
|
61
|
-
**Exemplars:** VS Code tree view, GitHub file tree, Figma.
|
|
62
|
-
**Rationale:** The diagram is one Tab stop from the page's perspective; arrow keys navigate inside. This is the ARIA composite-widget convention.
|
|
63
|
-
**Applies when:** Focus is on the element immediately before or after the diagram in tab order.
|
|
64
|
-
**Check:** Press Tab; focus lands on the diagram root. Press Tab again from inside; focus leaves the diagram.
|
|
65
|
-
**Severity:** high
|
|
66
|
-
|
|
67
|
-
### KBD-02
|
|
68
|
-
**Rule:** Arrow keys navigate between items inside the diagram composite widget when it has focus.
|
|
69
|
-
**Exemplars:** Figma (arrows move selection), tldraw, Excalidraw.
|
|
70
|
-
**Rationale:** Once inside the widget, the user needs a keyboard-only way to move the cursor/selection across items.
|
|
71
|
-
**Applies when:** Focus is inside the diagram and at least one item is selectable.
|
|
72
|
-
**Check:** Press an arrow key; focus or selection visibly moves to an adjacent item.
|
|
73
|
-
**Severity:** high
|
|
74
|
-
|
|
75
|
-
### KBD-03
|
|
76
|
-
**Rule:** Enter on a selected canvas item enters edit mode with the cursor at the end of the item's label.
|
|
77
|
-
**Exemplars:** Figma (text layers), Notion (table cells), tldraw (shapes), VS Code (F2 rename).
|
|
78
|
-
**Rationale:** Keyboard-first editing; no mouse round-trip after selection. The most-expected canvas-editor keybinding after Tab/Arrow.
|
|
79
|
-
**Applies when:** A single selectable item is selected and the diagram widget has focus.
|
|
80
|
-
**Check:** After selection, send Enter. Within 300ms the item's label should become an editable input, focused, with the caret at the end of the existing text.
|
|
81
|
-
**Severity:** high
|
|
82
|
-
|
|
83
|
-
### KBD-04
|
|
84
|
-
**Rule:** Escape while an item is in edit mode cancels the edit without committing changes.
|
|
85
|
-
**Exemplars:** Figma, Notion, tldraw, VS Code rename.
|
|
86
|
-
**Rationale:** Undoing an in-flight edit should never require actually committing then undoing. Escape is the universal cancel.
|
|
87
|
-
**Applies when:** An item is currently in edit mode and the input has unsaved changes.
|
|
88
|
-
**Check:** Enter edit mode, modify text, press Escape. Label reverts to pre-edit value; item exits edit mode.
|
|
89
|
-
**Severity:** high
|
|
90
|
-
|
|
91
|
-
### KBD-05
|
|
92
|
-
**Rule:** Escape on a selected (but not editing) item either deselects or exits the widget; it should not silently do nothing.
|
|
93
|
-
**Exemplars:** Figma, tldraw.
|
|
94
|
-
**Rationale:** Escape is the "get me out" key. Silent no-op leaves the user uncertain about what's selected.
|
|
95
|
-
**Applies when:** Focus is inside the diagram and exactly one item is selected (not in edit mode).
|
|
96
|
-
**Check:** Press Escape. Selection clears OR focus leaves the diagram widget.
|
|
97
|
-
**Severity:** med
|
|
98
|
-
|
|
99
|
-
### KBD-06
|
|
100
|
-
**Rule:** Tab inside edit mode commits the current edit and spawns a new sibling in edit mode (Miro pattern).
|
|
101
|
-
**Exemplars:** Miro sticky notes, Notion database rows, Linear issue creation.
|
|
102
|
-
**Rationale:** Speed-of-flow creation for power users. Not universally expected but is the gold standard when present.
|
|
103
|
-
**Applies when:** An item is in edit mode.
|
|
104
|
-
**Check:** Type label, press Tab. Edit commits; a new sibling of the same type appears next in order, already in edit mode with focus.
|
|
105
|
-
**Severity:** med
|
|
106
|
-
|
|
107
|
-
---
|
|
108
|
-
|
|
109
|
-
## EDT — Inline editing
|
|
110
|
-
|
|
111
|
-
### EDT-01
|
|
112
|
-
**Rule:** Entering edit mode replaces the label rendering with a focused, editable input in the same visual position.
|
|
113
|
-
**Exemplars:** Figma, Notion, tldraw.
|
|
114
|
-
**Rationale:** Prevents layout shift and makes the edit feel like direct manipulation rather than a modal.
|
|
115
|
-
**Applies when:** An item is entering edit mode by any means (Enter, double-click, toolbar).
|
|
116
|
-
**Check:** The input element is visible at the label's prior position; no modal or popover opens; the input has focus.
|
|
117
|
-
**Severity:** high
|
|
118
|
-
|
|
119
|
-
### EDT-02
|
|
120
|
-
**Rule:** On edit mode entry via Enter, the caret is placed at the end of the existing text with no pre-selection.
|
|
121
|
-
**Exemplars:** Notion cell edit, Linear issue title edit.
|
|
122
|
-
**Rationale:** Appending to an existing label (the common case) should not require arrow-right; deleting the whole label should be an explicit second step.
|
|
123
|
-
**Applies when:** Edit mode was entered via Enter on a selected item with an existing, non-empty label.
|
|
124
|
-
**Check:** After entering edit mode, caret is at end-of-text; no characters are pre-selected.
|
|
125
|
-
**Severity:** med
|
|
126
|
-
|
|
127
|
-
### EDT-03
|
|
128
|
-
**Rule:** Edit mode entered on a newly inserted item places an empty input with focus, ready to accept typing.
|
|
129
|
-
**Exemplars:** Miro sticky notes, Notion new row, tldraw new shape.
|
|
130
|
-
**Rationale:** New items should not require a second click to start typing.
|
|
131
|
-
**Applies when:** A new item was just inserted and is expected to be named.
|
|
132
|
-
**Check:** Immediately after insertion, the item is in edit mode with an empty input and keyboard focus.
|
|
133
|
-
**Severity:** high
|
|
134
|
-
|
|
135
|
-
### EDT-04
|
|
136
|
-
**Rule:** Committing an edit (Enter or blur) persists the change; cancelling (Escape) discards without side-effects.
|
|
137
|
-
**Exemplars:** Figma, Notion, VS Code rename.
|
|
138
|
-
**Rationale:** The commit/cancel contract is the most-trusted UX primitive in inline editing; violating it silently loses user work.
|
|
139
|
-
**Applies when:** An item is in edit mode.
|
|
140
|
-
**Check:** Make an edit. Press Enter → change persists in the DSL and on the canvas. Separately, make an edit and press Escape → change is fully discarded.
|
|
141
|
-
**Severity:** high
|
|
142
|
-
|
|
143
|
-
---
|
|
144
|
-
|
|
145
|
-
## FOC — Focus management
|
|
146
|
-
|
|
147
|
-
### FOC-01
|
|
148
|
-
**Rule:** After inserting a new item via keyboard, focus lands on the new item in edit mode.
|
|
149
|
-
**Exemplars:** Miro stickies, tldraw new shapes, Excalidraw text boxes.
|
|
150
|
-
**Rationale:** The user's next likely action on a new item is to name it. Requiring a separate selection step is friction.
|
|
151
|
-
**Applies when:** An insertion was triggered via keyboard (shortcut, Tab-to-sibling, Enter on a "plus" affordance).
|
|
152
|
-
**Check:** Immediately after insertion, the new item is selected AND in edit mode AND has keyboard focus.
|
|
153
|
-
**Severity:** high
|
|
154
|
-
|
|
155
|
-
### FOC-02
|
|
156
|
-
**Rule:** After deleting an item, focus moves to a predictable sibling (previous if any, else next, else parent).
|
|
157
|
-
**Exemplars:** VS Code file explorer, Linear list delete, Notion row delete.
|
|
158
|
-
**Rationale:** Focus-left-hanging after delete is one of the top accessibility complaints in web apps; any sibling is better than the document root.
|
|
159
|
-
**Applies when:** An item is deleted while the diagram widget has focus.
|
|
160
|
-
**Check:** After delete, a sibling or parent element has focus (not `document.body`, not `:focus-visible` on nothing).
|
|
161
|
-
**Severity:** med
|
|
162
|
-
|
|
163
|
-
### FOC-03
|
|
164
|
-
**Rule:** Undo restores selection and focus to the pre-operation state, not just the data.
|
|
165
|
-
**Exemplars:** Figma undo, Linear undo.
|
|
166
|
-
**Rationale:** The point of undo is to undo what the user *experienced*, which includes selection and focus. Undoing data without selection is disorienting.
|
|
167
|
-
**Applies when:** Undo was triggered after an operation that changed selection or focus.
|
|
168
|
-
**Check:** Before operation: selection = X. After operation: selection = Y. After undo: selection = X.
|
|
169
|
-
**Severity:** med
|
|
170
|
-
|
|
171
|
-
### FOC-04
|
|
172
|
-
**Rule:** Focus indicator is always visible when keyboard-focused; `:focus-visible` suppression is not applied to the entire widget.
|
|
173
|
-
**Exemplars:** any WAI-ARIA-compliant widget.
|
|
174
|
-
**Rationale:** A keyboard user should always know where focus is.
|
|
175
|
-
**Applies when:** A focusable element inside the diagram is focused via keyboard navigation.
|
|
176
|
-
**Check:** Inspect the focused element; it has a visible focus outline or equivalent.
|
|
177
|
-
**Severity:** med
|
|
178
|
-
|
|
179
|
-
---
|
|
180
|
-
|
|
181
|
-
## INS — Insertion affordances
|
|
182
|
-
|
|
183
|
-
### INS-01
|
|
184
|
-
**Rule:** A new item can be inserted without opening or touching the DSL editor pane directly.
|
|
185
|
-
**Exemplars:** Mermaid Live (no, this is a known weakness; cited as a negative exemplar), tldraw (yes), Figma (yes).
|
|
186
|
-
**Rationale:** For a tool that is text-first but growing canvas editing, the canvas should be a primary creation surface. Falling back to the DSL is acceptable; being forced into it is a gap.
|
|
187
|
-
**Applies when:** A scenario's target state requires inserting a new participant, message, note, or other item.
|
|
188
|
-
**Check:** The skill must find at least one insertion path that does not require editing the DSL editor text area.
|
|
189
|
-
**Severity:** high
|
|
190
|
-
|
|
191
|
-
### INS-02
|
|
192
|
-
**Rule:** The primary insertion affordance is discoverable by a new user within ~10 seconds of looking at the canvas.
|
|
193
|
-
**Exemplars:** tldraw (visible toolbar), Figma (visible plus button).
|
|
194
|
-
**Rationale:** Discoverability is the gateway to every other interaction; hidden affordances turn new users away.
|
|
195
|
-
**Applies when:** A scenario involves inserting something.
|
|
196
|
-
**Check:** Subjective; the skill records whether the insertion affordance was obvious on first look and, if not, how long it took to find.
|
|
197
|
-
**Severity:** med
|
|
198
|
-
|
|
199
|
-
### INS-03
|
|
200
|
-
**Rule:** Insertion has at least one keyboard-only path.
|
|
201
|
-
**Exemplars:** Miro (Tab-to-sibling), Linear (Cmd+Enter on issues).
|
|
202
|
-
**Rationale:** Text-first tool users are keyboard-native; a mouse-only insertion affordance loses them.
|
|
203
|
-
**Applies when:** A scenario involves inserting something.
|
|
204
|
-
**Check:** The skill must find at least one path from "blank state" to "new item present" that uses only the keyboard.
|
|
205
|
-
**Severity:** high
|
|
206
|
-
|
|
207
|
-
---
|
|
208
|
-
|
|
209
|
-
## UND — Undo / redo
|
|
210
|
-
|
|
211
|
-
### UND-01
|
|
212
|
-
**Rule:** Ctrl/Cmd+Z undoes the last logical operation.
|
|
213
|
-
**Exemplars:** every text editor, every canvas editor.
|
|
214
|
-
**Rationale:** The universal baseline.
|
|
215
|
-
**Applies when:** At least one undoable operation has occurred.
|
|
216
|
-
**Check:** Perform operation X. Press Ctrl/Cmd+Z. State reverts to pre-X.
|
|
217
|
-
**Severity:** high
|
|
218
|
-
|
|
219
|
-
### UND-02
|
|
220
|
-
**Rule:** Undo/redo granularity matches a logical user action, not individual keystrokes during a label edit.
|
|
221
|
-
**Exemplars:** Figma undo, Notion undo, Linear undo.
|
|
222
|
-
**Rationale:** One undo should undo one perceived action. Undoing character-by-character turns Ctrl+Z into an "erase this text" macro, which is worse than useless.
|
|
223
|
-
**Applies when:** A label was edited and then undo was pressed.
|
|
224
|
-
**Check:** Edit a label from `A` to `Alice`. Press Ctrl/Cmd+Z once. The label returns to `A`, not `Alic`.
|
|
225
|
-
**Severity:** high
|
|
226
|
-
|
|
227
|
-
### UND-03
|
|
228
|
-
**Rule:** Undo restores the selection to the item that was operated on, not an arbitrary state.
|
|
229
|
-
**Exemplars:** Figma, Linear.
|
|
230
|
-
**Rationale:** Undo should put the user back where they can immediately re-try or explore, which requires selection to match.
|
|
231
|
-
**Applies when:** An operation that affected selection is being undone.
|
|
232
|
-
**Check:** Before: select X, modify X. After undo: X is selected again.
|
|
233
|
-
**Severity:** med
|
|
234
|
-
|
|
235
|
-
---
|
|
236
|
-
|
|
237
|
-
## FBK — Visual feedback
|
|
238
|
-
|
|
239
|
-
### FBK-01
|
|
240
|
-
**Rule:** Hover states are visible on interactive elements.
|
|
241
|
-
**Exemplars:** every canvas editor.
|
|
242
|
-
**Rationale:** Hover is the pre-interaction affordance; its absence forces trial-and-error clicks.
|
|
243
|
-
**Applies when:** A clickable or draggable element exists on the canvas.
|
|
244
|
-
**Check:** Hover over the element; visual state changes (cursor, outline, tint).
|
|
245
|
-
**Severity:** low
|
|
246
|
-
|
|
247
|
-
### FBK-02
|
|
248
|
-
**Rule:** Invalid actions show immediate non-blocking feedback rather than silently failing.
|
|
249
|
-
**Exemplars:** Figma toast, Linear inline errors.
|
|
250
|
-
**Rationale:** Silent failure trains users to distrust the tool; even a toast is better than nothing.
|
|
251
|
-
**Applies when:** The user attempts an operation that is not currently valid (e.g., delete with nothing selected).
|
|
252
|
-
**Check:** Trigger an invalid operation. Observe any feedback within 500ms.
|
|
253
|
-
**Severity:** med
|
|
254
|
-
|
|
255
|
-
### FBK-03
|
|
256
|
-
**Rule:** Drop targets or alignment guides are shown during drag operations where applicable.
|
|
257
|
-
**Exemplars:** Figma smart guides, tldraw snap lines.
|
|
258
|
-
**Rationale:** Without guides, drag feels imprecise.
|
|
259
|
-
**Applies when:** The scenario involves a drag operation.
|
|
260
|
-
**Check:** During an active drag, alignment guides or drop indicators appear before release.
|
|
261
|
-
**Severity:** low
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
# Diagramming Tool UX — Best-Practice Overview
|
|
2
|
-
|
|
3
|
-
This document frames the interaction-design context the ZenUML UX research skill reasons about. It is **not** a checklist. Atomic, testable rules live in `assertion-catalog.md`. This file provides the *why* behind the rules.
|
|
4
|
-
|
|
5
|
-
## Two tool families
|
|
6
|
-
|
|
7
|
-
Diagramming tools split along a single axis: **what is the primary input method for the user who is actively creating diagram content?**
|
|
8
|
-
|
|
9
|
-
### Text-first (DSL-driven)
|
|
10
|
-
|
|
11
|
-
The user types structured text; the rendered diagram is a side-effect.
|
|
12
|
-
|
|
13
|
-
Examples: **Mermaid Live**, **PlantUML editors**, **D2 Playground**, **ZenUML**.
|
|
14
|
-
|
|
15
|
-
Typical strengths:
|
|
16
|
-
- Keyboard-first by construction.
|
|
17
|
-
- Versionable, diffable, pasteable content.
|
|
18
|
-
- Fast iteration for users who know the DSL.
|
|
19
|
-
|
|
20
|
-
Typical weaknesses:
|
|
21
|
-
- Discoverability for new users is poor ("what's the syntax for a loop?").
|
|
22
|
-
- Visual affordances (clicking a participant to rename it, dragging to reorder) are bolted on, not native.
|
|
23
|
-
- Round-trip between "I see a shape on the canvas" and "I edit the text that produced it" is often clunky.
|
|
24
|
-
|
|
25
|
-
### Drag-first (graphical, canvas-driven)
|
|
26
|
-
|
|
27
|
-
The user drags shapes; a model is built behind the scenes.
|
|
28
|
-
|
|
29
|
-
Examples: **Lucidchart**, **draw.io (diagrams.net)**, **Figma**, **Miro**, **tldraw**, **Excalidraw**.
|
|
30
|
-
|
|
31
|
-
Typical strengths:
|
|
32
|
-
- New-user discoverability is very high.
|
|
33
|
-
- Inline editing on the canvas is the default path.
|
|
34
|
-
- Rich direct-manipulation gestures (drag, marquee, snap).
|
|
35
|
-
|
|
36
|
-
Typical weaknesses:
|
|
37
|
-
- Power-user keyboard flows are often worse than text-first tools.
|
|
38
|
-
- Hard to version or diff the output.
|
|
39
|
-
- Harder to reuse content across diagrams.
|
|
40
|
-
|
|
41
|
-
### Hybrids
|
|
42
|
-
|
|
43
|
-
Some tools occupy the middle and are the most instructive comparisons for ZenUML, which is fundamentally text-first but is growing canvas affordances:
|
|
44
|
-
|
|
45
|
-
- **Mermaid Live** — text-first with live preview and basic canvas interactions (click-to-select in generated SVG, no canvas editing).
|
|
46
|
-
- **tldraw** / **Excalidraw** — drag-first, but with aggressive keyboard shortcuts and inline editing patterns that text-first tools can borrow.
|
|
47
|
-
- **Notion databases / Airtable** — not diagramming, but their inline edit + Tab-to-sibling patterns are the gold standard for keyboard-first editing in any grid/canvas context.
|
|
48
|
-
- **Miro sticky note flows** — the current "speed of thought" standard for inserting, renaming, and connecting items without touching a mouse.
|
|
49
|
-
|
|
50
|
-
## Why this matters for ZenUML
|
|
51
|
-
|
|
52
|
-
ZenUML is text-first but is moving toward canvas-embedded editing. That means every scenario this skill audits has at least two valid interaction paths — DSL and canvas — and the user experience should be coherent across both. The assertion catalog is structured so that each rule is testable in either path; the walkthrough tries the most discoverable new-user path first and notes alternative paths second.
|
|
53
|
-
|
|
54
|
-
## How this overview is used by the skill
|
|
55
|
-
|
|
56
|
-
During Phase B (hypothesis formation), the skill reads this overview to calibrate expectations: for a text-first tool, "you can always fall back to the DSL editor" is a valid mitigation; "this requires a mouse" is a valid finding worth recording, because ZenUML's history of DSL-first users means keyboard-only paths matter disproportionately.
|