@markdy/renderer-dom 0.7.27 → 0.7.28

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.
Files changed (2) hide show
  1. package/dist/index.js +439 -409
  2. 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 = /* @__PURE__ */ new Set([
313
- "service",
314
- "api",
315
- "microservice",
316
- "client",
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 SHOWCASE_STYLE_ID = "markdy-showcase-surface-styles";
330
- function ensureShowcaseStyles(doc) {
331
- if (doc.getElementById(SHOWCASE_STYLE_ID)) return;
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 = SHOWCASE_STYLE_ID;
326
+ style.id = VISUAL_PRIMITIVE_STYLE_ID;
334
327
  style.textContent = `
335
- .markdy-showcase {
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-showcase::before {
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-showcase::after {
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-showcase--byte_viz { width: 420px; }
384
- .markdy-showcase__top {
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-showcase__title {
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-showcase__pill {
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-showcase__body { position: absolute; inset: 48px 14px 14px; }
415
- .markdy-showcase--parking_map { --accent: #38bdf8; --accent-2: #22c55e; }
416
- .parking-map__road {
417
- position: absolute;
418
- left: 14px;
419
- right: 14px;
420
- top: 78px;
421
- height: 50px;
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
- .parking-map__scan {
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: 28px;
431
- top: 42px;
432
- width: 66px;
433
- height: 124px;
434
- border-radius: 18px;
435
- border: 1px solid rgba(56, 189, 248, 0.55);
436
- background: linear-gradient(180deg, rgba(56, 189, 248, 0.22), transparent);
437
- box-shadow: 0 0 24px rgba(56, 189, 248, 0.28);
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
- .parking-map__car {
458
+ .visual-panel__rails {
441
459
  position: absolute;
442
- left: 48px;
443
- top: 86px;
444
- width: 46px;
445
- height: 22px;
446
- border-radius: 11px 15px 15px 11px;
447
- background: linear-gradient(90deg, #22d3ee, #818cf8);
448
- box-shadow: 0 0 18px rgba(56, 189, 248, 0.55), 0 8px 18px rgba(2, 6, 23, 0.35);
449
- animation: markdyCarGlide 3.8s cubic-bezier(.4,0,.2,1) infinite;
450
- }
451
- .parking-map__car::before,
452
- .parking-map__car::after {
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
- bottom: -4px;
456
- width: 8px;
457
- height: 8px;
472
+ left: 110px;
473
+ right: 78px;
474
+ bottom: 64px;
475
+ height: 3px;
458
476
  border-radius: 999px;
459
- background: #020617;
460
- border: 2px solid #cbd5e1;
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
- .parking-map__car::before { left: 7px; }
463
- .parking-map__car::after { right: 7px; }
464
- .parking-map__slots {
481
+ .visual-panel__cells {
465
482
  position: absolute;
466
- right: 12px;
467
- top: 24px;
483
+ right: 18px;
484
+ top: 22px;
468
485
  display: grid;
469
- grid-template-columns: repeat(4, 44px);
470
- gap: 8px;
486
+ grid-template-columns: repeat(4, 42px);
487
+ gap: 7px;
471
488
  }
472
- .parking-map__slot {
473
- height: 34px;
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
- .parking-map__slot:nth-child(3),
480
- .parking-map__slot:nth-child(6),
481
- .parking-map__slot:nth-child(8) {
482
- border-color: rgba(34, 197, 94, 0.78);
483
- background: rgba(20, 83, 45, 0.5);
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
- .parking-map__route {
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
- .ascii-map__chrome span {
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
- .ascii-map__code {
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: 19px;
524
+ font-size: 18px;
555
525
  line-height: 1.55;
556
- color: #bbf7d0;
557
- text-shadow: 0 0 12px rgba(34, 197, 94, 0.45);
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
- .ascii-map__code b {
560
- color: #67e8f9;
561
- animation: markdyBlink 1.2s steps(2, end) infinite;
529
+ .visual-terminal__line {
530
+ overflow: hidden;
531
+ text-overflow: ellipsis;
532
+ white-space: nowrap;
562
533
  }
563
- .ascii-map__minimap {
564
- position: absolute;
565
- right: 18px;
566
- top: 48px;
567
- width: 102px;
568
- height: 122px;
569
- display: grid;
570
- grid-template-columns: repeat(3, 1fr);
571
- gap: 7px;
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
- .ascii-map__mini-slot {
574
- border-radius: 7px;
575
- border: 1px solid rgba(148, 163, 184, 0.28);
576
- background: rgba(15, 23, 42, 0.72);
545
+ .visual-metric strong {
546
+ flex: 0 0 auto;
547
+ color: #f8fafc;
548
+ font-size: 15px;
549
+ line-height: 1;
577
550
  }
578
- .ascii-map__mini-slot:nth-child(2),
579
- .ascii-map__mini-slot:nth-child(6) {
580
- border-color: rgba(34, 197, 94, 0.85);
581
- background: rgba(20, 83, 45, 0.56);
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
- .ascii-map__transform {
562
+ .visual-grid {
584
563
  position: absolute;
585
- left: 16px;
586
- right: 16px;
587
- bottom: 10px;
564
+ inset: 10px;
588
565
  display: grid;
589
- grid-template-columns: 1fr 1fr 1fr;
590
- gap: 8px;
566
+ gap: 7px;
591
567
  }
592
- .markdy-showcase--game_scene { --accent: #f59e0b; --accent-2: #22c55e; }
593
- .game-scene__world {
594
- position: absolute;
595
- inset: 0;
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
- .game-scene__world::before {
603
- content: "";
604
- position: absolute;
605
- inset: 0;
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
- .game-scene__road {
578
+ .visual-lane {
610
579
  position: absolute;
611
- left: -35px;
612
- right: -35px;
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, #e2e8f0 0 24px, transparent 24px 46px) center / 100% 4px no-repeat,
618
- linear-gradient(180deg, #334155, #0f172a);
619
- box-shadow: 0 18px 32px rgba(2, 6, 23, 0.42);
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
- .game-scene__cones {
587
+ .visual-lane::after {
588
+ content: "";
645
589
  position: absolute;
646
- right: 80px;
647
- bottom: 34px;
648
- display: flex;
649
- gap: 14px;
650
- }
651
- .game-scene__cone {
652
- width: 0;
653
- height: 0;
654
- border-left: 10px solid transparent;
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
- .game-scene__hud {
600
+ .visual-marker {
660
601
  position: absolute;
661
- left: 14px;
662
- top: 14px;
663
- min-width: 120px;
664
- border-color: rgba(245, 158, 11, 0.38);
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
- .game-scene__hud strong { color: #fed7aa; font-size: 18px; }
667
- .game-scene__perfect {
668
- position: absolute;
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
- inset: 4px;
682
- display: grid;
683
- grid-template-columns: 98px 1fr 122px;
684
- gap: 12px;
685
- align-items: stretch;
611
+ bottom: -3px;
612
+ width: 8px;
613
+ height: 8px;
614
+ border-radius: 999px;
615
+ background: #020617;
616
+ border: 2px solid #cbd5e1;
686
617
  }
687
- .byte-viz__glyph {
688
- display: grid;
689
- place-items: center;
690
- border-radius: 22px;
691
- border: 1px solid rgba(167, 139, 250, 0.45);
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
- .byte-viz__chip {
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: #ddd6fe;
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
- .byte-viz__arrow {
716
- color: #67e8f9;
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
- height: 31px;
729
- border-radius: 8px;
730
- background: rgba(15, 23, 42, 0.82);
731
- border: 1px solid rgba(56, 189, 248, 0.28);
732
- color: #bae6fd;
733
- font-family: "SFMono-Regular", Consolas, monospace;
734
- font-size: 12px;
735
- font-weight: 900;
736
- animation: markdyBitFlip 1.9s ease-in-out infinite;
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 markdyCarGlide { 0%, 12% { transform: translateX(0); } 68%, 100% { transform: translateX(198px); } }
745
- @keyframes markdySlotGlow { 50% { box-shadow: 0 0 20px rgba(34, 197, 94, 0.38); } }
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 createShowcaseSurfaceEl(type, def) {
757
- ensureShowcaseStyles(document);
758
- const label = def.args[0] || type.replace("_", " ");
670
+ function escapeHtml(value) {
671
+ return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
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-showcase markdy-showcase--${type}`;
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 (type === "parking_map") {
742
+ if (visualType === "panel") {
743
+ const tag = escapeHtml(args[1] || "live");
744
+ root.dataset.tone = toneArg({ ...def, args }, 2);
764
745
  root.innerHTML = `
765
- <div class="markdy-showcase__top"><div class="markdy-showcase__title"></div><div class="markdy-showcase__pill">live ops</div></div>
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>
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>
770
752
  </div>`;
771
- } else if (type === "ascii_map") {
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("");
772
756
  root.innerHTML = `
773
- <div class="markdy-showcase__top"><div class="markdy-showcase__title"></div><div class="markdy-showcase__pill">parser</div></div>
774
- <div class="markdy-showcase__body">
775
- <div class="ascii-map__terminal"><div class="ascii-map__chrome"><span></span></div><div class="ascii-map__code">[P1][P2][<b> </b>][EV]<br />[IN]===LANE===[OUT]<br />0101 0000 0100 0001</div><div class="ascii-map__minimap"><i class="ascii-map__mini-slot"></i><i class="ascii-map__mini-slot"></i><i class="ascii-map__mini-slot"></i><i class="ascii-map__mini-slot"></i><i class="ascii-map__mini-slot"></i><i class="ascii-map__mini-slot"></i></div><div class="ascii-map__transform"><div class="ascii-map__badge">tokens</div><div class="ascii-map__badge">graph</div><div class="ascii-map__badge">slots</div></div></div>
776
- </div>`;
777
- } else if (type === "game_scene") {
778
- root.innerHTML = `
779
- <div class="markdy-showcase__top"><div class="markdy-showcase__title"></div><div class="markdy-showcase__pill">60 fps</div></div>
780
- <div class="markdy-showcase__body">
781
- <div class="game-scene__world"><div class="game-scene__hud">combo<br /><strong>x4.2</strong></div><div class="game-scene__perfect">PERFECT PARK</div><div class="game-scene__road"></div><div class="game-scene__spot"></div><div class="game-scene__car"></div><div class="game-scene__cones"><i class="game-scene__cone"></i><i class="game-scene__cone"></i><i class="game-scene__cone"></i></div></div>
782
- </div>`;
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.innerHTML = `
785
- <div class="markdy-showcase__top"><div class="markdy-showcase__title"></div><div class="markdy-showcase__pill">UTF-8</div></div>
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-type="service"],
896
- .markdy-arch-node[data-markdy-system-type="api"],
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-type="client"],
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-type="database"],
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
- }
912
- .markdy-arch-node[data-markdy-system-type="cache"] {
913
- --markdy-node-accent: #a3e635;
914
- --markdy-node-accent-2: #22c55e;
915
- border-style: dashed;
916
896
  }
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-type="cloud"],
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-type="container"],
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-type="service"] .markdy-arch-node__icon::before,
934
- .markdy-arch-node[data-markdy-system-type="api"] .markdy-arch-node__icon::before,
935
- .markdy-arch-node[data-markdy-system-type="microservice"] .markdy-arch-node__icon::before {
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-type="service"] .markdy-arch-node__icon::after,
941
- .markdy-arch-node[data-markdy-system-type="api"] .markdy-arch-node__icon::after,
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-type="client"] .markdy-arch-node__icon::before,
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-type="client"] .markdy-arch-node__icon::after,
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-type="database"] .markdy-arch-node__icon::before,
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-type="database"] .markdy-arch-node__icon::after,
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-type="queue"] .markdy-arch-node__icon::before {
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-type="queue"] .markdy-arch-node__icon::after {
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-type="cloud"] .markdy-arch-node__icon::before,
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-type="cloud"] .markdy-arch-node__icon::after,
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-type="container"] .markdy-arch-node__icon::before,
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-type="container"] .markdy-arch-node__icon::after,
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 isShowcaseSurfaceType(type) {
1029
- return SHOWCASE_SURFACE_TYPES.has(type);
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
- case "parking_map":
1105
- case "ascii_map":
1106
- case "game_scene":
1107
- case "byte_viz": {
1108
- el = createShowcaseSurfaceEl(def.type, def);
1109
- break;
1110
- }
1111
- case "service":
1112
- case "api":
1113
- case "microservice":
1114
- case "client":
1115
- case "user":
1116
- case "db":
1117
- case "database":
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 (isShowcaseSurfaceType(def.type)) el.style.zIndex = "25";
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
- service: { width: 184, height: 88 },
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: 420, height: 250 }
1673
+ byte_viz: { width: 390, height: 250 }
1644
1674
  };
1645
1675
  var DEFAULT_ACTOR_SIZE = { width: 140, height: 42 };
1646
1676
  function actorSizeByType(type) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@markdy/renderer-dom",
3
- "version": "0.7.27",
3
+ "version": "0.7.28",
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.27"
46
+ "@markdy/core": "0.7.28"
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.27"
53
+ "@markdy/stdlib-systems": "0.7.28"
54
54
  },
55
55
  "scripts": {
56
56
  "build": "tsup",