yumiamd 0.1.10 → 0.1.13

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,23 +49,35 @@ pnpm add yumiamd
49
49
  Once installed globally or locally, the `yumia` / `yumiamd` commands are available in your terminal:
50
50
 
51
51
  ```bash
52
- # Initialize a new presentation template
53
- yumia init my-presentation
52
+ # Initialize a new presentation template (supports --theme and custom color overrides)
53
+ yumia init my-presentation --theme cyberpunk --primary "#FF2E88"
54
+
55
+ # Start instant live-reload dev server with HTML preview (zero config!)
56
+ yumia dev presentation.yumia.md --open
57
+
58
+ # Compile to native editable PowerPoint (.pptx)
59
+ yumia build presentation.yumia.md --out dist/presentation.pptx
60
+
61
+ # Compile to crisp vector PDF document (.pdf)
62
+ yumia build presentation.yumia.md --format pdf --out dist/presentation.pdf
63
+
64
+ # Compile to standalone interactive HTML5 presentation deck (.html)
65
+ yumia build presentation.yumia.md --format html --out dist/presentation.html
66
+
67
+ # Watch presentation file and recompile automatically on save
68
+ yumia watch presentation.yumia.md --format pdf
54
69
 
55
70
  # Validate markdown syntax and AST structure (supports --json for CI & AI agents)
56
71
  yumia validate presentation.yumia.md --json
57
72
 
58
- # Lint presentation for vertical overflow and layout issues
59
- yumia lint presentation.yumia.md --json
73
+ # Lint presentation for overflow, high density, and layout issues
74
+ yumia lint presentation.yumia.md --strict
60
75
 
61
76
  # Inspect parsed AST and computed layout bounding boxes
62
77
  yumia inspect presentation.yumia.md --layout
63
78
 
64
79
  # Export machine-readable JSON schema for LLMs & AI prompt generation
65
80
  yumia schema
66
-
67
- # Compile to native editable PowerPoint (.pptx)
68
- yumia build presentation.yumia.md --out dist/presentation.pptx
69
81
  ```
70
82
 
71
83
  ---
package/dist/bin.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  runCli
4
- } from "./chunk-PQYPVPV2.js";
4
+ } from "./chunk-6GEDN7OB.js";
5
5
 
6
6
  // src/bin.ts
7
7
  var result = await runCli(process.argv);
@@ -2393,15 +2393,16 @@ var HtmlRenderer = class {
2393
2393
  right: 24px;
2394
2394
  display: flex;
2395
2395
  align-items: center;
2396
- gap: 12px;
2397
- background: rgba(15, 23, 42, 0.85);
2396
+ gap: 10px;
2397
+ background: rgba(15, 23, 42, 0.88);
2398
2398
  backdrop-filter: blur(12px);
2399
- padding: 8px 16px;
2399
+ padding: 6px 14px;
2400
2400
  border-radius: 30px;
2401
2401
  border: 1px solid rgba(255, 255, 255, 0.15);
2402
2402
  z-index: 1000;
2403
2403
  font-size: 13px;
2404
2404
  color: #e2e8f0;
2405
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.5);
2405
2406
  }
2406
2407
 
2407
2408
  .yumia-btn {
@@ -2409,17 +2410,18 @@ var HtmlRenderer = class {
2409
2410
  border: none;
2410
2411
  color: #f8fafc;
2411
2412
  cursor: pointer;
2412
- padding: 4px 8px;
2413
+ padding: 5px 9px;
2413
2414
  border-radius: 6px;
2414
2415
  font-size: 14px;
2415
2416
  display: flex;
2416
2417
  align-items: center;
2417
2418
  justify-content: center;
2418
- transition: background 0.15s ease;
2419
+ transition: background 0.15s ease, transform 0.1s ease;
2419
2420
  }
2420
2421
 
2421
2422
  .yumia-btn:hover {
2422
2423
  background: rgba(255, 255, 255, 0.15);
2424
+ transform: translateY(-1px);
2423
2425
  }
2424
2426
 
2425
2427
  .yumia-progress-bar {
@@ -2437,47 +2439,291 @@ var HtmlRenderer = class {
2437
2439
  bottom: 0;
2438
2440
  left: 0;
2439
2441
  right: 0;
2440
- max-height: 220px;
2441
- background: rgba(10, 10, 18, 0.95);
2442
+ max-height: 240px;
2443
+ background: rgba(10, 10, 18, 0.96);
2442
2444
  backdrop-filter: blur(16px);
2443
- border-top: 1px solid var(--yumia-primary);
2444
- padding: 16px 24px;
2445
+ border-top: 2px solid var(--yumia-primary);
2446
+ padding: 18px 28px;
2445
2447
  overflow-y: auto;
2446
2448
  display: none;
2447
2449
  z-index: 2000;
2448
- font-size: 14px;
2450
+ font-size: 15px;
2449
2451
  line-height: 1.6;
2450
2452
  color: #cbd5e1;
2453
+ box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.5);
2451
2454
  }
2452
2455
 
2453
2456
  .yumia-notes-drawer.open {
2454
2457
  display: block;
2455
2458
  }
2459
+
2460
+ /* Slide Overview Modal */
2461
+ .yumia-overview-modal {
2462
+ position: fixed;
2463
+ top: 0;
2464
+ left: 0;
2465
+ width: 100vw;
2466
+ height: 100vh;
2467
+ background: rgba(5, 5, 10, 0.94);
2468
+ backdrop-filter: blur(20px);
2469
+ z-index: 3000;
2470
+ display: none;
2471
+ flex-direction: column;
2472
+ padding: 40px;
2473
+ overflow-y: auto;
2474
+ }
2475
+
2476
+ .yumia-overview-modal.open {
2477
+ display: flex;
2478
+ }
2479
+
2480
+ .yumia-overview-header {
2481
+ display: flex;
2482
+ justify-content: space-between;
2483
+ align-items: center;
2484
+ margin-bottom: 30px;
2485
+ color: #fff;
2486
+ }
2487
+
2488
+ .yumia-overview-grid {
2489
+ display: grid;
2490
+ grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
2491
+ gap: 24px;
2492
+ width: 100%;
2493
+ }
2494
+
2495
+ .yumia-overview-card {
2496
+ aspect-ratio: var(--yumia-ratio);
2497
+ background-color: var(--yumia-bg);
2498
+ border: 2px solid rgba(255, 255, 255, 0.1);
2499
+ border-radius: 8px;
2500
+ padding: 16px;
2501
+ cursor: pointer;
2502
+ position: relative;
2503
+ overflow: hidden;
2504
+ transform-origin: center;
2505
+ transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
2506
+ display: flex;
2507
+ flex-direction: column;
2508
+ }
2509
+
2510
+ .yumia-overview-card:hover {
2511
+ transform: scale(1.04);
2512
+ border-color: var(--yumia-primary);
2513
+ box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.8), 0 0 15px var(--yumia-primary);
2514
+ }
2515
+
2516
+ .yumia-overview-card.current {
2517
+ border-color: var(--yumia-accent);
2518
+ box-shadow: 0 0 0 2px var(--yumia-accent);
2519
+ }
2520
+
2521
+ .yumia-overview-badge {
2522
+ position: absolute;
2523
+ top: 8px;
2524
+ right: 8px;
2525
+ background: rgba(0, 0, 0, 0.6);
2526
+ color: #fff;
2527
+ font-size: 11px;
2528
+ font-weight: 700;
2529
+ padding: 2px 8px;
2530
+ border-radius: 10px;
2531
+ }
2532
+
2533
+ /* Speaker View Layout (When loaded in speaker mode ?speaker=true) */
2534
+ .speaker-layout {
2535
+ display: grid;
2536
+ grid-template-rows: 60px 1fr;
2537
+ width: 100vw;
2538
+ height: 100vh;
2539
+ background: #09090f;
2540
+ color: #f8fafc;
2541
+ overflow: hidden;
2542
+ }
2543
+
2544
+ .speaker-topbar {
2545
+ display: flex;
2546
+ justify-content: space-between;
2547
+ align-items: center;
2548
+ padding: 0 24px;
2549
+ background: #11111b;
2550
+ border-bottom: 1px solid rgba(255, 255, 255, 0.1);
2551
+ }
2552
+
2553
+ .speaker-timer-group {
2554
+ display: flex;
2555
+ align-items: center;
2556
+ gap: 16px;
2557
+ font-family: var(--yumia-font-code);
2558
+ font-size: 18px;
2559
+ }
2560
+
2561
+ .speaker-timer-btn {
2562
+ background: rgba(255, 255, 255, 0.1);
2563
+ color: #fff;
2564
+ border: none;
2565
+ padding: 4px 10px;
2566
+ border-radius: 4px;
2567
+ cursor: pointer;
2568
+ font-size: 12px;
2569
+ }
2570
+
2571
+ .speaker-timer-btn:hover {
2572
+ background: var(--yumia-primary);
2573
+ }
2574
+
2575
+ .speaker-main-grid {
2576
+ display: grid;
2577
+ grid-template-columns: 55% 45%;
2578
+ gap: 20px;
2579
+ padding: 20px;
2580
+ height: calc(100vh - 60px);
2581
+ box-sizing: border-box;
2582
+ }
2583
+
2584
+ .speaker-pane {
2585
+ background: #151522;
2586
+ border-radius: 10px;
2587
+ border: 1px solid rgba(255, 255, 255, 0.08);
2588
+ padding: 16px;
2589
+ display: flex;
2590
+ flex-direction: column;
2591
+ overflow: hidden;
2592
+ }
2593
+
2594
+ .speaker-pane-title {
2595
+ font-size: 12px;
2596
+ font-weight: 700;
2597
+ text-transform: uppercase;
2598
+ letter-spacing: 0.05em;
2599
+ color: var(--yumia-muted);
2600
+ margin-bottom: 12px;
2601
+ display: flex;
2602
+ justify-content: space-between;
2603
+ }
2604
+
2605
+ .speaker-preview-box {
2606
+ flex: 1;
2607
+ position: relative;
2608
+ display: flex;
2609
+ align-items: center;
2610
+ justify-content: center;
2611
+ background: #000;
2612
+ border-radius: 8px;
2613
+ overflow: hidden;
2614
+ }
2615
+
2616
+ .speaker-preview-box .yumia-slide-wrapper {
2617
+ display: flex !important;
2618
+ transform: scale(0.6);
2619
+ width: 160% !important;
2620
+ height: 160% !important;
2621
+ }
2622
+
2623
+ .speaker-notes-box {
2624
+ flex: 1;
2625
+ background: #11111a;
2626
+ border-radius: 8px;
2627
+ padding: 16px;
2628
+ font-size: 16px;
2629
+ line-height: 1.7;
2630
+ color: #e2e8f0;
2631
+ overflow-y: auto;
2632
+ }
2456
2633
  </style>
2457
2634
  </head>
2458
2635
  <body>
2459
- <div id="yumia-deck">
2460
- ${slidesHtml}
2636
+ <div id="deck-container">
2637
+ <div id="yumia-deck">
2638
+ ${slidesHtml}
2639
+ </div>
2640
+
2641
+ <div class="yumia-controls" id="deck-controls">
2642
+ <button class="yumia-btn" id="btn-prev" title="Previous Slide (\u2190)">\u25C0</button>
2643
+ <span id="slide-indicator">1 / ${presentation.slides.length}</span>
2644
+ <button class="yumia-btn" id="btn-next" title="Next Slide (\u2192)">\u25B6</button>
2645
+ <button class="yumia-btn" id="btn-overview" title="Slide Overview (ESC / O)">\u25A6</button>
2646
+ <button class="yumia-btn" id="btn-speaker" title="Speaker View (S)">\u{1F3A4}</button>
2647
+ <button class="yumia-btn" id="btn-notes" title="Toggle Notes (N)">\u{1F4DD}</button>
2648
+ <button class="yumia-btn" id="btn-fs" title="Fullscreen (F)">\u26F6</button>
2649
+ </div>
2650
+
2651
+ <div id="notes-drawer" class="yumia-notes-drawer"></div>
2652
+
2653
+ <div id="overview-modal" class="yumia-overview-modal">
2654
+ <div class="yumia-overview-header">
2655
+ <h2>Slide Overview</h2>
2656
+ <button class="yumia-btn" id="btn-close-overview" style="font-size: 18px;">\u2715 Close (ESC)</button>
2657
+ </div>
2658
+ <div class="yumia-overview-grid" id="overview-grid"></div>
2659
+ </div>
2461
2660
  </div>
2462
2661
 
2463
- <div class="yumia-controls">
2464
- <button class="yumia-btn" id="btn-prev" title="Previous Slide (\u2190)">\u25C0</button>
2465
- <span id="slide-indicator">1 / ${presentation.slides.length}</span>
2466
- <button class="yumia-btn" id="btn-next" title="Next Slide (\u2192)">\u25B6</button>
2467
- <button class="yumia-btn" id="btn-notes" title="Toggle Notes (N)">\u{1F4DD}</button>
2468
- <button class="yumia-btn" id="btn-fs" title="Fullscreen (F)">\u26F6</button>
2469
- </div>
2470
-
2471
- <div id="notes-drawer" class="yumia-notes-drawer"></div>
2472
-
2473
2662
  <script>
2474
2663
  (function() {
2475
- const slides = document.querySelectorAll('.yumia-slide-wrapper');
2664
+ const isSpeakerMode = new URLSearchParams(window.location.search).get('speaker') === 'true';
2665
+ const slides = Array.from(document.querySelectorAll('.yumia-slide-wrapper'));
2476
2666
  const indicator = document.getElementById('slide-indicator');
2477
2667
  const notesDrawer = document.getElementById('notes-drawer');
2668
+ const overviewModal = document.getElementById('overview-modal');
2669
+ const overviewGrid = document.getElementById('overview-grid');
2478
2670
  let currentIdx = 0;
2479
2671
 
2480
- function updateSlide(newIdx) {
2672
+ // Real-time synchronization channel
2673
+ let syncChannel = null;
2674
+ try {
2675
+ syncChannel = new BroadcastChannel('yumia_presentation_sync');
2676
+ syncChannel.onmessage = function(e) {
2677
+ if (e.data && typeof e.data.index === 'number') {
2678
+ goToSlide(e.data.index, false);
2679
+ }
2680
+ };
2681
+ } catch (err) {
2682
+ // Fallback if BroadcastChannel unavailable
2683
+ }
2684
+
2685
+ function buildOverviewGrid() {
2686
+ if (!overviewGrid) return;
2687
+ overviewGrid.innerHTML = '';
2688
+ slides.forEach((slide, idx) => {
2689
+ const card = document.createElement('div');
2690
+ card.className = 'yumia-overview-card' + (idx === currentIdx ? ' current' : '');
2691
+ const badge = document.createElement('span');
2692
+ badge.className = 'yumia-overview-badge';
2693
+ badge.textContent = (idx + 1);
2694
+
2695
+ const heading = slide.querySelector('h1, h2, h3');
2696
+ const titleText = heading ? heading.textContent : 'Slide ' + (idx + 1);
2697
+
2698
+ const titleDiv = document.createElement('div');
2699
+ titleDiv.style.fontWeight = '600';
2700
+ titleDiv.style.fontSize = '14px';
2701
+ titleDiv.style.color = 'var(--yumia-primary)';
2702
+ titleDiv.textContent = titleText;
2703
+
2704
+ card.appendChild(badge);
2705
+ card.appendChild(titleDiv);
2706
+
2707
+ card.addEventListener('click', () => {
2708
+ goToSlide(idx);
2709
+ toggleOverview(false);
2710
+ });
2711
+ overviewGrid.appendChild(card);
2712
+ });
2713
+ }
2714
+
2715
+ function toggleOverview(force) {
2716
+ if (!overviewModal) return;
2717
+ const isOpen = force !== undefined ? force : !overviewModal.classList.contains('open');
2718
+ if (isOpen) {
2719
+ buildOverviewGrid();
2720
+ overviewModal.classList.add('open');
2721
+ } else {
2722
+ overviewModal.classList.remove('open');
2723
+ }
2724
+ }
2725
+
2726
+ function goToSlide(newIdx, broadcast = true) {
2481
2727
  if (newIdx < 0 || newIdx >= slides.length) return;
2482
2728
  slides[currentIdx]?.classList.remove('active');
2483
2729
  currentIdx = newIdx;
@@ -2490,23 +2736,166 @@ var HtmlRenderer = class {
2490
2736
  const currentSlide = slides[currentIdx];
2491
2737
  const notes = currentSlide ? currentSlide.getAttribute('data-notes') : '';
2492
2738
  if (notesDrawer) {
2493
- notesDrawer.innerHTML = notes ? '<strong>Speaker Notes:</strong><br>' + notes : '<em>No notes for this slide.</em>';
2739
+ notesDrawer.innerHTML = notes ? '<strong>Speaker Notes:</strong><br>' + notes : '<em>No speaker notes for this slide.</em>';
2494
2740
  }
2495
2741
 
2496
2742
  window.location.hash = '#' + (currentIdx + 1);
2743
+
2744
+ if (broadcast && syncChannel) {
2745
+ syncChannel.postMessage({ index: currentIdx });
2746
+ }
2747
+ }
2748
+
2749
+ function openSpeakerWindow() {
2750
+ const url = new URL(window.location.href);
2751
+ url.searchParams.set('speaker', 'true');
2752
+ window.open(url.toString(), 'yumia_speaker_' + Date.now(), 'width=1180,height=760,menubar=no,toolbar=no');
2753
+ }
2754
+
2755
+ function initSpeakerLayout() {
2756
+ document.body.innerHTML = \`
2757
+ <div class="speaker-layout">
2758
+ <div class="speaker-topbar">
2759
+ <div style="font-weight:700; color:var(--yumia-primary); display:flex; align-items:center; gap:8px;">
2760
+ <span>\u{1F399}\uFE0F YumiaMD Speaker View</span>
2761
+ </div>
2762
+ <div class="speaker-timer-group">
2763
+ <span id="speaker-clock">00:00:00</span>
2764
+ <span style="color:var(--yumia-muted);">|</span>
2765
+ <span id="speaker-timer" style="color:var(--yumia-accent);">00:00</span>
2766
+ <button class="speaker-timer-btn" id="btn-timer-toggle">Pause</button>
2767
+ <button class="speaker-timer-btn" id="btn-timer-reset">Reset</button>
2768
+ </div>
2769
+ <div>
2770
+ <span id="speaker-slide-num" style="font-weight:600;">1 / \${slides.length}</span>
2771
+ </div>
2772
+ </div>
2773
+ <div class="speaker-main-grid">
2774
+ <div class="speaker-pane">
2775
+ <div class="speaker-pane-title">Current Slide</div>
2776
+ <div class="speaker-preview-box" id="speaker-current-box"></div>
2777
+ </div>
2778
+ <div style="display:grid; grid-template-rows: 45% 55%; gap:20px;">
2779
+ <div class="speaker-pane">
2780
+ <div class="speaker-pane-title">Next Slide Preview</div>
2781
+ <div class="speaker-preview-box" id="speaker-next-box"></div>
2782
+ </div>
2783
+ <div class="speaker-pane">
2784
+ <div class="speaker-pane-title">Speaker Notes</div>
2785
+ <div class="speaker-notes-box" id="speaker-notes-content"></div>
2786
+ </div>
2787
+ </div>
2788
+ </div>
2789
+ </div>
2790
+ \`;
2791
+
2792
+ // Live Clock
2793
+ setInterval(() => {
2794
+ const now = new Date();
2795
+ const clockEl = document.getElementById('speaker-clock');
2796
+ if (clockEl) clockEl.textContent = now.toLocaleTimeString();
2797
+ }, 1000);
2798
+
2799
+ // Elapsed Timer
2800
+ let elapsedSeconds = 0;
2801
+ let timerRunning = true;
2802
+ let timerInterval = setInterval(() => {
2803
+ if (!timerRunning) return;
2804
+ elapsedSeconds++;
2805
+ const mins = String(Math.floor(elapsedSeconds / 60)).padStart(2, '0');
2806
+ const secs = String(elapsedSeconds % 60).padStart(2, '0');
2807
+ const timerEl = document.getElementById('speaker-timer');
2808
+ if (timerEl) timerEl.textContent = \`\${mins}:\${secs}\`;
2809
+ }, 1000);
2810
+
2811
+ document.getElementById('btn-timer-toggle')?.addEventListener('click', (e) => {
2812
+ timerRunning = !timerRunning;
2813
+ e.target.textContent = timerRunning ? 'Pause' : 'Start';
2814
+ });
2815
+
2816
+ document.getElementById('btn-timer-reset')?.addEventListener('click', () => {
2817
+ elapsedSeconds = 0;
2818
+ const timerEl = document.getElementById('speaker-timer');
2819
+ if (timerEl) timerEl.textContent = '00:00';
2820
+ });
2821
+
2822
+ function updateSpeakerView(idx) {
2823
+ currentIdx = idx;
2824
+ const numEl = document.getElementById('speaker-slide-num');
2825
+ if (numEl) numEl.textContent = (currentIdx + 1) + ' / ' + slides.length;
2826
+
2827
+ // Render current slide
2828
+ const curBox = document.getElementById('speaker-current-box');
2829
+ if (curBox && slides[currentIdx]) {
2830
+ curBox.innerHTML = slides[currentIdx].outerHTML;
2831
+ curBox.firstElementChild?.classList.add('active');
2832
+ }
2833
+
2834
+ // Render next slide
2835
+ const nextBox = document.getElementById('speaker-next-box');
2836
+ if (nextBox) {
2837
+ if (slides[currentIdx + 1]) {
2838
+ nextBox.innerHTML = slides[currentIdx + 1].outerHTML;
2839
+ nextBox.firstElementChild?.classList.add('active');
2840
+ } else {
2841
+ nextBox.innerHTML = '<div style="color:var(--yumia-muted); font-size:14px;">End of presentation</div>';
2842
+ }
2843
+ }
2844
+
2845
+ // Render notes
2846
+ const notesBox = document.getElementById('speaker-notes-content');
2847
+ if (notesBox && slides[currentIdx]) {
2848
+ const rawNotes = slides[currentIdx].getAttribute('data-notes');
2849
+ notesBox.innerHTML = rawNotes ? rawNotes : '<em style="color:var(--yumia-muted);">No notes provided for this slide.</em>';
2850
+ }
2851
+ }
2852
+
2853
+ window.addEventListener('keydown', (e) => {
2854
+ if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'PageDown') {
2855
+ e.preventDefault();
2856
+ if (currentIdx < slides.length - 1) {
2857
+ goToSlide(currentIdx + 1);
2858
+ updateSpeakerView(currentIdx);
2859
+ }
2860
+ } else if (e.key === 'ArrowLeft' || e.key === 'Backspace' || e.key === 'PageUp') {
2861
+ e.preventDefault();
2862
+ if (currentIdx > 0) {
2863
+ goToSlide(currentIdx - 1);
2864
+ updateSpeakerView(currentIdx);
2865
+ }
2866
+ }
2867
+ });
2868
+
2869
+ if (syncChannel) {
2870
+ syncChannel.onmessage = (e) => {
2871
+ if (e.data && typeof e.data.index === 'number') {
2872
+ updateSpeakerView(e.data.index);
2873
+ }
2874
+ };
2875
+ }
2876
+
2877
+ const initialHash = parseInt(window.location.hash.replace('#', ''), 10) - 1;
2878
+ updateSpeakerView(isNaN(initialHash) ? 0 : initialHash);
2497
2879
  }
2498
2880
 
2499
2881
  function init() {
2882
+ if (isSpeakerMode) {
2883
+ initSpeakerLayout();
2884
+ return;
2885
+ }
2886
+
2500
2887
  const hash = window.location.hash.replace('#', '');
2501
2888
  const initialIdx = parseInt(hash, 10) - 1;
2502
- updateSlide(isNaN(initialIdx) ? 0 : initialIdx);
2889
+ goToSlide(isNaN(initialIdx) ? 0 : initialIdx, false);
2503
2890
  }
2504
2891
 
2505
2892
  window.deckController = {
2506
2893
  init: init,
2507
- next: function() { updateSlide(currentIdx + 1); },
2508
- prev: function() { updateSlide(currentIdx - 1); },
2894
+ next: function() { goToSlide(currentIdx + 1); },
2895
+ prev: function() { goToSlide(currentIdx - 1); },
2509
2896
  toggleNotes: function() { notesDrawer?.classList.toggle('open'); },
2897
+ toggleOverview: function() { toggleOverview(); },
2898
+ openSpeaker: openSpeakerWindow,
2510
2899
  toggleFs: function() {
2511
2900
  if (!document.fullscreenElement) {
2512
2901
  document.documentElement.requestFullscreen().catch(() => {});
@@ -2519,19 +2908,33 @@ var HtmlRenderer = class {
2519
2908
  document.getElementById('btn-next')?.addEventListener('click', window.deckController.next);
2520
2909
  document.getElementById('btn-prev')?.addEventListener('click', window.deckController.prev);
2521
2910
  document.getElementById('btn-notes')?.addEventListener('click', window.deckController.toggleNotes);
2911
+ document.getElementById('btn-overview')?.addEventListener('click', window.deckController.toggleOverview);
2912
+ document.getElementById('btn-close-overview')?.addEventListener('click', () => toggleOverview(false));
2913
+ document.getElementById('btn-speaker')?.addEventListener('click', window.deckController.openSpeaker);
2522
2914
  document.getElementById('btn-fs')?.addEventListener('click', window.deckController.toggleFs);
2523
2915
 
2524
2916
  window.addEventListener('keydown', function(e) {
2525
- if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'PageDown') {
2917
+ if (overviewModal && overviewModal.classList.contains('open')) {
2918
+ if (e.key === 'Escape' || e.key.toLowerCase() === 'o') {
2919
+ toggleOverview(false);
2920
+ }
2921
+ return;
2922
+ }
2923
+
2924
+ if (e.key === 'ArrowRight' || e.key === ' ' || e.key === 'PageDown' || e.key.toLowerCase() === 'l') {
2526
2925
  e.preventDefault();
2527
2926
  window.deckController.next();
2528
- } else if (e.key === 'ArrowLeft' || e.key === 'Backspace' || e.key === 'PageUp') {
2927
+ } else if (e.key === 'ArrowLeft' || e.key === 'Backspace' || e.key === 'PageUp' || e.key.toLowerCase() === 'h') {
2529
2928
  e.preventDefault();
2530
2929
  window.deckController.prev();
2531
2930
  } else if (e.key.toLowerCase() === 'f') {
2532
2931
  window.deckController.toggleFs();
2932
+ } else if (e.key.toLowerCase() === 's') {
2933
+ window.deckController.openSpeaker();
2533
2934
  } else if (e.key.toLowerCase() === 'n') {
2534
2935
  window.deckController.toggleNotes();
2936
+ } else if (e.key === 'Escape' || e.key.toLowerCase() === 'o') {
2937
+ window.deckController.toggleOverview();
2535
2938
  }
2536
2939
  });
2537
2940
 
@@ -2667,6 +3070,268 @@ var HtmlRenderer = class {
2667
3070
  }
2668
3071
  };
2669
3072
 
3073
+ // ../renderer-pdf/dist/renderer.js
3074
+ import PDFDocument from "pdfkit";
3075
+ var PdfRenderer = class {
3076
+ name = "PdfRenderer";
3077
+ targetFormat = "pdf";
3078
+ async render(presentation, context = {}) {
3079
+ const colorOverrides = presentation.metadata.colors ? { colors: presentation.metadata.colors } : void 0;
3080
+ const resolvedTheme = resolveTheme(presentation.metadata.theme, colorOverrides);
3081
+ const theme = context.theme || resolvedTheme || defaultTheme;
3082
+ const is43 = presentation.metadata.aspectRatio === "4:3";
3083
+ const pageWidth = is43 ? 720 : 960;
3084
+ const pageHeight = 540;
3085
+ return new Promise((resolvePromise, rejectPromise) => {
3086
+ try {
3087
+ const doc = new PDFDocument({
3088
+ autoFirstPage: false,
3089
+ margin: 0,
3090
+ info: {
3091
+ Title: presentation.metadata.title || "YumiaMD Presentation",
3092
+ Author: presentation.metadata.author || "YumiaMD",
3093
+ Creator: "YumiaMD Vector PDF Compiler"
3094
+ }
3095
+ });
3096
+ const chunks = [];
3097
+ doc.on("data", (chunk) => chunks.push(chunk));
3098
+ doc.on("end", () => {
3099
+ const buffer = Buffer.concat(chunks);
3100
+ resolvePromise({
3101
+ format: "pdf",
3102
+ data: new Uint8Array(buffer),
3103
+ pageCount: presentation.slides.length,
3104
+ slideCount: presentation.slides.length
3105
+ });
3106
+ });
3107
+ doc.on("error", (err) => rejectPromise(err));
3108
+ const totalSlides = presentation.slides.length;
3109
+ for (let i = 0; i < totalSlides; i++) {
3110
+ const slide = presentation.slides[i];
3111
+ this.renderSlide(doc, slide, i + 1, totalSlides, pageWidth, pageHeight, theme);
3112
+ }
3113
+ doc.end();
3114
+ } catch (err) {
3115
+ rejectPromise(err);
3116
+ }
3117
+ });
3118
+ }
3119
+ renderSlide(doc, slide, slideNum, totalSlides, pageWidth, pageHeight, theme) {
3120
+ doc.addPage({
3121
+ size: [pageWidth, pageHeight],
3122
+ margins: { top: 0, bottom: 0, left: 0, right: 0 }
3123
+ });
3124
+ doc.rect(0, 0, pageWidth, pageHeight).fill(theme.colors.background);
3125
+ const padX = pageWidth * 0.06;
3126
+ const padY = pageHeight * 0.08;
3127
+ const contentWidth = pageWidth - padX * 2;
3128
+ let cursorY = padY;
3129
+ for (const element of slide.elements) {
3130
+ cursorY = this.renderElement(doc, element, padX, cursorY, contentWidth, theme);
3131
+ cursorY += 12;
3132
+ }
3133
+ const progressWidth = slideNum / totalSlides * pageWidth;
3134
+ doc.rect(0, pageHeight - 4, progressWidth, 4).fill(theme.colors.primary);
3135
+ doc.font("Helvetica").fontSize(10).fillColor(theme.colors.muted || "#888888").text(`${slideNum} / ${totalSlides}`, pageWidth - padX - 60, pageHeight - 24, {
3136
+ width: 60,
3137
+ align: "right"
3138
+ });
3139
+ }
3140
+ renderElement(doc, element, x, y, width, theme) {
3141
+ switch (element.type) {
3142
+ case "heading": {
3143
+ const h = element;
3144
+ const fontSize = h.level === 1 ? 28 : h.level === 2 ? 22 : 18;
3145
+ const color = h.level === 1 ? theme.colors.primary : theme.colors.text;
3146
+ doc.font("Helvetica-Bold").fontSize(fontSize).fillColor(color);
3147
+ doc.text(this.stripFormatting(h.text), x, y, { width, lineGap: 4 });
3148
+ const height = doc.heightOfString(this.stripFormatting(h.text), { width });
3149
+ return y + height;
3150
+ }
3151
+ case "paragraph": {
3152
+ const p = element;
3153
+ doc.font("Helvetica").fontSize(14).fillColor(theme.colors.text);
3154
+ doc.text(this.stripFormatting(p.text), x, y, { width, lineGap: 4 });
3155
+ const height = doc.heightOfString(this.stripFormatting(p.text), { width });
3156
+ return y + height;
3157
+ }
3158
+ case "list": {
3159
+ const l = element;
3160
+ let currentY = y;
3161
+ const itemGap = 6;
3162
+ l.items.forEach((item, idx) => {
3163
+ const bullet = l.ordered ? `${idx + 1}.` : "\u2022";
3164
+ doc.font("Helvetica-Bold").fontSize(13).fillColor(theme.colors.primary).text(bullet, x, currentY, { width: 18 });
3165
+ doc.font("Helvetica").fontSize(13).fillColor(theme.colors.text).text(this.stripFormatting(item.text), x + 20, currentY, {
3166
+ width: width - 20,
3167
+ lineGap: 3
3168
+ });
3169
+ const itemHeight = Math.max(18, doc.heightOfString(this.stripFormatting(item.text), { width: width - 20 }));
3170
+ currentY += itemHeight + itemGap;
3171
+ });
3172
+ return currentY;
3173
+ }
3174
+ case "quote": {
3175
+ const q = element;
3176
+ const quoteText = `\u201C${this.stripFormatting(q.text)}\u201D`;
3177
+ const authorText = q.author ? `\u2014 ${this.stripFormatting(q.author)}` : "";
3178
+ doc.font("Helvetica-Oblique").fontSize(13).fillColor(theme.colors.muted || "#aaaaaa");
3179
+ const textHeight = doc.heightOfString(quoteText, { width: width - 24 });
3180
+ const authorHeight = authorText ? 18 : 0;
3181
+ const totalHeight = textHeight + authorHeight + 16;
3182
+ doc.roundedRect(x, y, width, totalHeight, 6).fill(theme.colors.surface || "rgba(255,255,255,0.05)");
3183
+ doc.rect(x, y, 4, totalHeight).fill(theme.colors.accent || theme.colors.primary);
3184
+ doc.font("Helvetica-Oblique").fontSize(13).fillColor(theme.colors.text).text(quoteText, x + 16, y + 8, { width: width - 28 });
3185
+ if (authorText) {
3186
+ doc.font("Helvetica").fontSize(11).fillColor(theme.colors.muted || "#888888").text(authorText, x + 16, y + 8 + textHeight + 4, { width: width - 28 });
3187
+ }
3188
+ return y + totalHeight;
3189
+ }
3190
+ case "code": {
3191
+ const c = element;
3192
+ const codeText = c.code;
3193
+ doc.font("Courier").fontSize(11);
3194
+ const textHeight = doc.heightOfString(codeText, { width: width - 24 });
3195
+ const boxHeight = textHeight + 20;
3196
+ doc.roundedRect(x, y, width, boxHeight, 6).fill("#0a0a10").strokeColor(theme.colors.border || "rgba(255,255,255,0.1)").stroke();
3197
+ doc.font("Courier").fontSize(11).fillColor(theme.colors.accent || "#38bdf8").text(codeText, x + 12, y + 10, { width: width - 24 });
3198
+ return y + boxHeight;
3199
+ }
3200
+ case "card": {
3201
+ const card = element;
3202
+ const variantColor = this.getVariantColor(card.variant, theme);
3203
+ const cardPad = 14;
3204
+ let cardCursorY = y + cardPad;
3205
+ if (card.title) {
3206
+ doc.font("Helvetica-Bold").fontSize(15).fillColor(variantColor).text(this.stripFormatting(card.title), x + cardPad, cardCursorY, {
3207
+ width: width - cardPad * 2
3208
+ });
3209
+ cardCursorY += 22;
3210
+ }
3211
+ if (card.elements) {
3212
+ for (const child of card.elements) {
3213
+ cardCursorY = this.renderElement(doc, child, x + cardPad, cardCursorY, width - cardPad * 2, theme);
3214
+ cardCursorY += 8;
3215
+ }
3216
+ }
3217
+ const totalCardHeight = Math.max(70, cardCursorY - y + cardPad);
3218
+ doc.save();
3219
+ doc.roundedRect(x, y, width, totalCardHeight, 8).fill(theme.colors.surface || "rgba(255,255,255,0.06)");
3220
+ doc.roundedRect(x, y, width, totalCardHeight, 8).lineWidth(1.5).strokeColor(variantColor).stroke();
3221
+ doc.restore();
3222
+ let renderTop = y + cardPad;
3223
+ if (card.title) {
3224
+ doc.font("Helvetica-Bold").fontSize(15).fillColor(variantColor).text(this.stripFormatting(card.title), x + cardPad, renderTop, {
3225
+ width: width - cardPad * 2
3226
+ });
3227
+ renderTop += 22;
3228
+ }
3229
+ if (card.elements) {
3230
+ for (const child of card.elements) {
3231
+ renderTop = this.renderElement(doc, child, x + cardPad, renderTop, width - cardPad * 2, theme);
3232
+ renderTop += 8;
3233
+ }
3234
+ }
3235
+ return y + totalCardHeight;
3236
+ }
3237
+ case "metric": {
3238
+ const m = element;
3239
+ const variantColor = this.getVariantColor(m.variant, theme);
3240
+ const boxHeight = 90;
3241
+ doc.roundedRect(x, y, width, boxHeight, 8).fill(theme.colors.surface || "rgba(255,255,255,0.06)");
3242
+ doc.roundedRect(x, y, width, boxHeight, 8).lineWidth(1.5).strokeColor(variantColor).stroke();
3243
+ doc.font("Helvetica-Bold").fontSize(11).fillColor(theme.colors.muted || "#888888").text(m.label.toUpperCase(), x + 16, y + 14, { width: width - 32 });
3244
+ const displayVal = m.unit ? `${m.value} ${m.unit}` : m.value;
3245
+ doc.font("Helvetica-Bold").fontSize(28).fillColor(theme.colors.primary).text(displayVal, x + 16, y + 32, { width: width - 32 });
3246
+ if (m.change) {
3247
+ const changeColor = m.change.startsWith("+") ? "#10b981" : "#ef4444";
3248
+ doc.font("Helvetica-Bold").fontSize(12).fillColor(changeColor).text(m.change, x + width - 90, y + 38, { width: 74, align: "right" });
3249
+ }
3250
+ return y + boxHeight;
3251
+ }
3252
+ case "columns": {
3253
+ const cols = element;
3254
+ const colCount = cols.columns.length;
3255
+ const gap = 16;
3256
+ const availableWidth = width - gap * (colCount - 1);
3257
+ let ratios = Array(colCount).fill(1);
3258
+ if (cols.ratios) {
3259
+ const parsed = cols.ratios.split(":").map((r) => parseFloat(r) || 1);
3260
+ if (parsed.length === colCount)
3261
+ ratios = parsed;
3262
+ }
3263
+ const totalRatio = ratios.reduce((a, b) => a + b, 0);
3264
+ let curX = x;
3265
+ let maxY = y;
3266
+ for (let i = 0; i < colCount; i++) {
3267
+ const col = cols.columns[i];
3268
+ const colWidth = ratios[i] / totalRatio * availableWidth;
3269
+ let colCursorY = y;
3270
+ for (const child of col.elements) {
3271
+ colCursorY = this.renderElement(doc, child, curX, colCursorY, colWidth, theme);
3272
+ colCursorY += 8;
3273
+ }
3274
+ if (colCursorY > maxY)
3275
+ maxY = colCursorY;
3276
+ curX += colWidth + gap;
3277
+ }
3278
+ return maxY;
3279
+ }
3280
+ case "table": {
3281
+ const t = element;
3282
+ const headers = t.headers || [];
3283
+ const rows = t.rows || [];
3284
+ const colCount = Math.max(headers.length, ...rows.map((r) => r.length), 1);
3285
+ const colWidth = width / colCount;
3286
+ const rowHeight = 26;
3287
+ let curY = y;
3288
+ if (headers.length > 0) {
3289
+ doc.rect(x, curY, width, rowHeight).fill(theme.colors.primary);
3290
+ headers.forEach((h, idx) => {
3291
+ doc.font("Helvetica-Bold").fontSize(12).fillColor("#ffffff").text(this.stripFormatting(h), x + idx * colWidth + 6, curY + 6, {
3292
+ width: colWidth - 12
3293
+ });
3294
+ });
3295
+ curY += rowHeight;
3296
+ }
3297
+ rows.forEach((row, rowIdx) => {
3298
+ const isEven = rowIdx % 2 === 0;
3299
+ const rowBg = isEven ? theme.colors.surface || "rgba(255,255,255,0.04)" : "rgba(255,255,255,0.01)";
3300
+ doc.rect(x, curY, width, rowHeight).fill(rowBg);
3301
+ row.forEach((cell, idx) => {
3302
+ doc.font("Helvetica").fontSize(11).fillColor(theme.colors.text).text(this.stripFormatting(cell), x + idx * colWidth + 6, curY + 6, {
3303
+ width: colWidth - 12
3304
+ });
3305
+ });
3306
+ curY += rowHeight;
3307
+ });
3308
+ doc.rect(x, y, width, curY - y).strokeColor(theme.colors.border || "rgba(255,255,255,0.1)").stroke();
3309
+ return curY;
3310
+ }
3311
+ default:
3312
+ return y;
3313
+ }
3314
+ }
3315
+ getVariantColor(variant, theme) {
3316
+ switch (variant) {
3317
+ case "warning":
3318
+ return theme.colors.warning || "#f59e0b";
3319
+ case "info":
3320
+ return theme.colors.info || "#3b82f6";
3321
+ case "success":
3322
+ return theme.colors.success || "#10b981";
3323
+ case "danger":
3324
+ return theme.colors.danger || "#ef4444";
3325
+ case "primary":
3326
+ default:
3327
+ return theme.colors.primary;
3328
+ }
3329
+ }
3330
+ stripFormatting(text) {
3331
+ return text.replace(/\*\*(.*?)\*\*/g, "$1").replace(/\*(.*?)\*/g, "$1").replace(/`(.*?)`/g, "$1");
3332
+ }
3333
+ };
3334
+
2670
3335
  // src/dev-server.ts
2671
3336
  import { createServer } from "http";
2672
3337
  import { readFileSync, watch } from "fs";
@@ -2766,7 +3431,7 @@ function startDevServer(filePath, options = {}) {
2766
3431
  // src/cli.ts
2767
3432
  import { mkdirSync, readFileSync as readFileSync2, watch as fsWatch, writeFileSync } from "fs";
2768
3433
  import { basename, dirname, extname, join, resolve as resolve2 } from "path";
2769
- var VERSION = "0.1.10";
3434
+ var VERSION = "0.1.13";
2770
3435
  function printHelp() {
2771
3436
  return `
2772
3437
  YumiaMD \u2014 Markdown-based presentation compiler (v${VERSION})
@@ -2782,7 +3447,7 @@ Commands:
2782
3447
  lint <file> Analyze presentation for layout overflows and accessibility
2783
3448
  inspect <file> Inspect the AST and geometric layout tree
2784
3449
  schema Output machine-readable JSON schema for AI agents
2785
- build <file> Compile a presentation to PowerPoint (.pptx) or HTML (.html)
3450
+ build <file> Compile a presentation to PowerPoint (.pptx), PDF (.pdf), or HTML (.html)
2786
3451
 
2787
3452
  Theming & Color Options:
2788
3453
  --theme, -t <name> Base theme: default | cyberpunk | minimal | corporate | terminal | academic
@@ -2797,7 +3462,7 @@ Server & Compiler Options:
2797
3462
  --open Open default browser automatically in dev mode
2798
3463
  --watch, -w Watch for file changes during compilation
2799
3464
  --out, -o <file> Specify output file path (default: dist/<name>.<format>)
2800
- --format, -f <fmt> Target output format: pptx (default) | html
3465
+ --format, -f <fmt> Target output format: pptx (default) | pdf | html
2801
3466
  --strict Enforce zero warnings in 'lint' (exits with code 1 on warning)
2802
3467
  --json Output results formatted as JSON for CI/CD and AI tools
2803
3468
  --layout Show computed geometric bounding boxes in 'inspect'
@@ -3120,7 +3785,8 @@ ${summary}${isStrict && report.warnings.length > 0 ? " (failed due to --strict)"
3120
3785
  try {
3121
3786
  const resolvedInput = resolve2(process.cwd(), target);
3122
3787
  const isHtml = cliFormat === "html";
3123
- const targetExtension = isHtml ? ".html" : ".pptx";
3788
+ const isPdf = cliFormat === "pdf";
3789
+ const targetExtension = isHtml ? ".html" : isPdf ? ".pdf" : ".pptx";
3124
3790
  let outputPath = "";
3125
3791
  const outFlagIndex = args.findIndex((a) => a === "--out" || a === "-o");
3126
3792
  if (outFlagIndex !== -1 && args[outFlagIndex + 1]) {
@@ -3149,6 +3815,14 @@ ${summary}${isStrict && report.warnings.length > 0 ? " (failed due to --strict)"
3149
3815
  });
3150
3816
  writeFileSync(outputPath, result2.html, "utf-8");
3151
3817
  return { slideCount: result2.slideCount, format: result2.format };
3818
+ } else if (isPdf) {
3819
+ const pdfRenderer = new PdfRenderer();
3820
+ const result2 = await compiler.compile(source, pdfRenderer, {
3821
+ ...renderTheme ? { renderContext: { theme: renderTheme } } : {}
3822
+ });
3823
+ const buffer = result2.data instanceof Uint8Array ? Buffer.from(result2.data) : Buffer.from(new Uint8Array(result2.data));
3824
+ writeFileSync(outputPath, buffer);
3825
+ return { slideCount: result2.slideCount, format: result2.format };
3152
3826
  } else {
3153
3827
  const pptxRenderer = new PptxRenderer();
3154
3828
  const result2 = await compiler.compile(source, pptxRenderer, {
@@ -3186,9 +3860,10 @@ ${summary}${isStrict && report.warnings.length > 0 ? " (failed due to --strict)"
3186
3860
  };
3187
3861
  }
3188
3862
  const watchMsg = command === "watch" || isWatch ? " [Watching for changes...]" : "";
3863
+ const formatDesc = isHtml ? "interactive HTML slides" : isPdf ? "vector PDF slides" : "native editable slides";
3189
3864
  return {
3190
3865
  exitCode: 0,
3191
- output: `\u2713 Successfully compiled '${target}' \u2794 '${outputPath}' (${result.slideCount} ${isHtml ? "interactive HTML slides" : "native editable slides"})${watchMsg}`
3866
+ output: `\u2713 Successfully compiled '${target}' \u2794 '${outputPath}' (${result.slideCount} ${formatDesc})${watchMsg}`
3192
3867
  };
3193
3868
  } catch (err) {
3194
3869
  const msg = err instanceof Error ? err.message : String(err);
@@ -3243,6 +3918,7 @@ export {
3243
3918
  parseInlineMarkdown,
3244
3919
  PptxRenderer,
3245
3920
  HtmlRenderer,
3921
+ PdfRenderer,
3246
3922
  startDevServer,
3247
3923
  VERSION,
3248
3924
  printHelp,
package/dist/index.d.ts CHANGED
@@ -7,8 +7,9 @@ export * from '@yumiamd/layout';
7
7
  export * from '@yumiamd/renderer';
8
8
  export * from '@yumiamd/renderer-pptx';
9
9
  export * from '@yumiamd/renderer-html';
10
+ export * from '@yumiamd/renderer-pdf';
10
11
 
11
- declare const VERSION = "0.1.10";
12
+ declare const VERSION = "0.1.13";
12
13
  declare function printHelp(): string;
13
14
  declare function runCli(argv: string[]): Promise<{
14
15
  exitCode: number;
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import {
3
3
  DefaultLayoutEngine,
4
4
  DefaultYumiaParser,
5
5
  HtmlRenderer,
6
+ PdfRenderer,
6
7
  PptxRenderer,
7
8
  THEME_REGISTRY,
8
9
  VERSION,
@@ -38,12 +39,13 @@ import {
38
39
  runCli,
39
40
  startDevServer,
40
41
  terminalTheme
41
- } from "./chunk-PQYPVPV2.js";
42
+ } from "./chunk-6GEDN7OB.js";
42
43
  export {
43
44
  DEFAULT_VIEWPORT,
44
45
  DefaultLayoutEngine,
45
46
  DefaultYumiaParser,
46
47
  HtmlRenderer,
48
+ PdfRenderer,
47
49
  PptxRenderer,
48
50
  THEME_REGISTRY,
49
51
  VERSION,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "yumiamd",
3
- "version": "0.1.10",
3
+ "version": "0.1.13",
4
4
  "description": "Command line interface and compiler for YumiaMD presentations",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -16,18 +16,20 @@
16
16
  }
17
17
  },
18
18
  "dependencies": {
19
+ "pdfkit": "^0.20.2",
19
20
  "pptxgenjs": "^4.0.1"
20
21
  },
21
22
  "devDependencies": {
22
23
  "tsup": "^8.5.1",
23
- "@yumiamd/ast": "0.1.10",
24
- "@yumiamd/layout": "0.1.10",
25
- "@yumiamd/core": "0.1.10",
26
- "@yumiamd/parser": "0.1.10",
27
- "@yumiamd/renderer": "0.1.10",
28
- "@yumiamd/renderer-pptx": "0.1.10",
29
- "@yumiamd/renderer-html": "0.1.10",
30
- "@yumiamd/theme": "0.1.10"
24
+ "@yumiamd/core": "0.1.13",
25
+ "@yumiamd/parser": "0.1.13",
26
+ "@yumiamd/renderer": "0.1.13",
27
+ "@yumiamd/ast": "0.1.13",
28
+ "@yumiamd/layout": "0.1.13",
29
+ "@yumiamd/renderer-html": "0.1.13",
30
+ "@yumiamd/renderer-pdf": "0.1.13",
31
+ "@yumiamd/renderer-pptx": "0.1.13",
32
+ "@yumiamd/theme": "0.1.13"
31
33
  },
32
34
  "keywords": [
33
35
  "yumia",
@@ -53,7 +55,7 @@
53
55
  "LICENSE"
54
56
  ],
55
57
  "scripts": {
56
- "build": "tsup src/bin.ts src/index.ts --format esm --dts --clean --external pptxgenjs",
58
+ "build": "tsup src/bin.ts src/index.ts --format esm --dts --clean --external pptxgenjs,pdfkit",
57
59
  "typecheck": "tsc --noEmit"
58
60
  }
59
61
  }