@markdy/renderer-dom 0.7.26 → 0.7.27
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 +1190 -82
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -309,6 +309,730 @@ function readRotation(el) {
|
|
|
309
309
|
}
|
|
310
310
|
|
|
311
311
|
// 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"
|
|
326
|
+
]);
|
|
327
|
+
var SHOWCASE_SURFACE_TYPES = /* @__PURE__ */ new Set(["parking_map", "ascii_map", "game_scene", "byte_viz"]);
|
|
328
|
+
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;
|
|
332
|
+
const style = doc.createElement("style");
|
|
333
|
+
style.id = SHOWCASE_STYLE_ID;
|
|
334
|
+
style.textContent = `
|
|
335
|
+
.markdy-showcase {
|
|
336
|
+
--surface-a: rgba(15, 23, 42, 0.9);
|
|
337
|
+
--accent: #38bdf8;
|
|
338
|
+
--accent-2: #22c55e;
|
|
339
|
+
position: relative;
|
|
340
|
+
box-sizing: border-box;
|
|
341
|
+
width: 390px;
|
|
342
|
+
height: 250px;
|
|
343
|
+
overflow: hidden;
|
|
344
|
+
border: 1px solid rgba(148, 163, 184, 0.34);
|
|
345
|
+
border-radius: 24px;
|
|
346
|
+
color: #e5f3ff;
|
|
347
|
+
background:
|
|
348
|
+
radial-gradient(circle at 12% 0%, color-mix(in srgb, var(--accent) 32%, transparent), transparent 34%),
|
|
349
|
+
radial-gradient(circle at 90% 15%, color-mix(in srgb, var(--accent-2) 26%, transparent), transparent 34%),
|
|
350
|
+
linear-gradient(145deg, rgba(255, 255, 255, 0.13), rgba(255, 255, 255, 0.025) 32%, var(--surface-a));
|
|
351
|
+
box-shadow:
|
|
352
|
+
0 26px 70px rgba(2, 6, 23, 0.42),
|
|
353
|
+
0 0 0 1px rgba(255, 255, 255, 0.06) inset,
|
|
354
|
+
0 1px 0 rgba(255, 255, 255, 0.18) inset,
|
|
355
|
+
0 0 44px color-mix(in srgb, var(--accent) 24%, transparent);
|
|
356
|
+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
357
|
+
isolation: isolate;
|
|
358
|
+
contain: layout paint style;
|
|
359
|
+
backdrop-filter: blur(16px) saturate(1.2);
|
|
360
|
+
-webkit-backdrop-filter: blur(16px) saturate(1.2);
|
|
361
|
+
}
|
|
362
|
+
.markdy-showcase::before {
|
|
363
|
+
content: "";
|
|
364
|
+
position: absolute;
|
|
365
|
+
inset: 0;
|
|
366
|
+
z-index: -1;
|
|
367
|
+
background:
|
|
368
|
+
linear-gradient(90deg, transparent 0 48%, rgba(255, 255, 255, 0.09) 50%, transparent 52%) 0 0 / 34px 34px,
|
|
369
|
+
linear-gradient(0deg, transparent 0 48%, rgba(255, 255, 255, 0.055) 50%, transparent 52%) 0 0 / 34px 34px;
|
|
370
|
+
mask-image: linear-gradient(to bottom, rgba(0,0,0,0.85), transparent 82%);
|
|
371
|
+
opacity: 0.48;
|
|
372
|
+
animation: markdyGridDrift 7s linear infinite;
|
|
373
|
+
}
|
|
374
|
+
.markdy-showcase::after {
|
|
375
|
+
content: "";
|
|
376
|
+
position: absolute;
|
|
377
|
+
inset: -40% -20%;
|
|
378
|
+
z-index: -1;
|
|
379
|
+
background: conic-gradient(from 90deg, transparent, color-mix(in srgb, var(--accent) 20%, transparent), transparent 32%);
|
|
380
|
+
opacity: 0.6;
|
|
381
|
+
animation: markdyAurora 9s linear infinite;
|
|
382
|
+
}
|
|
383
|
+
.markdy-showcase--byte_viz { width: 420px; }
|
|
384
|
+
.markdy-showcase__top {
|
|
385
|
+
display: flex;
|
|
386
|
+
align-items: center;
|
|
387
|
+
justify-content: space-between;
|
|
388
|
+
gap: 12px;
|
|
389
|
+
padding: 14px 16px 8px;
|
|
390
|
+
}
|
|
391
|
+
.markdy-showcase__title {
|
|
392
|
+
min-width: 0;
|
|
393
|
+
overflow: hidden;
|
|
394
|
+
text-overflow: ellipsis;
|
|
395
|
+
white-space: nowrap;
|
|
396
|
+
font-size: 15px;
|
|
397
|
+
font-weight: 820;
|
|
398
|
+
letter-spacing: 0.01em;
|
|
399
|
+
color: #f8fafc;
|
|
400
|
+
}
|
|
401
|
+
.markdy-showcase__pill {
|
|
402
|
+
flex: 0 0 auto;
|
|
403
|
+
border: 1px solid color-mix(in srgb, var(--accent) 42%, transparent);
|
|
404
|
+
border-radius: 999px;
|
|
405
|
+
padding: 4px 8px;
|
|
406
|
+
color: #bae6fd;
|
|
407
|
+
background: rgba(8, 47, 73, 0.54);
|
|
408
|
+
font-size: 10px;
|
|
409
|
+
font-weight: 800;
|
|
410
|
+
letter-spacing: 0.08em;
|
|
411
|
+
text-transform: uppercase;
|
|
412
|
+
box-shadow: 0 0 16px color-mix(in srgb, var(--accent) 22%, transparent);
|
|
413
|
+
}
|
|
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;
|
|
422
|
+
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
|
+
}
|
|
428
|
+
.parking-map__scan {
|
|
429
|
+
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);
|
|
438
|
+
animation: markdyScanPulse 1.8s ease-in-out infinite;
|
|
439
|
+
}
|
|
440
|
+
.parking-map__car {
|
|
441
|
+
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: "";
|
|
454
|
+
position: absolute;
|
|
455
|
+
bottom: -4px;
|
|
456
|
+
width: 8px;
|
|
457
|
+
height: 8px;
|
|
458
|
+
border-radius: 999px;
|
|
459
|
+
background: #020617;
|
|
460
|
+
border: 2px solid #cbd5e1;
|
|
461
|
+
}
|
|
462
|
+
.parking-map__car::before { left: 7px; }
|
|
463
|
+
.parking-map__car::after { right: 7px; }
|
|
464
|
+
.parking-map__slots {
|
|
465
|
+
position: absolute;
|
|
466
|
+
right: 12px;
|
|
467
|
+
top: 24px;
|
|
468
|
+
display: grid;
|
|
469
|
+
grid-template-columns: repeat(4, 44px);
|
|
470
|
+
gap: 8px;
|
|
471
|
+
}
|
|
472
|
+
.parking-map__slot {
|
|
473
|
+
height: 34px;
|
|
474
|
+
border-radius: 10px;
|
|
475
|
+
border: 1px solid rgba(148, 163, 184, 0.34);
|
|
476
|
+
background: rgba(15, 23, 42, 0.7);
|
|
477
|
+
box-shadow: 0 0 0 1px rgba(255,255,255,0.035) inset;
|
|
478
|
+
}
|
|
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);
|
|
484
|
+
animation: markdySlotGlow 1.7s ease-in-out infinite;
|
|
485
|
+
}
|
|
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 {
|
|
535
|
+
height: 28px;
|
|
536
|
+
padding-left: 12px;
|
|
537
|
+
display: flex;
|
|
538
|
+
align-items: center;
|
|
539
|
+
gap: 6px;
|
|
540
|
+
border-bottom: 1px solid rgba(148, 163, 184, 0.16);
|
|
541
|
+
}
|
|
542
|
+
.ascii-map__chrome span {
|
|
543
|
+
width: 8px;
|
|
544
|
+
height: 8px;
|
|
545
|
+
border-radius: 999px;
|
|
546
|
+
background: #ef4444;
|
|
547
|
+
box-shadow: 14px 0 #f59e0b, 28px 0 #22c55e;
|
|
548
|
+
}
|
|
549
|
+
.ascii-map__code {
|
|
550
|
+
position: absolute;
|
|
551
|
+
left: 16px;
|
|
552
|
+
top: 46px;
|
|
553
|
+
font-family: "SFMono-Regular", Consolas, monospace;
|
|
554
|
+
font-size: 19px;
|
|
555
|
+
line-height: 1.55;
|
|
556
|
+
color: #bbf7d0;
|
|
557
|
+
text-shadow: 0 0 12px rgba(34, 197, 94, 0.45);
|
|
558
|
+
}
|
|
559
|
+
.ascii-map__code b {
|
|
560
|
+
color: #67e8f9;
|
|
561
|
+
animation: markdyBlink 1.2s steps(2, end) infinite;
|
|
562
|
+
}
|
|
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;
|
|
572
|
+
}
|
|
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);
|
|
577
|
+
}
|
|
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);
|
|
582
|
+
}
|
|
583
|
+
.ascii-map__transform {
|
|
584
|
+
position: absolute;
|
|
585
|
+
left: 16px;
|
|
586
|
+
right: 16px;
|
|
587
|
+
bottom: 10px;
|
|
588
|
+
display: grid;
|
|
589
|
+
grid-template-columns: 1fr 1fr 1fr;
|
|
590
|
+
gap: 8px;
|
|
591
|
+
}
|
|
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%);
|
|
601
|
+
}
|
|
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;
|
|
608
|
+
}
|
|
609
|
+
.game-scene__road {
|
|
610
|
+
position: absolute;
|
|
611
|
+
left: -35px;
|
|
612
|
+
right: -35px;
|
|
613
|
+
top: 94px;
|
|
614
|
+
height: 76px;
|
|
615
|
+
transform: rotate(-8deg);
|
|
616
|
+
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));
|
|
643
|
+
}
|
|
644
|
+
.game-scene__cones {
|
|
645
|
+
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));
|
|
658
|
+
}
|
|
659
|
+
.game-scene__hud {
|
|
660
|
+
position: absolute;
|
|
661
|
+
left: 14px;
|
|
662
|
+
top: 14px;
|
|
663
|
+
min-width: 120px;
|
|
664
|
+
border-color: rgba(245, 158, 11, 0.38);
|
|
665
|
+
}
|
|
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 {
|
|
680
|
+
position: absolute;
|
|
681
|
+
inset: 4px;
|
|
682
|
+
display: grid;
|
|
683
|
+
grid-template-columns: 98px 1fr 122px;
|
|
684
|
+
gap: 12px;
|
|
685
|
+
align-items: stretch;
|
|
686
|
+
}
|
|
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 {
|
|
700
|
+
display: flex;
|
|
701
|
+
align-items: center;
|
|
702
|
+
gap: 7px;
|
|
703
|
+
}
|
|
704
|
+
.byte-viz__chip {
|
|
705
|
+
flex: 1 1 0;
|
|
706
|
+
border: 1px solid rgba(148, 163, 184, 0.25);
|
|
707
|
+
border-radius: 12px;
|
|
708
|
+
padding: 8px 10px;
|
|
709
|
+
background: rgba(2, 6, 23, 0.42);
|
|
710
|
+
color: #ddd6fe;
|
|
711
|
+
font-family: "SFMono-Regular", Consolas, monospace;
|
|
712
|
+
font-size: 12px;
|
|
713
|
+
font-weight: 800;
|
|
714
|
+
}
|
|
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 {
|
|
726
|
+
display: grid;
|
|
727
|
+
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;
|
|
737
|
+
}
|
|
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
|
+
@keyframes markdyGridDrift { to { background-position: 34px 34px, 34px 34px; } }
|
|
742
|
+
@keyframes markdyAurora { to { transform: rotate(1turn); } }
|
|
743
|
+
@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); } }
|
|
753
|
+
`;
|
|
754
|
+
doc.head.appendChild(style);
|
|
755
|
+
}
|
|
756
|
+
function createShowcaseSurfaceEl(type, def) {
|
|
757
|
+
ensureShowcaseStyles(document);
|
|
758
|
+
const label = def.args[0] || type.replace("_", " ");
|
|
759
|
+
const root = document.createElement("div");
|
|
760
|
+
root.className = `markdy-showcase markdy-showcase--${type}`;
|
|
761
|
+
root.setAttribute("role", "img");
|
|
762
|
+
root.setAttribute("aria-label", label);
|
|
763
|
+
if (type === "parking_map") {
|
|
764
|
+
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>
|
|
770
|
+
</div>`;
|
|
771
|
+
} else if (type === "ascii_map") {
|
|
772
|
+
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>`;
|
|
783
|
+
} 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>`;
|
|
789
|
+
}
|
|
790
|
+
const title = root.querySelector(".markdy-showcase__title");
|
|
791
|
+
if (title) title.textContent = label;
|
|
792
|
+
return root;
|
|
793
|
+
}
|
|
794
|
+
function ensureArchitectureStyles(doc) {
|
|
795
|
+
if (doc.getElementById(ARCHITECTURE_STYLE_ID)) return;
|
|
796
|
+
const style = doc.createElement("style");
|
|
797
|
+
style.id = ARCHITECTURE_STYLE_ID;
|
|
798
|
+
style.textContent = `
|
|
799
|
+
.markdy-arch-node {
|
|
800
|
+
--markdy-node-accent: #38bdf8;
|
|
801
|
+
--markdy-node-accent-2: #22c55e;
|
|
802
|
+
--markdy-node-surface: rgba(15, 23, 42, 0.82);
|
|
803
|
+
--markdy-node-border: rgba(148, 163, 184, 0.34);
|
|
804
|
+
--markdy-node-glow: rgba(56, 189, 248, 0.24);
|
|
805
|
+
position: relative;
|
|
806
|
+
isolation: isolate;
|
|
807
|
+
width: 184px;
|
|
808
|
+
min-height: 88px;
|
|
809
|
+
box-sizing: border-box;
|
|
810
|
+
display: grid;
|
|
811
|
+
grid-template-columns: 34px minmax(0, 1fr);
|
|
812
|
+
align-items: center;
|
|
813
|
+
gap: 10px;
|
|
814
|
+
padding: 13px 14px;
|
|
815
|
+
border: 1px solid var(--markdy-node-border);
|
|
816
|
+
border-radius: 14px;
|
|
817
|
+
color: #e5eefb;
|
|
818
|
+
background:
|
|
819
|
+
linear-gradient(145deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0.02) 34%, rgba(15, 23, 42, 0.88) 100%),
|
|
820
|
+
radial-gradient(circle at 18% 0%, color-mix(in srgb, var(--markdy-node-accent) 34%, transparent), transparent 42%),
|
|
821
|
+
var(--markdy-node-surface);
|
|
822
|
+
box-shadow:
|
|
823
|
+
0 16px 34px rgba(2, 6, 23, 0.28),
|
|
824
|
+
0 0 0 1px rgba(255, 255, 255, 0.04) inset,
|
|
825
|
+
0 1px 0 rgba(255, 255, 255, 0.12) inset,
|
|
826
|
+
0 0 28px var(--markdy-node-glow);
|
|
827
|
+
overflow: hidden;
|
|
828
|
+
contain: layout paint style;
|
|
829
|
+
backdrop-filter: blur(14px) saturate(1.18);
|
|
830
|
+
-webkit-backdrop-filter: blur(14px) saturate(1.18);
|
|
831
|
+
}
|
|
832
|
+
.markdy-arch-node::before {
|
|
833
|
+
content: "";
|
|
834
|
+
position: absolute;
|
|
835
|
+
inset: 0;
|
|
836
|
+
z-index: -1;
|
|
837
|
+
background:
|
|
838
|
+
linear-gradient(90deg, transparent 0 24%, rgba(255, 255, 255, 0.06) 50%, transparent 76%) -180px 0 / 180px 100% no-repeat,
|
|
839
|
+
repeating-linear-gradient(135deg, rgba(255, 255, 255, 0.055) 0 1px, transparent 1px 10px);
|
|
840
|
+
opacity: 0.6;
|
|
841
|
+
}
|
|
842
|
+
.markdy-arch-node::after {
|
|
843
|
+
content: "";
|
|
844
|
+
position: absolute;
|
|
845
|
+
left: 14px;
|
|
846
|
+
right: 14px;
|
|
847
|
+
bottom: 9px;
|
|
848
|
+
height: 2px;
|
|
849
|
+
border-radius: 999px;
|
|
850
|
+
background: linear-gradient(90deg, transparent, var(--markdy-node-accent), var(--markdy-node-accent-2), transparent);
|
|
851
|
+
opacity: 0.82;
|
|
852
|
+
filter: drop-shadow(0 0 6px var(--markdy-node-accent));
|
|
853
|
+
}
|
|
854
|
+
.markdy-arch-node__icon {
|
|
855
|
+
position: relative;
|
|
856
|
+
width: 32px;
|
|
857
|
+
height: 32px;
|
|
858
|
+
border-radius: 11px;
|
|
859
|
+
background:
|
|
860
|
+
radial-gradient(circle at 35% 25%, rgba(255, 255, 255, 0.28), transparent 42%),
|
|
861
|
+
linear-gradient(145deg, var(--markdy-node-accent), color-mix(in srgb, var(--markdy-node-accent) 38%, #020617));
|
|
862
|
+
box-shadow:
|
|
863
|
+
0 0 0 1px rgba(255, 255, 255, 0.16) inset,
|
|
864
|
+
0 10px 20px color-mix(in srgb, var(--markdy-node-accent) 25%, transparent);
|
|
865
|
+
}
|
|
866
|
+
.markdy-arch-node__icon::before,
|
|
867
|
+
.markdy-arch-node__icon::after {
|
|
868
|
+
content: "";
|
|
869
|
+
position: absolute;
|
|
870
|
+
box-sizing: border-box;
|
|
871
|
+
border-color: rgba(255, 255, 255, 0.9);
|
|
872
|
+
}
|
|
873
|
+
.markdy-arch-node__label {
|
|
874
|
+
min-width: 0;
|
|
875
|
+
font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
876
|
+
font-size: 15px;
|
|
877
|
+
font-weight: 720;
|
|
878
|
+
line-height: 1.08;
|
|
879
|
+
color: #f8fafc;
|
|
880
|
+
text-shadow: 0 1px 12px rgba(15, 23, 42, 0.8);
|
|
881
|
+
white-space: nowrap;
|
|
882
|
+
overflow: hidden;
|
|
883
|
+
text-overflow: ellipsis;
|
|
884
|
+
}
|
|
885
|
+
.markdy-arch-node__type {
|
|
886
|
+
display: block;
|
|
887
|
+
margin-top: 5px;
|
|
888
|
+
font-size: 9px;
|
|
889
|
+
font-weight: 740;
|
|
890
|
+
letter-spacing: 0.08em;
|
|
891
|
+
text-transform: uppercase;
|
|
892
|
+
color: color-mix(in srgb, var(--markdy-node-accent) 70%, #e2e8f0);
|
|
893
|
+
opacity: 0.86;
|
|
894
|
+
}
|
|
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"] {
|
|
898
|
+
--markdy-node-accent: #38bdf8;
|
|
899
|
+
--markdy-node-accent-2: #818cf8;
|
|
900
|
+
}
|
|
901
|
+
.markdy-arch-node[data-markdy-system-type="client"],
|
|
902
|
+
.markdy-arch-node[data-markdy-system-type="user"] {
|
|
903
|
+
--markdy-node-accent: #f59e0b;
|
|
904
|
+
--markdy-node-accent-2: #fb7185;
|
|
905
|
+
}
|
|
906
|
+
.markdy-arch-node[data-markdy-system-type="database"],
|
|
907
|
+
.markdy-arch-node[data-markdy-system-type="db"] {
|
|
908
|
+
--markdy-node-accent: #22c55e;
|
|
909
|
+
--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
|
+
}
|
|
917
|
+
.markdy-arch-node[data-markdy-system-type="queue"] {
|
|
918
|
+
--markdy-node-accent: #a78bfa;
|
|
919
|
+
--markdy-node-accent-2: #38bdf8;
|
|
920
|
+
}
|
|
921
|
+
.markdy-arch-node[data-markdy-system-type="cloud"],
|
|
922
|
+
.markdy-arch-node[data-markdy-system-type="region"] {
|
|
923
|
+
--markdy-node-accent: #60a5fa;
|
|
924
|
+
--markdy-node-accent-2: #67e8f9;
|
|
925
|
+
border-radius: 999px;
|
|
926
|
+
}
|
|
927
|
+
.markdy-arch-node[data-markdy-system-type="container"],
|
|
928
|
+
.markdy-arch-node[data-markdy-system-type="cluster"] {
|
|
929
|
+
--markdy-node-accent: #c084fc;
|
|
930
|
+
--markdy-node-accent-2: #f472b6;
|
|
931
|
+
border-radius: 10px;
|
|
932
|
+
}
|
|
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 {
|
|
936
|
+
inset: 9px 7px;
|
|
937
|
+
border-top: 3px solid rgba(255, 255, 255, 0.92);
|
|
938
|
+
border-bottom: 3px solid rgba(255, 255, 255, 0.92);
|
|
939
|
+
}
|
|
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 {
|
|
943
|
+
inset: 14px 7px auto;
|
|
944
|
+
border-top: 3px solid rgba(255, 255, 255, 0.92);
|
|
945
|
+
}
|
|
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 {
|
|
948
|
+
left: 8px;
|
|
949
|
+
right: 8px;
|
|
950
|
+
top: 8px;
|
|
951
|
+
height: 13px;
|
|
952
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
953
|
+
border-radius: 3px;
|
|
954
|
+
}
|
|
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 {
|
|
957
|
+
left: 12px;
|
|
958
|
+
right: 12px;
|
|
959
|
+
bottom: 7px;
|
|
960
|
+
border-top: 2px solid rgba(255, 255, 255, 0.92);
|
|
961
|
+
}
|
|
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 {
|
|
965
|
+
inset: 7px 7px 9px;
|
|
966
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
967
|
+
border-radius: 50% / 16%;
|
|
968
|
+
}
|
|
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 {
|
|
972
|
+
left: 8px;
|
|
973
|
+
right: 8px;
|
|
974
|
+
top: 12px;
|
|
975
|
+
border-top: 2px solid rgba(255, 255, 255, 0.72);
|
|
976
|
+
}
|
|
977
|
+
.markdy-arch-node[data-markdy-system-type="queue"] .markdy-arch-node__icon::before {
|
|
978
|
+
inset: 9px 8px;
|
|
979
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
980
|
+
border-radius: 999px;
|
|
981
|
+
}
|
|
982
|
+
.markdy-arch-node[data-markdy-system-type="queue"] .markdy-arch-node__icon::after {
|
|
983
|
+
left: 13px;
|
|
984
|
+
top: 9px;
|
|
985
|
+
width: 8px;
|
|
986
|
+
height: 14px;
|
|
987
|
+
border-left: 2px solid rgba(255, 255, 255, 0.82);
|
|
988
|
+
border-right: 2px solid rgba(255, 255, 255, 0.82);
|
|
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 {
|
|
992
|
+
left: 7px;
|
|
993
|
+
right: 7px;
|
|
994
|
+
bottom: 9px;
|
|
995
|
+
height: 12px;
|
|
996
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
997
|
+
border-radius: 999px;
|
|
998
|
+
}
|
|
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 {
|
|
1001
|
+
left: 10px;
|
|
1002
|
+
top: 7px;
|
|
1003
|
+
width: 13px;
|
|
1004
|
+
height: 13px;
|
|
1005
|
+
border-top: 2px solid rgba(255, 255, 255, 0.92);
|
|
1006
|
+
border-left: 2px solid rgba(255, 255, 255, 0.92);
|
|
1007
|
+
border-radius: 999px 0 0 0;
|
|
1008
|
+
}
|
|
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 {
|
|
1011
|
+
inset: 8px;
|
|
1012
|
+
border: 2px solid rgba(255, 255, 255, 0.92);
|
|
1013
|
+
border-radius: 4px;
|
|
1014
|
+
}
|
|
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 {
|
|
1017
|
+
left: 10px;
|
|
1018
|
+
right: 10px;
|
|
1019
|
+
top: 14px;
|
|
1020
|
+
border-top: 2px solid rgba(255, 255, 255, 0.72);
|
|
1021
|
+
}
|
|
1022
|
+
`;
|
|
1023
|
+
doc.head.appendChild(style);
|
|
1024
|
+
}
|
|
1025
|
+
function isArchitectureNodeType(type) {
|
|
1026
|
+
return ARCHITECTURE_NODE_TYPES.has(type);
|
|
1027
|
+
}
|
|
1028
|
+
function isShowcaseSurfaceType(type) {
|
|
1029
|
+
return SHOWCASE_SURFACE_TYPES.has(type);
|
|
1030
|
+
}
|
|
1031
|
+
function architectureTypeLabel(type) {
|
|
1032
|
+
if (type === "db") return "database";
|
|
1033
|
+
if (type === "api") return "service";
|
|
1034
|
+
return type;
|
|
1035
|
+
}
|
|
312
1036
|
function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
313
1037
|
let el;
|
|
314
1038
|
switch (def.type) {
|
|
@@ -377,62 +1101,44 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
377
1101
|
el = createFigureEl(def);
|
|
378
1102
|
break;
|
|
379
1103
|
}
|
|
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
|
+
}
|
|
380
1111
|
case "service":
|
|
1112
|
+
case "api":
|
|
1113
|
+
case "microservice":
|
|
381
1114
|
case "client":
|
|
1115
|
+
case "user":
|
|
382
1116
|
case "db":
|
|
383
|
-
case "
|
|
1117
|
+
case "database":
|
|
1118
|
+
case "queue":
|
|
1119
|
+
case "cache":
|
|
1120
|
+
case "cloud":
|
|
1121
|
+
case "region":
|
|
1122
|
+
case "container":
|
|
1123
|
+
case "cluster": {
|
|
1124
|
+
ensureArchitectureStyles(document);
|
|
384
1125
|
const card = document.createElement("div");
|
|
1126
|
+
card.className = "markdy-arch-node";
|
|
1127
|
+
card.dataset.markdySystemType = def.type;
|
|
1128
|
+
card.setAttribute("role", "img");
|
|
1129
|
+
card.setAttribute("aria-label", `${architectureTypeLabel(def.type)} ${def.args[0] ?? name}`);
|
|
1130
|
+
const icon = document.createElement("span");
|
|
1131
|
+
icon.className = "markdy-arch-node__icon";
|
|
1132
|
+
icon.setAttribute("aria-hidden", "true");
|
|
385
1133
|
const label = document.createElement("div");
|
|
1134
|
+
label.className = "markdy-arch-node__label";
|
|
386
1135
|
label.textContent = def.args[0] ?? "";
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
lineHeight: "1.2",
|
|
394
|
-
pointerEvents: "none",
|
|
395
|
-
whiteSpace: "nowrap",
|
|
396
|
-
overflow: "hidden",
|
|
397
|
-
textOverflow: "ellipsis",
|
|
398
|
-
maxWidth: "100%"
|
|
399
|
-
});
|
|
400
|
-
Object.assign(card.style, {
|
|
401
|
-
width: "180px",
|
|
402
|
-
height: "84px",
|
|
403
|
-
boxSizing: "border-box",
|
|
404
|
-
border: "1px solid #475569",
|
|
405
|
-
background: "#0f172a",
|
|
406
|
-
display: "grid",
|
|
407
|
-
placeItems: "center",
|
|
408
|
-
padding: "10px 12px"
|
|
409
|
-
});
|
|
410
|
-
if (def.type === "service") {
|
|
411
|
-
card.style.borderRadius = "12px";
|
|
412
|
-
card.style.background = "linear-gradient(180deg, #1e293b 0%, #0f172a 100%)";
|
|
413
|
-
} else if (def.type === "client") {
|
|
414
|
-
const bar = document.createElement("div");
|
|
415
|
-
Object.assign(bar.style, {
|
|
416
|
-
position: "absolute",
|
|
417
|
-
top: "8px",
|
|
418
|
-
left: "8px",
|
|
419
|
-
right: "8px",
|
|
420
|
-
height: "8px",
|
|
421
|
-
borderRadius: "6px",
|
|
422
|
-
background: "#334155"
|
|
423
|
-
});
|
|
424
|
-
card.style.position = "relative";
|
|
425
|
-
card.style.borderRadius = "10px";
|
|
426
|
-
card.style.paddingTop = "20px";
|
|
427
|
-
card.appendChild(bar);
|
|
428
|
-
} else if (def.type === "db") {
|
|
429
|
-
card.style.borderRadius = "50% / 14%";
|
|
430
|
-
card.style.background = "linear-gradient(180deg, #334155 0%, #0f172a 70%)";
|
|
431
|
-
card.style.boxShadow = "inset 0 10px 0 rgba(226, 232, 240, 0.12)";
|
|
432
|
-
} else if (def.type === "queue") {
|
|
433
|
-
card.style.borderRadius = "8px";
|
|
434
|
-
card.style.boxShadow = "-6px -6px 0 rgba(30, 41, 59, 0.9), -12px -12px 0 rgba(15, 23, 42, 0.9)";
|
|
435
|
-
}
|
|
1136
|
+
label.style.fontSize = `${def.size ?? 15}px`;
|
|
1137
|
+
const typeLabel = document.createElement("span");
|
|
1138
|
+
typeLabel.className = "markdy-arch-node__type";
|
|
1139
|
+
typeLabel.textContent = architectureTypeLabel(def.type);
|
|
1140
|
+
label.appendChild(typeLabel);
|
|
1141
|
+
card.appendChild(icon);
|
|
436
1142
|
card.appendChild(label);
|
|
437
1143
|
el = card;
|
|
438
1144
|
break;
|
|
@@ -456,6 +1162,8 @@ function createActorEl(name, def, assetDefs, assetOverrides) {
|
|
|
456
1162
|
el.style.opacity = String(def.opacity ?? 1);
|
|
457
1163
|
if (def.z !== void 0) el.style.zIndex = String(def.z);
|
|
458
1164
|
else if (def.type === "caption") el.style.zIndex = "100";
|
|
1165
|
+
else if (isShowcaseSurfaceType(def.type)) el.style.zIndex = "25";
|
|
1166
|
+
else if (isArchitectureNodeType(def.type)) el.style.zIndex = "10";
|
|
459
1167
|
return el;
|
|
460
1168
|
}
|
|
461
1169
|
|
|
@@ -776,27 +1484,185 @@ var bounce = ({ ev, el, state, baseOpts, anims, tx: tx2 }) => {
|
|
|
776
1484
|
anims.push(el.animate(keyframes, { ...baseOpts, easing: "ease-out" }));
|
|
777
1485
|
};
|
|
778
1486
|
|
|
1487
|
+
// src/actions/effects.ts
|
|
1488
|
+
function numeric(value, fallback) {
|
|
1489
|
+
return typeof value === "number" ? value : fallback;
|
|
1490
|
+
}
|
|
1491
|
+
function stringParam(value, fallback) {
|
|
1492
|
+
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
1493
|
+
}
|
|
1494
|
+
var spring = ({ ev, el, state, baseOpts, anims, tx: tx2 }) => {
|
|
1495
|
+
const to = ev.params.to;
|
|
1496
|
+
const toX = to?.[0] ?? state.x;
|
|
1497
|
+
const toY = to?.[1] ?? state.y;
|
|
1498
|
+
const stiffness = numeric(ev.params.stiffness, 0.18);
|
|
1499
|
+
const overshootX = toX + (toX - state.x) * stiffness;
|
|
1500
|
+
const overshootY = toY + (toY - state.y) * stiffness;
|
|
1501
|
+
anims.push(
|
|
1502
|
+
el.animate(
|
|
1503
|
+
[
|
|
1504
|
+
{ transform: tx2(state), offset: 0 },
|
|
1505
|
+
{ transform: tx2({ ...state, x: overshootX, y: overshootY }), offset: 0.72 },
|
|
1506
|
+
{ transform: tx2({ ...state, x: toX, y: toY }), offset: 1 }
|
|
1507
|
+
],
|
|
1508
|
+
{ ...baseOpts, easing: "cubic-bezier(.2,1.35,.35,1)" }
|
|
1509
|
+
)
|
|
1510
|
+
);
|
|
1511
|
+
state.x = toX;
|
|
1512
|
+
state.y = toY;
|
|
1513
|
+
};
|
|
1514
|
+
var followPath = ({ ev, el, baseOpts, anims }) => {
|
|
1515
|
+
const path = stringParam(ev.params.path, "M 0 0 L 120 0");
|
|
1516
|
+
const rotate2 = ev.params.rotate === false ? "0deg" : "auto";
|
|
1517
|
+
anims.push(
|
|
1518
|
+
el.animate(
|
|
1519
|
+
[
|
|
1520
|
+
{ offsetPath: `path('${path}')`, offsetDistance: "0%", offsetRotate: rotate2 },
|
|
1521
|
+
{ offsetPath: `path('${path}')`, offsetDistance: "100%", offsetRotate: rotate2 }
|
|
1522
|
+
],
|
|
1523
|
+
baseOpts
|
|
1524
|
+
)
|
|
1525
|
+
);
|
|
1526
|
+
};
|
|
1527
|
+
var pulse = ({ ev, el, state, baseOpts, anims, tx: tx2 }) => {
|
|
1528
|
+
const amount = numeric(ev.params.amount, 1.08);
|
|
1529
|
+
anims.push(
|
|
1530
|
+
el.animate(
|
|
1531
|
+
[
|
|
1532
|
+
{ transform: tx2(state), offset: 0 },
|
|
1533
|
+
{ transform: tx2({ ...state, scale: state.scale * amount }), offset: 0.48 },
|
|
1534
|
+
{ transform: tx2(state), offset: 1 }
|
|
1535
|
+
],
|
|
1536
|
+
{ ...baseOpts, easing: "ease-in-out" }
|
|
1537
|
+
)
|
|
1538
|
+
);
|
|
1539
|
+
};
|
|
1540
|
+
var glow = ({ ev, el, baseOpts, anims }) => {
|
|
1541
|
+
const color = stringParam(ev.params.color, "#38bdf8");
|
|
1542
|
+
const strength = numeric(ev.params.strength, 24);
|
|
1543
|
+
anims.push(
|
|
1544
|
+
el.animate(
|
|
1545
|
+
[
|
|
1546
|
+
{ filter: "drop-shadow(0 0 0 transparent)", boxShadow: "0 0 0 rgba(0,0,0,0)" },
|
|
1547
|
+
{ filter: `drop-shadow(0 0 ${strength}px ${color})`, boxShadow: `0 0 ${strength}px ${color}` },
|
|
1548
|
+
{ filter: "drop-shadow(0 0 0 transparent)", boxShadow: "0 0 0 rgba(0,0,0,0)" }
|
|
1549
|
+
],
|
|
1550
|
+
{ ...baseOpts, easing: "ease-in-out" }
|
|
1551
|
+
)
|
|
1552
|
+
);
|
|
1553
|
+
};
|
|
1554
|
+
var ripple = ({ ev, el, delayMs, durMs, anims }) => {
|
|
1555
|
+
const color = stringParam(ev.params.color, "#38bdf8");
|
|
1556
|
+
const size = numeric(ev.params.size, 140);
|
|
1557
|
+
const ring = document.createElement("span");
|
|
1558
|
+
ring.setAttribute("data-markdy-ripple", "1");
|
|
1559
|
+
Object.assign(ring.style, {
|
|
1560
|
+
position: "absolute",
|
|
1561
|
+
left: "50%",
|
|
1562
|
+
top: "50%",
|
|
1563
|
+
width: `${size}px`,
|
|
1564
|
+
height: `${size}px`,
|
|
1565
|
+
marginLeft: `${-size / 2}px`,
|
|
1566
|
+
marginTop: `${-size / 2}px`,
|
|
1567
|
+
border: `2px solid ${color}`,
|
|
1568
|
+
borderRadius: "999px",
|
|
1569
|
+
pointerEvents: "none",
|
|
1570
|
+
opacity: "0"
|
|
1571
|
+
});
|
|
1572
|
+
el.appendChild(ring);
|
|
1573
|
+
anims.push(
|
|
1574
|
+
ring.animate(
|
|
1575
|
+
[
|
|
1576
|
+
{ transform: "scale(0.2)", opacity: 0.6 },
|
|
1577
|
+
{ transform: "scale(1)", opacity: 0 }
|
|
1578
|
+
],
|
|
1579
|
+
{ delay: delayMs, duration: durMs, fill: "forwards", easing: "ease-out" }
|
|
1580
|
+
)
|
|
1581
|
+
);
|
|
1582
|
+
};
|
|
1583
|
+
var blur = ({ ev, el, baseOpts, anims }) => {
|
|
1584
|
+
const from = numeric(ev.params.from, 0);
|
|
1585
|
+
const to = numeric(ev.params.to, 8);
|
|
1586
|
+
anims.push(el.animate([{ filter: `blur(${from}px)` }, { filter: `blur(${to}px)` }], baseOpts));
|
|
1587
|
+
};
|
|
1588
|
+
var lineReveal = ({ ev, el, baseOpts, anims }) => {
|
|
1589
|
+
const from = stringParam(ev.params.from, "left");
|
|
1590
|
+
const start = from === "right" ? "inset(0 0 0 100%)" : "inset(0 100% 0 0)";
|
|
1591
|
+
anims.push(el.animate([{ clipPath: start }, { clipPath: "inset(0 0 0 0)" }], baseOpts));
|
|
1592
|
+
};
|
|
1593
|
+
var mask = ({ ev, el, baseOpts, anims }) => {
|
|
1594
|
+
const from = numeric(ev.params.from, 0);
|
|
1595
|
+
const to = numeric(ev.params.to, 120);
|
|
1596
|
+
anims.push(
|
|
1597
|
+
el.animate(
|
|
1598
|
+
[
|
|
1599
|
+
{ clipPath: `circle(${from}% at 50% 50%)` },
|
|
1600
|
+
{ clipPath: `circle(${to}% at 50% 50%)` }
|
|
1601
|
+
],
|
|
1602
|
+
baseOpts
|
|
1603
|
+
)
|
|
1604
|
+
);
|
|
1605
|
+
};
|
|
1606
|
+
var parallax = ({ ev, el, state, baseOpts, anims, tx: tx2 }) => {
|
|
1607
|
+
const depth = numeric(ev.params.depth, 0.35);
|
|
1608
|
+
const by = ev.params.by;
|
|
1609
|
+
const dx = (by?.[0] ?? 24) * depth;
|
|
1610
|
+
const dy = (by?.[1] ?? 0) * depth;
|
|
1611
|
+
anims.push(
|
|
1612
|
+
el.animate(
|
|
1613
|
+
[
|
|
1614
|
+
{ transform: tx2(state) },
|
|
1615
|
+
{ transform: tx2({ ...state, x: state.x + dx, y: state.y + dy }) }
|
|
1616
|
+
],
|
|
1617
|
+
baseOpts
|
|
1618
|
+
)
|
|
1619
|
+
);
|
|
1620
|
+
};
|
|
1621
|
+
|
|
779
1622
|
// src/geometry/rect.ts
|
|
780
1623
|
var ACTOR_SIZES = {
|
|
781
|
-
service: { width:
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
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 },
|
|
785
1637
|
box: { width: 100, height: 100 },
|
|
786
1638
|
caption: { width: 260, height: 56 },
|
|
787
|
-
figure: { width: 120, height: 170 }
|
|
1639
|
+
figure: { width: 120, height: 170 },
|
|
1640
|
+
parking_map: { width: 390, height: 250 },
|
|
1641
|
+
ascii_map: { width: 390, height: 250 },
|
|
1642
|
+
game_scene: { width: 390, height: 250 },
|
|
1643
|
+
byte_viz: { width: 420, height: 250 }
|
|
788
1644
|
};
|
|
789
1645
|
var DEFAULT_ACTOR_SIZE = { width: 140, height: 42 };
|
|
790
1646
|
function actorSizeByType(type) {
|
|
791
1647
|
return ACTOR_SIZES[type] ?? DEFAULT_ACTOR_SIZE;
|
|
792
1648
|
}
|
|
793
1649
|
function actorCenter(state, actorType) {
|
|
794
|
-
const
|
|
795
|
-
return { x:
|
|
1650
|
+
const rect = actorRect(state, actorType);
|
|
1651
|
+
return { x: rect.x1 + (rect.x2 - rect.x1) / 2, y: rect.y1 + (rect.y2 - rect.y1) / 2 };
|
|
796
1652
|
}
|
|
797
1653
|
function actorRect(state, actorType) {
|
|
798
1654
|
const { width, height } = actorSizeByType(actorType);
|
|
799
|
-
|
|
1655
|
+
const scale2 = Math.max(1e-3, state.scale);
|
|
1656
|
+
const scaledWidth = width * scale2;
|
|
1657
|
+
const scaledHeight = height * scale2;
|
|
1658
|
+
const dx = (scaledWidth - width) / 2;
|
|
1659
|
+
const dy = (scaledHeight - height) / 2;
|
|
1660
|
+
return {
|
|
1661
|
+
x1: state.x - dx,
|
|
1662
|
+
y1: state.y - dy,
|
|
1663
|
+
x2: state.x + width + dx,
|
|
1664
|
+
y2: state.y + height + dy
|
|
1665
|
+
};
|
|
800
1666
|
}
|
|
801
1667
|
function inflateRect(rect, pad) {
|
|
802
1668
|
return {
|
|
@@ -849,19 +1715,58 @@ function polylineLength(points) {
|
|
|
849
1715
|
}
|
|
850
1716
|
return Math.max(1, total);
|
|
851
1717
|
}
|
|
852
|
-
function
|
|
853
|
-
|
|
1718
|
+
function segmentLength(a, b) {
|
|
1719
|
+
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
1720
|
+
}
|
|
1721
|
+
function labelPointForPath(points, lane) {
|
|
1722
|
+
if (points.length < 2) return points[0] ?? { x: 0, y: 0 };
|
|
1723
|
+
let bestIndex = 0;
|
|
1724
|
+
let bestLength = -1;
|
|
854
1725
|
for (let i = 0; i < points.length - 1; i++) {
|
|
855
|
-
const
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
const t = seg <= 0 ? 0 : Math.min(1, remain / seg);
|
|
860
|
-
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
1726
|
+
const len = segmentLength(points[i], points[i + 1]);
|
|
1727
|
+
if (len > bestLength) {
|
|
1728
|
+
bestIndex = i;
|
|
1729
|
+
bestLength = len;
|
|
861
1730
|
}
|
|
862
|
-
remain -= seg;
|
|
863
1731
|
}
|
|
864
|
-
|
|
1732
|
+
const a = points[bestIndex];
|
|
1733
|
+
const b = points[bestIndex + 1];
|
|
1734
|
+
const mid = { x: (a.x + b.x) / 2, y: (a.y + b.y) / 2 };
|
|
1735
|
+
const offset = lane * 8;
|
|
1736
|
+
if (Math.abs(a.x - b.x) >= Math.abs(a.y - b.y)) {
|
|
1737
|
+
return { x: mid.x, y: mid.y - 10 - offset };
|
|
1738
|
+
}
|
|
1739
|
+
return { x: mid.x + 10 + offset, y: mid.y };
|
|
1740
|
+
}
|
|
1741
|
+
function clamp(n, min, max) {
|
|
1742
|
+
if (max < min) return n;
|
|
1743
|
+
return Math.min(max, Math.max(min, n));
|
|
1744
|
+
}
|
|
1745
|
+
function clampPointToScene(point, ast) {
|
|
1746
|
+
const pad = 14;
|
|
1747
|
+
return {
|
|
1748
|
+
x: round1(clamp(point.x, pad, ast.meta.width - pad)),
|
|
1749
|
+
y: round1(clamp(point.y, pad, ast.meta.height - pad))
|
|
1750
|
+
};
|
|
1751
|
+
}
|
|
1752
|
+
function routeLength(points) {
|
|
1753
|
+
let total = 0;
|
|
1754
|
+
for (let i = 0; i < points.length - 1; i++) total += segmentLength(points[i], points[i + 1]);
|
|
1755
|
+
return total;
|
|
1756
|
+
}
|
|
1757
|
+
function routeBends(points) {
|
|
1758
|
+
let bends = 0;
|
|
1759
|
+
for (let i = 1; i < points.length - 1; i++) {
|
|
1760
|
+
const prev = points[i - 1];
|
|
1761
|
+
const cur = points[i];
|
|
1762
|
+
const next = points[i + 1];
|
|
1763
|
+
const dx1 = Math.sign(cur.x - prev.x);
|
|
1764
|
+
const dy1 = Math.sign(cur.y - prev.y);
|
|
1765
|
+
const dx2 = Math.sign(next.x - cur.x);
|
|
1766
|
+
const dy2 = Math.sign(next.y - cur.y);
|
|
1767
|
+
if (dx1 !== dx2 || dy1 !== dy2) bends++;
|
|
1768
|
+
}
|
|
1769
|
+
return bends;
|
|
865
1770
|
}
|
|
866
1771
|
function routeFlowPath(sourceName, targetName, sourceState, targetState, states, ast, lane) {
|
|
867
1772
|
const sourceType = ast.actors[sourceName]?.type ?? "box";
|
|
@@ -898,17 +1803,25 @@ function routeFlowPath(sourceName, targetName, sourceState, targetState, states,
|
|
|
898
1803
|
[source, { x: source.x, y: topLane }, { x: target.x, y: topLane }, target],
|
|
899
1804
|
[source, { x: source.x, y: bottomLane }, { x: target.x, y: bottomLane }, target]
|
|
900
1805
|
);
|
|
1806
|
+
const minObstacleX = obstacles.length ? Math.min(...obstacles.map((o) => o.x1)) : Math.min(source.x, target.x);
|
|
1807
|
+
const maxObstacleX = obstacles.length ? Math.max(...obstacles.map((o) => o.x2)) : Math.max(source.x, target.x);
|
|
1808
|
+
const leftLane = Math.max(16, minObstacleX - 24 - lane * 12);
|
|
1809
|
+
const rightLane = Math.min(ast.meta.width - 16, maxObstacleX + 24 + lane * 12);
|
|
1810
|
+
candidates.push(
|
|
1811
|
+
[source, { x: leftLane, y: source.y }, { x: leftLane, y: target.y }, target],
|
|
1812
|
+
[source, { x: rightLane, y: source.y }, { x: rightLane, y: target.y }, target]
|
|
1813
|
+
);
|
|
901
1814
|
let best = candidates[0];
|
|
902
|
-
let
|
|
1815
|
+
let bestScore = Number.POSITIVE_INFINITY;
|
|
903
1816
|
for (const candidate of candidates) {
|
|
904
1817
|
const hits = countPathIntersections(candidate, obstacles);
|
|
905
|
-
|
|
1818
|
+
const score = hits * 1e5 + routeBends(candidate) * 800 + routeLength(candidate);
|
|
1819
|
+
if (score < bestScore) {
|
|
906
1820
|
best = candidate;
|
|
907
|
-
|
|
908
|
-
if (hits === 0) break;
|
|
1821
|
+
bestScore = score;
|
|
909
1822
|
}
|
|
910
1823
|
}
|
|
911
|
-
return best;
|
|
1824
|
+
return best.map((point) => clampPointToScene(point, ast));
|
|
912
1825
|
}
|
|
913
1826
|
|
|
914
1827
|
// src/actions/flow.ts
|
|
@@ -938,6 +1851,41 @@ function ensureEdgeLayer(scene) {
|
|
|
938
1851
|
scene.appendChild(svg);
|
|
939
1852
|
return svg;
|
|
940
1853
|
}
|
|
1854
|
+
function ensureEdgeDefs(svg) {
|
|
1855
|
+
if (svg.querySelector("defs[data-markdy-flow-defs='1']")) return;
|
|
1856
|
+
const defs = document.createElementNS("http://www.w3.org/2000/svg", "defs");
|
|
1857
|
+
defs.setAttribute("data-markdy-flow-defs", "1");
|
|
1858
|
+
const glow2 = document.createElementNS("http://www.w3.org/2000/svg", "filter");
|
|
1859
|
+
glow2.setAttribute("id", "markdy-flow-glow");
|
|
1860
|
+
glow2.setAttribute("x", "-40%");
|
|
1861
|
+
glow2.setAttribute("y", "-40%");
|
|
1862
|
+
glow2.setAttribute("width", "180%");
|
|
1863
|
+
glow2.setAttribute("height", "180%");
|
|
1864
|
+
const blur2 = document.createElementNS("http://www.w3.org/2000/svg", "feGaussianBlur");
|
|
1865
|
+
blur2.setAttribute("stdDeviation", "3");
|
|
1866
|
+
blur2.setAttribute("result", "coloredBlur");
|
|
1867
|
+
const merge = document.createElementNS("http://www.w3.org/2000/svg", "feMerge");
|
|
1868
|
+
const glowNode = document.createElementNS("http://www.w3.org/2000/svg", "feMergeNode");
|
|
1869
|
+
glowNode.setAttribute("in", "coloredBlur");
|
|
1870
|
+
const sourceNode = document.createElementNS("http://www.w3.org/2000/svg", "feMergeNode");
|
|
1871
|
+
sourceNode.setAttribute("in", "SourceGraphic");
|
|
1872
|
+
merge.append(glowNode, sourceNode);
|
|
1873
|
+
glow2.append(blur2, merge);
|
|
1874
|
+
const arrow = document.createElementNS("http://www.w3.org/2000/svg", "marker");
|
|
1875
|
+
arrow.setAttribute("id", "markdy-flow-arrow");
|
|
1876
|
+
arrow.setAttribute("viewBox", "0 0 10 10");
|
|
1877
|
+
arrow.setAttribute("refX", "8");
|
|
1878
|
+
arrow.setAttribute("refY", "5");
|
|
1879
|
+
arrow.setAttribute("markerWidth", "6");
|
|
1880
|
+
arrow.setAttribute("markerHeight", "6");
|
|
1881
|
+
arrow.setAttribute("orient", "auto-start-reverse");
|
|
1882
|
+
const arrowPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
1883
|
+
arrowPath.setAttribute("d", "M 1 1 L 9 5 L 1 9 z");
|
|
1884
|
+
arrowPath.setAttribute("fill", "context-stroke");
|
|
1885
|
+
arrow.appendChild(arrowPath);
|
|
1886
|
+
defs.append(glow2, arrow);
|
|
1887
|
+
svg.prepend(defs);
|
|
1888
|
+
}
|
|
941
1889
|
function isDashed(ctx) {
|
|
942
1890
|
const style = String(ctx.ev.params.style ?? "");
|
|
943
1891
|
return style === "dashed" || style === "fire_and_forget" || ctx.ev.action === "response";
|
|
@@ -951,38 +1899,51 @@ function buildEdge(ctx, targetName) {
|
|
|
951
1899
|
const length = polylineLength(points);
|
|
952
1900
|
const pathD = toPathD(points);
|
|
953
1901
|
const stroke = STROKE_BY_ACTION[ev.action] ?? DEFAULT_STROKE;
|
|
1902
|
+
const svg = ensureEdgeLayer(scene);
|
|
1903
|
+
ensureEdgeDefs(svg);
|
|
954
1904
|
const group = document.createElementNS("http://www.w3.org/2000/svg", "g");
|
|
955
1905
|
group.setAttribute("data-markdy-flow-edge", "1");
|
|
956
1906
|
const path = document.createElementNS("http://www.w3.org/2000/svg", "path");
|
|
957
1907
|
path.setAttribute("d", pathD);
|
|
958
1908
|
path.setAttribute("fill", "none");
|
|
959
1909
|
path.setAttribute("stroke", stroke);
|
|
960
|
-
path.setAttribute("stroke-width", "
|
|
1910
|
+
path.setAttribute("stroke-width", "3");
|
|
1911
|
+
path.setAttribute("stroke-linecap", "round");
|
|
1912
|
+
path.setAttribute("stroke-linejoin", "round");
|
|
1913
|
+
path.setAttribute("marker-end", "url(#markdy-flow-arrow)");
|
|
1914
|
+
path.setAttribute("filter", "url(#markdy-flow-glow)");
|
|
961
1915
|
path.setAttribute("data-markdy-flow-action", ev.action);
|
|
962
1916
|
path.style.strokeDasharray = isDashed(ctx) ? "8 6" : `${length}`;
|
|
963
1917
|
path.style.strokeDashoffset = `${length}`;
|
|
964
1918
|
group.appendChild(path);
|
|
965
1919
|
const marker = document.createElementNS("http://www.w3.org/2000/svg", "circle");
|
|
966
|
-
marker.setAttribute("r", "
|
|
1920
|
+
marker.setAttribute("r", "4.5");
|
|
967
1921
|
marker.setAttribute("fill", stroke);
|
|
1922
|
+
marker.setAttribute("filter", "url(#markdy-flow-glow)");
|
|
968
1923
|
marker.style.offsetPath = `path('${pathD}')`;
|
|
969
1924
|
marker.style.offsetDistance = "0%";
|
|
970
1925
|
marker.style.opacity = "0";
|
|
971
1926
|
group.appendChild(marker);
|
|
972
1927
|
const labelText = String(ev.params.label ?? "");
|
|
973
1928
|
if (labelText) {
|
|
974
|
-
const midPoint =
|
|
1929
|
+
const midPoint = labelPointForPath(points, lane);
|
|
975
1930
|
const label = document.createElementNS("http://www.w3.org/2000/svg", "text");
|
|
976
1931
|
label.setAttribute("x", `${round1(midPoint.x)}`);
|
|
977
1932
|
label.setAttribute("y", `${round1(midPoint.y - 8)}`);
|
|
978
1933
|
label.setAttribute("text-anchor", "middle");
|
|
979
1934
|
label.setAttribute("font-size", "12");
|
|
1935
|
+
label.setAttribute("font-weight", "700");
|
|
1936
|
+
label.setAttribute("paint-order", "stroke");
|
|
1937
|
+
label.setAttribute("stroke", "rgba(2, 6, 23, 0.88)");
|
|
1938
|
+
label.setAttribute("stroke-width", "5");
|
|
1939
|
+
label.setAttribute("stroke-linejoin", "round");
|
|
980
1940
|
label.setAttribute("fill", "#cbd5e1");
|
|
1941
|
+
label.setAttribute("filter", "url(#markdy-flow-glow)");
|
|
981
1942
|
label.setAttribute("data-full-label", labelText);
|
|
982
1943
|
label.textContent = labelText.length > LABEL_MAX_CHARS ? `${labelText.slice(0, LABEL_MAX_CHARS - 1)}\u2026` : labelText;
|
|
983
1944
|
group.appendChild(label);
|
|
984
1945
|
}
|
|
985
|
-
|
|
1946
|
+
svg.appendChild(group);
|
|
986
1947
|
anims.push(
|
|
987
1948
|
path.animate([{ strokeDashoffset: length }, { strokeDashoffset: 0 }], baseOpts),
|
|
988
1949
|
marker.animate(
|
|
@@ -1164,9 +2125,18 @@ var ACTION_HANDLERS = Object.freeze({
|
|
|
1164
2125
|
exit,
|
|
1165
2126
|
fade_in: fadeIn,
|
|
1166
2127
|
fade_out: fadeOut,
|
|
2128
|
+
spring,
|
|
2129
|
+
follow_path: followPath,
|
|
1167
2130
|
scale,
|
|
1168
2131
|
rotate,
|
|
1169
2132
|
shake,
|
|
2133
|
+
pulse,
|
|
2134
|
+
glow,
|
|
2135
|
+
ripple,
|
|
2136
|
+
blur,
|
|
2137
|
+
line_reveal: lineReveal,
|
|
2138
|
+
mask,
|
|
2139
|
+
parallax,
|
|
1170
2140
|
jump,
|
|
1171
2141
|
bounce,
|
|
1172
2142
|
say,
|
|
@@ -1196,7 +2166,7 @@ var DEFAULT_EASE_BY_ACTION = {
|
|
|
1196
2166
|
exit: "in",
|
|
1197
2167
|
fade_out: "in"
|
|
1198
2168
|
};
|
|
1199
|
-
function buildAnimations(ast, actorEls,
|
|
2169
|
+
function buildAnimations(ast, actorEls, actorLayer, cameraLayer, assetOverrides, faceSwaps) {
|
|
1200
2170
|
const anims = [];
|
|
1201
2171
|
const states = /* @__PURE__ */ new Map();
|
|
1202
2172
|
for (const [name, def] of Object.entries(ast.actors)) {
|
|
@@ -1222,7 +2192,7 @@ function buildAnimations(ast, actorEls, scene, assetOverrides, faceSwaps) {
|
|
|
1222
2192
|
easing: toEasing(ev.params.ease ?? DEFAULT_EASE_BY_ACTION[ev.action])
|
|
1223
2193
|
};
|
|
1224
2194
|
if (ev.actor === "camera") {
|
|
1225
|
-
buildCameraAction(ev,
|
|
2195
|
+
buildCameraAction(ev, cameraLayer, ast, baseOpts, anims, cameraState);
|
|
1226
2196
|
continue;
|
|
1227
2197
|
}
|
|
1228
2198
|
const el = actorEls.get(ev.actor);
|
|
@@ -1239,7 +2209,7 @@ function buildAnimations(ast, actorEls, scene, assetOverrides, faceSwaps) {
|
|
|
1239
2209
|
ast,
|
|
1240
2210
|
states,
|
|
1241
2211
|
actorEls,
|
|
1242
|
-
scene,
|
|
2212
|
+
scene: actorLayer,
|
|
1243
2213
|
assetOverrides,
|
|
1244
2214
|
faceSwaps,
|
|
1245
2215
|
anims,
|
|
@@ -1251,6 +2221,134 @@ function buildAnimations(ast, actorEls, scene, assetOverrides, faceSwaps) {
|
|
|
1251
2221
|
}
|
|
1252
2222
|
|
|
1253
2223
|
// src/player.ts
|
|
2224
|
+
var SCENE_STYLE_ID = "markdy-scene-ambience-styles";
|
|
2225
|
+
var SAFE_FRAME_PADDING = 28;
|
|
2226
|
+
function ensureSceneStyles(doc) {
|
|
2227
|
+
if (doc.getElementById(SCENE_STYLE_ID)) return;
|
|
2228
|
+
const style = doc.createElement("style");
|
|
2229
|
+
style.id = SCENE_STYLE_ID;
|
|
2230
|
+
style.textContent = `
|
|
2231
|
+
.markdy-scene-root {
|
|
2232
|
+
--markdy-scene-grid: rgba(148, 163, 184, 0.13);
|
|
2233
|
+
--markdy-scene-grid-strong: rgba(148, 163, 184, 0.2);
|
|
2234
|
+
--markdy-scene-vignette: rgba(2, 6, 23, 0.72);
|
|
2235
|
+
--markdy-scene-accent: rgba(56, 189, 248, 0.16);
|
|
2236
|
+
isolation: isolate;
|
|
2237
|
+
}
|
|
2238
|
+
.markdy-scene-root::before,
|
|
2239
|
+
.markdy-scene-root::after {
|
|
2240
|
+
content: "";
|
|
2241
|
+
position: absolute;
|
|
2242
|
+
inset: 0;
|
|
2243
|
+
pointer-events: none;
|
|
2244
|
+
}
|
|
2245
|
+
.markdy-scene-root::before {
|
|
2246
|
+
z-index: 0;
|
|
2247
|
+
background:
|
|
2248
|
+
linear-gradient(var(--markdy-scene-grid) 1px, transparent 1px) 0 0 / 32px 32px,
|
|
2249
|
+
linear-gradient(90deg, var(--markdy-scene-grid) 1px, transparent 1px) 0 0 / 32px 32px,
|
|
2250
|
+
linear-gradient(var(--markdy-scene-grid-strong) 1px, transparent 1px) 0 0 / 160px 160px,
|
|
2251
|
+
linear-gradient(90deg, var(--markdy-scene-grid-strong) 1px, transparent 1px) 0 0 / 160px 160px;
|
|
2252
|
+
mask-image: linear-gradient(to bottom, transparent, #000 10%, #000 90%, transparent);
|
|
2253
|
+
opacity: 0.82;
|
|
2254
|
+
}
|
|
2255
|
+
.markdy-scene-root::after {
|
|
2256
|
+
z-index: 1;
|
|
2257
|
+
background:
|
|
2258
|
+
radial-gradient(ellipse at 50% 0%, var(--markdy-scene-accent), transparent 42%),
|
|
2259
|
+
linear-gradient(180deg, transparent 0%, rgba(2, 6, 23, 0.08) 58%, var(--markdy-scene-vignette) 100%),
|
|
2260
|
+
linear-gradient(90deg, rgba(255, 255, 255, 0.035), transparent 18%, transparent 82%, rgba(255, 255, 255, 0.035));
|
|
2261
|
+
mix-blend-mode: screen;
|
|
2262
|
+
opacity: 0.8;
|
|
2263
|
+
}
|
|
2264
|
+
.markdy-scene-root[data-markdy-scene-tone="light"] {
|
|
2265
|
+
--markdy-scene-grid: rgba(15, 23, 42, 0.09);
|
|
2266
|
+
--markdy-scene-grid-strong: rgba(15, 23, 42, 0.14);
|
|
2267
|
+
--markdy-scene-vignette: rgba(241, 245, 249, 0.74);
|
|
2268
|
+
--markdy-scene-accent: rgba(14, 165, 233, 0.12);
|
|
2269
|
+
}
|
|
2270
|
+
.markdy-scene-content {
|
|
2271
|
+
z-index: 2;
|
|
2272
|
+
}
|
|
2273
|
+
.markdy-scene-actor-layer {
|
|
2274
|
+
position: absolute;
|
|
2275
|
+
inset: 0;
|
|
2276
|
+
overflow: visible;
|
|
2277
|
+
transform-origin: 0 0;
|
|
2278
|
+
will-change: transform;
|
|
2279
|
+
}
|
|
2280
|
+
`;
|
|
2281
|
+
doc.head.appendChild(style);
|
|
2282
|
+
}
|
|
2283
|
+
function unionRect(a, b) {
|
|
2284
|
+
if (!a) return b;
|
|
2285
|
+
return {
|
|
2286
|
+
x1: Math.min(a.x1, b.x1),
|
|
2287
|
+
y1: Math.min(a.y1, b.y1),
|
|
2288
|
+
x2: Math.max(a.x2, b.x2),
|
|
2289
|
+
y2: Math.max(a.y2, b.y2)
|
|
2290
|
+
};
|
|
2291
|
+
}
|
|
2292
|
+
function numericPair(value) {
|
|
2293
|
+
if (!Array.isArray(value) || value.length < 2) return null;
|
|
2294
|
+
const [x, y] = value;
|
|
2295
|
+
return typeof x === "number" && typeof y === "number" ? [x, y] : null;
|
|
2296
|
+
}
|
|
2297
|
+
function computeContentBounds(ast) {
|
|
2298
|
+
let bounds = null;
|
|
2299
|
+
const maxScaleByActor = /* @__PURE__ */ new Map();
|
|
2300
|
+
const positionsByActor = /* @__PURE__ */ new Map();
|
|
2301
|
+
for (const [name, def] of Object.entries(ast.actors)) {
|
|
2302
|
+
maxScaleByActor.set(name, Math.max(1e-3, def.scale ?? 1));
|
|
2303
|
+
positionsByActor.set(name, [[def.x, def.y]]);
|
|
2304
|
+
}
|
|
2305
|
+
for (const ev of ast.events) {
|
|
2306
|
+
if (ev.actor === "camera") continue;
|
|
2307
|
+
if (ev.action === "scale" && typeof ev.params.to === "number") {
|
|
2308
|
+
maxScaleByActor.set(ev.actor, Math.max(maxScaleByActor.get(ev.actor) ?? 1, ev.params.to));
|
|
2309
|
+
}
|
|
2310
|
+
if (ev.action === "move" || ev.action === "spring") {
|
|
2311
|
+
const to = numericPair(ev.params.to);
|
|
2312
|
+
if (to) positionsByActor.get(ev.actor)?.push(to);
|
|
2313
|
+
}
|
|
2314
|
+
}
|
|
2315
|
+
for (const [name, def] of Object.entries(ast.actors)) {
|
|
2316
|
+
const positions = positionsByActor.get(name) ?? [[def.x, def.y]];
|
|
2317
|
+
const scale2 = maxScaleByActor.get(name) ?? def.scale ?? 1;
|
|
2318
|
+
for (const [x, y] of positions) {
|
|
2319
|
+
bounds = unionRect(bounds, actorRect({ ...stateFrom(def), x, y, scale: scale2 }, def.type));
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
return bounds;
|
|
2323
|
+
}
|
|
2324
|
+
function computeSafeFrame(ast) {
|
|
2325
|
+
const bounds = computeContentBounds(ast);
|
|
2326
|
+
if (!bounds) return { x: 0, y: 0, scale: 1 };
|
|
2327
|
+
const boundsWidth = Math.max(1, bounds.x2 - bounds.x1);
|
|
2328
|
+
const boundsHeight = Math.max(1, bounds.y2 - bounds.y1);
|
|
2329
|
+
const availableWidth = Math.max(1, ast.meta.width - SAFE_FRAME_PADDING * 2);
|
|
2330
|
+
const availableHeight = Math.max(1, ast.meta.height - SAFE_FRAME_PADDING * 2);
|
|
2331
|
+
const scale2 = Math.min(1, availableWidth / boundsWidth, availableHeight / boundsHeight);
|
|
2332
|
+
const scaledWidth = boundsWidth * scale2;
|
|
2333
|
+
const scaledHeight = boundsHeight * scale2;
|
|
2334
|
+
function axisOffset(min, max, sceneSize, scaledSize) {
|
|
2335
|
+
const paddedMin = SAFE_FRAME_PADDING;
|
|
2336
|
+
const paddedMax = sceneSize - SAFE_FRAME_PADDING;
|
|
2337
|
+
const scaledMin = min * scale2;
|
|
2338
|
+
const scaledMax = max * scale2;
|
|
2339
|
+
if (scaledSize > paddedMax - paddedMin) return (sceneSize - scaledSize) / 2 - scaledMin;
|
|
2340
|
+
if (scaledMin < paddedMin) return paddedMin - scaledMin;
|
|
2341
|
+
if (scaledMax > paddedMax) return paddedMax - scaledMax;
|
|
2342
|
+
return 0;
|
|
2343
|
+
}
|
|
2344
|
+
const x = axisOffset(bounds.x1, bounds.x2, ast.meta.width, scaledWidth);
|
|
2345
|
+
const y = axisOffset(bounds.y1, bounds.y2, ast.meta.height, scaledHeight);
|
|
2346
|
+
return {
|
|
2347
|
+
x: Math.round(x * 1e3) / 1e3,
|
|
2348
|
+
y: Math.round(y * 1e3) / 1e3,
|
|
2349
|
+
scale: Math.round(scale2 * 1e3) / 1e3
|
|
2350
|
+
};
|
|
2351
|
+
}
|
|
1254
2352
|
function bgToTextColor(bg) {
|
|
1255
2353
|
let hex = bg.trim().replace(/^#/, "");
|
|
1256
2354
|
if (hex.length === 3) hex = hex[0] + hex[0] + hex[1] + hex[1] + hex[2] + hex[2];
|
|
@@ -1350,6 +2448,9 @@ function createPlayer(opts) {
|
|
|
1350
2448
|
}
|
|
1351
2449
|
}
|
|
1352
2450
|
const scene = document.createElement("div");
|
|
2451
|
+
ensureSceneStyles(document);
|
|
2452
|
+
scene.className = "markdy-scene-root";
|
|
2453
|
+
scene.dataset.markdySceneTone = bgToTextColor(ast.meta.bg) === "#1a1a1a" ? "light" : "dark";
|
|
1353
2454
|
Object.assign(scene.style, {
|
|
1354
2455
|
position: "absolute",
|
|
1355
2456
|
top: "0",
|
|
@@ -1364,6 +2465,7 @@ function createPlayer(opts) {
|
|
|
1364
2465
|
});
|
|
1365
2466
|
viewport.appendChild(scene);
|
|
1366
2467
|
const sceneContent = document.createElement("div");
|
|
2468
|
+
sceneContent.className = "markdy-scene-content";
|
|
1367
2469
|
Object.assign(sceneContent.style, {
|
|
1368
2470
|
position: "absolute",
|
|
1369
2471
|
top: "0",
|
|
@@ -1374,6 +2476,12 @@ function createPlayer(opts) {
|
|
|
1374
2476
|
willChange: "transform"
|
|
1375
2477
|
});
|
|
1376
2478
|
scene.appendChild(sceneContent);
|
|
2479
|
+
const actorLayer = document.createElement("div");
|
|
2480
|
+
actorLayer.className = "markdy-scene-actor-layer";
|
|
2481
|
+
const safeFrame = computeSafeFrame(ast);
|
|
2482
|
+
actorLayer.dataset.markdySafeFrame = `${safeFrame.x},${safeFrame.y},${safeFrame.scale}`;
|
|
2483
|
+
actorLayer.style.transform = `translate(${safeFrame.x}px, ${safeFrame.y}px) scale(${safeFrame.scale})`;
|
|
2484
|
+
sceneContent.appendChild(actorLayer);
|
|
1377
2485
|
function scaleScene() {
|
|
1378
2486
|
const s = viewport.clientWidth / ast.meta.width;
|
|
1379
2487
|
scene.style.transform = `scale(${s})`;
|
|
@@ -1384,11 +2492,11 @@ function createPlayer(opts) {
|
|
|
1384
2492
|
const actorEls = /* @__PURE__ */ new Map();
|
|
1385
2493
|
for (const [name, def] of Object.entries(ast.actors)) {
|
|
1386
2494
|
const el = createActorEl(name, def, ast.assets, assetOverrides);
|
|
1387
|
-
|
|
2495
|
+
actorLayer.appendChild(el);
|
|
1388
2496
|
actorEls.set(name, el);
|
|
1389
2497
|
}
|
|
1390
2498
|
const faceSwaps = [];
|
|
1391
|
-
const allAnims = buildAnimations(ast, actorEls, sceneContent, assetOverrides, faceSwaps);
|
|
2499
|
+
const allAnims = buildAnimations(ast, actorEls, actorLayer, sceneContent, assetOverrides, faceSwaps);
|
|
1392
2500
|
faceSwaps.sort((a, b) => a.timeMs - b.timeMs);
|
|
1393
2501
|
for (const anim of allAnims) {
|
|
1394
2502
|
anim.pause();
|