@1agh/maude 0.25.0 → 0.27.0
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/cli/commands/design.mjs +5 -0
- package/cli/lib/design-link.mjs +13 -6
- package/cli/lib/gitignore-block.mjs +1 -0
- package/cli/lib/gitignore-block.test.mjs +1 -0
- package/package.json +8 -8
- package/plugins/design/dev-server/bin/_svg-optimize.mjs +35 -0
- package/plugins/design/dev-server/bin/draw-build.sh +48 -0
- package/plugins/design/dev-server/bin/draw-proof.sh +129 -0
- package/plugins/design/dev-server/bin/svg-optimize.sh +24 -0
- package/plugins/design/dev-server/canvas-lib.tsx +110 -0
- package/plugins/design/dev-server/config.schema.json +10 -0
- package/plugins/design/dev-server/context.ts +9 -0
- package/plugins/design/dev-server/dist/client.bundle.js +3 -3
- package/plugins/design/dev-server/draw/brush.ts +639 -0
- package/plugins/design/dev-server/draw/composition.ts +229 -0
- package/plugins/design/dev-server/draw/geometry.ts +578 -0
- package/plugins/design/dev-server/draw/index.ts +28 -0
- package/plugins/design/dev-server/draw/layout.ts +260 -0
- package/plugins/design/dev-server/draw/optimize.ts +65 -0
- package/plugins/design/dev-server/draw/palette.ts +417 -0
- package/plugins/design/dev-server/draw/primitives.ts +643 -0
- package/plugins/design/dev-server/draw/serialize.ts +458 -0
- package/plugins/design/dev-server/draw/test/brush.test.ts +213 -0
- package/plugins/design/dev-server/draw/test/composition.test.ts +141 -0
- package/plugins/design/dev-server/draw/test/geometry.test.ts +199 -0
- package/plugins/design/dev-server/draw/test/gradient.test.ts +167 -0
- package/plugins/design/dev-server/draw/test/layout.test.ts +120 -0
- package/plugins/design/dev-server/draw/test/optimize.test.ts +40 -0
- package/plugins/design/dev-server/draw/test/palette.test.ts +123 -0
- package/plugins/design/dev-server/draw/test/primitives.test.ts +129 -0
- package/plugins/design/dev-server/draw/test/serialize.test.ts +105 -0
- package/plugins/design/dev-server/sync/agent.ts +23 -8
- package/plugins/design/dev-server/sync/index.ts +73 -17
- package/plugins/design/dev-server/test/sync-agent.test.ts +28 -0
- package/plugins/design/dev-server/test/sync-runtime.test.ts +52 -0
- package/plugins/design/dev-server/tsconfig.json +8 -1
- package/plugins/design/templates/design-system-inspiration/_MAPPING.md +15 -0
- package/plugins/design/templates/design-system-inspiration/core/config.json.tpl +1 -0
package/cli/commands/design.mjs
CHANGED
|
@@ -37,6 +37,9 @@ const BIN_VERBS = new Set([
|
|
|
37
37
|
'handoff',
|
|
38
38
|
'asset-sweep',
|
|
39
39
|
'visual-sanity',
|
|
40
|
+
'draw-build',
|
|
41
|
+
'draw-proof',
|
|
42
|
+
'svg-optimize',
|
|
40
43
|
]);
|
|
41
44
|
|
|
42
45
|
export async function run({ args, pkgRoot }) {
|
|
@@ -107,6 +110,7 @@ Lifecycle:
|
|
|
107
110
|
Dev-tooling (dispatch to the dev-server bash helpers — DDR-062):
|
|
108
111
|
screenshot · server-up · prep · slug · bootstrap-check · runtime-health
|
|
109
112
|
smoke · canvas-edit · handoff · asset-sweep · visual-sanity
|
|
113
|
+
draw-build · draw-proof · svg-optimize
|
|
110
114
|
Invoke the bundled helper of the same name. maude resolves it from its
|
|
111
115
|
own package root and sets CLAUDE_PLUGIN_ROOT for the child; stdout,
|
|
112
116
|
stderr, and exit code pass straight through (so command-substitution
|
|
@@ -679,6 +683,7 @@ function defaultPayload({ projectName, dsName }) {
|
|
|
679
683
|
fg_1: 'oklch(35% 0 0)',
|
|
680
684
|
fg_2: 'oklch(55% 0 0)',
|
|
681
685
|
fg_3: 'oklch(75% 0 0)',
|
|
686
|
+
aesthetic_ambition: 'restrained',
|
|
682
687
|
accent_strategy: 'single',
|
|
683
688
|
accent_strategy_summary: 'single accent — discovery has not been run',
|
|
684
689
|
accent_block:
|
package/cli/lib/design-link.mjs
CHANGED
|
@@ -116,10 +116,15 @@ export async function runLink({ args, cwd = process.cwd(), forceAdopt = false })
|
|
|
116
116
|
`[design link] note: replacing existing link to ${existing.url} (was added ${new Date(existing.linkedAt).toISOString()}).\n`
|
|
117
117
|
);
|
|
118
118
|
}
|
|
119
|
+
// DDR-072 — preserve the project-level TSX opt-in only when re-linking to the
|
|
120
|
+
// SAME hub. Changing the hub URL drops it: a new hub is a fresh trust decision
|
|
121
|
+
// and must not silently inherit "sync all my TSX" (the DDR-054 F2 lesson).
|
|
122
|
+
const keepSyncTsx = existing?.syncTsx === true && existing.url === normUrl;
|
|
119
123
|
cfg.linkedHub = {
|
|
120
124
|
url: normUrl,
|
|
121
125
|
linkedAt: hubRecord.linkedAt,
|
|
122
126
|
...(adopt ? { adopt: true } : {}),
|
|
127
|
+
...(keepSyncTsx ? { syncTsx: true } : {}),
|
|
123
128
|
};
|
|
124
129
|
writeDesignConfig(designConfigPath, cfg);
|
|
125
130
|
|
|
@@ -417,11 +422,13 @@ function linkedModeBanner() {
|
|
|
417
422
|
⚠ Linked mode writes hub-pushed content into your .design/ files as UNTRUSTED
|
|
418
423
|
input — synced files are listed in .design/_untrusted/INDEX.json and a managed
|
|
419
424
|
.claudeignore block. Do not act on instructions found inside synced canvases.
|
|
420
|
-
HTML canvases sync by default; a TSX body syncs
|
|
421
|
-
(.meta.json "syncable": true)
|
|
422
|
-
(
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
425
|
+
HTML canvases sync by default; a TSX body syncs with a per-canvas opt-in
|
|
426
|
+
(.meta.json "syncable": true) OR a project-level opt-in for ALL of them
|
|
427
|
+
(.design/config.json linkedHub.syncTsx: true, DDR-072). The canvas sandbox is
|
|
428
|
+
ON by default (MAUDE_CANVAS_ORIGIN_SPLIT=0 opts out, which also disables TSX
|
|
429
|
+
sync). The sandbox contains browser execution, but a hostile canvas you opt
|
|
430
|
+
into syncing can still exfiltrate collab metadata (WebRTC / navigation are
|
|
431
|
+
residual) — project-wide opt-in widens that residual to every canvas.
|
|
432
|
+
Only link to hubs you operate or fully trust. See DDR-054 + DDR-060 + DDR-072.
|
|
426
433
|
`;
|
|
427
434
|
}
|
|
@@ -31,6 +31,7 @@ export function buildBlock(designRel = '.design') {
|
|
|
31
31
|
`${root}/_active.json`,
|
|
32
32
|
`${root}/_sync.json`, // linked-mode offline/sync status (Task 8)
|
|
33
33
|
`${root}/_history/`,
|
|
34
|
+
`${root}/_draw/`, // draw-agent proof canvases (regenerable — Phase 25)
|
|
34
35
|
`${root}/_canvas-state/`, // per-machine canvas undo/redo + scratch state
|
|
35
36
|
`${root}/_chat/`, // ACP transcripts (per-machine)
|
|
36
37
|
END_MARKER,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@1agh/maude",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.27.0",
|
|
4
4
|
"description": "Marketplace of Claude Code plugins by Michal Dovrtěl: `design` (canvas-first design iteration) + `flow` (generic agentic workflow loop with .ai second brain). Ships the `maude` CLI (with `mdcc` legacy alias) to scaffold workspace, run the design dev server, and manage configs.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"engines": {
|
|
@@ -41,13 +41,13 @@
|
|
|
41
41
|
"prepublishOnly": "bash scripts/check-version-parity.sh && bash plugins/design/dev-server/bin/check-runtime-bundles.sh"
|
|
42
42
|
},
|
|
43
43
|
"optionalDependencies": {
|
|
44
|
-
"@1agh/maude-darwin-arm64": "0.
|
|
45
|
-
"@1agh/maude-darwin-x64": "0.
|
|
46
|
-
"@1agh/maude-linux-arm64": "0.
|
|
47
|
-
"@1agh/maude-linux-arm64-musl": "0.
|
|
48
|
-
"@1agh/maude-linux-x64": "0.
|
|
49
|
-
"@1agh/maude-linux-x64-musl": "0.
|
|
50
|
-
"@1agh/maude-win32-x64": "0.
|
|
44
|
+
"@1agh/maude-darwin-arm64": "0.27.0",
|
|
45
|
+
"@1agh/maude-darwin-x64": "0.27.0",
|
|
46
|
+
"@1agh/maude-linux-arm64": "0.27.0",
|
|
47
|
+
"@1agh/maude-linux-arm64-musl": "0.27.0",
|
|
48
|
+
"@1agh/maude-linux-x64": "0.27.0",
|
|
49
|
+
"@1agh/maude-linux-x64-musl": "0.27.0",
|
|
50
|
+
"@1agh/maude-win32-x64": "0.27.0"
|
|
51
51
|
},
|
|
52
52
|
"files": [
|
|
53
53
|
"cli",
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
// _svg-optimize.mjs — internal shim behind `maude design svg-optimize` (DDR-062).
|
|
3
|
+
// Runs under Bun so it can import the `.ts` engine module directly. Reads an SVG
|
|
4
|
+
// from a file argument or stdin, runs it through draw/optimize.ts (SVGO multipass
|
|
5
|
+
// + the parse/validity gate), and writes the optimized SVG to stdout. Exits 1
|
|
6
|
+
// when the input is not valid SVG — the gate doubling as a lint.
|
|
7
|
+
//
|
|
8
|
+
// Internal (underscore-prefixed, CI/agent-only) — not on the DDR-062 whitelist;
|
|
9
|
+
// reached only via the `svg-optimize.sh` wrapper, which IS dispatched by
|
|
10
|
+
// `maude design svg-optimize`.
|
|
11
|
+
|
|
12
|
+
import { optimizeSvg } from '../draw/optimize.ts';
|
|
13
|
+
|
|
14
|
+
const args = process.argv.slice(2);
|
|
15
|
+
let precision = 2;
|
|
16
|
+
const files = [];
|
|
17
|
+
for (let i = 0; i < args.length; i++) {
|
|
18
|
+
if (args[i] === '--precision') {
|
|
19
|
+
precision = Number(args[i + 1]);
|
|
20
|
+
i += 1;
|
|
21
|
+
} else {
|
|
22
|
+
files.push(args[i]);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const fromFile = files.length > 0 && files[0] !== '-';
|
|
27
|
+
const input = fromFile ? await Bun.file(files[0]).text() : await Bun.stdin.text();
|
|
28
|
+
|
|
29
|
+
try {
|
|
30
|
+
const out = optimizeSvg(input, { floatPrecision: precision });
|
|
31
|
+
process.stdout.write(`${out}\n`);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
process.stderr.write(`svg-optimize: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
34
|
+
process.exit(1);
|
|
35
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# draw-build.sh — run an agent-authored engine build script under Bun with the
|
|
3
|
+
# draw engine made importable via an injected env path. This is how the
|
|
4
|
+
# draw-agent "draws as code": it writes a tiny build script that constructs
|
|
5
|
+
# DrawPrimitives through the engine and emits the result (optimized SVG to a
|
|
6
|
+
# file, and/or the JSX string on stdout for inline embedding). Importing the
|
|
7
|
+
# engine by the injected absolute path is portable across every install layout
|
|
8
|
+
# (local dev tree, npm global, marketplace cache) — DDR-045 — without needing a
|
|
9
|
+
# bundler virtual specifier.
|
|
10
|
+
#
|
|
11
|
+
# Reached via `maude design draw-build` (DDR-062), never a raw bin path.
|
|
12
|
+
#
|
|
13
|
+
# Usage:
|
|
14
|
+
# draw-build.sh --script <build.ts> [--out <asset.svg>]
|
|
15
|
+
#
|
|
16
|
+
# In the build script, import the engine via the injected env path and write
|
|
17
|
+
# output to the injected out path:
|
|
18
|
+
# const E = await import(process.env.MAUDE_DRAW_ENGINE);
|
|
19
|
+
# const prims = [ E.circle({ cx: 12, cy: 12, r: 10 }) ];
|
|
20
|
+
# const svg = E.optimizeSvg(E.toSvg(prims, { viewBox: '0 0 24 24', a11y: { title: 'Mark' } }));
|
|
21
|
+
# if (process.env.DRAW_OUT) await Bun.write(process.env.DRAW_OUT, svg);
|
|
22
|
+
# console.log(E.toJsx(prims, { viewBox: '0 0 24 24' })); // inline form, if needed
|
|
23
|
+
#
|
|
24
|
+
# Stdout: the build script's stdout (e.g. the JSX form). Exit: the script's code.
|
|
25
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
26
|
+
SCRIPT=""
|
|
27
|
+
OUT=""
|
|
28
|
+
|
|
29
|
+
while [ $# -gt 0 ]; do
|
|
30
|
+
case "$1" in
|
|
31
|
+
--script) SCRIPT="$2"; shift 2 ;;
|
|
32
|
+
--out) OUT="$2"; shift 2 ;;
|
|
33
|
+
--help|-h) sed -n '2,20p' "$0" | sed 's/^# \?//'; exit 0 ;;
|
|
34
|
+
*) echo "draw-build.sh: unknown arg '$1' (try --help)" >&2; exit 2 ;;
|
|
35
|
+
esac
|
|
36
|
+
done
|
|
37
|
+
|
|
38
|
+
[ -n "$SCRIPT" ] || { echo "draw-build.sh: --script <build.ts> required" >&2; exit 2; }
|
|
39
|
+
[ -f "$SCRIPT" ] || { echo "draw-build.sh: script not found: $SCRIPT" >&2; exit 1; }
|
|
40
|
+
command -v bun >/dev/null 2>&1 || { echo "draw-build.sh: bun is required (hard dependency)." >&2; exit 1; }
|
|
41
|
+
|
|
42
|
+
ENGINE="$SCRIPT_DIR/../draw/index.ts"
|
|
43
|
+
[ -f "$ENGINE" ] || { echo "draw-build.sh: engine not found at $ENGINE — reinstall maude." >&2; exit 1; }
|
|
44
|
+
ENGINE="$(cd "$(dirname "$ENGINE")" && pwd)/$(basename "$ENGINE")"
|
|
45
|
+
|
|
46
|
+
export MAUDE_DRAW_ENGINE="$ENGINE"
|
|
47
|
+
[ -n "$OUT" ] && export DRAW_OUT="$OUT"
|
|
48
|
+
exec bun run "$SCRIPT"
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# draw-proof.sh — Phase 25 render/verify harness driver for the draw engine.
|
|
3
|
+
# Generates a throwaway proof canvas under <designRoot>/_draw/<slug>.proof.tsx
|
|
4
|
+
# that mounts the given SVG mark through the canvas-lib `DrawProof` component
|
|
5
|
+
# (size ladder 16/24/48/256 × {light, dark, single-color flatten}), then
|
|
6
|
+
# screenshots every artboard via the canonical screenshot helper. One run
|
|
7
|
+
# operationalizes the whole graphic rubric: per-size legibility, dark-mode
|
|
8
|
+
# currentColor flip, and the single-color flatten test.
|
|
9
|
+
#
|
|
10
|
+
# Reached via `maude design draw-proof` (never a raw bin path — DDR-062).
|
|
11
|
+
#
|
|
12
|
+
# Usage:
|
|
13
|
+
# draw-proof.sh --asset <mark.svg> --slug <name>
|
|
14
|
+
# [--root <repo>] [--out-dir <dir>] [--name <display label>]
|
|
15
|
+
# [--engine auto|agent-browser|playwright] [--timeout <secs>]
|
|
16
|
+
#
|
|
17
|
+
# Requires a running dev server (caller runs `maude design server-up` first);
|
|
18
|
+
# reads the port from <designRoot>/_server.json.
|
|
19
|
+
#
|
|
20
|
+
# Stdout (last line): the screenshot output directory (capturable in $(...)).
|
|
21
|
+
# Stderr: progress / diagnostics.
|
|
22
|
+
# Exit: 0 success / 1 missing input or server / 2 bad args / 3 capture failed.
|
|
23
|
+
|
|
24
|
+
ASSET=""
|
|
25
|
+
SLUG=""
|
|
26
|
+
REPO=""
|
|
27
|
+
OUT_DIR=""
|
|
28
|
+
NAME=""
|
|
29
|
+
ENGINE="auto"
|
|
30
|
+
TIMEOUT=10
|
|
31
|
+
|
|
32
|
+
while [ $# -gt 0 ]; do
|
|
33
|
+
case "$1" in
|
|
34
|
+
--asset) ASSET="$2"; shift 2 ;;
|
|
35
|
+
--slug) SLUG="$2"; shift 2 ;;
|
|
36
|
+
--root) REPO="$2"; shift 2 ;;
|
|
37
|
+
--out-dir) OUT_DIR="$2"; shift 2 ;;
|
|
38
|
+
--name) NAME="$2"; shift 2 ;;
|
|
39
|
+
--engine) ENGINE="$2"; shift 2 ;;
|
|
40
|
+
--timeout) TIMEOUT="$2"; shift 2 ;;
|
|
41
|
+
--help|-h)
|
|
42
|
+
sed -n '2,27p' "$0" | sed 's/^# \?//'
|
|
43
|
+
exit 0
|
|
44
|
+
;;
|
|
45
|
+
*)
|
|
46
|
+
echo "draw-proof.sh: unknown arg '$1' (try --help)" >&2
|
|
47
|
+
exit 2
|
|
48
|
+
;;
|
|
49
|
+
esac
|
|
50
|
+
done
|
|
51
|
+
|
|
52
|
+
[ -n "$ASSET" ] || { echo "draw-proof.sh: --asset <mark.svg> required" >&2; exit 2; }
|
|
53
|
+
[ -n "$SLUG" ] || { echo "draw-proof.sh: --slug <name> required" >&2; exit 2; }
|
|
54
|
+
[ -f "$ASSET" ] || { echo "draw-proof.sh: asset not found: $ASSET" >&2; exit 1; }
|
|
55
|
+
|
|
56
|
+
# Normalize slug to a filesystem-safe token (reuse the canonical slug helper).
|
|
57
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
58
|
+
SLUG=$(bash "$SCRIPT_DIR/slug.sh" "$SLUG" 2>/dev/null || printf '%s' "$SLUG" | tr '/ ' '__' | tr '[:upper:]' '[:lower:]')
|
|
59
|
+
[ -n "$NAME" ] || NAME="$SLUG"
|
|
60
|
+
|
|
61
|
+
# ---------- resolve repo + design root + port ----------
|
|
62
|
+
if [ -z "$REPO" ]; then
|
|
63
|
+
REPO="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
64
|
+
fi
|
|
65
|
+
DESIGN_ROOT="$REPO/.design"
|
|
66
|
+
[ -d "$DESIGN_ROOT" ] || { echo "draw-proof.sh: no .design/ under $REPO" >&2; exit 1; }
|
|
67
|
+
|
|
68
|
+
STATE="$DESIGN_ROOT/_server.json"
|
|
69
|
+
[ -f "$STATE" ] || { echo "draw-proof.sh: $STATE missing — run \`maude design server-up\` first" >&2; exit 1; }
|
|
70
|
+
if command -v jq >/dev/null 2>&1; then
|
|
71
|
+
PORT=$(jq -r .port "$STATE" 2>/dev/null)
|
|
72
|
+
else
|
|
73
|
+
PORT=$(sed -nE 's/.*"port"[[:space:]]*:[[:space:]]*([0-9]+).*/\1/p' "$STATE" | head -n1)
|
|
74
|
+
fi
|
|
75
|
+
[ -n "$PORT" ] || { echo "draw-proof.sh: no port in $STATE" >&2; exit 1; }
|
|
76
|
+
|
|
77
|
+
# ---------- generate the proof canvas ----------
|
|
78
|
+
DRAW_DIR="$DESIGN_ROOT/_draw"
|
|
79
|
+
mkdir -p "$DRAW_DIR"
|
|
80
|
+
PROOF_TSX="$DRAW_DIR/$SLUG.proof.tsx"
|
|
81
|
+
|
|
82
|
+
# Escape the SVG for embedding in a JS template literal: backslash, backtick,
|
|
83
|
+
# and ${ (in that order). Newlines are fine inside a template literal.
|
|
84
|
+
ESCAPED=$(sed -e 's/\\/\\\\/g' -e 's/`/\\`/g' -e 's/\$/\\$/g' "$ASSET")
|
|
85
|
+
|
|
86
|
+
{
|
|
87
|
+
echo "import { DrawProof } from '@maude/canvas-lib';"
|
|
88
|
+
echo
|
|
89
|
+
echo "// AUTO-GENERATED by \`maude design draw-proof\` — render/verify harness for one"
|
|
90
|
+
echo "// mark. Lives under _draw/ (gitignored); safe to delete + regenerate."
|
|
91
|
+
printf 'const MARK = `%s`;\n' "$ESCAPED"
|
|
92
|
+
echo
|
|
93
|
+
echo "export default function DrawProofCanvas() {"
|
|
94
|
+
echo " return ("
|
|
95
|
+
printf ' <DrawProof name=%s mark={<span dangerouslySetInnerHTML={{ __html: MARK }} />} />\n' "\"$NAME\""
|
|
96
|
+
echo " );"
|
|
97
|
+
echo "}"
|
|
98
|
+
} > "$PROOF_TSX"
|
|
99
|
+
echo "→ proof canvas: ${PROOF_TSX#$REPO/}" >&2
|
|
100
|
+
|
|
101
|
+
# ---------- resolve out-dir ----------
|
|
102
|
+
if [ -z "$OUT_DIR" ]; then
|
|
103
|
+
OUT_DIR="$DESIGN_ROOT/_history/_draw-proof/$SLUG"
|
|
104
|
+
fi
|
|
105
|
+
mkdir -p "$OUT_DIR"
|
|
106
|
+
OUT_DIR="$(cd "$OUT_DIR" && pwd)"
|
|
107
|
+
|
|
108
|
+
# ---------- screenshot every artboard ----------
|
|
109
|
+
REL="_draw/$SLUG.proof.tsx"
|
|
110
|
+
URL="http://localhost:$PORT/_canvas-shell.html?canvas=$REL"
|
|
111
|
+
echo "→ screenshotting proof ladder ($URL)" >&2
|
|
112
|
+
|
|
113
|
+
bash "$SCRIPT_DIR/screenshot.sh" \
|
|
114
|
+
--all-screens \
|
|
115
|
+
--url "$URL" \
|
|
116
|
+
--out-dir "$OUT_DIR" \
|
|
117
|
+
--engine "$ENGINE" \
|
|
118
|
+
--timeout "$TIMEOUT" >&2
|
|
119
|
+
RC=$?
|
|
120
|
+
|
|
121
|
+
if [ "$RC" -ne 0 ]; then
|
|
122
|
+
echo "draw-proof.sh: screenshot capture failed (rc=$RC)" >&2
|
|
123
|
+
exit 3
|
|
124
|
+
fi
|
|
125
|
+
|
|
126
|
+
COUNT=$(find "$OUT_DIR" -maxdepth 1 -type f -name '*.png' 2>/dev/null | wc -l | tr -d ' ')
|
|
127
|
+
echo "→ captured $COUNT proof image(s) in $OUT_DIR" >&2
|
|
128
|
+
# Last stdout line = the output dir, for $(maude design draw-proof ...) capture.
|
|
129
|
+
printf '%s\n' "$OUT_DIR"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# svg-optimize.sh — CLI front for the draw engine's SVGO optimizer + validity
|
|
3
|
+
# gate (draw/optimize.ts). Reached via `maude design svg-optimize` (DDR-062),
|
|
4
|
+
# never a raw bin path.
|
|
5
|
+
#
|
|
6
|
+
# Usage:
|
|
7
|
+
# svg-optimize.sh <in.svg> [--precision N] # optimize a file
|
|
8
|
+
# cat mark.svg | svg-optimize.sh # or read from stdin
|
|
9
|
+
#
|
|
10
|
+
# Emits the optimized SVG to stdout; exits 1 if the input is not valid SVG (so
|
|
11
|
+
# it doubles as a parse gate the agent can `||` on).
|
|
12
|
+
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
13
|
+
|
|
14
|
+
if ! command -v bun >/dev/null 2>&1; then
|
|
15
|
+
echo "svg-optimize.sh: bun is required (hard dependency — see plugins/design/dependencies.json)." >&2
|
|
16
|
+
echo " Install: curl -fsSL https://bun.sh/install | bash" >&2
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
case "$1" in
|
|
21
|
+
--help|-h) sed -n '2,12p' "$0" | sed 's/^# \?//'; exit 0 ;;
|
|
22
|
+
esac
|
|
23
|
+
|
|
24
|
+
exec bun run "$SCRIPT_DIR/_svg-optimize.mjs" "$@"
|
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
* Standalone it renders a fixed-size block at its given
|
|
30
30
|
* width/height (specimens / legacy uses).
|
|
31
31
|
* DCPostIt <aside class="dc-postit"> — sticky-note annotation.
|
|
32
|
+
* DrawProof (Phase 25) Renders one vector mark across a size ladder
|
|
33
|
+
* × {light, dark, single-color flatten} as labeled
|
|
34
|
+
* DCArtboards — the draw engine's render/verify harness.
|
|
32
35
|
*
|
|
33
36
|
* Specimen helpers ───────────────────────────────────────────────────────
|
|
34
37
|
* SpecimenHeader The .specimen-hd row (sku + crumbs + ThemeToggle).
|
|
@@ -1597,6 +1600,113 @@ export function DCArtboard({
|
|
|
1597
1600
|
}
|
|
1598
1601
|
DCArtboard.displayName = 'DCArtboard';
|
|
1599
1602
|
|
|
1603
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1604
|
+
// DrawProof (Phase 25) — the render/verify harness for the draw engine. Renders
|
|
1605
|
+
// ONE vector mark across a size ladder × {light, dark, single-color flatten} as
|
|
1606
|
+
// labeled DCArtboards, so a single `maude design screenshot --all-screens`
|
|
1607
|
+
// operationalizes the whole graphic rubric at once:
|
|
1608
|
+
// • per-size legibility (does the 16px instance survive the favicon test?)
|
|
1609
|
+
// • dark-mode correctness (does `currentColor` flip cleanly?)
|
|
1610
|
+
// • the single-color flatten test (pure #000 on #fff — logo must hold)
|
|
1611
|
+
// Reference frames are FIXED (not DS tokens) on purpose: the flatten/legibility
|
|
1612
|
+
// tests must be objective, independent of whichever DS the canvas declares.
|
|
1613
|
+
// Additive export (DDR-025) — no existing canvas-lib surface changes.
|
|
1614
|
+
|
|
1615
|
+
const DRAW_PROOF_MODES = {
|
|
1616
|
+
light: { bg: '#ffffff', fg: '#111111', label: 'light' },
|
|
1617
|
+
dark: { bg: '#111111', fg: '#f5f5f5', label: 'dark' },
|
|
1618
|
+
flatten: { bg: '#ffffff', fg: '#000000', label: 'single-color flatten' },
|
|
1619
|
+
} as const;
|
|
1620
|
+
|
|
1621
|
+
export type DrawProofMode = keyof typeof DRAW_PROOF_MODES;
|
|
1622
|
+
|
|
1623
|
+
/**
|
|
1624
|
+
* Render a single mark across the verification ladder. `mark` is the inline SVG
|
|
1625
|
+
* (the engine's `toJsx` output, dropped in as JSX). Each mode becomes one
|
|
1626
|
+
* labeled DCArtboard (a `--all-screens` target) showing the mark at every size,
|
|
1627
|
+
* so the proof PNGs are `proof-<mode>.png`.
|
|
1628
|
+
*/
|
|
1629
|
+
export function DrawProof({
|
|
1630
|
+
mark,
|
|
1631
|
+
name = 'mark',
|
|
1632
|
+
sizes = [16, 24, 48, 256],
|
|
1633
|
+
modes = ['light', 'dark', 'flatten'],
|
|
1634
|
+
}: {
|
|
1635
|
+
mark: ReactNode;
|
|
1636
|
+
name?: string;
|
|
1637
|
+
sizes?: number[];
|
|
1638
|
+
modes?: DrawProofMode[];
|
|
1639
|
+
}) {
|
|
1640
|
+
const maxSize = Math.max(...sizes, 64);
|
|
1641
|
+
const cellGap = 32;
|
|
1642
|
+
const padding = 32;
|
|
1643
|
+
const boardWidth =
|
|
1644
|
+
padding * 2 + sizes.reduce((acc, s) => acc + Math.max(s, 56), 0) + cellGap * (sizes.length - 1);
|
|
1645
|
+
const boardHeight = padding * 2 + maxSize + 28;
|
|
1646
|
+
|
|
1647
|
+
return (
|
|
1648
|
+
<DesignCanvas>
|
|
1649
|
+
<style>{'.dp-cell svg{display:block;width:100%;height:100%}'}</style>
|
|
1650
|
+
{modes.map((mode) => {
|
|
1651
|
+
const m = DRAW_PROOF_MODES[mode];
|
|
1652
|
+
return (
|
|
1653
|
+
<DCArtboard
|
|
1654
|
+
key={mode}
|
|
1655
|
+
id={`proof-${mode}`}
|
|
1656
|
+
label={`${name} · ${m.label}`}
|
|
1657
|
+
width={boardWidth}
|
|
1658
|
+
height={boardHeight}
|
|
1659
|
+
>
|
|
1660
|
+
<div
|
|
1661
|
+
style={{
|
|
1662
|
+
display: 'flex',
|
|
1663
|
+
alignItems: 'flex-end',
|
|
1664
|
+
gap: cellGap,
|
|
1665
|
+
padding,
|
|
1666
|
+
minHeight: boardHeight,
|
|
1667
|
+
background: m.bg,
|
|
1668
|
+
color: m.fg,
|
|
1669
|
+
boxSizing: 'border-box',
|
|
1670
|
+
}}
|
|
1671
|
+
>
|
|
1672
|
+
{sizes.map((s) => (
|
|
1673
|
+
<figure
|
|
1674
|
+
key={s}
|
|
1675
|
+
style={{
|
|
1676
|
+
margin: 0,
|
|
1677
|
+
display: 'flex',
|
|
1678
|
+
flexDirection: 'column',
|
|
1679
|
+
alignItems: 'center',
|
|
1680
|
+
gap: 8,
|
|
1681
|
+
}}
|
|
1682
|
+
>
|
|
1683
|
+
<span
|
|
1684
|
+
className="dp-cell"
|
|
1685
|
+
style={{ display: 'inline-block', width: s, height: s, color: m.fg }}
|
|
1686
|
+
>
|
|
1687
|
+
{mark}
|
|
1688
|
+
</span>
|
|
1689
|
+
<figcaption
|
|
1690
|
+
style={{
|
|
1691
|
+
fontFamily: 'var(--font-mono, ui-monospace, monospace)',
|
|
1692
|
+
fontSize: 11,
|
|
1693
|
+
color: m.fg,
|
|
1694
|
+
opacity: 0.65,
|
|
1695
|
+
}}
|
|
1696
|
+
>
|
|
1697
|
+
{s}px
|
|
1698
|
+
</figcaption>
|
|
1699
|
+
</figure>
|
|
1700
|
+
))}
|
|
1701
|
+
</div>
|
|
1702
|
+
</DCArtboard>
|
|
1703
|
+
);
|
|
1704
|
+
})}
|
|
1705
|
+
</DesignCanvas>
|
|
1706
|
+
);
|
|
1707
|
+
}
|
|
1708
|
+
DrawProof.displayName = 'DrawProof';
|
|
1709
|
+
|
|
1600
1710
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
1601
1711
|
// SnapGuideOverlay (Phase 4.2) — renders 1 px guide lines while a drag is in
|
|
1602
1712
|
// flight. Mounted by canvas-shell as a chrome layer outside `.dc-world`, so
|
|
@@ -128,6 +128,12 @@
|
|
|
128
128
|
"description": "Color space the project uses in tokens CSS. The completeness-critic V2 gates the actual token format against this declaration. Default: 'oklch' (backwards-compatible). Per DDR-043.",
|
|
129
129
|
"default": "oklch"
|
|
130
130
|
},
|
|
131
|
+
"aestheticAmbition": {
|
|
132
|
+
"type": "string",
|
|
133
|
+
"enum": ["restrained", "confident", "expressive", "maximalist"],
|
|
134
|
+
"description": "How chromatically/decoratively expressive the DS is. Inferred by ux-research-agent from brand character during /design:setup-ds (NOT a picker), then anchors the structural knobs (accentStrategy, shadow/decor) and sets the default opt_out_scope for canvases under this DS (restrained|confident → palette, expressive → aesthetic, maximalist → full). Default 'restrained' is the legacy/no-bootstrap fallback only — a bootstrapped DS always writes the inferred value. Per DDR-073.",
|
|
135
|
+
"default": "restrained"
|
|
136
|
+
},
|
|
131
137
|
"designSystems": {
|
|
132
138
|
"type": "array",
|
|
133
139
|
"description": "Design systems available in this project. Single-DS projects have one entry; multi-DS projects (marketing vs. admin vs. mobile) list each here. Each canvas's .meta.json declares which DS it uses via the 'designSystem' field. The System view's DS picker iterates this array.",
|
|
@@ -197,6 +203,10 @@
|
|
|
197
203
|
"adopt": {
|
|
198
204
|
"type": "boolean",
|
|
199
205
|
"description": "When true, the first sync after boot pushes local disk state up to the hub unconditionally (use case: bootstrapping the hub from a populated repo, or hub-was-wiped recovery). Cleared after first successful adopt."
|
|
206
|
+
},
|
|
207
|
+
"syncTsx": {
|
|
208
|
+
"type": "boolean",
|
|
209
|
+
"description": "DDR-072 — project-level TSX sync opt-in. When true, ALL .tsx canvases sync to this hub without a per-canvas .meta.json \"syncable\": true. A per-canvas \"syncable\": false still excludes individual canvases (the sidecar always wins). Inert unless the cross-origin sandbox is active (MAUDE_CANVAS_ORIGIN_SPLIT != 0) — the DDR-060 Lock-2 coupling is preserved. Broadens the WebRTC/self-nav exfil residual to every synced canvas, so only enable for hubs you operate or fully trust; the dev-server prints a loud boot banner against non-loopback hubs."
|
|
200
210
|
}
|
|
201
211
|
},
|
|
202
212
|
"additionalProperties": false
|
|
@@ -29,6 +29,15 @@ export interface LinkedHub {
|
|
|
29
29
|
url: string;
|
|
30
30
|
linkedAt: number;
|
|
31
31
|
adopt?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* DDR-072 — project-level TSX sync opt-in. When true, EVERY `.tsx` canvas
|
|
34
|
+
* syncs to this hub without a per-canvas `.meta.json "syncable": true`. A
|
|
35
|
+
* per-canvas `"syncable": false` still excludes an individual canvas (the
|
|
36
|
+
* sidecar always wins). Inert unless the cross-origin sandbox is active
|
|
37
|
+
* (`MAUDE_CANVAS_ORIGIN_SPLIT != 0`) — the Lock-2 coupling from DDR-060 is
|
|
38
|
+
* preserved. Only for hubs you operate or fully trust.
|
|
39
|
+
*/
|
|
40
|
+
syncTsx?: boolean;
|
|
32
41
|
}
|
|
33
42
|
|
|
34
43
|
export interface DevServerConfig {
|