@markdy/renderer-dom 0.7.27 → 0.7.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +522 -432
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -37,6 +37,9 @@ function toEasing(val) {
|
|
|
37
37
|
return "linear";
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
+
// src/actors.ts
|
|
41
|
+
import { TECHNICAL_NODE_KINDS, VISUAL_PRIMITIVE_TYPES } from "@markdy/core";
|
|
42
|
+
|
|
40
43
|
// src/figure.ts
|
|
41
44
|
function createFigureEl(def) {
|
|
42
45
|
const skinColor = def.args[0] || "#ffdbac";
|
|
@@ -309,30 +312,20 @@ function readRotation(el) {
|
|
|
309
312
|
}
|
|
310
313
|
|
|
311
314
|
// src/actors.ts
|
|
312
|
-
var ARCHITECTURE_NODE_TYPES =
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
"user",
|
|
318
|
-
"db",
|
|
319
|
-
"database",
|
|
320
|
-
"queue",
|
|
321
|
-
"cache",
|
|
322
|
-
"cloud",
|
|
323
|
-
"region",
|
|
324
|
-
"container",
|
|
325
|
-
"cluster"
|
|
315
|
+
var ARCHITECTURE_NODE_TYPES = new Set(Object.keys(TECHNICAL_NODE_KINDS));
|
|
316
|
+
var LEGACY_VISUAL_PRIMITIVE_TYPES = ["parking_map", "ascii_map", "game_scene", "byte_viz"];
|
|
317
|
+
var VISUAL_PRIMITIVE_TYPE_SET = /* @__PURE__ */ new Set([
|
|
318
|
+
...VISUAL_PRIMITIVE_TYPES,
|
|
319
|
+
...LEGACY_VISUAL_PRIMITIVE_TYPES
|
|
326
320
|
]);
|
|
327
|
-
var SHOWCASE_SURFACE_TYPES = /* @__PURE__ */ new Set(["parking_map", "ascii_map", "game_scene", "byte_viz"]);
|
|
328
321
|
var ARCHITECTURE_STYLE_ID = "markdy-architecture-node-styles";
|
|
329
|
-
var
|
|
330
|
-
function
|
|
331
|
-
if (doc.getElementById(
|
|
322
|
+
var VISUAL_PRIMITIVE_STYLE_ID = "markdy-visual-primitive-styles";
|
|
323
|
+
function ensureVisualPrimitiveStyles(doc) {
|
|
324
|
+
if (doc.getElementById(VISUAL_PRIMITIVE_STYLE_ID)) return;
|
|
332
325
|
const style = doc.createElement("style");
|
|
333
|
-
style.id =
|
|
326
|
+
style.id = VISUAL_PRIMITIVE_STYLE_ID;
|
|
334
327
|
style.textContent = `
|
|
335
|
-
.markdy-
|
|
328
|
+
.markdy-visual {
|
|
336
329
|
--surface-a: rgba(15, 23, 42, 0.9);
|
|
337
330
|
--accent: #38bdf8;
|
|
338
331
|
--accent-2: #22c55e;
|
|
@@ -354,12 +347,17 @@ function ensureShowcaseStyles(doc) {
|
|
|
354
347
|
0 1px 0 rgba(255, 255, 255, 0.18) inset,
|
|
355
348
|
0 0 44px color-mix(in srgb, var(--accent) 24%, transparent);
|
|
356
349
|
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
350
|
+
line-height: 1.2;
|
|
357
351
|
isolation: isolate;
|
|
358
352
|
contain: layout paint style;
|
|
359
353
|
backdrop-filter: blur(16px) saturate(1.2);
|
|
360
354
|
-webkit-backdrop-filter: blur(16px) saturate(1.2);
|
|
361
355
|
}
|
|
362
|
-
.markdy-
|
|
356
|
+
.markdy-visual,
|
|
357
|
+
.markdy-visual * {
|
|
358
|
+
box-sizing: border-box;
|
|
359
|
+
}
|
|
360
|
+
.markdy-visual::before {
|
|
363
361
|
content: "";
|
|
364
362
|
position: absolute;
|
|
365
363
|
inset: 0;
|
|
@@ -371,7 +369,7 @@ function ensureShowcaseStyles(doc) {
|
|
|
371
369
|
opacity: 0.48;
|
|
372
370
|
animation: markdyGridDrift 7s linear infinite;
|
|
373
371
|
}
|
|
374
|
-
.markdy-
|
|
372
|
+
.markdy-visual::after {
|
|
375
373
|
content: "";
|
|
376
374
|
position: absolute;
|
|
377
375
|
inset: -40% -20%;
|
|
@@ -380,15 +378,18 @@ function ensureShowcaseStyles(doc) {
|
|
|
380
378
|
opacity: 0.6;
|
|
381
379
|
animation: markdyAurora 9s linear infinite;
|
|
382
380
|
}
|
|
383
|
-
.markdy-
|
|
384
|
-
.markdy-
|
|
381
|
+
.markdy-visual[data-tone="green"] { --accent: #22c55e; --accent-2: #38bdf8; }
|
|
382
|
+
.markdy-visual[data-tone="amber"] { --accent: #f59e0b; --accent-2: #22c55e; }
|
|
383
|
+
.markdy-visual[data-tone="purple"] { --accent: #a78bfa; --accent-2: #38bdf8; }
|
|
384
|
+
.markdy-visual[data-tone="rose"] { --accent: #fb7185; --accent-2: #f59e0b; }
|
|
385
|
+
.markdy-visual__top {
|
|
385
386
|
display: flex;
|
|
386
387
|
align-items: center;
|
|
387
388
|
justify-content: space-between;
|
|
388
389
|
gap: 12px;
|
|
389
390
|
padding: 14px 16px 8px;
|
|
390
391
|
}
|
|
391
|
-
.markdy-
|
|
392
|
+
.markdy-visual__title {
|
|
392
393
|
min-width: 0;
|
|
393
394
|
overflow: hidden;
|
|
394
395
|
text-overflow: ellipsis;
|
|
@@ -398,7 +399,7 @@ function ensureShowcaseStyles(doc) {
|
|
|
398
399
|
letter-spacing: 0.01em;
|
|
399
400
|
color: #f8fafc;
|
|
400
401
|
}
|
|
401
|
-
.markdy-
|
|
402
|
+
.markdy-visual__pill {
|
|
402
403
|
flex: 0 0 auto;
|
|
403
404
|
border: 1px solid color-mix(in srgb, var(--accent) 42%, transparent);
|
|
404
405
|
border-radius: 999px;
|
|
@@ -411,127 +412,95 @@ function ensureShowcaseStyles(doc) {
|
|
|
411
412
|
text-transform: uppercase;
|
|
412
413
|
box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 22%, transparent);
|
|
413
414
|
}
|
|
414
|
-
.markdy-
|
|
415
|
-
.markdy-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
415
|
+
.markdy-visual__body { position: absolute; inset: 48px 14px 14px; }
|
|
416
|
+
.markdy-visual--metric {
|
|
417
|
+
width: 112px;
|
|
418
|
+
height: 44px;
|
|
419
|
+
border-radius: 14px;
|
|
420
|
+
}
|
|
421
|
+
.markdy-visual--grid {
|
|
422
|
+
width: 190px;
|
|
423
|
+
height: 92px;
|
|
424
|
+
border-radius: 18px;
|
|
425
|
+
}
|
|
426
|
+
.markdy-visual--lane {
|
|
427
|
+
width: 300px;
|
|
428
|
+
height: 44px;
|
|
422
429
|
border-radius: 999px;
|
|
423
|
-
background:
|
|
424
|
-
repeating-linear-gradient(90deg, rgba(226, 232, 240, 0.78) 0 18px, transparent 18px 34px) center / 100% 3px no-repeat,
|
|
425
|
-
linear-gradient(90deg, rgba(15, 23, 42, 0.96), rgba(30, 41, 59, 0.88));
|
|
426
|
-
box-shadow: 0 10px 28px rgba(2, 6, 23, 0.28) inset;
|
|
427
430
|
}
|
|
428
|
-
.
|
|
431
|
+
.markdy-visual--marker {
|
|
432
|
+
width: 50px;
|
|
433
|
+
height: 24px;
|
|
434
|
+
border-radius: 999px;
|
|
435
|
+
}
|
|
436
|
+
.markdy-visual--token_strip {
|
|
437
|
+
width: 300px;
|
|
438
|
+
height: 54px;
|
|
439
|
+
border-radius: 16px;
|
|
440
|
+
}
|
|
441
|
+
.markdy-visual--glyph_card {
|
|
442
|
+
width: 98px;
|
|
443
|
+
height: 120px;
|
|
444
|
+
border-radius: 22px;
|
|
445
|
+
}
|
|
446
|
+
.visual-panel__scan {
|
|
429
447
|
position: absolute;
|
|
430
|
-
left:
|
|
431
|
-
top:
|
|
432
|
-
width:
|
|
433
|
-
height:
|
|
434
|
-
border-radius:
|
|
435
|
-
border: 1px solid
|
|
436
|
-
background: linear-gradient(180deg,
|
|
437
|
-
box-shadow: 0 0 24px
|
|
448
|
+
left: 18px;
|
|
449
|
+
top: 18px;
|
|
450
|
+
width: 92px;
|
|
451
|
+
height: 122px;
|
|
452
|
+
border-radius: 24px;
|
|
453
|
+
border: 1px solid color-mix(in srgb, var(--accent) 54%, transparent);
|
|
454
|
+
background: linear-gradient(180deg, color-mix(in srgb, var(--accent) 22%, transparent), transparent);
|
|
455
|
+
box-shadow: 0 0 24px color-mix(in srgb, var(--accent) 28%, transparent);
|
|
438
456
|
animation: markdyScanPulse 1.8s ease-in-out infinite;
|
|
439
457
|
}
|
|
440
|
-
.
|
|
458
|
+
.visual-panel__rails {
|
|
441
459
|
position: absolute;
|
|
442
|
-
left:
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
height:
|
|
446
|
-
border-radius:
|
|
447
|
-
background:
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
.
|
|
453
|
-
content: "";
|
|
460
|
+
left: 18px;
|
|
461
|
+
right: 18px;
|
|
462
|
+
bottom: 42px;
|
|
463
|
+
height: 48px;
|
|
464
|
+
border-radius: 999px;
|
|
465
|
+
background:
|
|
466
|
+
repeating-linear-gradient(90deg, rgba(226, 232, 240, 0.74) 0 18px, transparent 18px 34px) center / 100% 3px no-repeat,
|
|
467
|
+
linear-gradient(90deg, rgba(15, 23, 42, 0.96), rgba(30, 41, 59, 0.88));
|
|
468
|
+
box-shadow: 0 10px 28px rgba(2, 6, 23, 0.28) inset;
|
|
469
|
+
}
|
|
470
|
+
.visual-panel__pulse {
|
|
454
471
|
position: absolute;
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
472
|
+
left: 110px;
|
|
473
|
+
right: 78px;
|
|
474
|
+
bottom: 64px;
|
|
475
|
+
height: 3px;
|
|
458
476
|
border-radius: 999px;
|
|
459
|
-
background:
|
|
460
|
-
|
|
477
|
+
background: linear-gradient(90deg, transparent, var(--accent-2), var(--accent), transparent);
|
|
478
|
+
filter: drop-shadow(0 0 8px var(--accent-2));
|
|
479
|
+
animation: markdyRouteFlow 1.5s linear infinite;
|
|
461
480
|
}
|
|
462
|
-
.
|
|
463
|
-
.parking-map__car::after { right: 7px; }
|
|
464
|
-
.parking-map__slots {
|
|
481
|
+
.visual-panel__cells {
|
|
465
482
|
position: absolute;
|
|
466
|
-
right:
|
|
467
|
-
top:
|
|
483
|
+
right: 18px;
|
|
484
|
+
top: 22px;
|
|
468
485
|
display: grid;
|
|
469
|
-
grid-template-columns: repeat(4,
|
|
470
|
-
gap:
|
|
486
|
+
grid-template-columns: repeat(4, 42px);
|
|
487
|
+
gap: 7px;
|
|
471
488
|
}
|
|
472
|
-
.
|
|
473
|
-
height:
|
|
489
|
+
.visual-panel__cell {
|
|
490
|
+
height: 30px;
|
|
474
491
|
border-radius: 10px;
|
|
475
492
|
border: 1px solid rgba(148, 163, 184, 0.34);
|
|
476
493
|
background: rgba(15, 23, 42, 0.7);
|
|
477
494
|
box-shadow: 0 0 0 1px rgba(255,255,255,0.035) inset;
|
|
478
495
|
}
|
|
479
|
-
.
|
|
480
|
-
.
|
|
481
|
-
.
|
|
482
|
-
border-color:
|
|
483
|
-
background: rgba(
|
|
496
|
+
.visual-panel__cell:nth-child(3),
|
|
497
|
+
.visual-panel__cell:nth-child(6),
|
|
498
|
+
.visual-panel__cell:nth-child(8) {
|
|
499
|
+
border-color: color-mix(in srgb, var(--accent-2) 78%, transparent);
|
|
500
|
+
background: color-mix(in srgb, var(--accent-2) 35%, rgba(15, 23, 42, 0.7));
|
|
484
501
|
animation: markdySlotGlow 1.7s ease-in-out infinite;
|
|
485
502
|
}
|
|
486
|
-
.
|
|
487
|
-
position: absolute;
|
|
488
|
-
left: 91px;
|
|
489
|
-
right: 95px;
|
|
490
|
-
top: 109px;
|
|
491
|
-
height: 3px;
|
|
492
|
-
border-radius: 999px;
|
|
493
|
-
background: linear-gradient(90deg, transparent, #22c55e, #38bdf8, transparent);
|
|
494
|
-
filter: drop-shadow(0 0 8px #22c55e);
|
|
495
|
-
animation: markdyRouteFlow 1.5s linear infinite;
|
|
496
|
-
}
|
|
497
|
-
.parking-map__stats {
|
|
498
|
-
position: absolute;
|
|
499
|
-
left: 12px;
|
|
500
|
-
right: 12px;
|
|
501
|
-
bottom: 5px;
|
|
502
|
-
display: grid;
|
|
503
|
-
grid-template-columns: repeat(3, 1fr);
|
|
504
|
-
gap: 8px;
|
|
505
|
-
}
|
|
506
|
-
.parking-map__stat,
|
|
507
|
-
.ascii-map__badge,
|
|
508
|
-
.game-scene__hud,
|
|
509
|
-
.byte-viz__badge {
|
|
510
|
-
border: 1px solid rgba(148, 163, 184, 0.24);
|
|
511
|
-
border-radius: 12px;
|
|
512
|
-
padding: 8px;
|
|
513
|
-
background: rgba(2, 6, 23, 0.42);
|
|
514
|
-
color: #cbd5e1;
|
|
515
|
-
font-size: 10px;
|
|
516
|
-
font-weight: 760;
|
|
517
|
-
}
|
|
518
|
-
.parking-map__stat strong,
|
|
519
|
-
.byte-viz__badge strong {
|
|
520
|
-
display: block;
|
|
521
|
-
margin-top: 2px;
|
|
522
|
-
color: #f8fafc;
|
|
523
|
-
font-size: 16px;
|
|
524
|
-
}
|
|
525
|
-
.markdy-showcase--ascii_map { --accent: #22c55e; --accent-2: #38bdf8; }
|
|
526
|
-
.ascii-map__terminal {
|
|
527
|
-
position: absolute;
|
|
528
|
-
inset: 0;
|
|
529
|
-
border-radius: 18px;
|
|
530
|
-
border: 1px solid rgba(34, 197, 94, 0.34);
|
|
531
|
-
background: linear-gradient(180deg, rgba(2, 6, 23, 0.72), rgba(2, 6, 23, 0.36));
|
|
532
|
-
box-shadow: 0 0 28px rgba(34, 197, 94, 0.16) inset;
|
|
533
|
-
}
|
|
534
|
-
.ascii-map__chrome {
|
|
503
|
+
.visual-terminal__chrome {
|
|
535
504
|
height: 28px;
|
|
536
505
|
padding-left: 12px;
|
|
537
506
|
display: flex;
|
|
@@ -539,256 +508,276 @@ function ensureShowcaseStyles(doc) {
|
|
|
539
508
|
gap: 6px;
|
|
540
509
|
border-bottom: 1px solid rgba(148, 163, 184, 0.16);
|
|
541
510
|
}
|
|
542
|
-
.
|
|
511
|
+
.visual-terminal__chrome span {
|
|
543
512
|
width: 8px;
|
|
544
513
|
height: 8px;
|
|
545
514
|
border-radius: 999px;
|
|
546
515
|
background: #ef4444;
|
|
547
516
|
box-shadow: 14px 0 #f59e0b, 28px 0 #22c55e;
|
|
548
517
|
}
|
|
549
|
-
.
|
|
518
|
+
.visual-terminal__lines {
|
|
550
519
|
position: absolute;
|
|
551
520
|
left: 16px;
|
|
521
|
+
right: 16px;
|
|
552
522
|
top: 46px;
|
|
553
523
|
font-family: "SFMono-Regular", Consolas, monospace;
|
|
554
|
-
font-size:
|
|
524
|
+
font-size: 18px;
|
|
555
525
|
line-height: 1.55;
|
|
556
|
-
color: #
|
|
557
|
-
text-shadow: 0 0 12px
|
|
526
|
+
color: color-mix(in srgb, var(--accent-2) 62%, #f8fafc);
|
|
527
|
+
text-shadow: 0 0 12px color-mix(in srgb, var(--accent-2) 38%, transparent);
|
|
558
528
|
}
|
|
559
|
-
.
|
|
560
|
-
|
|
561
|
-
|
|
529
|
+
.visual-terminal__line {
|
|
530
|
+
overflow: hidden;
|
|
531
|
+
text-overflow: ellipsis;
|
|
532
|
+
white-space: nowrap;
|
|
562
533
|
}
|
|
563
|
-
.
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
534
|
+
.visual-metric {
|
|
535
|
+
height: 100%;
|
|
536
|
+
padding: 7px 9px;
|
|
537
|
+
display: flex;
|
|
538
|
+
align-items: center;
|
|
539
|
+
justify-content: center;
|
|
540
|
+
gap: 6px;
|
|
541
|
+
min-width: 0;
|
|
542
|
+
overflow: hidden;
|
|
543
|
+
white-space: nowrap;
|
|
572
544
|
}
|
|
573
|
-
.
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
545
|
+
.visual-metric strong {
|
|
546
|
+
flex: 0 0 auto;
|
|
547
|
+
color: #f8fafc;
|
|
548
|
+
font-size: 15px;
|
|
549
|
+
line-height: 1;
|
|
577
550
|
}
|
|
578
|
-
.
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
551
|
+
.visual-metric span {
|
|
552
|
+
min-width: 0;
|
|
553
|
+
overflow: hidden;
|
|
554
|
+
color: #94a3b8;
|
|
555
|
+
font-size: 8px;
|
|
556
|
+
font-weight: 840;
|
|
557
|
+
letter-spacing: 0.08em;
|
|
558
|
+
line-height: 1;
|
|
559
|
+
text-overflow: ellipsis;
|
|
560
|
+
text-transform: uppercase;
|
|
582
561
|
}
|
|
583
|
-
.
|
|
562
|
+
.visual-grid {
|
|
584
563
|
position: absolute;
|
|
585
|
-
|
|
586
|
-
right: 16px;
|
|
587
|
-
bottom: 10px;
|
|
564
|
+
inset: 10px;
|
|
588
565
|
display: grid;
|
|
589
|
-
|
|
590
|
-
gap: 8px;
|
|
566
|
+
gap: 7px;
|
|
591
567
|
}
|
|
592
|
-
.
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
border-radius: 18px;
|
|
597
|
-
overflow: hidden;
|
|
598
|
-
background:
|
|
599
|
-
radial-gradient(circle at 80% 18%, rgba(245, 158, 11, 0.22), transparent 26%),
|
|
600
|
-
linear-gradient(160deg, #172554, #020617 72%);
|
|
568
|
+
.visual-grid__cell {
|
|
569
|
+
border-radius: 8px;
|
|
570
|
+
border: 1px solid rgba(148, 163, 184, 0.3);
|
|
571
|
+
background: rgba(15, 23, 42, 0.74);
|
|
601
572
|
}
|
|
602
|
-
.
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
background: repeating-linear-gradient(115deg, transparent 0 22px, rgba(255,255,255,0.06) 22px 24px);
|
|
607
|
-
animation: markdyRoadMove 4s linear infinite;
|
|
573
|
+
.visual-grid__cell.is-active {
|
|
574
|
+
border-color: color-mix(in srgb, var(--accent-2) 78%, transparent);
|
|
575
|
+
background: color-mix(in srgb, var(--accent-2) 35%, rgba(15, 23, 42, 0.74));
|
|
576
|
+
box-shadow: 0 0 18px color-mix(in srgb, var(--accent-2) 26%, transparent);
|
|
608
577
|
}
|
|
609
|
-
.
|
|
578
|
+
.visual-lane {
|
|
610
579
|
position: absolute;
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
top: 94px;
|
|
614
|
-
height: 76px;
|
|
615
|
-
transform: rotate(-8deg);
|
|
580
|
+
inset: 0;
|
|
581
|
+
border-radius: inherit;
|
|
616
582
|
background:
|
|
617
|
-
repeating-linear-gradient(90deg,
|
|
618
|
-
linear-gradient(
|
|
619
|
-
box-shadow: 0
|
|
620
|
-
}
|
|
621
|
-
.game-scene__car {
|
|
622
|
-
position: absolute;
|
|
623
|
-
left: 88px;
|
|
624
|
-
top: 126px;
|
|
625
|
-
width: 58px;
|
|
626
|
-
height: 30px;
|
|
627
|
-
border-radius: 12px 18px 18px 12px;
|
|
628
|
-
background: linear-gradient(90deg, #fb7185, #f59e0b);
|
|
629
|
-
transform: rotate(-8deg);
|
|
630
|
-
box-shadow: 0 0 24px rgba(245, 158, 11, 0.52);
|
|
631
|
-
animation: markdyCarPark 3.4s cubic-bezier(.2,1,.3,1) infinite;
|
|
632
|
-
}
|
|
633
|
-
.game-scene__spot {
|
|
634
|
-
position: absolute;
|
|
635
|
-
right: 54px;
|
|
636
|
-
top: 85px;
|
|
637
|
-
width: 90px;
|
|
638
|
-
height: 68px;
|
|
639
|
-
border: 3px solid rgba(34, 197, 94, 0.78);
|
|
640
|
-
border-left-style: dashed;
|
|
641
|
-
border-radius: 10px;
|
|
642
|
-
filter: drop-shadow(0 0 12px rgba(34, 197, 94, 0.48));
|
|
583
|
+
repeating-linear-gradient(90deg, rgba(226, 232, 240, 0.76) 0 18px, transparent 18px 34px) center / 100% 3px no-repeat,
|
|
584
|
+
linear-gradient(90deg, rgba(15, 23, 42, 0.96), rgba(30, 41, 59, 0.88));
|
|
585
|
+
box-shadow: 0 10px 28px rgba(2, 6, 23, 0.28) inset, 0 0 18px color-mix(in srgb, var(--accent) 22%, transparent);
|
|
643
586
|
}
|
|
644
|
-
.
|
|
587
|
+
.visual-lane::after {
|
|
588
|
+
content: "";
|
|
645
589
|
position: absolute;
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
border-right: 10px solid transparent;
|
|
656
|
-
border-bottom: 26px solid #f97316;
|
|
657
|
-
filter: drop-shadow(0 5px 8px rgba(2, 6, 23, 0.35));
|
|
590
|
+
left: 18%;
|
|
591
|
+
right: 18%;
|
|
592
|
+
top: 50%;
|
|
593
|
+
height: 3px;
|
|
594
|
+
border-radius: 999px;
|
|
595
|
+
transform: translateY(-50%);
|
|
596
|
+
background: linear-gradient(90deg, transparent, var(--accent-2), var(--accent), transparent);
|
|
597
|
+
filter: drop-shadow(0 0 8px var(--accent-2));
|
|
598
|
+
animation: markdyRouteFlow 1.5s linear infinite;
|
|
658
599
|
}
|
|
659
|
-
.
|
|
600
|
+
.visual-marker {
|
|
660
601
|
position: absolute;
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
602
|
+
inset: 0;
|
|
603
|
+
border-radius: inherit;
|
|
604
|
+
background: linear-gradient(90deg, var(--accent), #818cf8);
|
|
605
|
+
box-shadow: 0 0 18px color-mix(in srgb, var(--accent) 55%, transparent), 0 8px 18px rgba(2, 6, 23, 0.35);
|
|
665
606
|
}
|
|
666
|
-
.
|
|
667
|
-
.
|
|
668
|
-
|
|
669
|
-
left: 132px;
|
|
670
|
-
top: 54px;
|
|
671
|
-
color: #fef3c7;
|
|
672
|
-
font-size: 21px;
|
|
673
|
-
font-weight: 900;
|
|
674
|
-
letter-spacing: 0.05em;
|
|
675
|
-
text-shadow: 0 0 18px rgba(245, 158, 11, 0.7);
|
|
676
|
-
animation: markdyPerfectPop 1.6s ease-in-out infinite;
|
|
677
|
-
}
|
|
678
|
-
.markdy-showcase--byte_viz { --accent: #a78bfa; --accent-2: #38bdf8; }
|
|
679
|
-
.byte-viz__pipeline {
|
|
607
|
+
.visual-marker::before,
|
|
608
|
+
.visual-marker::after {
|
|
609
|
+
content: "";
|
|
680
610
|
position: absolute;
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
611
|
+
bottom: -3px;
|
|
612
|
+
width: 8px;
|
|
613
|
+
height: 8px;
|
|
614
|
+
border-radius: 999px;
|
|
615
|
+
background: #020617;
|
|
616
|
+
border: 2px solid #cbd5e1;
|
|
686
617
|
}
|
|
687
|
-
.
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
background: radial-gradient(circle at 30% 20%, rgba(167, 139, 250, 0.42), rgba(15, 23, 42, 0.78));
|
|
693
|
-
color: #fff;
|
|
694
|
-
font-size: 72px;
|
|
695
|
-
font-weight: 920;
|
|
696
|
-
box-shadow: 0 0 34px rgba(167, 139, 250, 0.32) inset;
|
|
697
|
-
}
|
|
698
|
-
.byte-viz__middle { display: grid; gap: 10px; }
|
|
699
|
-
.byte-viz__row {
|
|
618
|
+
.visual-marker::before { left: 9px; }
|
|
619
|
+
.visual-marker::after { right: 9px; }
|
|
620
|
+
.visual-tokens {
|
|
621
|
+
height: 100%;
|
|
622
|
+
padding: 8px;
|
|
700
623
|
display: flex;
|
|
701
624
|
align-items: center;
|
|
702
625
|
gap: 7px;
|
|
703
626
|
}
|
|
704
|
-
.
|
|
627
|
+
.visual-token {
|
|
705
628
|
flex: 1 1 0;
|
|
629
|
+
min-width: 0;
|
|
706
630
|
border: 1px solid rgba(148, 163, 184, 0.25);
|
|
707
631
|
border-radius: 12px;
|
|
708
632
|
padding: 8px 10px;
|
|
709
633
|
background: rgba(2, 6, 23, 0.42);
|
|
710
|
-
color: #
|
|
634
|
+
color: color-mix(in srgb, var(--accent) 45%, #f8fafc);
|
|
711
635
|
font-family: "SFMono-Regular", Consolas, monospace;
|
|
712
636
|
font-size: 12px;
|
|
713
637
|
font-weight: 800;
|
|
638
|
+
overflow: hidden;
|
|
639
|
+
text-overflow: ellipsis;
|
|
640
|
+
white-space: nowrap;
|
|
714
641
|
}
|
|
715
|
-
.
|
|
716
|
-
|
|
717
|
-
filter: drop-shadow(0 0 8px #38bdf8);
|
|
718
|
-
animation: markdyArrowPulse 1.1s ease-in-out infinite;
|
|
719
|
-
}
|
|
720
|
-
.byte-viz__bits {
|
|
721
|
-
display: grid;
|
|
722
|
-
grid-template-columns: repeat(8, 1fr);
|
|
723
|
-
gap: 5px;
|
|
724
|
-
}
|
|
725
|
-
.byte-viz__bit {
|
|
642
|
+
.visual-glyph {
|
|
643
|
+
height: 100%;
|
|
726
644
|
display: grid;
|
|
727
645
|
place-items: center;
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
color: #
|
|
733
|
-
font-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
646
|
+
padding: 10px;
|
|
647
|
+
text-align: center;
|
|
648
|
+
}
|
|
649
|
+
.visual-glyph strong {
|
|
650
|
+
color: #f8fafc;
|
|
651
|
+
font-size: 56px;
|
|
652
|
+
line-height: 1;
|
|
653
|
+
}
|
|
654
|
+
.visual-glyph span {
|
|
655
|
+
margin-top: 6px;
|
|
656
|
+
color: #cbd5e1;
|
|
657
|
+
font-size: 10px;
|
|
658
|
+
font-weight: 800;
|
|
659
|
+
letter-spacing: 0.08em;
|
|
660
|
+
text-transform: uppercase;
|
|
737
661
|
}
|
|
738
|
-
.byte-viz__bit:nth-child(2n) { animation-delay: 0.12s; }
|
|
739
|
-
.byte-viz__bit:nth-child(3n) { animation-delay: 0.24s; }
|
|
740
|
-
.byte-viz__side { display: grid; gap: 9px; }
|
|
741
662
|
@keyframes markdyGridDrift { to { background-position: 34px 34px, 34px 34px; } }
|
|
742
663
|
@keyframes markdyAurora { to { transform: rotate(1turn); } }
|
|
743
664
|
@keyframes markdyScanPulse { 50% { transform: translateX(18px); opacity: 0.72; } }
|
|
744
|
-
@keyframes
|
|
745
|
-
@keyframes
|
|
746
|
-
@keyframes markdyRouteFlow { to { filter: hue-rotate(70deg) drop-shadow(0 0 9px #38bdf8); } }
|
|
747
|
-
@keyframes markdyBlink { 50% { opacity: 0.25; } }
|
|
748
|
-
@keyframes markdyRoadMove { to { background-position: 44px 0; } }
|
|
749
|
-
@keyframes markdyCarPark { 0%, 12% { transform: translateX(0) rotate(-8deg); } 70%, 100% { transform: translateX(164px) translateY(-31px) rotate(-1deg); } }
|
|
750
|
-
@keyframes markdyPerfectPop { 0%, 100% { transform: scale(0.92); opacity: 0.72; } 50% { transform: scale(1.05); opacity: 1; } }
|
|
751
|
-
@keyframes markdyArrowPulse { 50% { transform: translateX(3px); opacity: 0.72; } }
|
|
752
|
-
@keyframes markdyBitFlip { 50% { transform: translateY(-2px); border-color: rgba(167, 139, 250, 0.75); } }
|
|
665
|
+
@keyframes markdySlotGlow { 50% { box-shadow: 0 0 20px color-mix(in srgb, var(--accent-2) 32%, transparent); } }
|
|
666
|
+
@keyframes markdyRouteFlow { to { filter: hue-rotate(70deg) drop-shadow(0 0 9px var(--accent)); } }
|
|
753
667
|
`;
|
|
754
668
|
doc.head.appendChild(style);
|
|
755
669
|
}
|
|
756
|
-
function
|
|
757
|
-
|
|
758
|
-
|
|
670
|
+
function escapeHtml(value) {
|
|
671
|
+
return value.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">").replaceAll('"', """).replaceAll("'", "'");
|
|
672
|
+
}
|
|
673
|
+
function toneArg(def, index, fallback = "cyan") {
|
|
674
|
+
const tone = def.args[index]?.trim().toLowerCase() || fallback;
|
|
675
|
+
return /^(cyan|green|amber|purple|rose)$/.test(tone) ? tone : fallback;
|
|
676
|
+
}
|
|
677
|
+
function parseGridSpec(spec) {
|
|
678
|
+
const match = /^(\d+)x(\d+)$/i.exec(spec?.trim() ?? "");
|
|
679
|
+
const cols = match ? Number(match[1]) : 4;
|
|
680
|
+
const rows = match ? Number(match[2]) : 2;
|
|
681
|
+
return {
|
|
682
|
+
cols: Math.min(Math.max(cols, 1), 8),
|
|
683
|
+
rows: Math.min(Math.max(rows, 1), 4)
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
function activeCellSet(value) {
|
|
687
|
+
return new Set(
|
|
688
|
+
(value ?? "").split(/[|\s]+/).map((part) => Number(part.trim())).filter((part) => Number.isInteger(part) && part > 0)
|
|
689
|
+
);
|
|
690
|
+
}
|
|
691
|
+
function canonicalVisualType(type) {
|
|
692
|
+
switch (type) {
|
|
693
|
+
case "surface":
|
|
694
|
+
return "panel";
|
|
695
|
+
case "stat":
|
|
696
|
+
return "metric";
|
|
697
|
+
case "matrix":
|
|
698
|
+
return "grid";
|
|
699
|
+
case "track":
|
|
700
|
+
return "lane";
|
|
701
|
+
case "dot":
|
|
702
|
+
return "marker";
|
|
703
|
+
case "chips":
|
|
704
|
+
return "token_strip";
|
|
705
|
+
case "glyph":
|
|
706
|
+
return "glyph_card";
|
|
707
|
+
case "parking_map":
|
|
708
|
+
case "game_scene":
|
|
709
|
+
case "byte_viz":
|
|
710
|
+
return "panel";
|
|
711
|
+
case "ascii_map":
|
|
712
|
+
return "terminal";
|
|
713
|
+
default:
|
|
714
|
+
return type;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
function legacyVisualArgs(type, args) {
|
|
718
|
+
const label = args[0] || type.replace("_", " ");
|
|
719
|
+
switch (type) {
|
|
720
|
+
case "parking_map":
|
|
721
|
+
return [label, "live ops", "cyan"];
|
|
722
|
+
case "ascii_map":
|
|
723
|
+
return [label, "[P1][P2][ ][EV]", "[IN]===LANE===[OUT]", "0101 0000 0100 0001", "green"];
|
|
724
|
+
case "game_scene":
|
|
725
|
+
return [label, "60 fps", "amber"];
|
|
726
|
+
case "byte_viz":
|
|
727
|
+
return [label, "UTF-8", "purple"];
|
|
728
|
+
default:
|
|
729
|
+
return args;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
function createVisualPrimitiveEl(type, def) {
|
|
733
|
+
ensureVisualPrimitiveStyles(document);
|
|
734
|
+
const visualType = canonicalVisualType(type);
|
|
735
|
+
const args = legacyVisualArgs(type, def.args);
|
|
736
|
+
const label = args[0] || type.replace("_", " ");
|
|
759
737
|
const root = document.createElement("div");
|
|
760
|
-
root.className = `markdy-
|
|
738
|
+
root.className = `markdy-visual markdy-visual--${visualType}`;
|
|
739
|
+
root.dataset.visualType = visualType;
|
|
761
740
|
root.setAttribute("role", "img");
|
|
762
741
|
root.setAttribute("aria-label", label);
|
|
763
|
-
if (
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
<div class="markdy-showcase__body">
|
|
767
|
-
<div class="parking-map__scan"></div><div class="parking-map__road"></div><div class="parking-map__route"></div><div class="parking-map__car"></div>
|
|
768
|
-
<div class="parking-map__slots"><span class="parking-map__slot"></span><span class="parking-map__slot"></span><span class="parking-map__slot"></span><span class="parking-map__slot"></span><span class="parking-map__slot"></span><span class="parking-map__slot"></span><span class="parking-map__slot"></span><span class="parking-map__slot"></span></div>
|
|
769
|
-
<div class="parking-map__stats"><div class="parking-map__stat">occupancy<strong>87%</strong></div><div class="parking-map__stat">OCR<strong>18ms</strong></div><div class="parking-map__stat">route<strong>A-17</strong></div></div>
|
|
770
|
-
</div>`;
|
|
771
|
-
} else if (type === "ascii_map") {
|
|
742
|
+
if (visualType === "panel") {
|
|
743
|
+
const tag = escapeHtml(args[1] || "live");
|
|
744
|
+
root.dataset.tone = toneArg({ ...def, args }, 2);
|
|
772
745
|
root.innerHTML = `
|
|
773
|
-
<div class="markdy-
|
|
774
|
-
<div class="markdy-
|
|
775
|
-
<div class="
|
|
746
|
+
<div class="markdy-visual__top"><div class="markdy-visual__title">${escapeHtml(label)}</div><div class="markdy-visual__pill">${tag}</div></div>
|
|
747
|
+
<div class="markdy-visual__body">
|
|
748
|
+
<div class="visual-panel__scan"></div>
|
|
749
|
+
<div class="visual-panel__cells">${Array.from({ length: 8 }, () => '<span class="visual-panel__cell"></span>').join("")}</div>
|
|
750
|
+
<div class="visual-panel__rails"></div>
|
|
751
|
+
<div class="visual-panel__pulse"></div>
|
|
776
752
|
</div>`;
|
|
777
|
-
} else if (
|
|
753
|
+
} else if (visualType === "terminal") {
|
|
754
|
+
root.dataset.tone = toneArg({ ...def, args }, 4, "green");
|
|
755
|
+
const lines = [args[1], args[2], args[3]].filter((line) => typeof line === "string" && line.length > 0).map((line) => `<div class="visual-terminal__line">${escapeHtml(line)}</div>`).join("");
|
|
778
756
|
root.innerHTML = `
|
|
779
|
-
<div class="markdy-
|
|
780
|
-
<div class="markdy-
|
|
781
|
-
|
|
782
|
-
|
|
757
|
+
<div class="markdy-visual__top"><div class="markdy-visual__title">${escapeHtml(label)}</div><div class="markdy-visual__pill">terminal</div></div>
|
|
758
|
+
<div class="markdy-visual__body"><div class="visual-terminal__chrome"><span></span></div><div class="visual-terminal__lines">${lines}</div></div>`;
|
|
759
|
+
} else if (visualType === "metric") {
|
|
760
|
+
root.dataset.tone = toneArg({ ...def, args }, 2);
|
|
761
|
+
root.innerHTML = `<div class="visual-metric"><strong>${escapeHtml(args[1] || "\u2014")}</strong><span>${escapeHtml(label)}</span></div>`;
|
|
762
|
+
} else if (visualType === "grid") {
|
|
763
|
+
root.dataset.tone = toneArg({ ...def, args }, 3, "green");
|
|
764
|
+
const { cols, rows } = parseGridSpec(args[1]);
|
|
765
|
+
const active = activeCellSet(args[2]);
|
|
766
|
+
root.innerHTML = `<div class="visual-grid" style="grid-template-columns: repeat(${cols}, 1fr);">${Array.from({ length: cols * rows }, (_, i) => `<span class="visual-grid__cell${active.has(i + 1) ? " is-active" : ""}"></span>`).join("")}</div>`;
|
|
767
|
+
} else if (visualType === "lane") {
|
|
768
|
+
root.dataset.tone = toneArg({ ...def, args }, 1);
|
|
769
|
+
root.innerHTML = `<div class="visual-lane"></div>`;
|
|
770
|
+
} else if (visualType === "marker") {
|
|
771
|
+
root.dataset.tone = toneArg({ ...def, args }, 1);
|
|
772
|
+
root.innerHTML = `<div class="visual-marker"></div>`;
|
|
773
|
+
} else if (visualType === "token_strip") {
|
|
774
|
+
root.dataset.tone = toneArg({ ...def, args }, 1, "purple");
|
|
775
|
+
const tokens = (args[0] || "token").split("|").map((token) => token.trim()).filter(Boolean);
|
|
776
|
+
root.innerHTML = `<div class="visual-tokens">${tokens.map((token) => `<span class="visual-token">${escapeHtml(token)}</span>`).join("")}</div>`;
|
|
783
777
|
} else {
|
|
784
|
-
root.
|
|
785
|
-
|
|
786
|
-
<div class="markdy-showcase__body">
|
|
787
|
-
<div class="byte-viz__pipeline"><div class="byte-viz__glyph">A</div><div class="byte-viz__middle"><div class="byte-viz__row"><div class="byte-viz__chip">char</div><span class="byte-viz__arrow">-></span><div class="byte-viz__chip">U+0041</div></div><div class="byte-viz__row"><div class="byte-viz__chip">0x41</div><span class="byte-viz__arrow">-></span><div class="byte-viz__chip">01000001</div></div><div class="byte-viz__bits"><span class="byte-viz__bit">0</span><span class="byte-viz__bit">1</span><span class="byte-viz__bit">0</span><span class="byte-viz__bit">0</span><span class="byte-viz__bit">0</span><span class="byte-viz__bit">0</span><span class="byte-viz__bit">0</span><span class="byte-viz__bit">1</span></div></div><div class="byte-viz__side"><div class="byte-viz__badge">bytes<strong>1</strong></div><div class="byte-viz__badge">planes<strong>BMP</strong></div><div class="byte-viz__badge">glyph<strong>paint</strong></div></div></div>
|
|
788
|
-
</div>`;
|
|
778
|
+
root.dataset.tone = toneArg({ ...def, args }, 2, "purple");
|
|
779
|
+
root.innerHTML = `<div class="visual-glyph"><div><strong>${escapeHtml(args[0] || "A")}</strong><span>${escapeHtml(args[1] || "glyph")}</span></div></div>`;
|
|
789
780
|
}
|
|
790
|
-
const title = root.querySelector(".markdy-showcase__title");
|
|
791
|
-
if (title) title.textContent = label;
|
|
792
781
|
return root;
|
|
793
782
|
}
|
|
794
783
|
function ensureArchitectureStyles(doc) {
|
|
@@ -892,59 +881,75 @@ function ensureArchitectureStyles(doc) {
|
|
|
892
881
|
color: color-mix(in srgb, var(--markdy-node-accent) 70%, #e2e8f0);
|
|
893
882
|
opacity: 0.86;
|
|
894
883
|
}
|
|
895
|
-
.markdy-arch-node[data-markdy-system-
|
|
896
|
-
.markdy-arch-node[data-markdy-system-
|
|
897
|
-
.markdy-arch-node[data-markdy-system-type="microservice"] {
|
|
884
|
+
.markdy-arch-node[data-markdy-system-kind="compute"],
|
|
885
|
+
.markdy-arch-node[data-markdy-system-kind="code"] {
|
|
898
886
|
--markdy-node-accent: #38bdf8;
|
|
899
887
|
--markdy-node-accent-2: #818cf8;
|
|
900
888
|
}
|
|
901
|
-
.markdy-arch-node[data-markdy-system-
|
|
902
|
-
.markdy-arch-node[data-markdy-system-type="user"] {
|
|
889
|
+
.markdy-arch-node[data-markdy-system-kind="client"] {
|
|
903
890
|
--markdy-node-accent: #f59e0b;
|
|
904
891
|
--markdy-node-accent-2: #fb7185;
|
|
905
892
|
}
|
|
906
|
-
.markdy-arch-node[data-markdy-system-
|
|
907
|
-
.markdy-arch-node[data-markdy-system-type="db"] {
|
|
893
|
+
.markdy-arch-node[data-markdy-system-kind="data"] {
|
|
908
894
|
--markdy-node-accent: #22c55e;
|
|
909
895
|
--markdy-node-accent-2: #14b8a6;
|
|
910
|
-
border-radius: 18px 18px 24px 24px;
|
|
911
896
|
}
|
|
912
|
-
.markdy-arch-node[data-markdy-system-
|
|
913
|
-
--markdy-node-accent: #a3e635;
|
|
914
|
-
--markdy-node-accent-2: #22c55e;
|
|
915
|
-
border-style: dashed;
|
|
916
|
-
}
|
|
917
|
-
.markdy-arch-node[data-markdy-system-type="queue"] {
|
|
897
|
+
.markdy-arch-node[data-markdy-system-kind="messaging"] {
|
|
918
898
|
--markdy-node-accent: #a78bfa;
|
|
919
899
|
--markdy-node-accent-2: #38bdf8;
|
|
920
900
|
}
|
|
921
|
-
.markdy-arch-node[data-markdy-system-
|
|
922
|
-
.markdy-arch-node[data-markdy-system-type="region"] {
|
|
901
|
+
.markdy-arch-node[data-markdy-system-kind="network"] {
|
|
923
902
|
--markdy-node-accent: #60a5fa;
|
|
924
903
|
--markdy-node-accent-2: #67e8f9;
|
|
925
|
-
border-radius: 999px;
|
|
926
904
|
}
|
|
927
|
-
.markdy-arch-node[data-markdy-system-
|
|
928
|
-
.markdy-arch-node[data-markdy-system-type="cluster"] {
|
|
905
|
+
.markdy-arch-node[data-markdy-system-kind="platform"] {
|
|
929
906
|
--markdy-node-accent: #c084fc;
|
|
930
907
|
--markdy-node-accent-2: #f472b6;
|
|
908
|
+
}
|
|
909
|
+
.markdy-arch-node[data-markdy-system-kind="security"] {
|
|
910
|
+
--markdy-node-accent: #fb7185;
|
|
911
|
+
--markdy-node-accent-2: #f59e0b;
|
|
912
|
+
}
|
|
913
|
+
.markdy-arch-node[data-markdy-system-kind="delivery"] {
|
|
914
|
+
--markdy-node-accent: #facc15;
|
|
915
|
+
--markdy-node-accent-2: #22c55e;
|
|
916
|
+
}
|
|
917
|
+
.markdy-arch-node[data-markdy-system-kind="observability"] {
|
|
918
|
+
--markdy-node-accent: #2dd4bf;
|
|
919
|
+
--markdy-node-accent-2: #38bdf8;
|
|
920
|
+
}
|
|
921
|
+
.markdy-arch-node[data-markdy-system-kind="flow"] {
|
|
922
|
+
--markdy-node-accent: #e879f9;
|
|
923
|
+
--markdy-node-accent-2: #a78bfa;
|
|
924
|
+
}
|
|
925
|
+
.markdy-arch-node[data-markdy-system-kind="distributed"] {
|
|
926
|
+
--markdy-node-accent: #94a3b8;
|
|
927
|
+
--markdy-node-accent-2: #38bdf8;
|
|
928
|
+
}
|
|
929
|
+
.markdy-arch-node[data-markdy-system-kind="data"] {
|
|
930
|
+
border-radius: 18px 18px 24px 24px;
|
|
931
|
+
}
|
|
932
|
+
.markdy-arch-node[data-markdy-system-kind="network"] {
|
|
933
|
+
border-radius: 999px;
|
|
934
|
+
}
|
|
935
|
+
.markdy-arch-node[data-markdy-system-kind="platform"] {
|
|
931
936
|
border-radius: 10px;
|
|
932
937
|
}
|
|
933
|
-
.markdy-arch-node[data-markdy-system-
|
|
934
|
-
|
|
935
|
-
|
|
938
|
+
.markdy-arch-node[data-markdy-system-kind="security"] {
|
|
939
|
+
border-style: solid;
|
|
940
|
+
}
|
|
941
|
+
.markdy-arch-node[data-markdy-system-kind="compute"] .markdy-arch-node__icon::before,
|
|
942
|
+
.markdy-arch-node[data-markdy-system-kind="code"] .markdy-arch-node__icon::before {
|
|
936
943
|
inset: 9px 7px;
|
|
937
944
|
border-top: 3px solid rgba(255, 255, 255, 0.92);
|
|
938
945
|
border-bottom: 3px solid rgba(255, 255, 255, 0.92);
|
|
939
946
|
}
|
|
940
|
-
.markdy-arch-node[data-markdy-system-
|
|
941
|
-
.markdy-arch-node[data-markdy-system-
|
|
942
|
-
.markdy-arch-node[data-markdy-system-type="microservice"] .markdy-arch-node__icon::after {
|
|
947
|
+
.markdy-arch-node[data-markdy-system-kind="compute"] .markdy-arch-node__icon::after,
|
|
948
|
+
.markdy-arch-node[data-markdy-system-kind="code"] .markdy-arch-node__icon::after {
|
|
943
949
|
inset: 14px 7px auto;
|
|
944
950
|
border-top: 3px solid rgba(255, 255, 255, 0.92);
|
|
945
951
|
}
|
|
946
|
-
.markdy-arch-node[data-markdy-system-
|
|
947
|
-
.markdy-arch-node[data-markdy-system-type="user"] .markdy-arch-node__icon::before {
|
|
952
|
+
.markdy-arch-node[data-markdy-system-kind="client"] .markdy-arch-node__icon::before {
|
|
948
953
|
left: 8px;
|
|
949
954
|
right: 8px;
|
|
950
955
|
top: 8px;
|
|
@@ -952,34 +957,29 @@ function ensureArchitectureStyles(doc) {
|
|
|
952
957
|
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
953
958
|
border-radius: 3px;
|
|
954
959
|
}
|
|
955
|
-
.markdy-arch-node[data-markdy-system-
|
|
956
|
-
.markdy-arch-node[data-markdy-system-type="user"] .markdy-arch-node__icon::after {
|
|
960
|
+
.markdy-arch-node[data-markdy-system-kind="client"] .markdy-arch-node__icon::after {
|
|
957
961
|
left: 12px;
|
|
958
962
|
right: 12px;
|
|
959
963
|
bottom: 7px;
|
|
960
964
|
border-top: 2px solid rgba(255, 255, 255, 0.92);
|
|
961
965
|
}
|
|
962
|
-
.markdy-arch-node[data-markdy-system-
|
|
963
|
-
.markdy-arch-node[data-markdy-system-type="db"] .markdy-arch-node__icon::before,
|
|
964
|
-
.markdy-arch-node[data-markdy-system-type="cache"] .markdy-arch-node__icon::before {
|
|
966
|
+
.markdy-arch-node[data-markdy-system-kind="data"] .markdy-arch-node__icon::before {
|
|
965
967
|
inset: 7px 7px 9px;
|
|
966
968
|
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
967
969
|
border-radius: 50% / 16%;
|
|
968
970
|
}
|
|
969
|
-
.markdy-arch-node[data-markdy-system-
|
|
970
|
-
.markdy-arch-node[data-markdy-system-type="db"] .markdy-arch-node__icon::after,
|
|
971
|
-
.markdy-arch-node[data-markdy-system-type="cache"] .markdy-arch-node__icon::after {
|
|
971
|
+
.markdy-arch-node[data-markdy-system-kind="data"] .markdy-arch-node__icon::after {
|
|
972
972
|
left: 8px;
|
|
973
973
|
right: 8px;
|
|
974
974
|
top: 12px;
|
|
975
975
|
border-top: 2px solid rgba(255, 255, 255, 0.72);
|
|
976
976
|
}
|
|
977
|
-
.markdy-arch-node[data-markdy-system-
|
|
977
|
+
.markdy-arch-node[data-markdy-system-kind="messaging"] .markdy-arch-node__icon::before {
|
|
978
978
|
inset: 9px 8px;
|
|
979
979
|
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
980
980
|
border-radius: 999px;
|
|
981
981
|
}
|
|
982
|
-
.markdy-arch-node[data-markdy-system-
|
|
982
|
+
.markdy-arch-node[data-markdy-system-kind="messaging"] .markdy-arch-node__icon::after {
|
|
983
983
|
left: 13px;
|
|
984
984
|
top: 9px;
|
|
985
985
|
width: 8px;
|
|
@@ -987,8 +987,7 @@ function ensureArchitectureStyles(doc) {
|
|
|
987
987
|
border-left: 2px solid rgba(255, 255, 255, 0.82);
|
|
988
988
|
border-right: 2px solid rgba(255, 255, 255, 0.82);
|
|
989
989
|
}
|
|
990
|
-
.markdy-arch-node[data-markdy-system-
|
|
991
|
-
.markdy-arch-node[data-markdy-system-type="region"] .markdy-arch-node__icon::before {
|
|
990
|
+
.markdy-arch-node[data-markdy-system-kind="network"] .markdy-arch-node__icon::before {
|
|
992
991
|
left: 7px;
|
|
993
992
|
right: 7px;
|
|
994
993
|
bottom: 9px;
|
|
@@ -996,8 +995,7 @@ function ensureArchitectureStyles(doc) {
|
|
|
996
995
|
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
997
996
|
border-radius: 999px;
|
|
998
997
|
}
|
|
999
|
-
.markdy-arch-node[data-markdy-system-
|
|
1000
|
-
.markdy-arch-node[data-markdy-system-type="region"] .markdy-arch-node__icon::after {
|
|
998
|
+
.markdy-arch-node[data-markdy-system-kind="network"] .markdy-arch-node__icon::after {
|
|
1001
999
|
left: 10px;
|
|
1002
1000
|
top: 7px;
|
|
1003
1001
|
width: 13px;
|
|
@@ -1006,33 +1004,74 @@ function ensureArchitectureStyles(doc) {
|
|
|
1006
1004
|
border-left: 2px solid rgba(255, 255, 255, 0.92);
|
|
1007
1005
|
border-radius: 999px 0 0 0;
|
|
1008
1006
|
}
|
|
1009
|
-
.markdy-arch-node[data-markdy-system-
|
|
1010
|
-
.markdy-arch-node[data-markdy-system-type="cluster"] .markdy-arch-node__icon::before {
|
|
1007
|
+
.markdy-arch-node[data-markdy-system-kind="platform"] .markdy-arch-node__icon::before {
|
|
1011
1008
|
inset: 8px;
|
|
1012
1009
|
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
1013
1010
|
border-radius: 4px;
|
|
1014
1011
|
}
|
|
1015
|
-
.markdy-arch-node[data-markdy-system-
|
|
1016
|
-
.markdy-arch-node[data-markdy-system-type="cluster"] .markdy-arch-node__icon::after {
|
|
1012
|
+
.markdy-arch-node[data-markdy-system-kind="platform"] .markdy-arch-node__icon::after {
|
|
1017
1013
|
left: 10px;
|
|
1018
1014
|
right: 10px;
|
|
1019
1015
|
top: 14px;
|
|
1020
1016
|
border-top: 2px solid rgba(255, 255, 255, 0.72);
|
|
1021
1017
|
}
|
|
1018
|
+
.markdy-arch-node[data-markdy-system-kind="security"] .markdy-arch-node__icon::before {
|
|
1019
|
+
left: 9px;
|
|
1020
|
+
right: 9px;
|
|
1021
|
+
top: 7px;
|
|
1022
|
+
bottom: 7px;
|
|
1023
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
1024
|
+
border-radius: 10px 10px 14px 14px;
|
|
1025
|
+
}
|
|
1026
|
+
.markdy-arch-node[data-markdy-system-kind="security"] .markdy-arch-node__icon::after {
|
|
1027
|
+
left: 14px;
|
|
1028
|
+
right: 14px;
|
|
1029
|
+
top: 14px;
|
|
1030
|
+
border-top: 2px solid rgba(255, 255, 255, 0.82);
|
|
1031
|
+
}
|
|
1032
|
+
.markdy-arch-node[data-markdy-system-kind="delivery"] .markdy-arch-node__icon::before,
|
|
1033
|
+
.markdy-arch-node[data-markdy-system-kind="observability"] .markdy-arch-node__icon::before,
|
|
1034
|
+
.markdy-arch-node[data-markdy-system-kind="distributed"] .markdy-arch-node__icon::before {
|
|
1035
|
+
inset: 8px;
|
|
1036
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
1037
|
+
border-radius: 999px;
|
|
1038
|
+
}
|
|
1039
|
+
.markdy-arch-node[data-markdy-system-kind="delivery"] .markdy-arch-node__icon::after,
|
|
1040
|
+
.markdy-arch-node[data-markdy-system-kind="observability"] .markdy-arch-node__icon::after,
|
|
1041
|
+
.markdy-arch-node[data-markdy-system-kind="distributed"] .markdy-arch-node__icon::after {
|
|
1042
|
+
left: 15px;
|
|
1043
|
+
top: 7px;
|
|
1044
|
+
bottom: 7px;
|
|
1045
|
+
border-left: 2px solid rgba(255, 255, 255, 0.82);
|
|
1046
|
+
}
|
|
1047
|
+
.markdy-arch-node[data-markdy-system-kind="flow"] .markdy-arch-node__icon::before {
|
|
1048
|
+
inset: 8px;
|
|
1049
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
1050
|
+
transform: rotate(45deg);
|
|
1051
|
+
}
|
|
1052
|
+
.markdy-arch-node[data-markdy-system-kind="flow"] .markdy-arch-node__icon::after {
|
|
1053
|
+
left: 14px;
|
|
1054
|
+
right: 14px;
|
|
1055
|
+
top: 15px;
|
|
1056
|
+
border-top: 2px solid rgba(255, 255, 255, 0.82);
|
|
1057
|
+
}
|
|
1022
1058
|
`;
|
|
1023
1059
|
doc.head.appendChild(style);
|
|
1024
1060
|
}
|
|
1025
1061
|
function isArchitectureNodeType(type) {
|
|
1026
1062
|
return ARCHITECTURE_NODE_TYPES.has(type);
|
|
1027
1063
|
}
|
|
1028
|
-
function
|
|
1029
|
-
return
|
|
1064
|
+
function isVisualPrimitiveType(type) {
|
|
1065
|
+
return VISUAL_PRIMITIVE_TYPE_SET.has(type);
|
|
1030
1066
|
}
|
|
1031
1067
|
function architectureTypeLabel(type) {
|
|
1032
1068
|
if (type === "db") return "database";
|
|
1033
1069
|
if (type === "api") return "service";
|
|
1034
1070
|
return type;
|
|
1035
1071
|
}
|
|
1072
|
+
function architectureNodeKind(type) {
|
|
1073
|
+
return TECHNICAL_NODE_KINDS[type] ?? "compute";
|
|
1074
|
+
}
|
|
1036
1075
|
function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
1037
1076
|
let el;
|
|
1038
1077
|
switch (def.type) {
|
|
@@ -1101,30 +1140,25 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
1101
1140
|
el = createFigureEl(def);
|
|
1102
1141
|
break;
|
|
1103
1142
|
}
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
case "queue":
|
|
1119
|
-
case "cache":
|
|
1120
|
-
case "cloud":
|
|
1121
|
-
case "region":
|
|
1122
|
-
case "container":
|
|
1123
|
-
case "cluster": {
|
|
1143
|
+
default: {
|
|
1144
|
+
if (VISUAL_PRIMITIVE_TYPE_SET.has(def.type)) {
|
|
1145
|
+
el = createVisualPrimitiveEl(def.type, def);
|
|
1146
|
+
break;
|
|
1147
|
+
}
|
|
1148
|
+
if (!isArchitectureNodeType(def.type)) {
|
|
1149
|
+
const div = document.createElement("div");
|
|
1150
|
+
div.style.width = "100px";
|
|
1151
|
+
div.style.height = "100px";
|
|
1152
|
+
div.style.background = "#999";
|
|
1153
|
+
div.style.boxSizing = "border-box";
|
|
1154
|
+
el = div;
|
|
1155
|
+
break;
|
|
1156
|
+
}
|
|
1124
1157
|
ensureArchitectureStyles(document);
|
|
1125
1158
|
const card = document.createElement("div");
|
|
1126
1159
|
card.className = "markdy-arch-node";
|
|
1127
1160
|
card.dataset.markdySystemType = def.type;
|
|
1161
|
+
card.dataset.markdySystemKind = architectureNodeKind(def.type);
|
|
1128
1162
|
card.setAttribute("role", "img");
|
|
1129
1163
|
card.setAttribute("aria-label", `${architectureTypeLabel(def.type)} ${def.args[0] ?? name}`);
|
|
1130
1164
|
const icon = document.createElement("span");
|
|
@@ -1143,15 +1177,6 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
1143
1177
|
el = card;
|
|
1144
1178
|
break;
|
|
1145
1179
|
}
|
|
1146
|
-
default: {
|
|
1147
|
-
const div = document.createElement("div");
|
|
1148
|
-
div.style.width = "100px";
|
|
1149
|
-
div.style.height = "100px";
|
|
1150
|
-
div.style.background = "#999";
|
|
1151
|
-
div.style.boxSizing = "border-box";
|
|
1152
|
-
el = div;
|
|
1153
|
-
break;
|
|
1154
|
-
}
|
|
1155
1180
|
}
|
|
1156
1181
|
el.dataset.markdyActor = name;
|
|
1157
1182
|
el.style.position = "absolute";
|
|
@@ -1162,7 +1187,7 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
1162
1187
|
el.style.opacity = String(def.opacity ?? 1);
|
|
1163
1188
|
if (def.z !== void 0) el.style.zIndex = String(def.z);
|
|
1164
1189
|
else if (def.type === "caption") el.style.zIndex = "100";
|
|
1165
|
-
else if (
|
|
1190
|
+
else if (isVisualPrimitiveType(def.type)) el.style.zIndex = "25";
|
|
1166
1191
|
else if (isArchitectureNodeType(def.type)) el.style.zIndex = "10";
|
|
1167
1192
|
return el;
|
|
1168
1193
|
}
|
|
@@ -1620,27 +1645,32 @@ var parallax = ({ ev, el, state, baseOpts, anims, tx: tx2 }) => {
|
|
|
1620
1645
|
};
|
|
1621
1646
|
|
|
1622
1647
|
// src/geometry/rect.ts
|
|
1648
|
+
import { TECHNICAL_NODE_TYPES } from "@markdy/core";
|
|
1649
|
+
var SYSTEM_NODE_SIZE = { width: 184, height: 88 };
|
|
1623
1650
|
var ACTOR_SIZES = {
|
|
1624
|
-
|
|
1625
|
-
api: { width: 184, height: 88 },
|
|
1626
|
-
microservice: { width: 184, height: 88 },
|
|
1627
|
-
client: { width: 184, height: 88 },
|
|
1628
|
-
user: { width: 184, height: 88 },
|
|
1629
|
-
db: { width: 184, height: 88 },
|
|
1630
|
-
database: { width: 184, height: 88 },
|
|
1631
|
-
queue: { width: 184, height: 88 },
|
|
1632
|
-
cache: { width: 184, height: 88 },
|
|
1633
|
-
cloud: { width: 184, height: 88 },
|
|
1634
|
-
region: { width: 184, height: 88 },
|
|
1635
|
-
container: { width: 184, height: 88 },
|
|
1636
|
-
cluster: { width: 184, height: 88 },
|
|
1651
|
+
...Object.fromEntries(TECHNICAL_NODE_TYPES.map((type) => [type, SYSTEM_NODE_SIZE])),
|
|
1637
1652
|
box: { width: 100, height: 100 },
|
|
1638
1653
|
caption: { width: 260, height: 56 },
|
|
1639
1654
|
figure: { width: 120, height: 170 },
|
|
1655
|
+
panel: { width: 390, height: 250 },
|
|
1656
|
+
surface: { width: 390, height: 250 },
|
|
1657
|
+
terminal: { width: 390, height: 250 },
|
|
1658
|
+
metric: { width: 112, height: 44 },
|
|
1659
|
+
stat: { width: 112, height: 44 },
|
|
1660
|
+
grid: { width: 190, height: 92 },
|
|
1661
|
+
matrix: { width: 190, height: 92 },
|
|
1662
|
+
lane: { width: 300, height: 44 },
|
|
1663
|
+
track: { width: 300, height: 44 },
|
|
1664
|
+
marker: { width: 50, height: 24 },
|
|
1665
|
+
dot: { width: 50, height: 24 },
|
|
1666
|
+
token_strip: { width: 300, height: 54 },
|
|
1667
|
+
chips: { width: 300, height: 54 },
|
|
1668
|
+
glyph_card: { width: 98, height: 120 },
|
|
1669
|
+
glyph: { width: 98, height: 120 },
|
|
1640
1670
|
parking_map: { width: 390, height: 250 },
|
|
1641
1671
|
ascii_map: { width: 390, height: 250 },
|
|
1642
1672
|
game_scene: { width: 390, height: 250 },
|
|
1643
|
-
byte_viz: { width:
|
|
1673
|
+
byte_viz: { width: 390, height: 250 }
|
|
1644
1674
|
};
|
|
1645
1675
|
var DEFAULT_ACTOR_SIZE = { width: 140, height: 42 };
|
|
1646
1676
|
function actorSizeByType(type) {
|
|
@@ -1718,25 +1748,59 @@ function polylineLength(points) {
|
|
|
1718
1748
|
function segmentLength(a, b) {
|
|
1719
1749
|
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
1720
1750
|
}
|
|
1721
|
-
function
|
|
1722
|
-
|
|
1751
|
+
function rectsOverlap(a, b) {
|
|
1752
|
+
return a.x1 < b.x2 && a.x2 > b.x1 && a.y1 < b.y2 && a.y2 > b.y1;
|
|
1753
|
+
}
|
|
1754
|
+
function overlapCount(rect, obstacles) {
|
|
1755
|
+
let hits = 0;
|
|
1756
|
+
for (const o of obstacles) if (rectsOverlap(rect, o)) hits++;
|
|
1757
|
+
return hits;
|
|
1758
|
+
}
|
|
1759
|
+
var LABEL_BOX_HEIGHT = 18;
|
|
1760
|
+
function placeFlowLabel(points, textWidth, obstacles, ast) {
|
|
1723
1761
|
let bestIndex = 0;
|
|
1724
1762
|
let bestLength = -1;
|
|
1725
1763
|
for (let i = 0; i < points.length - 1; i++) {
|
|
1726
1764
|
const len = segmentLength(points[i], points[i + 1]);
|
|
1727
1765
|
if (len > bestLength) {
|
|
1728
|
-
bestIndex = i;
|
|
1729
1766
|
bestLength = len;
|
|
1767
|
+
bestIndex = i;
|
|
1730
1768
|
}
|
|
1731
1769
|
}
|
|
1732
|
-
const a = points[bestIndex];
|
|
1733
|
-
const b = points[bestIndex + 1];
|
|
1770
|
+
const a = points[bestIndex] ?? { x: 0, y: 0 };
|
|
1771
|
+
const b = points[bestIndex + 1] ?? a;
|
|
1734
1772
|
const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
1735
|
-
const
|
|
1736
|
-
|
|
1737
|
-
|
|
1773
|
+
const horizontal = Math.abs(a.x - b.x) >= Math.abs(a.y - b.y);
|
|
1774
|
+
const half = textWidth / 2;
|
|
1775
|
+
const halfH = LABEL_BOX_HEIGHT / 2;
|
|
1776
|
+
const pad = 8;
|
|
1777
|
+
const base = horizontal ? 15 : half + 12;
|
|
1778
|
+
const step = horizontal ? LABEL_BOX_HEIGHT + 3 : textWidth + 12;
|
|
1779
|
+
const order = horizontal ? [-1, 1] : [1, -1];
|
|
1780
|
+
const offsets = [];
|
|
1781
|
+
for (let k = 0; k < 7; k++) {
|
|
1782
|
+
for (const sign of order) offsets.push(sign * (base + k * step));
|
|
1783
|
+
}
|
|
1784
|
+
let fallback = null;
|
|
1785
|
+
let fallbackHits = Number.POSITIVE_INFINITY;
|
|
1786
|
+
for (const off of offsets) {
|
|
1787
|
+
let cx = horizontal ? mid.x : mid.x + off;
|
|
1788
|
+
let cy = horizontal ? mid.y + off : mid.y;
|
|
1789
|
+
cx = clamp(cx, pad + half, ast.meta.width - pad - half);
|
|
1790
|
+
cy = clamp(cy, pad + halfH, ast.meta.height - pad - halfH);
|
|
1791
|
+
const rect = { x1: cx - half, y1: cy - halfH, x2: cx + half, y2: cy + halfH };
|
|
1792
|
+
const hits = overlapCount(rect, obstacles);
|
|
1793
|
+
if (hits === 0) return { x: round1(cx), y: round1(cy), rect };
|
|
1794
|
+
if (hits < fallbackHits) {
|
|
1795
|
+
fallbackHits = hits;
|
|
1796
|
+
fallback = { x: round1(cx), y: round1(cy), rect };
|
|
1797
|
+
}
|
|
1738
1798
|
}
|
|
1739
|
-
return
|
|
1799
|
+
return fallback ?? {
|
|
1800
|
+
x: round1(mid.x),
|
|
1801
|
+
y: round1(mid.y),
|
|
1802
|
+
rect: { x1: mid.x - half, y1: mid.y - halfH, x2: mid.x + half, y2: mid.y + halfH }
|
|
1803
|
+
};
|
|
1740
1804
|
}
|
|
1741
1805
|
function clamp(n, min, max) {
|
|
1742
1806
|
if (max < min) return n;
|
|
@@ -1833,7 +1897,9 @@ var STROKE_BY_ACTION = {
|
|
|
1833
1897
|
};
|
|
1834
1898
|
var DEFAULT_STROKE = "#38bdf8";
|
|
1835
1899
|
var LABEL_MAX_CHARS = 28;
|
|
1836
|
-
var
|
|
1900
|
+
var LABEL_CHAR_PX = 6.8;
|
|
1901
|
+
var EDGE_REVEAL_MS = 220;
|
|
1902
|
+
var LABEL_RECTS = /* @__PURE__ */ new WeakMap();
|
|
1837
1903
|
function ensureEdgeLayer(scene) {
|
|
1838
1904
|
const existing = scene.querySelector(`svg[${EDGE_LAYER_ATTR}='1']`);
|
|
1839
1905
|
if (existing) return existing;
|
|
@@ -1890,6 +1956,12 @@ function isDashed(ctx) {
|
|
|
1890
1956
|
const style = String(ctx.ev.params.style ?? "");
|
|
1891
1957
|
return style === "dashed" || style === "fire_and_forget" || ctx.ev.action === "response";
|
|
1892
1958
|
}
|
|
1959
|
+
function nodeObstacleRect(state, type, sceneWidth) {
|
|
1960
|
+
const rect = actorRect(state, type);
|
|
1961
|
+
if (type !== "caption") return rect;
|
|
1962
|
+
const halfH = (rect.y2 - rect.y1) / 2 + 4;
|
|
1963
|
+
return { x1: 0, y1: state.y - halfH, x2: sceneWidth, y2: state.y + halfH };
|
|
1964
|
+
}
|
|
1893
1965
|
function buildEdge(ctx, targetName) {
|
|
1894
1966
|
const { ev, state, states, ast, scene, baseOpts, anims } = ctx;
|
|
1895
1967
|
const targetState = states.get(targetName);
|
|
@@ -1901,8 +1973,12 @@ function buildEdge(ctx, targetName) {
|
|
|
1901
1973
|
const stroke = STROKE_BY_ACTION[ev.action] ?? DEFAULT_STROKE;
|
|
1902
1974
|
const svg = ensureEdgeLayer(scene);
|
|
1903
1975
|
ensureEdgeDefs(svg);
|
|
1976
|
+
const startMs = Number(baseOpts.delay ?? 0);
|
|
1977
|
+
const durationMs = Math.max(1, Number(baseOpts.duration ?? 500));
|
|
1978
|
+
const revealMs = Math.min(EDGE_REVEAL_MS, durationMs);
|
|
1904
1979
|
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
1905
1980
|
group.setAttribute("data-markdy-flow-edge", "1");
|
|
1981
|
+
group.style.opacity = "0";
|
|
1906
1982
|
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
1907
1983
|
path.setAttribute("d", pathD);
|
|
1908
1984
|
path.setAttribute("fill", "none");
|
|
@@ -1926,37 +2002,51 @@ function buildEdge(ctx, targetName) {
|
|
|
1926
2002
|
group.appendChild(marker);
|
|
1927
2003
|
const labelText = String(ev.params.label ?? "");
|
|
1928
2004
|
if (labelText) {
|
|
1929
|
-
const
|
|
2005
|
+
const shown = labelText.length > LABEL_MAX_CHARS ? `${labelText.slice(0, LABEL_MAX_CHARS - 1)}\u2026` : labelText;
|
|
2006
|
+
const textWidth = shown.length * LABEL_CHAR_PX + 12;
|
|
2007
|
+
const placed = LABEL_RECTS.get(svg) ?? (LABEL_RECTS.set(svg, []), LABEL_RECTS.get(svg));
|
|
2008
|
+
const obstacles = [...placed];
|
|
2009
|
+
for (const [name, nodeState] of states.entries()) {
|
|
2010
|
+
const type = ast.actors[name]?.type ?? "box";
|
|
2011
|
+
obstacles.push(inflateRect(nodeObstacleRect(nodeState, type, ast.meta.width), 2));
|
|
2012
|
+
}
|
|
2013
|
+
const spot = placeFlowLabel(points, textWidth, obstacles, ast);
|
|
2014
|
+
placed.push(spot.rect);
|
|
1930
2015
|
const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
1931
|
-
label.setAttribute("x", `${
|
|
1932
|
-
label.setAttribute("y", `${
|
|
2016
|
+
label.setAttribute("x", `${spot.x}`);
|
|
2017
|
+
label.setAttribute("y", `${spot.y}`);
|
|
1933
2018
|
label.setAttribute("text-anchor", "middle");
|
|
2019
|
+
label.setAttribute("dominant-baseline", "middle");
|
|
1934
2020
|
label.setAttribute("font-size", "12");
|
|
1935
2021
|
label.setAttribute("font-weight", "700");
|
|
1936
2022
|
label.setAttribute("paint-order", "stroke");
|
|
1937
|
-
label.setAttribute("stroke", "rgba(2, 6, 23, 0.
|
|
2023
|
+
label.setAttribute("stroke", "rgba(2, 6, 23, 0.9)");
|
|
1938
2024
|
label.setAttribute("stroke-width", "5");
|
|
1939
2025
|
label.setAttribute("stroke-linejoin", "round");
|
|
1940
|
-
label.setAttribute("fill", "#
|
|
1941
|
-
label.setAttribute("filter", "url(#markdy-flow-glow)");
|
|
2026
|
+
label.setAttribute("fill", "#dbe4f0");
|
|
1942
2027
|
label.setAttribute("data-full-label", labelText);
|
|
1943
|
-
label.textContent =
|
|
2028
|
+
label.textContent = shown;
|
|
1944
2029
|
group.appendChild(label);
|
|
1945
2030
|
}
|
|
1946
2031
|
svg.appendChild(group);
|
|
1947
2032
|
anims.push(
|
|
1948
2033
|
path.animate([{ strokeDashoffset: length }, { strokeDashoffset: 0 }], baseOpts),
|
|
2034
|
+
// Travel the dot along the edge, then fade it at arrival so the finished
|
|
2035
|
+
// edge is a clean line + arrowhead rather than a dot resting on the tip.
|
|
1949
2036
|
marker.animate(
|
|
1950
2037
|
[
|
|
1951
|
-
{ offsetDistance: "0%", opacity: 1 },
|
|
1952
|
-
{ offsetDistance: "100%", opacity: 1 }
|
|
2038
|
+
{ offsetDistance: "0%", opacity: 1, offset: 0 },
|
|
2039
|
+
{ offsetDistance: "100%", opacity: 1, offset: 0.82 },
|
|
2040
|
+
{ offsetDistance: "100%", opacity: 0, offset: 1 }
|
|
1953
2041
|
],
|
|
1954
2042
|
baseOpts
|
|
1955
2043
|
),
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
2044
|
+
// Reveal the edge at its scheduled time and keep it (persist). `fill: both`
|
|
2045
|
+
// holds opacity 0 during the delay, so nothing appears before its turn.
|
|
2046
|
+
group.animate([{ opacity: 0 }, { opacity: 1 }], {
|
|
2047
|
+
delay: startMs,
|
|
2048
|
+
duration: revealMs,
|
|
2049
|
+
fill: "both"
|
|
1960
2050
|
})
|
|
1961
2051
|
);
|
|
1962
2052
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@markdy/renderer-dom",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.29",
|
|
4
4
|
"description": "Web Animations API renderer for MarkdyScript scenes.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -43,14 +43,14 @@
|
|
|
43
43
|
"access": "public"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@markdy/core": "0.7.
|
|
46
|
+
"@markdy/core": "0.7.29"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
49
|
"jsdom": "^29.1.1",
|
|
50
50
|
"tsup": "^8.5.1",
|
|
51
51
|
"typescript": "^5.9.3",
|
|
52
52
|
"vitest": "^4.1.7",
|
|
53
|
-
"@markdy/stdlib-systems": "0.7.
|
|
53
|
+
"@markdy/stdlib-systems": "0.7.29"
|
|
54
54
|
},
|
|
55
55
|
"scripts": {
|
|
56
56
|
"build": "tsup",
|