@markdy/core 1.0.9 → 1.0.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/index.d.ts +99 -8
- package/dist/index.js +321 -78
- package/package.json +1 -1
package/README.md
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -6,6 +6,65 @@ type LayoutDirection = "LR" | "RL" | "TB" | "BT";
|
|
|
6
6
|
type EdgeKind = "request" | "response" | "event" | "dependency";
|
|
7
7
|
type DiagramType = "architecture" | "flowchart" | "tree" | "state" | "sequence" | "constellation" | "loop" | "flywheel" | "medallion" | "quadrant" | "swimlane" | "pyramid" | "radar" | "timeline" | "gantt" | "venn" | "layers" | "nested";
|
|
8
8
|
type NodeShape = "card" | "rounded" | "diamond" | "circle" | "pill" | "terminal" | "container";
|
|
9
|
+
type PlayerProgress = "none" | "bar" | "boundary";
|
|
10
|
+
/** When and how fast the timeline runs. */
|
|
11
|
+
type PlayerPlaybackConfig = {
|
|
12
|
+
autoplay?: boolean;
|
|
13
|
+
loop?: boolean;
|
|
14
|
+
rate?: number;
|
|
15
|
+
};
|
|
16
|
+
/** Which toolbar affordances are mounted. Declaring the group opts in. */
|
|
17
|
+
type PlayerControlsConfig = {
|
|
18
|
+
play?: boolean;
|
|
19
|
+
restart?: boolean;
|
|
20
|
+
prevBeat?: boolean;
|
|
21
|
+
nextBeat?: boolean;
|
|
22
|
+
seek?: boolean;
|
|
23
|
+
speed?: boolean;
|
|
24
|
+
fit?: boolean;
|
|
25
|
+
resetView?: boolean;
|
|
26
|
+
svg?: boolean;
|
|
27
|
+
share?: boolean;
|
|
28
|
+
/** Speed multipliers offered by the speed buttons. */
|
|
29
|
+
speeds?: number[];
|
|
30
|
+
};
|
|
31
|
+
/** What pointer and key input do. Declaring the group opts in. */
|
|
32
|
+
type PlayerInteractionConfig = {
|
|
33
|
+
zoom?: boolean;
|
|
34
|
+
pan?: boolean;
|
|
35
|
+
clickToPlay?: boolean;
|
|
36
|
+
doubleClickToReset?: boolean;
|
|
37
|
+
/** Window-level shortcuts; opt-in because they capture space and arrows. */
|
|
38
|
+
keyboard?: boolean;
|
|
39
|
+
};
|
|
40
|
+
/** Non-interactive decoration drawn around the scene. */
|
|
41
|
+
type PlayerChromeConfig = {
|
|
42
|
+
badge?: boolean;
|
|
43
|
+
progress?: PlayerProgress;
|
|
44
|
+
progressColor?: string;
|
|
45
|
+
};
|
|
46
|
+
type PlayerConfig = {
|
|
47
|
+
playback?: PlayerPlaybackConfig;
|
|
48
|
+
controls?: PlayerControlsConfig;
|
|
49
|
+
interaction?: PlayerInteractionConfig;
|
|
50
|
+
chrome?: PlayerChromeConfig;
|
|
51
|
+
};
|
|
52
|
+
/** Fully defaulted player behavior produced by `resolvePlayer`. `enabled` is
|
|
53
|
+
* derived: a group is on when at least one of its affordances is on. */
|
|
54
|
+
type ResolvedPlayer = {
|
|
55
|
+
playback: Required<PlayerPlaybackConfig>;
|
|
56
|
+
controls: Required<PlayerControlsConfig> & {
|
|
57
|
+
enabled: boolean;
|
|
58
|
+
};
|
|
59
|
+
interaction: Required<PlayerInteractionConfig> & {
|
|
60
|
+
enabled: boolean;
|
|
61
|
+
};
|
|
62
|
+
chrome: {
|
|
63
|
+
badge: boolean;
|
|
64
|
+
progress: PlayerProgress;
|
|
65
|
+
progressColor?: string;
|
|
66
|
+
};
|
|
67
|
+
};
|
|
9
68
|
type SceneMeta = {
|
|
10
69
|
title?: string;
|
|
11
70
|
width: number;
|
|
@@ -16,19 +75,21 @@ type SceneMeta = {
|
|
|
16
75
|
duration?: number;
|
|
17
76
|
/** Opt-in diagram mode; defaults to architecture. */
|
|
18
77
|
type?: DiagramType;
|
|
19
|
-
/**
|
|
78
|
+
/** Playback, controls, interaction, and chrome behavior. Source of truth. */
|
|
79
|
+
player?: PlayerConfig;
|
|
80
|
+
/** @deprecated Mirror of `player.chrome.progressColor`. */
|
|
20
81
|
progressColor?: string;
|
|
21
|
-
/**
|
|
82
|
+
/** @deprecated Mirror of `player.controls.enabled`. */
|
|
22
83
|
controls?: boolean;
|
|
23
|
-
/**
|
|
84
|
+
/** @deprecated Mirror of `player.interaction.enabled`. */
|
|
24
85
|
interactiveViewport?: boolean;
|
|
25
|
-
/**
|
|
86
|
+
/** @deprecated Mirror of `player.playback.autoplay`. */
|
|
26
87
|
autoplay?: boolean;
|
|
27
|
-
/**
|
|
88
|
+
/** @deprecated Mirror of `player.playback.loop`. */
|
|
28
89
|
loop?: boolean;
|
|
29
|
-
/**
|
|
90
|
+
/** @deprecated Mirror of `player.chrome.badge`. */
|
|
30
91
|
copyright?: boolean;
|
|
31
|
-
/**
|
|
92
|
+
/** @deprecated Mirror of `player.playback.rate`. */
|
|
32
93
|
playbackRate?: number;
|
|
33
94
|
};
|
|
34
95
|
type NodeDecl = {
|
|
@@ -326,6 +387,36 @@ declare function parse(source: string, opts?: ParseOptions): DiagramAST;
|
|
|
326
387
|
declare function compile(ast: DiagramAST): RenderPlan;
|
|
327
388
|
declare function parseAndCompile(source: string): ParseResult;
|
|
328
389
|
|
|
390
|
+
/**
|
|
391
|
+
* Single source of truth for player configuration: schema, aliases, parsing,
|
|
392
|
+
* and default resolution. Hosts (DOM renderer, Astro, MDX, CLI) resolve
|
|
393
|
+
* behavior through `resolvePlayer` instead of re-deriving defaults.
|
|
394
|
+
*/
|
|
395
|
+
|
|
396
|
+
/** Groups own their own alias table, so `speed` can mean rate at the player
|
|
397
|
+
* root and the speed buttons inside `controls:`. */
|
|
398
|
+
type PlayerScope = "player" | "playback" | "controls" | "interaction" | "chrome";
|
|
399
|
+
declare const PLAYER_GROUPS: readonly ["playback", "controls", "interaction", "chrome"];
|
|
400
|
+
/** Keys usable as `scene` props and top-level directives. */
|
|
401
|
+
declare const PLAYER_FLAT_KEYS: string[];
|
|
402
|
+
/**
|
|
403
|
+
* Applies one `key value` pair into `config`. Returns an error message when the
|
|
404
|
+
* key is unknown or the value does not fit the setting type.
|
|
405
|
+
*/
|
|
406
|
+
declare function applyPlayerSetting(config: PlayerConfig, scope: PlayerScope, key: string, rawValue: string): string | undefined;
|
|
407
|
+
/** Host-supplied overrides always win over script configuration. */
|
|
408
|
+
type PlayerOverrides = {
|
|
409
|
+
autoplay?: boolean;
|
|
410
|
+
loop?: boolean;
|
|
411
|
+
playbackRate?: number;
|
|
412
|
+
copyright?: boolean;
|
|
413
|
+
controls?: boolean;
|
|
414
|
+
interactiveViewport?: boolean;
|
|
415
|
+
progress?: PlayerProgress;
|
|
416
|
+
progressColor?: string;
|
|
417
|
+
};
|
|
418
|
+
declare function resolvePlayer(config?: PlayerConfig, overrides?: PlayerOverrides): ResolvedPlayer;
|
|
419
|
+
|
|
329
420
|
declare const THEMES: Record<string, ThemeTokens>;
|
|
330
421
|
declare function resolveTheme(name: string): ThemeTokens;
|
|
331
422
|
|
|
@@ -537,4 +628,4 @@ declare function resolveOutputPreset(name: string): OutputPreset;
|
|
|
537
628
|
/** List all available preset names. */
|
|
538
629
|
declare function listOutputPresets(): string[];
|
|
539
630
|
|
|
540
|
-
export { ARCH_RULE_PRESETS, type AnnotationDecl, type ArchRuleType, type ArchitecturePreset, type ArchitectureRule, type ArchitectureViolation, BEAT_CUE_KEYWORDS, type BeatDecl, type BeatRange, type Box, CUE_ALIASES, type CardinalPort, type Cue, DIAGRAM_TYPES, type Diagnostic, type DiagramAST, type DiagramDiffResult, type DiagramType, type DiffChangeType, EDGE_OPERATORS, type EdgeDecl, type EdgeDiff, type EdgeKind, type EdgeSelector, type FlowSegment, type GroupBoundary, type GroupDecl, type LayoutDirection, type MarkdyConfig, NODE_ALIASES, NODE_KINDS, type NodeDecl, type NodeDiff, type NodeSelector, type NodeShape, OUTPUT_PRESETS, type OutputPreset, ParseError, type ParseOptions, type ParseResult, type PatternDecl, type Point, type PositionedNode, type RenderPlan, type RepairPromptBundle, type RoutedEdge, type RoutedPath, type RuleSeverity, SCENE_KEYS, type SceneMeta, type SemanticProfile, type SequenceActivation, type SequenceMessage, type StyleDecl, TECHNICAL_NODE_KINDS, TECHNICAL_NODE_TYPES, THEMES, type ThemeGeneratorOptions, type ThemeTokens, type TimedCue, type TreeBus, VISUAL_PRIMITIVE_TYPES, analyzeAndBuildRepairPrompt, canonicalNodeKind, classifyTechnology, compile, compilePlan, compressMarkdyToUrlHash, decompressMarkdyFromUrlHash, diffDiagramASTs, generateThemeFromBrand, getBoxPortPosition, humanizeId, listOutputPresets, nodeRole, parse, parseAndCompile, resolveArchitectureConfig, resolveOutputPreset, resolveTheme, routeOrthogonalEdge, selectOptimalPorts, validateArchitecture };
|
|
631
|
+
export { ARCH_RULE_PRESETS, type AnnotationDecl, type ArchRuleType, type ArchitecturePreset, type ArchitectureRule, type ArchitectureViolation, BEAT_CUE_KEYWORDS, type BeatDecl, type BeatRange, type Box, CUE_ALIASES, type CardinalPort, type Cue, DIAGRAM_TYPES, type Diagnostic, type DiagramAST, type DiagramDiffResult, type DiagramType, type DiffChangeType, EDGE_OPERATORS, type EdgeDecl, type EdgeDiff, type EdgeKind, type EdgeSelector, type FlowSegment, type GroupBoundary, type GroupDecl, type LayoutDirection, type MarkdyConfig, NODE_ALIASES, NODE_KINDS, type NodeDecl, type NodeDiff, type NodeSelector, type NodeShape, OUTPUT_PRESETS, type OutputPreset, PLAYER_FLAT_KEYS, PLAYER_GROUPS, ParseError, type ParseOptions, type ParseResult, type PatternDecl, type PlayerChromeConfig, type PlayerConfig, type PlayerControlsConfig, type PlayerInteractionConfig, type PlayerOverrides, type PlayerPlaybackConfig, type PlayerProgress, type PlayerScope, type Point, type PositionedNode, type RenderPlan, type RepairPromptBundle, type ResolvedPlayer, type RoutedEdge, type RoutedPath, type RuleSeverity, SCENE_KEYS, type SceneMeta, type SemanticProfile, type SequenceActivation, type SequenceMessage, type StyleDecl, TECHNICAL_NODE_KINDS, TECHNICAL_NODE_TYPES, THEMES, type ThemeGeneratorOptions, type ThemeTokens, type TimedCue, type TreeBus, VISUAL_PRIMITIVE_TYPES, analyzeAndBuildRepairPrompt, applyPlayerSetting, canonicalNodeKind, classifyTechnology, compile, compilePlan, compressMarkdyToUrlHash, decompressMarkdyFromUrlHash, diffDiagramASTs, generateThemeFromBrand, getBoxPortPosition, humanizeId, listOutputPresets, nodeRole, parse, parseAndCompile, resolveArchitectureConfig, resolveOutputPreset, resolvePlayer, resolveTheme, routeOrthogonalEdge, selectOptimalPorts, validateArchitecture };
|
package/dist/index.js
CHANGED
|
@@ -378,6 +378,258 @@ var TECHNICAL_NODE_KINDS = {
|
|
|
378
378
|
lock: "distributed"
|
|
379
379
|
};
|
|
380
380
|
|
|
381
|
+
// src/player.ts
|
|
382
|
+
function parseBooleanToken(raw) {
|
|
383
|
+
if (typeof raw === "boolean") return raw;
|
|
384
|
+
const s = String(raw).trim().toLowerCase();
|
|
385
|
+
if (["true", "on", "yes", "1"].includes(s)) return true;
|
|
386
|
+
if (["false", "off", "no", "0"].includes(s)) return false;
|
|
387
|
+
return void 0;
|
|
388
|
+
}
|
|
389
|
+
var CONTROL_KEYS = [
|
|
390
|
+
"play",
|
|
391
|
+
"restart",
|
|
392
|
+
"prevBeat",
|
|
393
|
+
"nextBeat",
|
|
394
|
+
"seek",
|
|
395
|
+
"speed",
|
|
396
|
+
"fit",
|
|
397
|
+
"resetView",
|
|
398
|
+
"svg",
|
|
399
|
+
"share"
|
|
400
|
+
];
|
|
401
|
+
var INTERACTION_KEYS = ["zoom", "pan", "doubleClickToReset"];
|
|
402
|
+
var PLAYBACK = {
|
|
403
|
+
autoplay: { group: "playback", key: "autoplay", type: "boolean" },
|
|
404
|
+
loop: { group: "playback", key: "loop", type: "boolean" },
|
|
405
|
+
rate: { group: "playback", key: "rate", type: "rate" },
|
|
406
|
+
speed: { group: "playback", key: "rate", type: "rate" },
|
|
407
|
+
playbackRate: { group: "playback", key: "rate", type: "rate" },
|
|
408
|
+
playback_rate: { group: "playback", key: "rate", type: "rate" }
|
|
409
|
+
};
|
|
410
|
+
var CONTROLS = {
|
|
411
|
+
controls: { group: "controls", key: "*", type: "group" },
|
|
412
|
+
play: { group: "controls", key: "play", type: "boolean" },
|
|
413
|
+
playButton: { group: "controls", key: "play", type: "boolean" },
|
|
414
|
+
play_button: { group: "controls", key: "play", type: "boolean" },
|
|
415
|
+
restart: { group: "controls", key: "restart", type: "boolean" },
|
|
416
|
+
restartButton: { group: "controls", key: "restart", type: "boolean" },
|
|
417
|
+
restart_button: { group: "controls", key: "restart", type: "boolean" },
|
|
418
|
+
prevBeat: { group: "controls", key: "prevBeat", type: "boolean" },
|
|
419
|
+
prev_beat: { group: "controls", key: "prevBeat", type: "boolean" },
|
|
420
|
+
nextBeat: { group: "controls", key: "nextBeat", type: "boolean" },
|
|
421
|
+
next_beat: { group: "controls", key: "nextBeat", type: "boolean" },
|
|
422
|
+
speeds: { group: "controls", key: "speeds", type: "rates" },
|
|
423
|
+
speedOptions: { group: "controls", key: "speeds", type: "rates" },
|
|
424
|
+
speed_options: { group: "controls", key: "speeds", type: "rates" },
|
|
425
|
+
seek: { group: "controls", key: "seek", type: "boolean" },
|
|
426
|
+
seekBar: { group: "controls", key: "seek", type: "boolean" },
|
|
427
|
+
seek_bar: { group: "controls", key: "seek", type: "boolean" },
|
|
428
|
+
speed: { group: "controls", key: "speed", type: "boolean" },
|
|
429
|
+
speedControls: { group: "controls", key: "speed", type: "boolean" },
|
|
430
|
+
speed_controls: { group: "controls", key: "speed", type: "boolean" },
|
|
431
|
+
fit: { group: "controls", key: "fit", type: "boolean" },
|
|
432
|
+
fitView: { group: "controls", key: "fit", type: "boolean" },
|
|
433
|
+
fit_view: { group: "controls", key: "fit", type: "boolean" },
|
|
434
|
+
fitViewButton: { group: "controls", key: "fit", type: "boolean" },
|
|
435
|
+
fit_view_button: { group: "controls", key: "fit", type: "boolean" },
|
|
436
|
+
resetView: { group: "controls", key: "resetView", type: "boolean" },
|
|
437
|
+
reset_view: { group: "controls", key: "resetView", type: "boolean" },
|
|
438
|
+
resetViewButton: { group: "controls", key: "resetView", type: "boolean" },
|
|
439
|
+
reset_view_button: { group: "controls", key: "resetView", type: "boolean" },
|
|
440
|
+
svg: { group: "controls", key: "svg", type: "boolean" },
|
|
441
|
+
exportSvg: { group: "controls", key: "svg", type: "boolean" },
|
|
442
|
+
export_svg: { group: "controls", key: "svg", type: "boolean" },
|
|
443
|
+
share: { group: "controls", key: "share", type: "boolean" },
|
|
444
|
+
shareLink: { group: "controls", key: "share", type: "boolean" },
|
|
445
|
+
share_link: { group: "controls", key: "share", type: "boolean" }
|
|
446
|
+
};
|
|
447
|
+
var INTERACTION = {
|
|
448
|
+
interactive: { group: "interaction", key: "*", type: "group" },
|
|
449
|
+
interactiveViewport: { group: "interaction", key: "*", type: "group" },
|
|
450
|
+
interactive_viewport: { group: "interaction", key: "*", type: "group" },
|
|
451
|
+
zoom: { group: "interaction", key: "zoom", type: "boolean" },
|
|
452
|
+
allowZoom: { group: "interaction", key: "zoom", type: "boolean" },
|
|
453
|
+
allow_zoom: { group: "interaction", key: "zoom", type: "boolean" },
|
|
454
|
+
pan: { group: "interaction", key: "pan", type: "boolean" },
|
|
455
|
+
allowPan: { group: "interaction", key: "pan", type: "boolean" },
|
|
456
|
+
allow_pan: { group: "interaction", key: "pan", type: "boolean" },
|
|
457
|
+
clickToPlay: { group: "interaction", key: "clickToPlay", type: "boolean" },
|
|
458
|
+
click_to_play: { group: "interaction", key: "clickToPlay", type: "boolean" },
|
|
459
|
+
keyboard: { group: "interaction", key: "keyboard", type: "boolean" },
|
|
460
|
+
shortcuts: { group: "interaction", key: "keyboard", type: "boolean" },
|
|
461
|
+
doubleClickToReset: { group: "interaction", key: "doubleClickToReset", type: "boolean" },
|
|
462
|
+
double_click_to_reset: { group: "interaction", key: "doubleClickToReset", type: "boolean" }
|
|
463
|
+
};
|
|
464
|
+
var CHROME = {
|
|
465
|
+
badge: { group: "chrome", key: "badge", type: "boolean" },
|
|
466
|
+
copyright: { group: "chrome", key: "badge", type: "boolean" },
|
|
467
|
+
progress: { group: "chrome", key: "progress", type: "progress" },
|
|
468
|
+
progressBar: { group: "chrome", key: "progress", type: "progress" },
|
|
469
|
+
progress_bar: { group: "chrome", key: "progress", type: "progress" },
|
|
470
|
+
sceneBoundaryProgress: { group: "chrome", key: "progress", type: "progress" },
|
|
471
|
+
progressColor: { group: "chrome", key: "progressColor", type: "color" },
|
|
472
|
+
progress_color: { group: "chrome", key: "progressColor", type: "color" },
|
|
473
|
+
progressBarColor: { group: "chrome", key: "progressColor", type: "color" },
|
|
474
|
+
progress_bar_color: { group: "chrome", key: "progressColor", type: "color" }
|
|
475
|
+
};
|
|
476
|
+
var FLAT = {
|
|
477
|
+
...PLAYBACK,
|
|
478
|
+
...CHROME,
|
|
479
|
+
controls: CONTROLS.controls,
|
|
480
|
+
playButton: CONTROLS.playButton,
|
|
481
|
+
play_button: CONTROLS.play_button,
|
|
482
|
+
restartButton: CONTROLS.restartButton,
|
|
483
|
+
restart_button: CONTROLS.restart_button,
|
|
484
|
+
seek: CONTROLS.seek,
|
|
485
|
+
seekBar: CONTROLS.seekBar,
|
|
486
|
+
seek_bar: CONTROLS.seek_bar,
|
|
487
|
+
speedControls: CONTROLS.speedControls,
|
|
488
|
+
speed_controls: CONTROLS.speed_controls,
|
|
489
|
+
speeds: CONTROLS.speeds,
|
|
490
|
+
speedOptions: CONTROLS.speedOptions,
|
|
491
|
+
speed_options: CONTROLS.speed_options,
|
|
492
|
+
prevBeat: CONTROLS.prevBeat,
|
|
493
|
+
prev_beat: CONTROLS.prev_beat,
|
|
494
|
+
nextBeat: CONTROLS.nextBeat,
|
|
495
|
+
next_beat: CONTROLS.next_beat,
|
|
496
|
+
keyboard: INTERACTION.keyboard,
|
|
497
|
+
shortcuts: INTERACTION.shortcuts,
|
|
498
|
+
fitView: CONTROLS.fitView,
|
|
499
|
+
fit_view: CONTROLS.fit_view,
|
|
500
|
+
fitViewButton: CONTROLS.fitViewButton,
|
|
501
|
+
fit_view_button: CONTROLS.fit_view_button,
|
|
502
|
+
resetViewButton: CONTROLS.resetViewButton,
|
|
503
|
+
reset_view_button: CONTROLS.reset_view_button,
|
|
504
|
+
exportSvg: CONTROLS.exportSvg,
|
|
505
|
+
export_svg: CONTROLS.export_svg,
|
|
506
|
+
shareLink: CONTROLS.shareLink,
|
|
507
|
+
share_link: CONTROLS.share_link,
|
|
508
|
+
interactive: INTERACTION.interactive,
|
|
509
|
+
interactiveViewport: INTERACTION.interactiveViewport,
|
|
510
|
+
interactive_viewport: INTERACTION.interactive_viewport,
|
|
511
|
+
allowZoom: INTERACTION.allowZoom,
|
|
512
|
+
allow_zoom: INTERACTION.allow_zoom,
|
|
513
|
+
allowPan: INTERACTION.allowPan,
|
|
514
|
+
allow_pan: INTERACTION.allow_pan,
|
|
515
|
+
clickToPlay: INTERACTION.clickToPlay,
|
|
516
|
+
click_to_play: INTERACTION.click_to_play,
|
|
517
|
+
doubleClickToReset: INTERACTION.doubleClickToReset,
|
|
518
|
+
double_click_to_reset: INTERACTION.double_click_to_reset
|
|
519
|
+
};
|
|
520
|
+
var SCOPES = {
|
|
521
|
+
player: FLAT,
|
|
522
|
+
playback: PLAYBACK,
|
|
523
|
+
controls: CONTROLS,
|
|
524
|
+
interaction: INTERACTION,
|
|
525
|
+
// `color` is unambiguous inside the block, but too generic at the root.
|
|
526
|
+
chrome: { ...CHROME, color: CHROME.progressColor }
|
|
527
|
+
};
|
|
528
|
+
var PLAYER_GROUPS = ["playback", "controls", "interaction", "chrome"];
|
|
529
|
+
var PLAYER_FLAT_KEYS = Object.keys(FLAT);
|
|
530
|
+
function applyPlayerSetting(config, scope, key, rawValue) {
|
|
531
|
+
const setting = SCOPES[scope][key];
|
|
532
|
+
if (!setting) return `unknown player property '${key}'`;
|
|
533
|
+
const value = unquote(rawValue).trim();
|
|
534
|
+
const group = config[setting.group] ??= {};
|
|
535
|
+
if (setting.type === "boolean" || setting.type === "group") {
|
|
536
|
+
const parsed = value ? parseBooleanToken(value) : true;
|
|
537
|
+
if (parsed === void 0) return `player property '${key}' expects true or false`;
|
|
538
|
+
if (setting.type === "boolean") group[setting.key] = parsed;
|
|
539
|
+
else for (const child of setting.group === "controls" ? CONTROL_KEYS : INTERACTION_KEYS) group[child] = parsed;
|
|
540
|
+
return void 0;
|
|
541
|
+
}
|
|
542
|
+
if (setting.type === "rate") {
|
|
543
|
+
const rate = Number(value);
|
|
544
|
+
if (!Number.isFinite(rate) || rate <= 0) return `player property '${key}' expects a positive number`;
|
|
545
|
+
group[setting.key] = rate;
|
|
546
|
+
return void 0;
|
|
547
|
+
}
|
|
548
|
+
if (setting.type === "rates") {
|
|
549
|
+
const rates = value.split(/[\s,]+/).filter(Boolean).map(Number);
|
|
550
|
+
if (!rates.length || rates.some((rate) => !Number.isFinite(rate) || rate <= 0)) {
|
|
551
|
+
return `player property '${key}' expects a list of positive numbers`;
|
|
552
|
+
}
|
|
553
|
+
group[setting.key] = rates;
|
|
554
|
+
return void 0;
|
|
555
|
+
}
|
|
556
|
+
if (setting.type === "color") {
|
|
557
|
+
if (value) group[setting.key] = value;
|
|
558
|
+
return void 0;
|
|
559
|
+
}
|
|
560
|
+
const mode = toProgressMode(value);
|
|
561
|
+
if (mode) group.progress = mode;
|
|
562
|
+
else if (value) group.progressColor = value;
|
|
563
|
+
return void 0;
|
|
564
|
+
}
|
|
565
|
+
function toProgressMode(value) {
|
|
566
|
+
const lower = value.toLowerCase();
|
|
567
|
+
if (lower === "none" || lower === "bar" || lower === "boundary") return lower;
|
|
568
|
+
const bool = parseBooleanToken(lower);
|
|
569
|
+
if (bool === true) return "boundary";
|
|
570
|
+
if (bool === false) return "none";
|
|
571
|
+
return void 0;
|
|
572
|
+
}
|
|
573
|
+
function unquote(raw) {
|
|
574
|
+
const value = raw.trim();
|
|
575
|
+
if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
|
|
576
|
+
return value.slice(1, -1);
|
|
577
|
+
}
|
|
578
|
+
return value;
|
|
579
|
+
}
|
|
580
|
+
function resolvePlayer(config = {}, overrides = {}) {
|
|
581
|
+
const playback = config.playback ?? {};
|
|
582
|
+
const interaction = config.interaction ?? {};
|
|
583
|
+
const chrome = config.chrome ?? {};
|
|
584
|
+
const controlsOn = overrides.controls !== false && (overrides.controls === true || config.controls !== void 0);
|
|
585
|
+
const controls = {
|
|
586
|
+
play: controlsOn && (config.controls?.play ?? true),
|
|
587
|
+
restart: controlsOn && (config.controls?.restart ?? true),
|
|
588
|
+
prevBeat: controlsOn && (config.controls?.prevBeat ?? true),
|
|
589
|
+
nextBeat: controlsOn && (config.controls?.nextBeat ?? true),
|
|
590
|
+
seek: controlsOn && (config.controls?.seek ?? true),
|
|
591
|
+
speed: controlsOn && (config.controls?.speed ?? true),
|
|
592
|
+
fit: controlsOn && (config.controls?.fit ?? true),
|
|
593
|
+
resetView: controlsOn && (config.controls?.resetView ?? true),
|
|
594
|
+
svg: controlsOn && (config.controls?.svg ?? true),
|
|
595
|
+
share: controlsOn && (config.controls?.share ?? true)
|
|
596
|
+
};
|
|
597
|
+
const interactionOn = overrides.interactiveViewport !== false && (overrides.interactiveViewport === true || config.interaction !== void 0 || overrides.controls === true);
|
|
598
|
+
const gestures = {
|
|
599
|
+
zoom: interactionOn && (interaction.zoom ?? true),
|
|
600
|
+
pan: interactionOn && (interaction.pan ?? true),
|
|
601
|
+
doubleClickToReset: interactionOn && (interaction.doubleClickToReset ?? true)
|
|
602
|
+
};
|
|
603
|
+
const interactionEnabled = gestures.zoom || gestures.pan || gestures.doubleClickToReset;
|
|
604
|
+
const resetView = controls.resetView && interactionEnabled;
|
|
605
|
+
const controlsEnabled = controls.play || controls.restart || controls.prevBeat || controls.nextBeat || controls.seek || controls.speed || controls.fit || controls.svg || controls.share || resetView;
|
|
606
|
+
const rate = overrides.playbackRate ?? playback.rate ?? 1;
|
|
607
|
+
return {
|
|
608
|
+
playback: {
|
|
609
|
+
autoplay: overrides.autoplay ?? playback.autoplay ?? true,
|
|
610
|
+
loop: overrides.loop ?? playback.loop ?? true,
|
|
611
|
+
rate: Number.isFinite(rate) && rate > 0 ? rate : 1
|
|
612
|
+
},
|
|
613
|
+
controls: {
|
|
614
|
+
...controls,
|
|
615
|
+
resetView,
|
|
616
|
+
enabled: controlsEnabled,
|
|
617
|
+
speeds: config.controls?.speeds?.length ? config.controls.speeds : [0.5, 1, 2]
|
|
618
|
+
},
|
|
619
|
+
interaction: {
|
|
620
|
+
...gestures,
|
|
621
|
+
enabled: interactionEnabled,
|
|
622
|
+
clickToPlay: interaction.clickToPlay ?? true,
|
|
623
|
+
keyboard: interaction.keyboard ?? false
|
|
624
|
+
},
|
|
625
|
+
chrome: {
|
|
626
|
+
badge: overrides.copyright ?? chrome.badge ?? true,
|
|
627
|
+
progress: overrides.progress ?? chrome.progress ?? "boundary",
|
|
628
|
+
progressColor: overrides.progressColor ?? chrome.progressColor
|
|
629
|
+
}
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
|
|
381
633
|
// src/registry.ts
|
|
382
634
|
var NODE_KINDS = /* @__PURE__ */ new Set([
|
|
383
635
|
...TECHNICAL_NODE_TYPES,
|
|
@@ -433,23 +685,7 @@ var SCENE_KEYS = /* @__PURE__ */ new Set([
|
|
|
433
685
|
"direction",
|
|
434
686
|
"layout",
|
|
435
687
|
"type",
|
|
436
|
-
|
|
437
|
-
"progressBarColor",
|
|
438
|
-
"progress_color",
|
|
439
|
-
"progress_bar_color",
|
|
440
|
-
"progress",
|
|
441
|
-
"progressBar",
|
|
442
|
-
"sceneBoundaryProgress",
|
|
443
|
-
"controls",
|
|
444
|
-
"interactive",
|
|
445
|
-
"interactiveViewport",
|
|
446
|
-
"interactive_viewport",
|
|
447
|
-
"autoplay",
|
|
448
|
-
"loop",
|
|
449
|
-
"copyright",
|
|
450
|
-
"playbackRate",
|
|
451
|
-
"playback_rate",
|
|
452
|
-
"speed"
|
|
688
|
+
...PLAYER_FLAT_KEYS
|
|
453
689
|
]);
|
|
454
690
|
function nodeRole(kind) {
|
|
455
691
|
const canonical = canonicalNodeKind(kind);
|
|
@@ -1658,7 +1894,7 @@ function compilePlan(ast, theme) {
|
|
|
1658
1894
|
...beats.map((b) => b.end),
|
|
1659
1895
|
1
|
|
1660
1896
|
);
|
|
1661
|
-
const title = ast.meta.title ?? "
|
|
1897
|
+
const title = ast.meta.title ?? "";
|
|
1662
1898
|
return {
|
|
1663
1899
|
meta: ast.meta,
|
|
1664
1900
|
theme,
|
|
@@ -1725,9 +1961,9 @@ var THEMES = {
|
|
|
1725
1961
|
canvas: "#f6f8fc",
|
|
1726
1962
|
surface: "#ffffff",
|
|
1727
1963
|
surfaceRaised: "#f0f4f9",
|
|
1728
|
-
border: "#
|
|
1964
|
+
border: "#cbd5e1",
|
|
1729
1965
|
text: "#0f1c2e",
|
|
1730
|
-
textMuted: "#
|
|
1966
|
+
textMuted: "#475569",
|
|
1731
1967
|
gridMinor: "rgba(15, 23, 42, 0.06)",
|
|
1732
1968
|
gridMajor: "rgba(15, 23, 42, 0.10)",
|
|
1733
1969
|
vignette: "rgba(226, 232, 240, 0.6)",
|
|
@@ -1788,7 +2024,7 @@ var THEMES = {
|
|
|
1788
2024
|
surfaceRaised: "#f8fafc",
|
|
1789
2025
|
border: "#e2e8f0",
|
|
1790
2026
|
text: "#0f172a",
|
|
1791
|
-
textMuted: "#
|
|
2027
|
+
textMuted: "#475569",
|
|
1792
2028
|
paper: "#fafafa",
|
|
1793
2029
|
ink: "#0f172a",
|
|
1794
2030
|
muted: "#6b7280",
|
|
@@ -2357,14 +2593,30 @@ function readIndentedBody(blocks, startIdx, parentIndent) {
|
|
|
2357
2593
|
}
|
|
2358
2594
|
return { body, nextIdx: i };
|
|
2359
2595
|
}
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2596
|
+
var PLAYER_KEYWORDS = [...PLAYER_FLAT_KEYS].sort((a, b) => b.length - a.length).join("|");
|
|
2597
|
+
var TOP_LEVEL_KEYWORDS_RE = new RegExp(
|
|
2598
|
+
`^(scene|player|layout|pattern|group|annotation|edge|beat|var|style|${PLAYER_KEYWORDS})\\b`
|
|
2599
|
+
);
|
|
2600
|
+
var PLAYER_DIRECTIVE_RE = new RegExp(`^(${PLAYER_KEYWORDS})\\b(?:\\s*[:=]?\\s*(.+))?$`);
|
|
2601
|
+
var PLAYER_GROUP_RE = /^(playback|controls|interaction|chrome)\s*:\s*$/;
|
|
2602
|
+
var PLAYER_SETTING_RE = /^(\w+)(?:\s*[:=]\s*|\s+)?(.*)$/;
|
|
2603
|
+
var PLAYER_FLAT_KEY_SET = new Set(PLAYER_FLAT_KEYS);
|
|
2604
|
+
function mirrorLegacySceneMeta(meta) {
|
|
2605
|
+
const player = meta.player;
|
|
2606
|
+
if (!player) return meta;
|
|
2607
|
+
const { playback, controls, interaction, chrome } = player;
|
|
2608
|
+
if (playback?.autoplay !== void 0) meta.autoplay = playback.autoplay;
|
|
2609
|
+
if (playback?.loop !== void 0) meta.loop = playback.loop;
|
|
2610
|
+
if (playback?.rate !== void 0) meta.playbackRate = playback.rate;
|
|
2611
|
+
if (controls) meta.controls = Object.values(controls).some(Boolean);
|
|
2612
|
+
if (interaction) {
|
|
2613
|
+
meta.interactiveViewport = Boolean(interaction.zoom ?? true) || Boolean(interaction.pan ?? true);
|
|
2614
|
+
}
|
|
2615
|
+
if (chrome?.badge !== void 0) meta.copyright = chrome.badge;
|
|
2616
|
+
if (chrome?.progress === "none") meta.progressColor = "none";
|
|
2617
|
+
else if (chrome?.progressColor !== void 0) meta.progressColor = chrome.progressColor;
|
|
2618
|
+
return meta;
|
|
2366
2619
|
}
|
|
2367
|
-
var TOP_LEVEL_KEYWORDS_RE = /^(scene|layout|pattern|group|annotation|edge|beat|var|style|controls|interactive|interactiveViewport|interactive_viewport|autoplay|loop|copyright|playbackRate|playback_rate|speed|progressColor|progressBarColor|progress_color|progress_bar_color|progress|progressBar)\b/;
|
|
2368
2620
|
function isTopLevelStatement(line) {
|
|
2369
2621
|
if (line === "}") return true;
|
|
2370
2622
|
if (TOP_LEVEL_KEYWORDS_RE.test(line)) return true;
|
|
@@ -2617,6 +2869,35 @@ function parse(source, opts = {}) {
|
|
|
2617
2869
|
const lineNo = block.line;
|
|
2618
2870
|
const unsupportedMessage = unsupportedSyntaxMessage(line);
|
|
2619
2871
|
if (unsupportedMessage) throw new ParseError(unsupportedMessage, lineNo);
|
|
2872
|
+
if (/^player\s*:\s*$/.test(line)) {
|
|
2873
|
+
const { body, nextIdx } = readIndentedBody(blocks, i + 1, block.indent);
|
|
2874
|
+
if (body.length === 0) throw new ParseError("player block requires at least one setting", lineNo);
|
|
2875
|
+
const player = meta.player ??= {};
|
|
2876
|
+
const applySetting = (scope, setting) => {
|
|
2877
|
+
const match = setting.text.match(PLAYER_SETTING_RE);
|
|
2878
|
+
const error = applyPlayerSetting(player, scope, match?.[1] ?? "", match?.[2] ?? "");
|
|
2879
|
+
if (error) diagnostics.push({ severity: "warning", message: error, line: setting.line });
|
|
2880
|
+
};
|
|
2881
|
+
let settingIdx = 0;
|
|
2882
|
+
while (settingIdx < body.length) {
|
|
2883
|
+
const setting = body[settingIdx];
|
|
2884
|
+
const groupMatch = setting.text.match(PLAYER_GROUP_RE);
|
|
2885
|
+
if (groupMatch) {
|
|
2886
|
+
const scope = groupMatch[1];
|
|
2887
|
+
const { body: childBody, nextIdx: childNextIdx } = readIndentedBody(body, settingIdx + 1, setting.indent);
|
|
2888
|
+
if (childBody.length === 0) {
|
|
2889
|
+
throw new ParseError(`player ${scope} block requires at least one setting`, setting.line);
|
|
2890
|
+
}
|
|
2891
|
+
for (const child of childBody) applySetting(scope, child);
|
|
2892
|
+
settingIdx = childNextIdx;
|
|
2893
|
+
continue;
|
|
2894
|
+
}
|
|
2895
|
+
applySetting("player", setting);
|
|
2896
|
+
settingIdx++;
|
|
2897
|
+
}
|
|
2898
|
+
i = nextIdx;
|
|
2899
|
+
continue;
|
|
2900
|
+
}
|
|
2620
2901
|
if (line.startsWith("scene")) {
|
|
2621
2902
|
const rest2 = line.slice(5).trim();
|
|
2622
2903
|
if (line.endsWith("{")) {
|
|
@@ -2643,28 +2924,9 @@ function parse(source, opts = {}) {
|
|
|
2643
2924
|
else if (k === "duration") meta.duration = Number(v);
|
|
2644
2925
|
else if (k === "theme") meta.theme = String(v);
|
|
2645
2926
|
else if (k === "direction" || k === "layout") meta.direction = String(v).toUpperCase();
|
|
2646
|
-
else if (k
|
|
2647
|
-
meta.
|
|
2648
|
-
|
|
2649
|
-
const bool = parseBooleanToken(v);
|
|
2650
|
-
if (bool !== void 0) {
|
|
2651
|
-
if (!bool) meta.progressColor = "none";
|
|
2652
|
-
} else {
|
|
2653
|
-
meta.progressColor = String(v);
|
|
2654
|
-
}
|
|
2655
|
-
} else if (k === "controls") {
|
|
2656
|
-
meta.controls = parseBooleanToken(v) ?? true;
|
|
2657
|
-
} else if (k === "interactive" || k === "interactiveViewport" || k === "interactive_viewport") {
|
|
2658
|
-
meta.interactiveViewport = parseBooleanToken(v) ?? true;
|
|
2659
|
-
} else if (k === "autoplay") {
|
|
2660
|
-
meta.autoplay = parseBooleanToken(v) ?? true;
|
|
2661
|
-
} else if (k === "loop") {
|
|
2662
|
-
meta.loop = parseBooleanToken(v) ?? true;
|
|
2663
|
-
} else if (k === "copyright") {
|
|
2664
|
-
meta.copyright = parseBooleanToken(v) ?? true;
|
|
2665
|
-
} else if (k === "playbackRate" || k === "playback_rate" || k === "speed") {
|
|
2666
|
-
const r = Number(v);
|
|
2667
|
-
if (!Number.isNaN(r) && r > 0) meta.playbackRate = r;
|
|
2927
|
+
else if (PLAYER_FLAT_KEY_SET.has(k)) {
|
|
2928
|
+
const error = applyPlayerSetting(meta.player ??= {}, "player", k, String(v));
|
|
2929
|
+
if (error) diagnostics.push({ severity: "warning", message: error, line: lineNo });
|
|
2668
2930
|
} else if (k === "type") {
|
|
2669
2931
|
const t = String(v).toLowerCase();
|
|
2670
2932
|
if (!DIAGRAM_TYPES.has(t)) {
|
|
@@ -2677,33 +2939,10 @@ function parse(source, opts = {}) {
|
|
|
2677
2939
|
i++;
|
|
2678
2940
|
continue;
|
|
2679
2941
|
}
|
|
2680
|
-
const directiveMatch = line.match(
|
|
2681
|
-
/^(controls|interactive|interactiveViewport|interactive_viewport|autoplay|loop|copyright|playbackRate|playback_rate|speed|progressColor|progressBarColor|progress_color|progress_bar_color|progress|progressBar)\b(?:\s*[:=]?\s*(.+))?$/
|
|
2682
|
-
);
|
|
2942
|
+
const directiveMatch = line.match(PLAYER_DIRECTIVE_RE);
|
|
2683
2943
|
if (directiveMatch) {
|
|
2684
|
-
const
|
|
2685
|
-
|
|
2686
|
-
const val = rawVal.startsWith('"') && rawVal.endsWith('"') || rawVal.startsWith("'") && rawVal.endsWith("'") ? rawVal.slice(1, -1) : rawVal;
|
|
2687
|
-
if (keyword === "controls") {
|
|
2688
|
-
meta.controls = val ? parseBooleanToken(val) ?? true : true;
|
|
2689
|
-
} else if (keyword === "interactive" || keyword === "interactiveViewport" || keyword === "interactive_viewport") {
|
|
2690
|
-
meta.interactiveViewport = val ? parseBooleanToken(val) ?? true : true;
|
|
2691
|
-
} else if (keyword === "autoplay") {
|
|
2692
|
-
meta.autoplay = val ? parseBooleanToken(val) ?? true : true;
|
|
2693
|
-
} else if (keyword === "loop") {
|
|
2694
|
-
meta.loop = val ? parseBooleanToken(val) ?? true : true;
|
|
2695
|
-
} else if (keyword === "copyright") {
|
|
2696
|
-
meta.copyright = val ? parseBooleanToken(val) ?? true : true;
|
|
2697
|
-
} else if (keyword === "playbackRate" || keyword === "playback_rate" || keyword === "speed") {
|
|
2698
|
-
const r = Number(val);
|
|
2699
|
-
if (!Number.isNaN(r) && r > 0) meta.playbackRate = r;
|
|
2700
|
-
} else if (keyword === "progressColor" || keyword === "progressBarColor" || keyword === "progress_color" || keyword === "progress_bar_color" || keyword === "progress") {
|
|
2701
|
-
if (val) meta.progressColor = val;
|
|
2702
|
-
} else if (keyword === "progressBar") {
|
|
2703
|
-
const bool = parseBooleanToken(val);
|
|
2704
|
-
if (bool === false) meta.progressColor = "none";
|
|
2705
|
-
else if (val) meta.progressColor = val;
|
|
2706
|
-
}
|
|
2944
|
+
const error = applyPlayerSetting(meta.player ??= {}, "player", directiveMatch[1], directiveMatch[2] ?? "");
|
|
2945
|
+
if (error) diagnostics.push({ severity: "warning", message: error, line: lineNo });
|
|
2707
2946
|
i++;
|
|
2708
2947
|
continue;
|
|
2709
2948
|
}
|
|
@@ -2859,7 +3098,7 @@ function parse(source, opts = {}) {
|
|
|
2859
3098
|
throw new ParseError(`unexpected statement`, lineNo);
|
|
2860
3099
|
}
|
|
2861
3100
|
const ast = {
|
|
2862
|
-
meta: { ...meta, title: title || void 0 },
|
|
3101
|
+
meta: { ...mirrorLegacySceneMeta(meta), title: title || void 0 },
|
|
2863
3102
|
styles,
|
|
2864
3103
|
nodes,
|
|
2865
3104
|
edges,
|
|
@@ -3579,7 +3818,7 @@ function diffDiagramASTs(beforeAST, afterAST) {
|
|
|
3579
3818
|
summaryLines.push("");
|
|
3580
3819
|
}
|
|
3581
3820
|
const evolutionLines = [
|
|
3582
|
-
`scene
|
|
3821
|
+
`scene theme=${afterAST.meta.theme || "paper"}`,
|
|
3583
3822
|
`layout ${afterAST.meta.direction || "LR"}`,
|
|
3584
3823
|
""
|
|
3585
3824
|
];
|
|
@@ -3947,6 +4186,8 @@ export {
|
|
|
3947
4186
|
NODE_ALIASES,
|
|
3948
4187
|
NODE_KINDS,
|
|
3949
4188
|
OUTPUT_PRESETS,
|
|
4189
|
+
PLAYER_FLAT_KEYS,
|
|
4190
|
+
PLAYER_GROUPS,
|
|
3950
4191
|
ParseError,
|
|
3951
4192
|
SCENE_KEYS,
|
|
3952
4193
|
TECHNICAL_NODE_KINDS,
|
|
@@ -3954,6 +4195,7 @@ export {
|
|
|
3954
4195
|
THEMES,
|
|
3955
4196
|
VISUAL_PRIMITIVE_TYPES,
|
|
3956
4197
|
analyzeAndBuildRepairPrompt,
|
|
4198
|
+
applyPlayerSetting,
|
|
3957
4199
|
canonicalNodeKind,
|
|
3958
4200
|
classifyTechnology,
|
|
3959
4201
|
compile,
|
|
@@ -3970,6 +4212,7 @@ export {
|
|
|
3970
4212
|
parseAndCompile,
|
|
3971
4213
|
resolveArchitectureConfig,
|
|
3972
4214
|
resolveOutputPreset,
|
|
4215
|
+
resolvePlayer,
|
|
3973
4216
|
resolveTheme,
|
|
3974
4217
|
routeOrthogonalEdge,
|
|
3975
4218
|
selectOptimalPorts,
|
package/package.json
CHANGED