@1agh/maude 0.58.2 → 0.59.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/apps/studio/annotations-bindings.ts +83 -4
- package/apps/studio/annotations-layer.tsx +49 -15
- package/apps/studio/api.ts +6 -1
- package/apps/studio/bin/_fetch-asset.mjs +169 -5
- package/apps/studio/bin/_import-asset.mjs +90 -0
- package/apps/studio/bin/_import-figma.mjs +1775 -0
- package/apps/studio/bin/_perf-probe-safari.mjs +332 -0
- package/apps/studio/bin/_perf-probe.mjs +228 -0
- package/apps/studio/bin/_perf-shared.mjs +345 -0
- package/apps/studio/bin/_video-playwright.mjs +103 -7
- package/apps/studio/bin/import-figma.sh +47 -0
- package/apps/studio/bin/perf.sh +228 -0
- package/apps/studio/bin/read-annotations.mjs +11 -1
- package/apps/studio/bin/smoke.sh +49 -5
- package/apps/studio/bun.lock +16 -22
- package/apps/studio/canvas-edit.ts +29 -5
- package/apps/studio/canvas-lib.tsx +148 -6
- package/apps/studio/client/app.jsx +196 -38
- package/apps/studio/client/export-center.jsx +42 -4
- package/apps/studio/client/panels/CloudBar.jsx +92 -1
- package/apps/studio/client/panels/FigmaImportPanel.jsx +264 -0
- package/apps/studio/client/panels/GitPanel.jsx +26 -6
- package/apps/studio/client/panels/SettingsPanel.jsx +181 -0
- package/apps/studio/client/panels/SetupChecklist.jsx +26 -2
- package/apps/studio/client/panels/SyncPanel.jsx +229 -0
- package/apps/studio/client/panels/TimelinePanel.jsx +31 -3
- package/apps/studio/client/panels/timeline-comp-target.js +101 -0
- package/apps/studio/client/panels/timeline-parse.js +3 -3
- package/apps/studio/client/styles/3-shell-maude.css +37 -0
- package/apps/studio/client/styles/4-components.css +134 -0
- package/apps/studio/clip-ops.ts +93 -17
- package/apps/studio/cloud/endpoints.ts +78 -10
- package/apps/studio/cloud/renew.ts +183 -0
- package/apps/studio/context.ts +2 -1
- package/apps/studio/dist/client.bundle.js +1231 -1231
- package/apps/studio/dist/runtime/@remotion_media.js +56 -136
- package/apps/studio/dist/runtime/@remotion_player.js +18 -18
- package/apps/studio/dist/runtime/@remotion_transitions.js +9 -9
- package/apps/studio/dist/runtime/@remotion_transitions_clock-wipe.js +1 -1
- package/apps/studio/dist/runtime/remotion.js +12 -12
- package/apps/studio/dist/styles.css +1 -1
- package/apps/studio/exporters/_browser-bundles.ts +20 -6
- package/apps/studio/exporters/_runtime.ts +19 -0
- package/apps/studio/exporters/degraded.ts +92 -0
- package/apps/studio/exporters/index.ts +5 -0
- package/apps/studio/exporters/jobs.ts +19 -0
- package/apps/studio/exporters/unsupported-media.ts +170 -0
- package/apps/studio/exporters/video-encode-lib.ts +35 -6
- package/apps/studio/exporters/video-render-lib.ts +6 -0
- package/apps/studio/exporters/video.ts +72 -1
- package/apps/studio/figma/assets.test.ts +464 -0
- package/apps/studio/figma/assets.ts +452 -0
- package/apps/studio/figma/client.test.ts +395 -0
- package/apps/studio/figma/client.ts +513 -0
- package/apps/studio/figma/codegen-client.test.ts +276 -0
- package/apps/studio/figma/codegen-client.ts +509 -0
- package/apps/studio/figma/codegen-fonts.test.ts +103 -0
- package/apps/studio/figma/codegen-fonts.ts +195 -0
- package/apps/studio/figma/codegen-values.test.ts +179 -0
- package/apps/studio/figma/codegen-values.ts +270 -0
- package/apps/studio/figma/comments-to-strokes.test.ts +194 -0
- package/apps/studio/figma/comments-to-strokes.ts +173 -0
- package/apps/studio/figma/endpoints.ts +273 -0
- package/apps/studio/figma/fig-decode.test.ts +702 -0
- package/apps/studio/figma/fig-decode.ts +617 -0
- package/apps/studio/figma/fig-kiwi.ts +410 -0
- package/apps/studio/figma/fig-zip.ts +270 -0
- package/apps/studio/figma/from-codegen.test.ts +408 -0
- package/apps/studio/figma/from-codegen.ts +1103 -0
- package/apps/studio/figma/sanitize.test.ts +325 -0
- package/apps/studio/figma/sanitize.ts +407 -0
- package/apps/studio/figma/style-map.ts +352 -0
- package/apps/studio/figma/tailwind-map.test.ts +142 -0
- package/apps/studio/figma/tailwind-map.ts +545 -0
- package/apps/studio/figma/to-artboard.test.ts +808 -0
- package/apps/studio/figma/to-artboard.ts +701 -0
- package/apps/studio/figma/to-render.test.ts +180 -0
- package/apps/studio/figma/to-render.ts +328 -0
- package/apps/studio/figma/to-strokes-roundtrip.test.ts +152 -0
- package/apps/studio/figma/to-strokes.test.ts +705 -0
- package/apps/studio/figma/to-strokes.ts +749 -0
- package/apps/studio/figma/to-tokens.test.ts +321 -0
- package/apps/studio/figma/to-tokens.ts +305 -0
- package/apps/studio/figma/types.ts +544 -0
- package/apps/studio/figma/url.test.ts +167 -0
- package/apps/studio/figma/url.ts +160 -0
- package/apps/studio/http.ts +176 -0
- package/apps/studio/sync/asset-push.ts +432 -0
- package/apps/studio/sync/connection-state.ts +82 -3
- package/apps/studio/sync/hub-link.ts +63 -7
- package/apps/studio/sync/hubs-config.ts +31 -3
- package/apps/studio/sync/index.ts +286 -27
- package/apps/studio/sync/migrate-flat-fallback.ts +121 -0
- package/apps/studio/sync/presentation.ts +45 -1
- package/apps/studio/sync/status.ts +18 -0
- package/apps/studio/sync/supervisor.ts +5 -1
- package/apps/studio/sync/workspace-signin.ts +7 -3
- package/apps/studio/test/annotations-bindings.test.ts +150 -12
- package/apps/studio/test/canvas-create-api.test.ts +4 -1
- package/apps/studio/test/canvas-origin-gate.test.ts +17 -0
- package/apps/studio/test/capture-determinism-shape.test.ts +135 -0
- package/apps/studio/test/clip-addressing.test.ts +6 -1
- package/apps/studio/test/clip-ops.test.ts +5 -1
- package/apps/studio/test/cloud-endpoints.test.ts +96 -0
- package/apps/studio/test/cloud-renew.test.ts +205 -0
- package/apps/studio/test/cloud-shell-surfaces.test.ts +11 -2
- package/apps/studio/test/exporters/degraded-propagation.test.ts +123 -0
- package/apps/studio/test/exporters/unsupported-media.test.ts +123 -0
- package/apps/studio/test/fetch-asset-gate.test.ts +189 -0
- package/apps/studio/test/figma-explode.test.ts +438 -0
- package/apps/studio/test/figma-provenance.test.ts +108 -0
- package/apps/studio/test/figma-routes.test.ts +294 -0
- package/apps/studio/test/fixtures/perf-canvas.mjs +201 -0
- package/apps/studio/test/git-cloud-posture.test.ts +50 -0
- package/apps/studio/test/hub-link.test.ts +11 -0
- package/apps/studio/test/import-figma.test.ts +667 -0
- package/apps/studio/test/sync-asset-push.test.ts +567 -0
- package/apps/studio/test/sync-connection-state.test.ts +79 -0
- package/apps/studio/test/sync-hubs-config.test.ts +5 -0
- package/apps/studio/test/sync-migrate-flat-fallback.test.ts +98 -0
- package/apps/studio/test/sync-panel-surface.test.ts +90 -0
- package/apps/studio/test/sync-path-pull.test.ts +63 -0
- package/apps/studio/test/sync-presentation.test.ts +77 -0
- package/apps/studio/test/sync-runtime.test.ts +316 -1
- package/apps/studio/test/sync-status.test.ts +28 -0
- package/apps/studio/test/timeline-comp-target.test.ts +139 -0
- package/apps/studio/test/video-comp.test.ts +104 -2
- package/apps/studio/test/video-encode-lib.test.ts +63 -0
- package/apps/studio/test/workspace-containment.test.ts +1 -0
- package/apps/studio/use-artboard-drag.tsx +37 -3
- package/apps/studio/video-comp.tsx +121 -6
- package/apps/studio/whats-new.json +98 -0
- package/apps/studio/workspace-mode.ts +4 -0
- package/cli/commands/design.mjs +15 -0
- package/cli/commands/kg.mjs +8 -1
- package/cli/commands/kg.test.mjs +24 -0
- package/cli/lib/figma-codegen-reachability.test.mjs +104 -0
- package/cli/lib/figma-import-controls.test.mjs +70 -0
- package/package.json +8 -8
- package/plugins/flow/.claude-plugin/config.schema.json +3 -3
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# perf.sh — render-performance benchmark for a canvas (`maude design perf`).
|
|
3
|
+
#
|
|
4
|
+
# Drives a scripted pan + zoom against a live canvas and reports frame-time
|
|
5
|
+
# percentiles, long-task count and the React render count during the gesture,
|
|
6
|
+
# with a DELTA against the previous run of the same (canvas, engine) pair. The
|
|
7
|
+
# history file makes "before and after" a property of the tool rather than
|
|
8
|
+
# something the operator has to remember to write down.
|
|
9
|
+
#
|
|
10
|
+
# Deliberately NOT a CI gate. Headless frame timings swing with GPU load and
|
|
11
|
+
# machine state, so an absolute threshold would go red for reasons unrelated to
|
|
12
|
+
# the code and train everyone to ignore it. The gate is the delta, read by a
|
|
13
|
+
# human, on one machine. (Plan: .ai/plans/feature-canvas-render-performance.md)
|
|
14
|
+
#
|
|
15
|
+
# Usage:
|
|
16
|
+
# perf.sh [--root <repo>] [--canvas <rel-path>] [--fixture]
|
|
17
|
+
# [--boards N] [--strokes N]
|
|
18
|
+
# [--pan N] [--zoom N] [--timeout S] [--repeat N]
|
|
19
|
+
# [--engine chromium|safari]
|
|
20
|
+
# [--history <path>] [--json]
|
|
21
|
+
#
|
|
22
|
+
# --engine safari measures WebKit through safaridriver (one-time
|
|
23
|
+
# `safaridriver --enable`, needs admin auth). Use it for anything the Tauri
|
|
24
|
+
# desktop shell has to be fast at: the desktop is WKWebView, and Chromium does
|
|
25
|
+
# NOT reproduce WebKit's compositing / re-raster behaviour — a canvas can sit
|
|
26
|
+
# at a warm 60fps in headless Chromium while being unusable in the .app.
|
|
27
|
+
#
|
|
28
|
+
# --canvas Canvas to measure, relative to <designRoot> (default: _active.json).
|
|
29
|
+
# --fixture Generate + measure the synthetic fixture instead (--boards/--strokes).
|
|
30
|
+
# --json Raw JSON (current + previous run) instead of the human report.
|
|
31
|
+
#
|
|
32
|
+
# Reads: $DESIGN_ROOT/_server.json (must exist — run `maude design server-up` first)
|
|
33
|
+
# Writes: $DESIGN_ROOT/_smoke/perf/history.jsonl (append-only, per-machine runtime state)
|
|
34
|
+
# $DESIGN_ROOT/ui/perf-fixture.tsx (only with --fixture)
|
|
35
|
+
#
|
|
36
|
+
# Exit: 0 measured / 1 missing dep or capture failure / 2 bad args.
|
|
37
|
+
|
|
38
|
+
REPO=""
|
|
39
|
+
CANVAS=""
|
|
40
|
+
FIXTURE=0
|
|
41
|
+
BOARDS=128
|
|
42
|
+
STROKES=150
|
|
43
|
+
PAN=60
|
|
44
|
+
ZOOM=40
|
|
45
|
+
REPEAT=3
|
|
46
|
+
PROBE_ENGINE="chromium"
|
|
47
|
+
FIT_ALL=0
|
|
48
|
+
STUDIO=0
|
|
49
|
+
TIMEOUT=30
|
|
50
|
+
HISTORY=""
|
|
51
|
+
JSON=0
|
|
52
|
+
|
|
53
|
+
while [ $# -gt 0 ]; do
|
|
54
|
+
case "$1" in
|
|
55
|
+
--root) REPO="$2"; shift 2 ;;
|
|
56
|
+
--canvas) CANVAS="$2"; shift 2 ;;
|
|
57
|
+
--fixture) FIXTURE=1; shift ;;
|
|
58
|
+
--boards) BOARDS="$2"; shift 2 ;;
|
|
59
|
+
--strokes) STROKES="$2"; shift 2 ;;
|
|
60
|
+
--pan) PAN="$2"; shift 2 ;;
|
|
61
|
+
--zoom) ZOOM="$2"; shift 2 ;;
|
|
62
|
+
--timeout) TIMEOUT="$2"; shift 2 ;;
|
|
63
|
+
--repeat) REPEAT="$2"; shift 2 ;;
|
|
64
|
+
--engine) PROBE_ENGINE="$2"; shift 2 ;;
|
|
65
|
+
--fit-all) FIT_ALL=1; shift ;;
|
|
66
|
+
--studio) STUDIO=1; shift ;;
|
|
67
|
+
--history) HISTORY="$2"; shift 2 ;;
|
|
68
|
+
--json) JSON=1; shift ;;
|
|
69
|
+
--help|-h)
|
|
70
|
+
sed -n '2,30p' "$0" | sed 's/^# \?//'
|
|
71
|
+
exit 0
|
|
72
|
+
;;
|
|
73
|
+
*)
|
|
74
|
+
echo "perf.sh: unknown arg '$1' (try --help)" >&2
|
|
75
|
+
exit 2
|
|
76
|
+
;;
|
|
77
|
+
esac
|
|
78
|
+
done
|
|
79
|
+
|
|
80
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
81
|
+
|
|
82
|
+
# JS runtime. The packaged desktop app ships no user `node` (DDR-177) but always
|
|
83
|
+
# has a `bun` on PATH (real, or the compiled-sidecar shim `maude` stages), so
|
|
84
|
+
# prefer bun and keep node as the developer-machine fallback.
|
|
85
|
+
if command -v bun >/dev/null 2>&1; then JS_RUNTIME="bun"; else JS_RUNTIME="node"; fi
|
|
86
|
+
|
|
87
|
+
# ---------- resolve repo + design root (mirrors smoke.sh) ----------
|
|
88
|
+
if [ -z "$REPO" ]; then
|
|
89
|
+
REPO="${CLAUDE_PROJECT_DIR:-$(git rev-parse --show-toplevel 2>/dev/null || pwd)}"
|
|
90
|
+
fi
|
|
91
|
+
DESIGN_ROOT="$REPO/.design"
|
|
92
|
+
[ -d "$DESIGN_ROOT" ] || { echo "perf.sh: no .design/ under $REPO" >&2; exit 1; }
|
|
93
|
+
|
|
94
|
+
STATE="$DESIGN_ROOT/_server.json"
|
|
95
|
+
[ -f "$STATE" ] || { echo "perf.sh: $STATE missing — run 'maude design server-up' first" >&2; exit 1; }
|
|
96
|
+
|
|
97
|
+
if command -v jq >/dev/null 2>&1; then
|
|
98
|
+
PORT=$(jq -r .port "$STATE" 2>/dev/null)
|
|
99
|
+
else
|
|
100
|
+
PORT=$(sed -nE 's/.*"port"[[:space:]]*:[[:space:]]*([0-9]+).*/\1/p' "$STATE" | head -n1)
|
|
101
|
+
fi
|
|
102
|
+
[ -n "$PORT" ] || { echo "perf.sh: no port in $STATE" >&2; exit 1; }
|
|
103
|
+
|
|
104
|
+
# ---------- fixture generation ----------
|
|
105
|
+
if [ "$FIXTURE" = "1" ]; then
|
|
106
|
+
# Counts are validated as plain integers and paths travel via argv, never
|
|
107
|
+
# interpolated into the script body: `--boards "1); <js>; ("` or a design root
|
|
108
|
+
# containing a quote would otherwise execute inside this node process, which
|
|
109
|
+
# runs with the user's full privileges. `maude design perf` is reachable from
|
|
110
|
+
# an agent session, so its arguments are not automatically trustworthy.
|
|
111
|
+
case "$BOARDS" in ''|*[!0-9]*) echo "perf.sh: --boards must be a positive integer" >&2; exit 2 ;; esac
|
|
112
|
+
case "$STROKES" in ''|*[!0-9]*) echo "perf.sh: --strokes must be a non-negative integer" >&2; exit 2 ;; esac
|
|
113
|
+
# Upper bound too: the guards above accept any magnitude, and `--boards 99999999`
|
|
114
|
+
# is a cheap way to make an auto-approved verb fill a disk.
|
|
115
|
+
[ "$BOARDS" -le 2000 ] || { echo "perf.sh: --boards must be <= 2000" >&2; exit 2; }
|
|
116
|
+
[ "$STROKES" -le 5000 ] || { echo "perf.sh: --strokes must be <= 5000" >&2; exit 2; }
|
|
117
|
+
"$JS_RUNTIME" -e '
|
|
118
|
+
const [modPath, designRoot, boards, strokes] = process.argv.slice(1);
|
|
119
|
+
import(modPath).then((m) => {
|
|
120
|
+
const r = m.writePerfCanvas({
|
|
121
|
+
designRoot,
|
|
122
|
+
boards: Number(boards),
|
|
123
|
+
strokes: Number(strokes),
|
|
124
|
+
});
|
|
125
|
+
console.error("→ fixture written: " + r.canvasPath);
|
|
126
|
+
}).catch((e) => {
|
|
127
|
+
console.error("perf.sh: fixture generation failed: " + e.message);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
});
|
|
130
|
+
' "$SCRIPT_DIR/../test/fixtures/perf-canvas.mjs" "$DESIGN_ROOT" "$BOARDS" "$STROKES" || exit 1
|
|
131
|
+
CANVAS="ui/perf-fixture.tsx"
|
|
132
|
+
fi
|
|
133
|
+
|
|
134
|
+
# ---------- resolve canvas ----------
|
|
135
|
+
if [ -z "$CANVAS" ]; then
|
|
136
|
+
ACTIVE_FILE="$DESIGN_ROOT/_active.json"
|
|
137
|
+
if [ -f "$ACTIVE_FILE" ] && command -v jq >/dev/null 2>&1; then
|
|
138
|
+
CANVAS=$(jq -r '.active // empty' "$ACTIVE_FILE" 2>/dev/null)
|
|
139
|
+
fi
|
|
140
|
+
fi
|
|
141
|
+
[ -n "$CANVAS" ] || { echo "perf.sh: no --canvas and no active canvas in _active.json" >&2; exit 2; }
|
|
142
|
+
|
|
143
|
+
# `_active.json` stores the path relative to the REPO (".design/ui/x.tsx"); the
|
|
144
|
+
# canvas-shell query param wants it the same way, so normalize either input
|
|
145
|
+
# shape to the repo-relative form rather than guessing at call sites.
|
|
146
|
+
DESIGN_REL="${DESIGN_ROOT#"$REPO"/}"
|
|
147
|
+
case "$CANVAS" in
|
|
148
|
+
"$DESIGN_REL"/*) REL_FULL="$CANVAS" ;;
|
|
149
|
+
*) REL_FULL="$DESIGN_REL/$CANVAS" ;;
|
|
150
|
+
esac
|
|
151
|
+
# Containment: an existence check alone would accept `--canvas ../../../x.tsx`
|
|
152
|
+
# and leave the boundary entirely to the dev-server route. A benchmark has no
|
|
153
|
+
# business probing that gate.
|
|
154
|
+
case "$REL_FULL" in
|
|
155
|
+
*..*) echo "perf.sh: --canvas must not contain '..'" >&2; exit 2 ;;
|
|
156
|
+
esac
|
|
157
|
+
[ -f "$REPO/$REL_FULL" ] || { echo "perf.sh: canvas not found: $REPO/$REL_FULL" >&2; exit 2; }
|
|
158
|
+
|
|
159
|
+
# Percent-encode the whole value, not just spaces: a canvas named with `#`, `&`
|
|
160
|
+
# or `%` would otherwise truncate or rewrite the query string.
|
|
161
|
+
REL_ENC=$("$JS_RUNTIME" -e 'process.stdout.write(encodeURIComponent(process.argv[1]))' "$REL_FULL")
|
|
162
|
+
URL="http://localhost:${PORT}/_canvas-shell.html?canvas=${REL_ENC}"
|
|
163
|
+
|
|
164
|
+
# ---------- history path ----------
|
|
165
|
+
# `_smoke/` is already IGNORED runtime state (DDR-115), so the benchmark log
|
|
166
|
+
# inherits the right gitignore posture without touching any of the three lists.
|
|
167
|
+
if [ -z "$HISTORY" ]; then
|
|
168
|
+
HISTORY="$DESIGN_ROOT/_smoke/perf/history.jsonl"
|
|
169
|
+
fi
|
|
170
|
+
# Containment: `perf` is auto-approved in ACP sessions (`Bash(maude:*)`), so an
|
|
171
|
+
# unconstrained --history would be an arbitrary mkdir + append outside every
|
|
172
|
+
# write-scope gate. The default already lives under the design root; require it.
|
|
173
|
+
HISTORY_ABS=$("$JS_RUNTIME" -e 'const p=require("path");process.stdout.write(p.resolve(process.argv[1]))' "$HISTORY")
|
|
174
|
+
DESIGN_ABS=$("$JS_RUNTIME" -e 'const p=require("path");process.stdout.write(p.resolve(process.argv[1]))' "$DESIGN_ROOT")
|
|
175
|
+
case "$HISTORY_ABS" in
|
|
176
|
+
"$DESIGN_ABS"/*) ;;
|
|
177
|
+
*) echo "perf.sh: --history must resolve under $DESIGN_ABS (got $HISTORY_ABS)" >&2; exit 2 ;;
|
|
178
|
+
esac
|
|
179
|
+
HISTORY="$HISTORY_ABS"
|
|
180
|
+
mkdir -p "$(dirname "$HISTORY")"
|
|
181
|
+
|
|
182
|
+
# ---------- engine tag ----------
|
|
183
|
+
# The tag is part of the history KEY, not decoration: a WKWebView number and a
|
|
184
|
+
# headless-Chromium number are not comparable, and silently averaging them would
|
|
185
|
+
# make every delta meaningless.
|
|
186
|
+
ENGINE_TAG="${MAUDE_PERF_ENGINE_TAG:-}"
|
|
187
|
+
if [ -z "$ENGINE_TAG" ]; then
|
|
188
|
+
if [ -n "$MAUDE_DESKTOP" ]; then ENGINE_TAG="webkit-desktop"; else ENGINE_TAG="blink-headless"; fi
|
|
189
|
+
fi
|
|
190
|
+
|
|
191
|
+
if [ "$PROBE_ENGINE" = "safari" ]; then
|
|
192
|
+
command -v safaridriver >/dev/null 2>&1 || {
|
|
193
|
+
echo "perf.sh: safaridriver not found (macOS only)" >&2
|
|
194
|
+
exit 1
|
|
195
|
+
}
|
|
196
|
+
PROBE_URL="$URL"
|
|
197
|
+
if [ "$STUDIO" = "1" ]; then
|
|
198
|
+
# Studio mode drives the real app shell (root URL + a file-tree click),
|
|
199
|
+
# not the bare canvas page — see _perf-probe-safari.mjs for why that
|
|
200
|
+
# difference changes the numbers.
|
|
201
|
+
PROBE_URL="http://localhost:${PORT}/"
|
|
202
|
+
SLUG=$(printf '%s' "${REL_FULL#"$DESIGN_REL"/}" \
|
|
203
|
+
| sed -E 's/\.[A-Za-z]+$//' | tr '[:upper:]' '[:lower:]' \
|
|
204
|
+
| sed -E 's/[^a-z0-9]+/-/g; s/^-+|-+$//g')
|
|
205
|
+
fi
|
|
206
|
+
echo "→ perf: $REL_FULL | port: $PORT | engine: webkit-safari${STUDIO:+ | studio}" >&2
|
|
207
|
+
ARGS=(--url "$PROBE_URL" --label "$REL_FULL$([ "$STUDIO" = "1" ] && echo " (studio)")" --history "$HISTORY"
|
|
208
|
+
--timeout "$TIMEOUT" --pan "$PAN" --zoom "$ZOOM" --repeat "$REPEAT")
|
|
209
|
+
[ "$STUDIO" = "1" ] && ARGS+=(--studio "$SLUG")
|
|
210
|
+
[ "$FIT_ALL" = "1" ] && ARGS+=(--fit-all)
|
|
211
|
+
[ "$JSON" = "1" ] && ARGS+=(--json)
|
|
212
|
+
exec "$JS_RUNTIME" "$SCRIPT_DIR/_perf-probe-safari.mjs" "${ARGS[@]}"
|
|
213
|
+
fi
|
|
214
|
+
|
|
215
|
+
AB="${MAUDE_AGENT_BROWSER:-agent-browser}"
|
|
216
|
+
command -v "$AB" >/dev/null 2>&1 || {
|
|
217
|
+
echo "perf.sh: agent-browser not on PATH (required — the probe needs scripted gestures + rAF timing)" >&2
|
|
218
|
+
exit 1
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
echo "→ perf: $REL_FULL | port: $PORT | engine: $ENGINE_TAG" >&2
|
|
222
|
+
|
|
223
|
+
ARGS=(--url "$URL" --label "$REL_FULL" --history "$HISTORY" --engine-tag "$ENGINE_TAG"
|
|
224
|
+
--timeout "$TIMEOUT" --pan "$PAN" --zoom "$ZOOM" --repeat "$REPEAT")
|
|
225
|
+
[ "$FIT_ALL" = "1" ] && ARGS+=(--fit-all)
|
|
226
|
+
[ "$JSON" = "1" ] && ARGS+=(--json)
|
|
227
|
+
|
|
228
|
+
exec "$JS_RUNTIME" "$SCRIPT_DIR/_perf-probe.mjs" "${ARGS[@]}"
|
|
@@ -106,6 +106,9 @@ Args:
|
|
|
106
106
|
|
|
107
107
|
FigJam v3 additive fields per annotation: z (render order), groupIds (deepest →
|
|
108
108
|
shallowest), author ("ai" for annotate-verb strokes), authorName/authorId
|
|
109
|
+
// (an IMPORTED stroke carries authorName "imported-figma" — DDR-216 D7, so a
|
|
110
|
+
// consuming skill can tell third-party content from what the user drew), the
|
|
111
|
+
// rendered fontSize for text/sticky (so 8 px is distinguishable from a heading)
|
|
109
112
|
(human-drawn stickies), and from/to host ids on bound arrows.
|
|
110
113
|
|
|
111
114
|
Section annotations additionally carry members: an array of every OTHER
|
|
@@ -210,6 +213,10 @@ function readText(attrs, inner) {
|
|
|
210
213
|
h: null,
|
|
211
214
|
text: decodeEntities(inner).trim(),
|
|
212
215
|
color: attr(attrs, 'fill') || attr(attrs, 'stroke') || null,
|
|
216
|
+
// DDR-216 D6b / review F5 — a consuming skill must be able to see HOW BIG
|
|
217
|
+
// this renders. Without it, text at the 8 px floor is indistinguishable
|
|
218
|
+
// from a heading in the JSON an agent is handed.
|
|
219
|
+
fontSize: num(attr(attrs, 'font-size')),
|
|
213
220
|
};
|
|
214
221
|
if (anchorId) o.anchorId = anchorId;
|
|
215
222
|
return o;
|
|
@@ -235,7 +242,8 @@ function readSticky(attrs, inner) {
|
|
|
235
242
|
// Geometry off the inner <rect>; paper tint off the group fill; body off the
|
|
236
243
|
// inner <text>. (annotations-layer.tsx strokeToSvgEl 'sticky' branch.)
|
|
237
244
|
const rectAttrs = inner.match(/<rect\b([^>]*?)\/?>/)?.[1] ?? '';
|
|
238
|
-
const
|
|
245
|
+
const textEl = inner.match(/<text\b([^>]*)>([\s\S]*?)<\/text>/);
|
|
246
|
+
const body = textEl?.[2] ?? '';
|
|
239
247
|
return {
|
|
240
248
|
tool: 'sticky',
|
|
241
249
|
id: attr(attrs, 'data-id') || '',
|
|
@@ -245,6 +253,8 @@ function readSticky(attrs, inner) {
|
|
|
245
253
|
h: num(attr(rectAttrs, 'height')),
|
|
246
254
|
text: decodeEntities(body).trim(),
|
|
247
255
|
color: attr(attrs, 'fill') || null,
|
|
256
|
+
// See readText — a consuming skill needs the rendered size.
|
|
257
|
+
fontSize: num(attr(textEl?.[1] ?? '', 'font-size')),
|
|
248
258
|
};
|
|
249
259
|
}
|
|
250
260
|
|
package/apps/studio/bin/smoke.sh
CHANGED
|
@@ -26,10 +26,14 @@
|
|
|
26
26
|
# [--changed-only] (default off — screenshot only canvases changed
|
|
27
27
|
# since the last smoke run; escalates to the full
|
|
28
28
|
# set when dev-server / canvas-lib / templates changed)
|
|
29
|
+
# [--perf] (also benchmark the heaviest canvas after the sweep
|
|
30
|
+
# and append the frame-time / render-count delta to
|
|
31
|
+
# the report — see perf.sh)
|
|
29
32
|
#
|
|
30
33
|
# Reads:
|
|
31
34
|
# $DESIGN_ROOT/_server.json (must exist — caller runs server-up.sh first)
|
|
32
|
-
# $DESIGN_ROOT/ui
|
|
35
|
+
# $DESIGN_ROOT/ui/**/*.tsx (canvases, RECURSIVELY — `--pages` imports
|
|
36
|
+
# land in ui/<folder>/ and were being missed)
|
|
33
37
|
# $DESIGN_ROOT/system/*/preview/*.tsx (specimens, when --include-system 1)
|
|
34
38
|
#
|
|
35
39
|
# Writes:
|
|
@@ -52,6 +56,7 @@ INCLUDE_SYSTEM=1
|
|
|
52
56
|
TIMEOUT=8
|
|
53
57
|
ENGINE="auto"
|
|
54
58
|
CHANGED_ONLY=0
|
|
59
|
+
PERF=0
|
|
55
60
|
|
|
56
61
|
while [ $# -gt 0 ]; do
|
|
57
62
|
case "$1" in
|
|
@@ -61,6 +66,7 @@ while [ $# -gt 0 ]; do
|
|
|
61
66
|
--timeout) TIMEOUT="$2"; shift 2 ;;
|
|
62
67
|
--engine) ENGINE="$2"; shift 2 ;;
|
|
63
68
|
--changed-only) CHANGED_ONLY=1; shift ;;
|
|
69
|
+
--perf) PERF=1; shift ;;
|
|
64
70
|
--help|-h)
|
|
65
71
|
sed -n '2,30p' "$0" | sed 's/^# \?//'
|
|
66
72
|
exit 0
|
|
@@ -111,13 +117,24 @@ fi
|
|
|
111
117
|
echo "→ smoke engine: $ENGINE | port: $PORT | out: $OUT_DIR" >&2
|
|
112
118
|
|
|
113
119
|
# ---------- collect canvases ----------
|
|
120
|
+
#
|
|
121
|
+
# RECURSIVE, and that is a fix, not a preference. This was `-maxdepth 1` and the
|
|
122
|
+
# consequence was measured on the first live Figma migration: `--pages` always
|
|
123
|
+
# writes to `ui/<folder>/`, so EVERY canvas the primary import route produces was
|
|
124
|
+
# invisible here. The run reported "52/52 canvases rendered styled" having never
|
|
125
|
+
# looked at the 6 imported pages — green, true, and worthless. The import-graph
|
|
126
|
+
# lint below already walks `ui/` recursively, which is exactly why the mismatch
|
|
127
|
+
# went unnoticed: the lint covered the imports, the screenshots did not.
|
|
128
|
+
#
|
|
129
|
+
# A `_`-prefixed DIRECTORY is skipped as well as a `_`-prefixed file, so runtime
|
|
130
|
+
# state (`_history/`, `_draw/`, `_smoke/` output itself) never enters the sweep —
|
|
131
|
+
# without that, recursing would screenshot our own previous reports.
|
|
114
132
|
CANVASES=""
|
|
115
133
|
if [ -d "$DESIGN_ROOT/ui" ]; then
|
|
116
134
|
while IFS= read -r f; do
|
|
117
|
-
|
|
118
|
-
case "$base" in _*) continue ;; esac
|
|
135
|
+
case "$f" in *'/_'*) continue ;; esac
|
|
119
136
|
CANVASES="$CANVASES$f"$'\n'
|
|
120
|
-
done < <(find "$DESIGN_ROOT/ui" -
|
|
137
|
+
done < <(find "$DESIGN_ROOT/ui" -type f -name '*.tsx' 2>/dev/null | sort)
|
|
121
138
|
fi
|
|
122
139
|
|
|
123
140
|
if [ "$INCLUDE_SYSTEM" = "1" ] && [ -d "$DESIGN_ROOT/system" ]; then
|
|
@@ -130,7 +147,7 @@ fi
|
|
|
130
147
|
|
|
131
148
|
CANVASES=$(printf '%s' "$CANVASES" | sed '/^$/d')
|
|
132
149
|
COUNT=$(printf '%s' "$CANVASES" | grep -c .)
|
|
133
|
-
[ "$COUNT" -gt 0 ] || { echo "smoke.sh: no canvases found (ui
|
|
150
|
+
[ "$COUNT" -gt 0 ] || { echo "smoke.sh: no canvases found (ui/**/*.tsx or system/*/preview/*.tsx)" >&2; exit 1; }
|
|
134
151
|
echo "→ found $COUNT canvases" >&2
|
|
135
152
|
|
|
136
153
|
# ---------- --changed-only incremental filter (Phase C / DDR-061) ----------
|
|
@@ -525,6 +542,33 @@ TOTAL_FAIL=$((FAILED + LINT_FAILED))
|
|
|
525
542
|
fi
|
|
526
543
|
} >> "$MD"
|
|
527
544
|
|
|
545
|
+
# ---------- optional perf pass (--perf) ----------
|
|
546
|
+
# Smoke answers "does it still render"; this answers "is it still fast", against
|
|
547
|
+
# the same canvases, in the same run. The heaviest canvas (most artboards) is the
|
|
548
|
+
# one worth timing — a 1-artboard specimen has nothing to say about pan/zoom.
|
|
549
|
+
if [ "$PERF" = "1" ]; then
|
|
550
|
+
HEAVIEST=""
|
|
551
|
+
HEAVIEST_N=0
|
|
552
|
+
while IFS= read -r f; do
|
|
553
|
+
[ -n "$f" ] || continue
|
|
554
|
+
n=$(grep -c 'DCArtboard' "$f" 2>/dev/null || echo 0)
|
|
555
|
+
if [ "$n" -gt "$HEAVIEST_N" ]; then HEAVIEST_N="$n"; HEAVIEST="$f"; fi
|
|
556
|
+
done <<< "$CANVASES"
|
|
557
|
+
if [ -n "$HEAVIEST" ]; then
|
|
558
|
+
REL_PERF="${HEAVIEST#"$REPO"/}"
|
|
559
|
+
echo "→ perf: benchmarking heaviest canvas ($HEAVIEST_N artboards): $REL_PERF" >&2
|
|
560
|
+
{
|
|
561
|
+
echo ""
|
|
562
|
+
echo "## Perf"
|
|
563
|
+
echo ""
|
|
564
|
+
echo '```'
|
|
565
|
+
bash "$(dirname "${BASH_SOURCE[0]}")/perf.sh" --root "$REPO" --canvas "$REL_PERF" 2>&1 || \
|
|
566
|
+
echo "(perf run failed — see stderr; smoke result above is unaffected)"
|
|
567
|
+
echo '```'
|
|
568
|
+
} >> "$MD"
|
|
569
|
+
fi
|
|
570
|
+
fi
|
|
571
|
+
|
|
528
572
|
echo "→ report: $MD" >&2
|
|
529
573
|
echo "→ tsv: $TSV" >&2
|
|
530
574
|
|
package/apps/studio/bun.lock
CHANGED
|
@@ -14,10 +14,10 @@
|
|
|
14
14
|
"@mediabunny/aac-encoder": "1.50.7",
|
|
15
15
|
"@mediabunny/flac-encoder": "1.50.7",
|
|
16
16
|
"@mediabunny/mp3-encoder": "1.50.7",
|
|
17
|
-
"@remotion/media": "4.0.
|
|
18
|
-
"@remotion/player": "4.0.
|
|
19
|
-
"@remotion/transitions": "4.0.
|
|
20
|
-
"@remotion/web-renderer": "4.0.
|
|
17
|
+
"@remotion/media": "4.0.507",
|
|
18
|
+
"@remotion/player": "4.0.507",
|
|
19
|
+
"@remotion/transitions": "4.0.507",
|
|
20
|
+
"@remotion/web-renderer": "4.0.507",
|
|
21
21
|
"dom-to-pptx": "^1.1.10",
|
|
22
22
|
"dom-to-svg": "^0.12.2",
|
|
23
23
|
"gifenc": "^1.0.3",
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
"pptxgenjs": "^4.0.1",
|
|
38
38
|
"react": "^19.2.7",
|
|
39
39
|
"react-dom": "^19.2.7",
|
|
40
|
-
"remotion": "4.0.
|
|
40
|
+
"remotion": "4.0.507",
|
|
41
41
|
"svgo": "^4.0.1",
|
|
42
42
|
"y-protocols": "^1.0.7",
|
|
43
43
|
"yjs": "^13.6.31",
|
|
@@ -323,19 +323,19 @@
|
|
|
323
323
|
|
|
324
324
|
"@radix-ui/rect": ["@radix-ui/rect@1.1.2", "", {}, "sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA=="],
|
|
325
325
|
|
|
326
|
-
"@remotion/licensing": ["@remotion/licensing@4.0.
|
|
326
|
+
"@remotion/licensing": ["@remotion/licensing@4.0.507", "", {}, "sha512-fdods4YD9c8Ww69wHdnmXpjx7W0rvct6B7gLb92cWsd+ITSUG3hKoh+NqSWXF0GK5bk8IFRmTtBAwJObxow9wA=="],
|
|
327
327
|
|
|
328
|
-
"@remotion/media": ["@remotion/media@4.0.
|
|
328
|
+
"@remotion/media": ["@remotion/media@4.0.507", "", { "dependencies": { "mediabunny": "1.50.8", "remotion": "4.0.507", "zod": "4.4.3" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-PpSbLq0x2E/yZGHyYcGsFpUWcocy+w2uV64qcTgASSN3Vd2ZSwNAaAGrNCUD9nN3EUaHjsoqheL/o8cRTZZ06g=="],
|
|
329
329
|
|
|
330
|
-
"@remotion/paths": ["@remotion/paths@4.0.
|
|
330
|
+
"@remotion/paths": ["@remotion/paths@4.0.507", "", {}, "sha512-/2vXtdZDvpicamS30CmW+qYkA/yWhTUCk/5MysLExZYll8pqCR+BTlluRwpkfqhH0H4VJ4LwDoY1ZRd3MQ1HeQ=="],
|
|
331
331
|
|
|
332
|
-
"@remotion/player": ["@remotion/player@4.0.
|
|
332
|
+
"@remotion/player": ["@remotion/player@4.0.507", "", { "dependencies": { "remotion": "4.0.507" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-ZAunyyCfOXSYh5sZrp+vFxZlSPatg5evmh7fHVCndAOWBUPIDVjdUWEM2D4i132MsN6GXasXDByi+6H0H+IkhQ=="],
|
|
333
333
|
|
|
334
|
-
"@remotion/shapes": ["@remotion/shapes@4.0.
|
|
334
|
+
"@remotion/shapes": ["@remotion/shapes@4.0.507", "", { "dependencies": { "@remotion/paths": "4.0.507", "remotion": "4.0.507" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-PinB0Va4FRdv9OeaoIxikPqius9XQj5S5xruQEg/Y1CX+1Eu9KOVXqPOrMgELjkfPLLQ0rA/I4gmKoVxhaoYDQ=="],
|
|
335
335
|
|
|
336
|
-
"@remotion/transitions": ["@remotion/transitions@4.0.
|
|
336
|
+
"@remotion/transitions": ["@remotion/transitions@4.0.507", "", { "dependencies": { "@remotion/paths": "4.0.507", "@remotion/shapes": "4.0.507", "remotion": "4.0.507" }, "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-d0rtF2gVdSxR4Q35kjSSEdQ1ji0WoKFRaeoNgx/7NO13c/3gDSECAg9m2LoP+fN5pkZFdfL8z+yhM16rL7rWjg=="],
|
|
337
337
|
|
|
338
|
-
"@remotion/web-renderer": ["@remotion/web-renderer@4.0.
|
|
338
|
+
"@remotion/web-renderer": ["@remotion/web-renderer@4.0.507", "", { "dependencies": { "@mediabunny/aac-encoder": "1.50.8", "@mediabunny/flac-encoder": "1.50.8", "@mediabunny/mp3-encoder": "1.50.8", "@remotion/licensing": "4.0.507", "mediabunny": "1.50.8", "remotion": "4.0.507" }, "peerDependencies": { "react": ">=18.0.0", "react-dom": ">=18.0.0" } }, "sha512-fH8iZX1e0hmeJ+hPqn3RfqrDBNxMGsZZzfdyX2QpTDZ9F2kKqOkh0dQsRqaU8o+YoE8JNV/+FyYm4yyDAh9o6Q=="],
|
|
339
339
|
|
|
340
340
|
"@stablelib/base64": ["@stablelib/base64@1.0.1", "", {}, "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ=="],
|
|
341
341
|
|
|
@@ -757,7 +757,7 @@
|
|
|
757
757
|
|
|
758
758
|
"readable-stream": ["readable-stream@4.7.0", "", { "dependencies": { "abort-controller": "^3.0.0", "buffer": "^6.0.3", "events": "^3.3.0", "process": "^0.11.10", "string_decoder": "^1.3.0" } }, "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg=="],
|
|
759
759
|
|
|
760
|
-
"remotion": ["remotion@4.0.
|
|
760
|
+
"remotion": ["remotion@4.0.507", "", { "peerDependencies": { "react": ">=16.8.0", "react-dom": ">=16.8.0" } }, "sha512-g/NrnRZKJyh0isE+/0sIxKlgJl6BH5v/CJ35W4TGYR1obQZf60fHkf9CGxSBHJEw27dG1PJCgKT75YGfoCZ7tg=="],
|
|
761
761
|
|
|
762
762
|
"require-from-string": ["require-from-string@2.0.2", "", {}, "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="],
|
|
763
763
|
|
|
@@ -881,17 +881,11 @@
|
|
|
881
881
|
|
|
882
882
|
"@pdf-lib/upng/pako": ["pako@1.0.11", "", {}, "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw=="],
|
|
883
883
|
|
|
884
|
-
"@remotion/
|
|
884
|
+
"@remotion/web-renderer/@mediabunny/aac-encoder": ["@mediabunny/aac-encoder@1.50.8", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-A5Se/LZd6RmYq/h36lBMSEsHvsyW8d0toR7FrAwpsFYbK+DVQYf90KiBT1Aw/mzLXx8/ypIOORJnd1sVZqOvJQ=="],
|
|
885
885
|
|
|
886
|
-
"@remotion/
|
|
886
|
+
"@remotion/web-renderer/@mediabunny/flac-encoder": ["@mediabunny/flac-encoder@1.50.8", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-4cfN03SbEoQaG+eBeYFUAb1R1ALaAHzf43dXFzQTr/oO5ueqzTgBoG3coKrIvBaAMU7Vv36mrBKLX8bvTppdAQ=="],
|
|
887
887
|
|
|
888
|
-
"@remotion/web-renderer/@mediabunny/
|
|
889
|
-
|
|
890
|
-
"@remotion/web-renderer/@mediabunny/flac-encoder": ["@mediabunny/flac-encoder@1.50.3", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-aIEHE3eQ+hG35rRvtNNYO6ufTiGkZpzgOBjcqK8CQuRAMtUY9/DzV12jj52L0nSj2zmBKXQQ6dWBWsusigV/dQ=="],
|
|
891
|
-
|
|
892
|
-
"@remotion/web-renderer/@mediabunny/mp3-encoder": ["@mediabunny/mp3-encoder@1.50.3", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-dyjWOhG27+ctlejfjY4vFy0g8wzo0NCRTNQ/GNsCaHxWkduaq0GI2BWKXm6UFCsfnUKgtDWMEu4zOPl9fKpbsA=="],
|
|
893
|
-
|
|
894
|
-
"@remotion/web-renderer/mediabunny": ["mediabunny@1.50.3", "", { "dependencies": { "@types/dom-mediacapture-transform": "^0.1.11", "@types/dom-webcodecs": "0.1.13" } }, "sha512-lw6NjC6++/p6MzHC3u7RbkpM0dnukEQcAAXzZwXlmmx9y8n6132DXUMer2WaNn8RPuGgUpnemi/QIVNpEnONhQ=="],
|
|
888
|
+
"@remotion/web-renderer/@mediabunny/mp3-encoder": ["@mediabunny/mp3-encoder@1.50.8", "", { "peerDependencies": { "mediabunny": "^1.0.0" } }, "sha512-eBT/H30tTu8AmZXqZ5RTpJ9VmwVlwednajuOrrWp0GS6cbGXsGMQ60Qvr3ZMIE0QDiadlEzb8/ozR+doP+MC1g=="],
|
|
895
889
|
|
|
896
890
|
"body-parser/content-type": ["content-type@2.0.0", "", {}, "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ=="],
|
|
897
891
|
|
|
@@ -1641,7 +1641,21 @@ const CLIP_TAGS = new Set(['Sequence', 'Series.Sequence', 'TransitionSeries.Sequ
|
|
|
1641
1641
|
/** Transition tags (occupy a slot between clips inside a TransitionSeries). */
|
|
1642
1642
|
const TRANSITION_TAGS = new Set(['Series.Transition', 'TransitionSeries.Transition']);
|
|
1643
1643
|
/** Media tags that carry a `src` (the replace-media + drop targets). */
|
|
1644
|
-
|
|
1644
|
+
// `Maude*` spellings are the collision-avoidance ALIASES clip-ops emits when a
|
|
1645
|
+
// canvas already declares a component of that name (e.g. `export default
|
|
1646
|
+
// function Video()`). They are the same elements and must tokenize the same,
|
|
1647
|
+
// or the Timeline silently loses the clip's media (RCA
|
|
1648
|
+
// issue-mp4-audio-export-html5audio-silent-degrade follow-up).
|
|
1649
|
+
const MEDIA_TAGS = new Set([
|
|
1650
|
+
'Video',
|
|
1651
|
+
'OffthreadVideo',
|
|
1652
|
+
'Audio',
|
|
1653
|
+
'Img',
|
|
1654
|
+
'Image',
|
|
1655
|
+
'MaudeVideo',
|
|
1656
|
+
'MaudeAudio',
|
|
1657
|
+
'MaudeImg',
|
|
1658
|
+
]);
|
|
1645
1659
|
/** Remotion/layout primitives that are structural, not their own timeline layer. */
|
|
1646
1660
|
const LAYER_SKIP_TAGS = new Set([
|
|
1647
1661
|
'AbsoluteFill',
|
|
@@ -4534,7 +4548,7 @@ export function assembleCompSource(
|
|
|
4534
4548
|
const dur = Math.max(1, Math.round(c.durationInFrames ?? defDur));
|
|
4535
4549
|
seqLines.push(
|
|
4536
4550
|
` <TransitionSeries.Sequence name="clip-${i + 1}" durationInFrames={${dur}}>`,
|
|
4537
|
-
` <
|
|
4551
|
+
` <Video src="${escapeAttr(c.src)}" />`,
|
|
4538
4552
|
` </TransitionSeries.Sequence>`
|
|
4539
4553
|
);
|
|
4540
4554
|
cursor += dur;
|
|
@@ -4557,16 +4571,26 @@ export function assembleCompSource(
|
|
|
4557
4571
|
// the cursor (with the historical defDur floor for degenerate inputs).
|
|
4558
4572
|
const total = videos.length || audios.length ? Math.max(cursor, defDur) : fps * 5;
|
|
4559
4573
|
|
|
4574
|
+
// Media elements come from @remotion/media, NEVER from 'remotion'. The export's
|
|
4575
|
+
// only audio-capable path (renderMediaOnWeb) rejects `remotion`'s `Audio`
|
|
4576
|
+
// (= Html5Audio) and `OffthreadVideo` outright, so a reel assembled with those
|
|
4577
|
+
// exports MUTED — and ~40x slower, on the frame-step fallback. Every reel this
|
|
4578
|
+
// function emits has a music bed by default, which made it the widest carrier
|
|
4579
|
+
// of the bug. RCA issue-mp4-audio-export-html5audio-silent-degrade.
|
|
4560
4580
|
const remotionImports = ['AbsoluteFill'];
|
|
4561
|
-
|
|
4562
|
-
if (
|
|
4581
|
+
const mediaImports: string[] = [];
|
|
4582
|
+
if (videos.length) mediaImports.push('Video');
|
|
4583
|
+
if (audios.length) mediaImports.push('Audio');
|
|
4563
4584
|
const transitionsImport = videos.length
|
|
4564
4585
|
? `import { TransitionSeries } from '@remotion/transitions';\n`
|
|
4565
4586
|
: '';
|
|
4587
|
+
const mediaImport = mediaImports.length
|
|
4588
|
+
? `import { ${mediaImports.join(', ')} } from '@remotion/media';\n`
|
|
4589
|
+
: '';
|
|
4566
4590
|
|
|
4567
4591
|
return [
|
|
4568
4592
|
`import { DesignCanvas, DCSection, DCArtboard, VideoComp } from '@maude/canvas-lib';`,
|
|
4569
|
-
`${transitionsImport}import { ${remotionImports.join(', ')} } from 'remotion';`,
|
|
4593
|
+
`${transitionsImport}${mediaImport}import { ${remotionImports.join(', ')} } from 'remotion';`,
|
|
4570
4594
|
``,
|
|
4571
4595
|
`const Comp = () => (`,
|
|
4572
4596
|
` <AbsoluteFill style={{ background: 'var(--bg-0)' }}>`,
|