@brett_lamy/docstream 1.9.1 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. package/README.md +54 -0
  2. package/dist/docs/DocsRenderer.d.ts.map +1 -1
  3. package/dist/docs/DocsRenderer.js +13 -1
  4. package/dist/docs/DocsRenderer.js.map +1 -1
  5. package/dist/index.d.ts +5 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +3 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/stl/StlViewer.d.ts +13 -0
  10. package/dist/stl/StlViewer.d.ts.map +1 -0
  11. package/dist/stl/StlViewer.js +277 -0
  12. package/dist/stl/StlViewer.js.map +1 -0
  13. package/dist/stl/index.d.ts +5 -0
  14. package/dist/stl/index.d.ts.map +1 -0
  15. package/dist/stl/index.js +3 -0
  16. package/dist/stl/index.js.map +1 -0
  17. package/dist/stl/parse.d.ts +13 -0
  18. package/dist/stl/parse.d.ts.map +1 -0
  19. package/dist/stl/parse.js +69 -0
  20. package/dist/stl/parse.js.map +1 -0
  21. package/dist/strudel/StepGrid.d.ts +10 -0
  22. package/dist/strudel/StepGrid.d.ts.map +1 -0
  23. package/dist/strudel/StepGrid.js +78 -0
  24. package/dist/strudel/StepGrid.js.map +1 -0
  25. package/dist/strudel/StrudelPlayer.d.ts +21 -0
  26. package/dist/strudel/StrudelPlayer.d.ts.map +1 -0
  27. package/dist/strudel/StrudelPlayer.js +207 -0
  28. package/dist/strudel/StrudelPlayer.js.map +1 -0
  29. package/dist/strudel/StrudelRack.d.ts +24 -0
  30. package/dist/strudel/StrudelRack.d.ts.map +1 -0
  31. package/dist/strudel/StrudelRack.js +123 -0
  32. package/dist/strudel/StrudelRack.js.map +1 -0
  33. package/dist/strudel/ast/edit.d.ts +41 -0
  34. package/dist/strudel/ast/edit.d.ts.map +1 -0
  35. package/dist/strudel/ast/edit.js +78 -0
  36. package/dist/strudel/ast/edit.js.map +1 -0
  37. package/dist/strudel/ast/index.d.ts +7 -0
  38. package/dist/strudel/ast/index.d.ts.map +1 -0
  39. package/dist/strudel/ast/index.js +4 -0
  40. package/dist/strudel/ast/index.js.map +1 -0
  41. package/dist/strudel/ast/mini.d.ts +86 -0
  42. package/dist/strudel/ast/mini.d.ts.map +1 -0
  43. package/dist/strudel/ast/mini.js +269 -0
  44. package/dist/strudel/ast/mini.js.map +1 -0
  45. package/dist/strudel/ast/program.d.ts +93 -0
  46. package/dist/strudel/ast/program.d.ts.map +1 -0
  47. package/dist/strudel/ast/program.js +288 -0
  48. package/dist/strudel/ast/program.js.map +1 -0
  49. package/dist/strudel/controls.d.ts +19 -0
  50. package/dist/strudel/controls.d.ts.map +1 -0
  51. package/dist/strudel/controls.js +109 -0
  52. package/dist/strudel/controls.js.map +1 -0
  53. package/dist/strudel/engine.d.ts +43 -0
  54. package/dist/strudel/engine.d.ts.map +1 -0
  55. package/dist/strudel/engine.js +79 -0
  56. package/dist/strudel/engine.js.map +1 -0
  57. package/dist/strudel/index.d.ts +13 -0
  58. package/dist/strudel/index.d.ts.map +1 -0
  59. package/dist/strudel/index.js +8 -0
  60. package/dist/strudel/index.js.map +1 -0
  61. package/dist/strudel/url.d.ts +5 -0
  62. package/dist/strudel/url.d.ts.map +1 -0
  63. package/dist/strudel/url.js +9 -0
  64. package/dist/strudel/url.js.map +1 -0
  65. package/dist/styles.css +564 -0
  66. package/package.json +15 -1
  67. package/src/docs/DocsRenderer.tsx +13 -1
  68. package/src/env.d.ts +3 -0
  69. package/src/index.ts +5 -0
  70. package/src/stl/StlViewer.tsx +334 -0
  71. package/src/stl/index.ts +4 -0
  72. package/src/stl/parse.ts +72 -0
  73. package/src/strudel/StepGrid.tsx +130 -0
  74. package/src/strudel/StrudelPlayer.tsx +317 -0
  75. package/src/strudel/StrudelRack.tsx +312 -0
  76. package/src/strudel/ast/edit.ts +95 -0
  77. package/src/strudel/ast/index.ts +19 -0
  78. package/src/strudel/ast/mini.ts +319 -0
  79. package/src/strudel/ast/program.ts +348 -0
  80. package/src/strudel/controls.tsx +145 -0
  81. package/src/strudel/engine.ts +112 -0
  82. package/src/strudel/index.ts +20 -0
  83. package/src/strudel/url.ts +9 -0
  84. package/src/styles.css +564 -0
package/dist/styles.css CHANGED
@@ -450,6 +450,570 @@
450
450
  border-radius: 12px;
451
451
  }
452
452
 
453
+ /* StlViewer: a WebGL preview of an .stl model ({% embed url="part.stl" %}). The model takes
454
+ its color from `color`, so it follows the theme's primary. */
455
+ .docstream-stl,
456
+ .docstream-strudel {
457
+ margin: 0;
458
+ display: flex;
459
+ flex-direction: column;
460
+ gap: 6px;
461
+ }
462
+
463
+ .docstream-stl__stage {
464
+ position: relative;
465
+ aspect-ratio: 16 / 9;
466
+ border: 1px solid var(--gb-border);
467
+ border-radius: 12px;
468
+ overflow: hidden;
469
+ color: var(--gb-primary, #6366f1);
470
+ background:
471
+ radial-gradient(circle at 50% 40%, color-mix(in srgb, var(--gb-muted, #f4f4f5) 40%, transparent), transparent 70%),
472
+ var(--gb-muted, #f4f4f5);
473
+ }
474
+
475
+ .docstream-stl__canvas {
476
+ display: block;
477
+ width: 100%;
478
+ height: 100%;
479
+ cursor: grab;
480
+ touch-action: none;
481
+ }
482
+
483
+ .docstream-stl__canvas:active {
484
+ cursor: grabbing;
485
+ }
486
+
487
+ .docstream-stl__canvas:focus-visible {
488
+ outline: 2px solid var(--gb-primary, #6366f1);
489
+ outline-offset: -2px;
490
+ border-radius: 12px;
491
+ }
492
+
493
+ .docstream-stl__status {
494
+ display: grid;
495
+ place-items: center;
496
+ height: 100%;
497
+ padding: 16px;
498
+ text-align: center;
499
+ font-size: 13px;
500
+ color: var(--gb-muted-foreground);
501
+ }
502
+
503
+ .docstream-stl__reset {
504
+ position: absolute;
505
+ top: 8px;
506
+ right: 8px;
507
+ padding: 3px 10px;
508
+ border: 1px solid var(--gb-border);
509
+ border-radius: 999px;
510
+ background: var(--gb-panel, #fff);
511
+ color: var(--gb-panel-foreground, inherit);
512
+ font: inherit;
513
+ font-size: 12px;
514
+ cursor: pointer;
515
+ opacity: 0.85;
516
+ }
517
+
518
+ .docstream-stl__reset:hover {
519
+ opacity: 1;
520
+ background: var(--gb-hover, var(--gb-accent));
521
+ }
522
+
523
+ .docstream-stl__caption {
524
+ display: flex;
525
+ flex-wrap: wrap;
526
+ justify-content: space-between;
527
+ gap: 4px 12px;
528
+ font-size: 12px;
529
+ color: var(--gb-muted-foreground);
530
+ }
531
+
532
+ .docstream-stl__caption a {
533
+ color: inherit;
534
+ font-weight: 500;
535
+ }
536
+
537
+ /* StrudelPlayer: a Strudel pattern as an audio player (```strudel fences, .strudel embeds). */
538
+ .docstream-strudel__bar {
539
+ display: flex;
540
+ align-items: center;
541
+ gap: 12px;
542
+ padding: 10px 12px;
543
+ border: 1px solid var(--gb-border);
544
+ border-radius: 12px;
545
+ background: var(--gb-panel, #fff);
546
+ color: var(--gb-panel-foreground, inherit);
547
+ }
548
+
549
+ .docstream-strudel__play {
550
+ flex: none;
551
+ display: grid;
552
+ place-items: center;
553
+ width: 40px;
554
+ height: 40px;
555
+ border: 0;
556
+ border-radius: 999px;
557
+ background: var(--gb-primary, #6366f1);
558
+ color: var(--gb-primary-foreground, #fff);
559
+ cursor: pointer;
560
+ }
561
+
562
+ .docstream-strudel__play:disabled {
563
+ opacity: 0.5;
564
+ cursor: default;
565
+ }
566
+
567
+ .docstream-strudel__play:focus-visible,
568
+ .docstream-strudel__toggle:focus-visible {
569
+ outline: 2px solid var(--gb-primary, #6366f1);
570
+ outline-offset: 2px;
571
+ }
572
+
573
+ .docstream-strudel__spin {
574
+ animation: docstream-strudel-spin 0.9s linear infinite;
575
+ }
576
+
577
+ @keyframes docstream-strudel-spin {
578
+ to {
579
+ transform: rotate(360deg);
580
+ }
581
+ }
582
+
583
+ .docstream-strudel__meta {
584
+ display: flex;
585
+ flex-direction: column;
586
+ min-width: 0;
587
+ flex: 0 1 auto;
588
+ max-width: 40%;
589
+ }
590
+
591
+ .docstream-strudel__title {
592
+ font-weight: 600;
593
+ font-size: 14px;
594
+ overflow: hidden;
595
+ text-overflow: ellipsis;
596
+ white-space: nowrap;
597
+ }
598
+
599
+ .docstream-strudel__sub {
600
+ font-size: 12px;
601
+ color: var(--gb-muted-foreground);
602
+ font-variant-numeric: tabular-nums;
603
+ }
604
+
605
+ .docstream-strudel__roll {
606
+ flex: 1 1 auto;
607
+ min-width: 60px;
608
+ height: 40px;
609
+ color: var(--gb-primary, #6366f1);
610
+ }
611
+
612
+ .docstream-strudel__toggle {
613
+ flex: none;
614
+ display: grid;
615
+ place-items: center;
616
+ width: 32px;
617
+ height: 32px;
618
+ border: 1px solid var(--gb-border);
619
+ border-radius: 8px;
620
+ background: transparent;
621
+ color: var(--gb-muted-foreground);
622
+ cursor: pointer;
623
+ }
624
+
625
+ .docstream-strudel__toggle[aria-expanded="true"],
626
+ .docstream-strudel__toggle:hover {
627
+ background: var(--gb-hover, var(--gb-accent));
628
+ color: inherit;
629
+ }
630
+
631
+ .docstream-strudel__error {
632
+ font-size: 12px;
633
+ color: var(--gb-danger, #dc2626);
634
+ white-space: pre-wrap;
635
+ }
636
+
637
+ .docstream-strudel__code {
638
+ border: 1px solid var(--gb-border);
639
+ border-radius: 12px;
640
+ background: var(--gb-code-bg);
641
+ color: var(--gb-code-fg);
642
+ padding: 12px 14px;
643
+ overflow-x: auto;
644
+ font-size: 13px;
645
+ white-space: pre;
646
+ }
647
+
648
+ /* StrudelRack: equipment generated from the code — a master strip, then one device per track. */
649
+ .docstream-strudel__revert {
650
+ align-self: flex-start;
651
+ display: inline-flex;
652
+ align-items: center;
653
+ gap: 4px;
654
+ padding: 2px 8px;
655
+ border: 1px solid var(--gb-border);
656
+ border-radius: 999px;
657
+ background: transparent;
658
+ color: var(--gb-muted-foreground);
659
+ font: inherit;
660
+ font-size: 12px;
661
+ cursor: pointer;
662
+ }
663
+
664
+ .strudel-rack {
665
+ --strudel-accent: var(--gb-primary, #6366f1);
666
+ display: flex;
667
+ flex-direction: column;
668
+ gap: 8px;
669
+ padding: 10px;
670
+ border: 1px solid var(--gb-border);
671
+ border-radius: 12px;
672
+ background: var(--gb-muted, #f4f4f5);
673
+ font-size: 12px;
674
+ }
675
+
676
+ .strudel-rack__master {
677
+ display: flex;
678
+ align-items: center;
679
+ gap: 14px;
680
+ padding: 4px 6px;
681
+ }
682
+
683
+ .strudel-rack__title {
684
+ font-weight: 600;
685
+ font-size: 13px;
686
+ }
687
+
688
+ .strudel-rack__summary {
689
+ margin-left: auto;
690
+ color: var(--gb-muted-foreground);
691
+ }
692
+
693
+ .strudel-rack__error,
694
+ .strudel-device__error {
695
+ margin: 0;
696
+ color: var(--gb-danger, #dc2626);
697
+ font-size: 12px;
698
+ }
699
+
700
+ .strudel-device {
701
+ border: 1px solid var(--gb-border);
702
+ border-radius: 10px;
703
+ background: var(--gb-panel, #fff);
704
+ color: var(--gb-panel-foreground, inherit);
705
+ overflow: hidden;
706
+ }
707
+
708
+ .strudel-device[data-audible="false"] .strudel-device__body {
709
+ opacity: 0.45;
710
+ }
711
+
712
+ .strudel-device__head {
713
+ display: flex;
714
+ align-items: center;
715
+ gap: 8px;
716
+ padding: 6px 8px 6px 10px;
717
+ border-bottom: 1px solid var(--gb-border);
718
+ color: var(--gb-muted-foreground);
719
+ }
720
+
721
+ .strudel-device[data-kind="drums"] .strudel-device__head svg { color: #f59e0b; }
722
+ .strudel-device[data-kind="melodic"] .strudel-device__head svg { color: var(--strudel-accent); }
723
+
724
+ .strudel-device__name {
725
+ flex: 1;
726
+ min-width: 0;
727
+ overflow: hidden;
728
+ text-overflow: ellipsis;
729
+ white-space: nowrap;
730
+ font-weight: 600;
731
+ color: var(--gb-panel-foreground, inherit);
732
+ }
733
+
734
+ .strudel-device__toggle {
735
+ width: 22px;
736
+ height: 22px;
737
+ border: 1px solid var(--gb-border);
738
+ border-radius: 5px;
739
+ background: transparent;
740
+ color: var(--gb-muted-foreground);
741
+ font: inherit;
742
+ font-size: 11px;
743
+ font-weight: 700;
744
+ cursor: pointer;
745
+ }
746
+
747
+ .strudel-device__toggle[data-kind="mute"][aria-pressed="true"] { background: #f59e0b; border-color: #f59e0b; color: #000; }
748
+ .strudel-device__toggle[data-kind="solo"][aria-pressed="true"] { background: var(--strudel-accent); border-color: var(--strudel-accent); color: var(--gb-primary-foreground, #fff); }
749
+
750
+ .strudel-device__body {
751
+ display: flex;
752
+ gap: 12px;
753
+ padding: 10px;
754
+ }
755
+
756
+ .strudel-device__main {
757
+ flex: 1;
758
+ min-width: 0;
759
+ display: flex;
760
+ flex-direction: column;
761
+ gap: 8px;
762
+ }
763
+
764
+ .strudel-device__selects {
765
+ display: flex;
766
+ flex-wrap: wrap;
767
+ gap: 6px 14px;
768
+ }
769
+
770
+ .strudel-device__selects label {
771
+ display: inline-flex;
772
+ align-items: center;
773
+ gap: 6px;
774
+ color: var(--gb-muted-foreground);
775
+ }
776
+
777
+ .strudel-device__selects select,
778
+ .strudel-device__add select {
779
+ font: inherit;
780
+ font-size: 12px;
781
+ padding: 2px 4px;
782
+ border: 1px solid var(--gb-border);
783
+ border-radius: 6px;
784
+ background: var(--gb-panel, #fff);
785
+ color: var(--gb-panel-foreground, inherit);
786
+ }
787
+
788
+ .strudel-device__knobs {
789
+ display: flex;
790
+ flex-wrap: wrap;
791
+ align-items: flex-start;
792
+ gap: 4px 10px;
793
+ }
794
+
795
+ .strudel-device__knob {
796
+ position: relative;
797
+ }
798
+
799
+ .strudel-device__remove {
800
+ position: absolute;
801
+ top: -2px;
802
+ right: -4px;
803
+ display: none;
804
+ place-items: center;
805
+ width: 14px;
806
+ height: 14px;
807
+ padding: 0;
808
+ border: 0;
809
+ border-radius: 999px;
810
+ background: var(--gb-muted-foreground);
811
+ color: var(--gb-panel, #fff);
812
+ cursor: pointer;
813
+ }
814
+
815
+ .strudel-device__knob:hover .strudel-device__remove,
816
+ .strudel-device__remove:focus-visible {
817
+ display: grid;
818
+ }
819
+
820
+ .strudel-device__add {
821
+ display: inline-flex;
822
+ align-items: center;
823
+ gap: 4px;
824
+ align-self: center;
825
+ color: var(--gb-muted-foreground);
826
+ }
827
+
828
+ .strudel-knob {
829
+ display: flex;
830
+ flex-direction: column;
831
+ align-items: center;
832
+ width: 52px;
833
+ user-select: none;
834
+ }
835
+
836
+ .strudel-knob__dial {
837
+ width: 38px;
838
+ height: 38px;
839
+ border-radius: 999px;
840
+ cursor: ns-resize;
841
+ touch-action: none;
842
+ }
843
+
844
+ .strudel-knob__dial:focus-visible,
845
+ .strudel-fader__track:focus-visible {
846
+ outline: 2px solid var(--strudel-accent, #6366f1);
847
+ outline-offset: 2px;
848
+ }
849
+
850
+ .strudel-knob__dial svg { width: 100%; height: 100%; display: block; }
851
+ .strudel-knob__track { fill: none; stroke: var(--gb-border); stroke-width: 3; stroke-linecap: round; }
852
+ .strudel-knob__fill { fill: none; stroke: var(--strudel-accent, #6366f1); stroke-width: 3; stroke-linecap: round; }
853
+ .strudel-knob__cap { fill: var(--gb-muted, #f4f4f5); stroke: var(--gb-border); }
854
+ .strudel-knob__pointer { stroke: var(--gb-panel-foreground, #18181b); stroke-width: 2; stroke-linecap: round; }
855
+
856
+ .strudel-knob__value,
857
+ .strudel-fader__value {
858
+ font-variant-numeric: tabular-nums;
859
+ font-size: 11px;
860
+ line-height: 1.3;
861
+ }
862
+
863
+ .strudel-knob__label,
864
+ .strudel-fader__label {
865
+ font-size: 10px;
866
+ color: var(--gb-muted-foreground);
867
+ text-transform: uppercase;
868
+ letter-spacing: 0.04em;
869
+ white-space: nowrap;
870
+ }
871
+
872
+ .strudel-knob[data-disabled] .strudel-knob__dial,
873
+ .strudel-fader[data-disabled] .strudel-fader__track {
874
+ cursor: not-allowed;
875
+ opacity: 0.6;
876
+ }
877
+
878
+ .strudel-fader {
879
+ display: flex;
880
+ flex-direction: column;
881
+ align-items: center;
882
+ gap: 4px;
883
+ width: 36px;
884
+ user-select: none;
885
+ }
886
+
887
+ .strudel-fader__track {
888
+ position: relative;
889
+ width: 8px;
890
+ height: 90px;
891
+ border-radius: 999px;
892
+ background: var(--gb-border);
893
+ cursor: ns-resize;
894
+ touch-action: none;
895
+ }
896
+
897
+ .strudel-fader__fill {
898
+ position: absolute;
899
+ inset: auto 0 0;
900
+ border-radius: 999px;
901
+ background: var(--strudel-accent, #6366f1);
902
+ }
903
+
904
+ .strudel-fader__thumb {
905
+ position: absolute;
906
+ left: -6px;
907
+ width: 20px;
908
+ height: 10px;
909
+ border-radius: 3px;
910
+ background: var(--gb-panel, #fff);
911
+ border: 1px solid var(--gb-muted-foreground);
912
+ box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);
913
+ }
914
+
915
+ /* StepGrid: mini-notation as a step sequencer. */
916
+ .strudel-steps {
917
+ display: flex;
918
+ flex-direction: column;
919
+ gap: 4px;
920
+ padding-top: 6px;
921
+ overflow-x: auto;
922
+ }
923
+
924
+ .strudel-step__layers {
925
+ display: flex;
926
+ flex-direction: column;
927
+ gap: 3px;
928
+ flex: 1;
929
+ }
930
+
931
+ .strudel-step__row {
932
+ display: flex;
933
+ gap: 3px;
934
+ min-width: 0;
935
+ }
936
+
937
+ .strudel-step {
938
+ position: relative;
939
+ flex: 1 1 0;
940
+ min-width: 18px;
941
+ display: flex;
942
+ }
943
+
944
+ .strudel-step__cell,
945
+ .strudel-step__input {
946
+ flex: 1;
947
+ min-width: 0;
948
+ height: 26px;
949
+ padding: 0 3px;
950
+ border: 1px solid var(--gb-border);
951
+ border-radius: 5px;
952
+ font: inherit;
953
+ font-size: 11px;
954
+ font-family: var(--gb-mono, ui-monospace, SFMono-Regular, Menlo, monospace);
955
+ overflow: hidden;
956
+ text-overflow: ellipsis;
957
+ white-space: nowrap;
958
+ }
959
+
960
+ .strudel-step__cell {
961
+ background: color-mix(in srgb, var(--strudel-accent, #6366f1) 22%, var(--gb-panel, #fff));
962
+ color: var(--gb-panel-foreground, inherit);
963
+ cursor: pointer;
964
+ }
965
+
966
+ .strudel-device[data-kind="drums"] .strudel-step__cell:not([data-rest]) {
967
+ background: color-mix(in srgb, #f59e0b 30%, var(--gb-panel, #fff));
968
+ }
969
+
970
+ .strudel-step__cell[data-rest] {
971
+ background: transparent;
972
+ border-style: dashed;
973
+ }
974
+
975
+ .strudel-step__cell:hover {
976
+ border-color: var(--strudel-accent, #6366f1);
977
+ }
978
+
979
+ .strudel-step__input {
980
+ background: var(--gb-panel, #fff);
981
+ color: inherit;
982
+ }
983
+
984
+ .strudel-step__nest {
985
+ flex: 1;
986
+ display: flex;
987
+ padding: 2px;
988
+ border: 1px solid var(--gb-border);
989
+ border-radius: 6px;
990
+ }
991
+
992
+ .strudel-step__nest > .strudel-step__row {
993
+ flex: 1;
994
+ }
995
+
996
+ .strudel-step__nest[data-kind="alternation"] {
997
+ border-style: dashed;
998
+ }
999
+
1000
+ .strudel-step__nest[data-kind="alternation"] > .strudel-step__layers > .strudel-step__row {
1001
+ flex-wrap: wrap;
1002
+ }
1003
+
1004
+ .strudel-step__badge {
1005
+ position: absolute;
1006
+ top: -6px;
1007
+ right: 2px;
1008
+ padding: 0 3px;
1009
+ border-radius: 4px;
1010
+ background: var(--gb-panel-foreground, #18181b);
1011
+ color: var(--gb-panel, #fff);
1012
+ font-size: 9px;
1013
+ line-height: 12px;
1014
+ pointer-events: none;
1015
+ }
1016
+
453
1017
  .docs-content-ref {
454
1018
  display: flex !important;
455
1019
  align-items: center;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brett_lamy/docstream",
3
- "version": "1.9.1",
3
+ "version": "1.11.0",
4
4
  "description": "GitBook-aware readonly markdown and AI stream renderer.",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -94,6 +94,18 @@
94
94
  "import": "./dist/video/index.js",
95
95
  "default": "./dist/video/index.js"
96
96
  },
97
+ "./stl": {
98
+ "source": "./src/stl/index.ts",
99
+ "types": "./dist/stl/index.d.ts",
100
+ "import": "./dist/stl/index.js",
101
+ "default": "./dist/stl/index.js"
102
+ },
103
+ "./strudel": {
104
+ "source": "./src/strudel/index.ts",
105
+ "types": "./dist/strudel/index.d.ts",
106
+ "import": "./dist/strudel/index.js",
107
+ "default": "./dist/strudel/index.js"
108
+ },
97
109
  "./viz": {
98
110
  "source": "./src/viz/index.ts",
99
111
  "types": "./dist/viz/index.d.ts",
@@ -127,6 +139,8 @@
127
139
  "./styles.css": "./dist/styles.css"
128
140
  },
129
141
  "dependencies": {
142
+ "@strudel/web": "1.3.0",
143
+ "acorn": "^8.15.0",
130
144
  "framer-motion": "^13.1.1",
131
145
  "gpu-lexer": "^0.0.2",
132
146
  "katex": "^0.18.5",
@@ -27,6 +27,9 @@ import { useSyncedTab } from "./tabs-sync"
27
27
  import { ReplayPreview } from "../replay/ReplayPreview"
28
28
  import { isReplayQaUrl } from "../replay/url"
29
29
  import { VideoEmbed } from "../video"
30
+ import { StlViewer, isStlUrl } from "../stl"
31
+ import { StrudelPlayer } from "../strudel/StrudelPlayer"
32
+ import { isStrudelFile, isStrudelLanguage } from "../strudel/url"
30
33
  import { OpenApiOperation } from "../openapi/OpenApiOperation"
31
34
  import { Mermaid } from "./Mermaid"
32
35
  import { HighlightedCode } from "./HighlightedCode"
@@ -153,7 +156,7 @@ function codeOnlyTabs(block: Extract<Block, { type: "tabs" }>): CodeBlockNode[]
153
156
  const codes: CodeBlockNode[] = []
154
157
  for (const tab of block.tabs) {
155
158
  const only = tab.children.length === 1 ? tab.children[0] : null
156
- if (!only || only.type !== "code" || only.live || only.language === "mermaid") return null
159
+ if (!only || only.type !== "code" || only.live || only.language === "mermaid" || isStrudelLanguage(only.language)) return null
157
160
  codes.push(only)
158
161
  }
159
162
  return codes
@@ -342,6 +345,9 @@ function BlockView({ block, liveRenderer, sourceRenderer }: { block: Block } & R
342
345
  />
343
346
  )
344
347
  }
348
+ if (isStrudelLanguage(block.language)) {
349
+ return <StrudelPlayer code={block.code} {...(block.title ? { title: block.title } : {})} />
350
+ }
345
351
  if (block.live && isReactLanguage(block.language) && liveRenderer) {
346
352
  const entry = block.entry ?? "/src/main.jsx"
347
353
  return liveRenderer({
@@ -419,6 +425,12 @@ function BlockView({ block, liveRenderer, sourceRenderer }: { block: Block } & R
419
425
  if (isReplayQaUrl(block.url)) {
420
426
  return <ReplayPreview source={block.url} title="Replay preview" />
421
427
  }
428
+ if (isStlUrl(block.url)) {
429
+ return <StlViewer src={resolveAsset(block.url)} {...(block.title ? { title: block.title } : {})} />
430
+ }
431
+ if (isStrudelFile(block.url)) {
432
+ return <StrudelPlayer src={resolveAsset(block.url)} {...(block.title ? { title: block.title } : {})} />
433
+ }
422
434
  const src = embedSrc(block.url)
423
435
  return src || isDirectVideo(block.url) ? (
424
436
  <VideoEmbed
package/src/env.d.ts CHANGED
@@ -2,3 +2,6 @@ declare module "*.css" {
2
2
  const href: string
3
3
  export default href
4
4
  }
5
+
6
+ // @strudel/web ships no types; src/strudel/engine.ts types the slice it uses.
7
+ declare module "@strudel/web"
package/src/index.ts CHANGED
@@ -88,6 +88,11 @@ export type { ReplayEvent } from "./replay/types"
88
88
  export { isReplayQaUrl, normalizeReplayEmbedUrl } from "./replay/url"
89
89
  export { VideoEmbed } from "./video"
90
90
  export type { VideoEmbedProps } from "./video"
91
+ export { StlViewer, isStlUrl, parseStl } from "./stl"
92
+ export type { StlMesh, StlViewerProps } from "./stl"
93
+ export { StrudelPlayer } from "./strudel/StrudelPlayer"
94
+ export { isStrudelFile, isStrudelLanguage } from "./strudel/url"
95
+ export type { StrudelPlayerProps } from "./strudel/StrudelPlayer"
91
96
  export { OpenApiOperation } from "./openapi/OpenApiOperation"
92
97
  export { createInlineDemoProject, createReactDemoFiles } from "./playground/project"
93
98
  export type {