@thanh01.pmt/presentation-kit 0.2.10 → 0.2.12

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/ai/index.cjs CHANGED
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunk3Q4RMZVQ_cjs = require('../chunk-3Q4RMZVQ.cjs');
3
+ var chunk53GLUCYC_cjs = require('../chunk-53GLUCYC.cjs');
4
4
  var zod = require('zod');
5
5
 
6
6
  var listSlidePresetsSchema = zod.z.object({
@@ -64,7 +64,7 @@ var generateDeckOutlineSchema = zod.z.object({
64
64
  // src/ai/tools.ts
65
65
  function executeListSlidePresets(params) {
66
66
  const category = params?.category;
67
- const presets = !category || category === "all" ? chunk3Q4RMZVQ_cjs.SLIDE_LAYOUT_PRESETS : chunk3Q4RMZVQ_cjs.getSlideLayoutPresetsByCategory(category);
67
+ const presets = !category || category === "all" ? chunk53GLUCYC_cjs.SLIDE_LAYOUT_PRESETS : chunk53GLUCYC_cjs.getSlideLayoutPresetsByCategory(category);
68
68
  return {
69
69
  count: presets.length,
70
70
  presets: presets.map((p) => ({
@@ -78,7 +78,7 @@ function executeListSlidePresets(params) {
78
78
  };
79
79
  }
80
80
  function executeCreateSlideFromPreset(params) {
81
- const preset = chunk3Q4RMZVQ_cjs.getSlideLayoutPresetById(params.presetId);
81
+ const preset = chunk53GLUCYC_cjs.getSlideLayoutPresetById(params.presetId);
82
82
  if (!preset) {
83
83
  return {
84
84
  success: false,
@@ -86,7 +86,7 @@ function executeCreateSlideFromPreset(params) {
86
86
  error: `Preset with ID "${params.presetId}" not found. Use listSlidePresets to see available layout templates.`
87
87
  };
88
88
  }
89
- const layoutComment = chunk3Q4RMZVQ_cjs.serializeLayoutToComment(preset.layout);
89
+ const layoutComment = chunk53GLUCYC_cjs.serializeLayoutToComment(preset.layout);
90
90
  const title = params.title;
91
91
  const subtitle = params.subtitle ? `
92
92
  ### ${params.subtitle}` : "";
@@ -227,7 +227,7 @@ Presenter Notes:
227
227
  function executeApplySlideLayout(params) {
228
228
  let layoutData = null;
229
229
  if (params.presetId) {
230
- const preset = chunk3Q4RMZVQ_cjs.getSlideLayoutPresetById(params.presetId);
230
+ const preset = chunk53GLUCYC_cjs.getSlideLayoutPresetById(params.presetId);
231
231
  if (!preset) {
232
232
  return {
233
233
  success: false,
@@ -239,7 +239,7 @@ function executeApplySlideLayout(params) {
239
239
  } else if (params.boxes && params.boxes.length > 0) {
240
240
  layoutData = { boxes: params.boxes };
241
241
  }
242
- const updatedMarkdown = chunk3Q4RMZVQ_cjs.updateSlideLayoutInMarkdown(
242
+ const updatedMarkdown = chunk53GLUCYC_cjs.updateSlideLayoutInMarkdown(
243
243
  params.markdown,
244
244
  params.slideIndex,
245
245
  layoutData
@@ -250,7 +250,7 @@ function executeApplySlideLayout(params) {
250
250
  };
251
251
  }
252
252
  function executeUpdatePresenterNotes(params) {
253
- const { frontmatter, slides } = chunk3Q4RMZVQ_cjs.splitMarkdownSlides(params.markdown);
253
+ const { frontmatter, slides } = chunk53GLUCYC_cjs.splitMarkdownSlides(params.markdown);
254
254
  if (params.slideIndex < 0 || params.slideIndex >= slides.length) {
255
255
  return {
256
256
  success: false,
@@ -412,18 +412,530 @@ When a precise coordinate layout is specified, include the clean YAML block at t
412
412
  pos: [670, 150, 530, 510]
413
413
  -->
414
414
  \`\`\`
415
+
416
+ ---
417
+
418
+ ## 7. STEP REVEAL & PROGRESSIVE DISCLOSURE
419
+ When presenting lists, comparisons, or multi-phase concepts, support sequential reveals:
420
+ - Annotate lists or elements with \`<!-- v-click -->\` or apply class \`.step-reveal\` / \`[data-step]\`.
421
+ - Clicking or pressing forward arrow reveals items sequentially before transitioning to the next slide.
422
+ - Keep list items concise (< 15 words) to maintain visual rhythm during progressive steps.
415
423
  `;
424
+ var validateSlideDeckSchema = zod.z.object({
425
+ format: zod.z.enum(["auto", "html", "markdown"]).default("auto").describe('Deck format to validate: "html", "markdown", or "auto"'),
426
+ markdown: zod.z.string().optional().describe("Raw Markdown / Marp slide presentation content"),
427
+ htmlDeck: zod.z.object({
428
+ title: zod.z.string().optional(),
429
+ subtitle: zod.z.string().optional(),
430
+ theme: zod.z.string().optional(),
431
+ slides: zod.z.array(zod.z.object({
432
+ layoutId: zod.z.string(),
433
+ slots: zod.z.record(zod.z.any()),
434
+ notes: zod.z.string().optional()
435
+ })).optional()
436
+ }).optional().describe("Structured HTML deck data matching HtmlDeckData"),
437
+ strict: zod.z.boolean().default(false).describe("If true, warnings cause valid to be false")
438
+ });
439
+ function countWords(str) {
440
+ if (!str) return 0;
441
+ return str.trim().split(/\s+/).filter(Boolean).length;
442
+ }
443
+ function validateHtmlSlideDeck(deck, strict = false) {
444
+ const issues = [];
445
+ const suggestions = [];
446
+ const slides = deck.slides || [];
447
+ const slideCount = slides.length;
448
+ if (slideCount === 0) {
449
+ return {
450
+ success: false,
451
+ valid: false,
452
+ score: 0,
453
+ format: "html",
454
+ slideCount: 0,
455
+ notesCoveragePercent: 0,
456
+ issues: [{
457
+ slideIndex: 0,
458
+ severity: "error",
459
+ rule: "EMPTY_DECK",
460
+ message: "Presentation deck contains no slides."
461
+ }],
462
+ suggestions: ["Add at least one slide (e.g. hero-cover) to the deck."]
463
+ };
464
+ }
465
+ let notesCount = 0;
466
+ let hasCover = false;
467
+ let hasQuiz = false;
468
+ let hasSummary = false;
469
+ slides.forEach((slide, idx) => {
470
+ const slideNumber = idx + 1;
471
+ const layoutId = slide.layoutId;
472
+ const preset = chunk53GLUCYC_cjs.HTML_SLIDE_PRESETS[layoutId];
473
+ if (!preset) {
474
+ issues.push({
475
+ slideIndex: slideNumber,
476
+ severity: "error",
477
+ rule: "INVALID_LAYOUT_PRESET",
478
+ message: `Unknown layoutId "${slide.layoutId}". Available presets: ${Object.keys(chunk53GLUCYC_cjs.HTML_SLIDE_PRESETS).join(", ")}`
479
+ });
480
+ return;
481
+ }
482
+ if (preset.category === "cover" && idx === 0) hasCover = true;
483
+ if (preset.id === "checkpoint-quiz") hasQuiz = true;
484
+ if (preset.id === "summary-takeaways") hasSummary = true;
485
+ for (const slotDef of preset.slots) {
486
+ if (slotDef.required) {
487
+ const val = slide.slots?.[slotDef.name];
488
+ if (val === void 0 || val === null || typeof val === "string" && val.trim() === "") {
489
+ issues.push({
490
+ slideIndex: slideNumber,
491
+ severity: "error",
492
+ rule: "MISSING_REQUIRED_SLOT",
493
+ message: `Slide ${slideNumber} (${layoutId}) is missing required slot "${slotDef.name}" (${slotDef.label}).`
494
+ });
495
+ }
496
+ }
497
+ }
498
+ const slots = slide.slots || {};
499
+ for (const [key, val] of Object.entries(slots)) {
500
+ if (typeof val === "string") {
501
+ const words = countWords(val);
502
+ if (key !== "code" && words > 50) {
503
+ issues.push({
504
+ slideIndex: slideNumber,
505
+ severity: "warning",
506
+ rule: "ZERO_SCROLL_WORD_BUDGET",
507
+ message: `Slot "${key}" on slide ${slideNumber} has ${words} words. Recommended max is 35-40 words to prevent vertical scrolling.`
508
+ });
509
+ }
510
+ } else if (Array.isArray(val)) {
511
+ if (val.length > 5) {
512
+ issues.push({
513
+ slideIndex: slideNumber,
514
+ severity: "warning",
515
+ rule: "EXCESSIVE_LIST_ITEMS",
516
+ message: `List slot "${key}" on slide ${slideNumber} has ${val.length} items. Keep to 3-4 items for optimal readability.`
517
+ });
518
+ }
519
+ val.forEach((item, itemIdx) => {
520
+ if (typeof item === "string") {
521
+ const w = countWords(item);
522
+ if (w > 20) {
523
+ issues.push({
524
+ slideIndex: slideNumber,
525
+ severity: "warning",
526
+ rule: "BULLET_WORD_BUDGET",
527
+ message: `Bullet #${itemIdx + 1} in "${key}" on slide ${slideNumber} is ${w} words. Keep bullet points concise (< 15 words).`
528
+ });
529
+ }
530
+ }
531
+ });
532
+ }
533
+ }
534
+ if (slide.notes && slide.notes.trim().length > 0) {
535
+ notesCount++;
536
+ const notes = slide.notes.trim();
537
+ const hasQuestion = notes.includes("?") || /cold-?call|question/i.test(notes);
538
+ const hasTip = /scaffold|tip|analogy|hint/i.test(notes);
539
+ if (!hasQuestion || !hasTip) {
540
+ issues.push({
541
+ slideIndex: slideNumber,
542
+ severity: "warning",
543
+ rule: "INCOMPLETE_PRESENTER_NOTES",
544
+ message: `Presenter notes for slide ${slideNumber} should follow the 3-part contract: Talk Track, Cold-Call Question, and Scaffolding Tip.`
545
+ });
546
+ }
547
+ } else {
548
+ issues.push({
549
+ slideIndex: slideNumber,
550
+ severity: "error",
551
+ rule: "MISSING_PRESENTER_NOTES",
552
+ message: `Slide ${slideNumber} is missing presenter notes. 100% presenter notes coverage is required.`
553
+ });
554
+ }
555
+ });
556
+ if (slideCount >= 3 && !hasCover) {
557
+ issues.push({
558
+ slideIndex: 1,
559
+ severity: "warning",
560
+ rule: "MISSING_HERO_COVER",
561
+ message: 'Slide 1 should ideally use the "hero-cover" layout preset to introduce the topic and objectives.'
562
+ });
563
+ }
564
+ if (slideCount >= 6 && !hasQuiz) {
565
+ issues.push({
566
+ slideIndex: Math.floor(slideCount / 2),
567
+ severity: "warning",
568
+ rule: "MISSING_FORMATIVE_CHECKPOINT",
569
+ message: `Deck has ${slideCount} slides but lacks a "checkpoint-quiz" for mid-lesson active recall.`
570
+ });
571
+ }
572
+ if (slideCount >= 4 && !hasSummary) {
573
+ issues.push({
574
+ slideIndex: slideCount,
575
+ severity: "warning",
576
+ rule: "MISSING_SUMMARY_SLIDE",
577
+ message: 'Deck lacks a "summary-takeaways" wrap-up slide at the conclusion of the presentation.'
578
+ });
579
+ }
580
+ const notesCoveragePercent = Math.round(notesCount / slideCount * 100);
581
+ const errorCount = issues.filter((i) => i.severity === "error").length;
582
+ const warningCount = issues.filter((i) => i.severity === "warning").length;
583
+ let score = 100 - errorCount * 15 - warningCount * 4;
584
+ score = Math.max(0, Math.min(100, score));
585
+ const valid = strict ? issues.length === 0 : errorCount === 0;
586
+ if (errorCount > 0) {
587
+ suggestions.push(`Resolve ${errorCount} blocking error(s) before presenting or publishing.`);
588
+ }
589
+ if (notesCoveragePercent < 100) {
590
+ suggestions.push(`Increase presenter notes coverage from ${notesCoveragePercent}% to 100%.`);
591
+ }
592
+ if (!hasQuiz && slideCount >= 6) {
593
+ suggestions.push("Add an interactive checkpoint quiz around the midpoint of the lesson.");
594
+ }
595
+ return {
596
+ success: true,
597
+ valid,
598
+ score,
599
+ format: "html",
600
+ slideCount,
601
+ notesCoveragePercent,
602
+ issues,
603
+ suggestions
604
+ };
605
+ }
606
+ function validateMarkdownSlideDeck(markdown, strict = false) {
607
+ const issues = [];
608
+ const suggestions = [];
609
+ if (!markdown || markdown.trim().length === 0) {
610
+ return {
611
+ success: false,
612
+ valid: false,
613
+ score: 0,
614
+ format: "markdown",
615
+ slideCount: 0,
616
+ notesCoveragePercent: 0,
617
+ issues: [{
618
+ slideIndex: 0,
619
+ severity: "error",
620
+ rule: "EMPTY_MARKDOWN",
621
+ message: "Markdown slide presentation is empty."
622
+ }],
623
+ suggestions: ['Provide Markdown slide content delimited by "---".']
624
+ };
625
+ }
626
+ const rawSlides = markdown.split(/\n---\n/);
627
+ const slideCount = rawSlides.length;
628
+ let notesCount = 0;
629
+ rawSlides.forEach((slideContent, idx) => {
630
+ const slideNumber = idx + 1;
631
+ const trimmed = slideContent.trim();
632
+ const notesMatch = trimmed.match(/<!--\s*(?:Presenter Notes:?[\s\S]*?|[\s\S]*?notes[\s\S]*?)-->/i);
633
+ if (notesMatch) {
634
+ notesCount++;
635
+ const noteBody = notesMatch[0];
636
+ const hasQuestion = noteBody.includes("?") || /cold-?call|question/i.test(noteBody);
637
+ const hasTip = /scaffold|tip|analogy|hint/i.test(noteBody);
638
+ if (!hasQuestion || !hasTip) {
639
+ issues.push({
640
+ slideIndex: slideNumber,
641
+ severity: "warning",
642
+ rule: "INCOMPLETE_PRESENTER_NOTES",
643
+ message: `Presenter notes on slide ${slideNumber} should include Talk Track, a Cold-Call Question, and a Scaffolding Tip.`
644
+ });
645
+ }
646
+ } else {
647
+ issues.push({
648
+ slideIndex: slideNumber,
649
+ severity: "error",
650
+ rule: "MISSING_PRESENTER_NOTES",
651
+ message: `Slide ${slideNumber} is missing presenter notes comments (<!-- Presenter Notes: ... -->).`
652
+ });
653
+ }
654
+ const codeBlockTokens = trimmed.match(/```/g);
655
+ if (codeBlockTokens && codeBlockTokens.length % 2 !== 0) {
656
+ issues.push({
657
+ slideIndex: slideNumber,
658
+ severity: "error",
659
+ rule: "UNCLOSED_CODE_BLOCK",
660
+ message: `Slide ${slideNumber} contains unclosed code fence backticks (\`\`\`).`
661
+ });
662
+ }
663
+ const cleanBody = trimmed.replace(/<!--[\s\S]*?-->/g, "").replace(/```[\s\S]*?```/g, "");
664
+ const words = countWords(cleanBody);
665
+ if (words > 100) {
666
+ issues.push({
667
+ slideIndex: slideNumber,
668
+ severity: "warning",
669
+ rule: "ZERO_SCROLL_WORD_BUDGET",
670
+ message: `Slide ${slideNumber} body has ${words} words. Keep within 40-70 words per slide to prevent vertical scroll.`
671
+ });
672
+ }
673
+ });
674
+ const notesCoveragePercent = Math.round(notesCount / slideCount * 100);
675
+ const errorCount = issues.filter((i) => i.severity === "error").length;
676
+ const warningCount = issues.filter((i) => i.severity === "warning").length;
677
+ let score = 100 - errorCount * 15 - warningCount * 4;
678
+ score = Math.max(0, Math.min(100, score));
679
+ const valid = strict ? issues.length === 0 : errorCount === 0;
680
+ return {
681
+ success: true,
682
+ valid,
683
+ score,
684
+ format: "markdown",
685
+ slideCount,
686
+ notesCoveragePercent,
687
+ issues,
688
+ suggestions
689
+ };
690
+ }
691
+ function executeValidateSlideDeck(input) {
692
+ const format = input.format || "auto";
693
+ if (format === "html" || format === "auto" && input.htmlDeck && input.htmlDeck.slides) {
694
+ return validateHtmlSlideDeck(input.htmlDeck || { slides: [] }, input.strict);
695
+ }
696
+ if (format === "markdown" || format === "auto" && input.markdown) {
697
+ return validateMarkdownSlideDeck(input.markdown || "", input.strict);
698
+ }
699
+ return {
700
+ success: false,
701
+ valid: false,
702
+ score: 0,
703
+ format: "html",
704
+ slideCount: 0,
705
+ notesCoveragePercent: 0,
706
+ issues: [{
707
+ slideIndex: 0,
708
+ severity: "error",
709
+ rule: "INVALID_INPUT",
710
+ message: "Neither htmlDeck nor markdown was supplied for slide deck validation."
711
+ }],
712
+ suggestions: ['Provide either "htmlDeck" object or "markdown" string in the validation parameters.']
713
+ };
714
+ }
715
+ var handleValidateSlideDeck = executeValidateSlideDeck;
716
+ var listHtmlSlidePresetsSchema = zod.z.object({
717
+ category: zod.z.enum(["all", "cover", "content", "split", "grid", "timeline", "callout", "assessment"]).optional().describe("Optional category filter for HTML layout presets")
718
+ });
719
+ var htmlSlideSlotDataSchema = zod.z.object({
720
+ layoutId: zod.z.enum([
721
+ "hero-cover",
722
+ "split-concept-code",
723
+ "two-columns-compare",
724
+ "three-cards-grid",
725
+ "timeline-steps",
726
+ "metric-callout",
727
+ "checkpoint-quiz",
728
+ "summary-takeaways"
729
+ ]).describe("Layout preset ID"),
730
+ slots: zod.z.record(zod.z.any()).describe("Key-value slot dictionary matching the chosen layout requirements"),
731
+ notes: zod.z.string().optional().describe("Presenter speech track or teaching guide for this slide")
732
+ });
733
+ var generateHtmlDeckSchema = zod.z.object({
734
+ title: zod.z.string().describe("Title of the presentation / lesson deck"),
735
+ subtitle: zod.z.string().optional().describe("Subtitle or target audience / grade"),
736
+ theme: zod.z.enum(["blue-professional", "editorial-forest", "cobalt-grid", "studio", "monochrome"]).default("blue-professional").describe("Visual theme palette"),
737
+ slides: zod.z.array(htmlSlideSlotDataSchema).min(1).describe("List of slides with designated layouts and slot contents")
738
+ });
739
+ var createHtmlSlideSchema = zod.z.object({
740
+ layoutId: zod.z.enum([
741
+ "hero-cover",
742
+ "split-concept-code",
743
+ "two-columns-compare",
744
+ "three-cards-grid",
745
+ "timeline-steps",
746
+ "metric-callout",
747
+ "checkpoint-quiz",
748
+ "summary-takeaways"
749
+ ]).describe("Layout preset ID"),
750
+ slots: zod.z.record(zod.z.any()).describe("Key-value content slots"),
751
+ notes: zod.z.string().optional().describe("Speaker talk track or question prompts")
752
+ });
753
+
754
+ // src/ai/html/prompt.ts
755
+ var SLIDE_HTML_PROMPT_CONTRACT = `
756
+ # \u{1F3A8} HTML SLIDE ENGINE \u2014 AGENT GENERATION CONTRACT
757
+
758
+ You are an expert Presentation Designer and Curriculum Architect producing professional, high-impact slide decks.
759
+ Instead of generating free-form HTML or brittle Markdown hacks, you MUST fill structured content into pre-tested **Layout Presets**.
760
+
761
+ ## Available Layout Presets & Required Slots:
762
+
763
+ 1. **hero-cover** (Cover / Title Slide)
764
+ - \`tag\` (string): e.g. "Unit 01 \xB7 Lesson 02"
765
+ - \`title\` (string): Main bold headline
766
+ - \`subtitle\` (string): Subtitle or 1-sentence learning objective
767
+ - \`author\` (string): Instructor / Organization
768
+ - \`date\` (string): Course term or date
769
+
770
+ 2. **split-concept-code** (Theory + Code Snippet)
771
+ - \`tag\` (string): Section topic tag
772
+ - \`title\` (string): Topic heading
773
+ - \`points\` (string[]): 3 to 4 concise bullet takeaways
774
+ - \`code\` (string): Executable source code
775
+ - \`language\` (string): Language name (e.g. "python", "typescript", "swift")
776
+ - \`codeNote\` (string, optional): One-line hint or execution output
777
+
778
+ 3. **two-columns-compare** (Comparison / Pros vs Cons)
779
+ - \`tag\` (string): Topic tag
780
+ - \`title\` (string): Headline
781
+ - \`col1Title\` (string): e.g. "Synchronous I/O"
782
+ - \`col1Items\` (string[]): 3 to 4 points
783
+ - \`col2Title\` (string): e.g. "Asynchronous I/O"
784
+ - \`col2Items\` (string[]): 3 to 4 points
785
+
786
+ 4. **three-cards-grid** (3 Core Pillars / Architecture)
787
+ - \`tag\` (string): e.g. "Core Principles"
788
+ - \`title\` (string): Overview headline
789
+ - \`cards\` (array of objects): Exactly 3 cards:
790
+ - \`badge\`: e.g. "01", "LAYER 1"
791
+ - \`title\`: Card headline
792
+ - \`desc\`: 1-2 sentence description
793
+ - \`footer\` (optional): Key takeaway
794
+
795
+ 5. **timeline-steps** (Algorithm / Execution Pipeline)
796
+ - \`tag\` (string): e.g. "Workflow"
797
+ - \`title\` (string): Headline
798
+ - \`steps\` (array of objects): 3 to 5 steps:
799
+ - \`stepNum\` (number/string): 1, 2, 3...
800
+ - \`title\`: Step name
801
+ - \`desc\`: What happens at this step
802
+
803
+ 6. **metric-callout** (Key Theorem / Benchmark Statistic)
804
+ - \`tag\` (string): e.g. "Time Complexity"
805
+ - \`metric\` (string): Big stat (e.g. "O(log N)", "99.99%", "10x")
806
+ - \`metricLabel\` (string): e.g. "Lookup Efficiency"
807
+ - \`title\` (string): Main takeaway
808
+ - \`desc\` (string): Contextual explanation
809
+
810
+ 7. **checkpoint-quiz** (Interactive Checkpoint)
811
+ - \`tag\` (string): e.g. "Quick Knowledge Check"
812
+ - \`question\` (string): Clear question prompt
813
+ - \`options\` (array of objects): 2 to 4 options:
814
+ - \`label\`: "A", "B", "C", "D"
815
+ - \`text\`: Option text
816
+ - \`explanation\` (string): Explanatory rationale
817
+
818
+ 8. **summary-takeaways** (Wrap-Up / Next Steps)
819
+ - \`tag\` (string): e.g. "Recap"
820
+ - \`title\` (string): Wrap-up headline
821
+ - \`takeaways\` (string[]): 3 to 4 memorable bullet points
822
+ - \`nextStep\` (string): Teaser for the next lesson or project
823
+
824
+ ## Aesthetic & Quality Invariants ("Anti-AI-Slop"):
825
+ - **Brevity is King (Zero-Scroll Invariant):** Each slide is calibrated for a 1920\xD71080 canvas. Maximum **35\u201340 words** per card or column; maximum **15 words** per bullet item. Never write dense multi-sentence paragraphs that cause vertical scrolling.
826
+ - **Pedagogical Pacing:** Start with \`hero-cover\`, alternate between \`split-concept-code\`, \`two-columns-compare\` and \`three-cards-grid\`, insert a \`checkpoint-quiz\` midway, and finish with \`summary-takeaways\`.
827
+ - **Theme Selection:**
828
+ - \`blue-professional\`: General academic, clean engineering, trustworthy.
829
+ - \`cobalt-grid\`: Advanced tech, algorithms, robotics, cybersecurity.
830
+ - \`editorial-forest\`: Thoughtful design, literature, ethics, science.
831
+ - \`studio\`: Minimalist product design, modern software.
832
+ - \`monochrome\`: Pure high-contrast dark mode.
833
+
834
+ ## \u{1FA84} Step Reveal & Progressive Disclosure:
835
+ - The presentation shell supports sequential step reveal via mouse click or Space/Arrow keys.
836
+ - Bullet lists (\`points\`, \`col1Items\`, \`col2Items\`), cards in \`three-cards-grid\`, and steps in \`timeline-steps\` reveal progressively one by one before navigating to the next slide.
837
+ - In custom HTML slots, you can attach \`class="step-reveal"\`, \`data-step\`, \`data-reveal\`, or \`data-auto-reveal="true"\` on parent containers to enable click-by-click stepped appearance.
838
+
839
+ ## \u{1F399}\uFE0F Mandatory 3-Part Presenter Notes Contract:
840
+ Every single slide MUST include the \`notes\` property structured with these 3 explicit components:
841
+ 1. **Talk Track:** 2-3 sentences of exact conversational speaking script for the teacher/presenter.
842
+ 2. **Cold-Call Check Question:** 1 diagnostic question to check understanding with a named student or attendee.
843
+ 3. **Scaffolding Tip:** 1 intuitive analogy or troubleshooting hint in case learners struggle with the concept.
844
+
845
+ Example Notes:
846
+ \`\`\`markdown
847
+ Talk Track: Here we contrast synchronous blocking I/O with asynchronous event-driven handling. Notice how threads remain idle while waiting for network responses.
848
+ Cold-Call: "Jordan, looking at the left column, what happens to thread pool throughput when network latency quadruples?"
849
+ Scaffolding Tip: Compare it to ordering coffee at a counter (async buzzer) versus waiting at the register until the cup is brewed (sync blocking).
850
+ \`\`\`
851
+ `;
852
+
853
+ // src/ai/html/tools.ts
854
+ function handleListHtmlSlidePresets(input) {
855
+ const category = input.category || "all";
856
+ const presets = Object.values(chunk53GLUCYC_cjs.HTML_SLIDE_PRESETS).filter((p) => category === "all" || p.category === category).map((p) => ({
857
+ id: p.id,
858
+ name: p.name,
859
+ category: p.category,
860
+ description: p.description,
861
+ slots: p.slots.map((s) => ({
862
+ name: s.name,
863
+ label: s.label,
864
+ type: s.type,
865
+ required: Boolean(s.required),
866
+ description: s.description
867
+ }))
868
+ }));
869
+ return {
870
+ success: true,
871
+ presets,
872
+ availableThemes: Object.keys(chunk53GLUCYC_cjs.HTML_THEMES)
873
+ };
874
+ }
875
+ function handleGenerateHtmlDeck(input) {
876
+ try {
877
+ const result = chunk53GLUCYC_cjs.compileHtmlDeck(input);
878
+ return {
879
+ success: true,
880
+ title: result.title,
881
+ slideCount: result.slideCount,
882
+ theme: result.theme.id,
883
+ html: result.html
884
+ };
885
+ } catch (err) {
886
+ return {
887
+ success: false,
888
+ error: err.message || "Failed to compile HTML slide deck"
889
+ };
890
+ }
891
+ }
892
+ function handleCreateHtmlSlide(input) {
893
+ const preset = chunk53GLUCYC_cjs.HTML_SLIDE_PRESETS[input.layoutId];
894
+ if (!preset) {
895
+ return {
896
+ success: false,
897
+ error: `Unknown layout preset: ${input.layoutId}`
898
+ };
899
+ }
900
+ return {
901
+ success: true,
902
+ slide: {
903
+ layoutId: input.layoutId,
904
+ slots: input.slots,
905
+ notes: input.notes
906
+ }
907
+ };
908
+ }
909
+ var executeListHtmlSlidePresets = handleListHtmlSlidePresets;
910
+ var executeGenerateHtmlDeck = handleGenerateHtmlDeck;
911
+ var executeCreateHtmlSlide = handleCreateHtmlSlide;
416
912
 
417
913
  exports.SLIDE_DESIGN_PROMPT_CONTRACT = SLIDE_DESIGN_PROMPT_CONTRACT;
914
+ exports.SLIDE_HTML_PROMPT_CONTRACT = SLIDE_HTML_PROMPT_CONTRACT;
418
915
  exports.applySlideLayoutSchema = applySlideLayoutSchema;
916
+ exports.createHtmlSlideSchema = createHtmlSlideSchema;
419
917
  exports.createSlideFromPresetSchema = createSlideFromPresetSchema;
420
918
  exports.executeApplySlideLayout = executeApplySlideLayout;
919
+ exports.executeCreateHtmlSlide = executeCreateHtmlSlide;
421
920
  exports.executeCreateSlideFromPreset = executeCreateSlideFromPreset;
422
921
  exports.executeGenerateDeckOutline = executeGenerateDeckOutline;
922
+ exports.executeGenerateHtmlDeck = executeGenerateHtmlDeck;
923
+ exports.executeListHtmlSlidePresets = executeListHtmlSlidePresets;
423
924
  exports.executeListSlidePresets = executeListSlidePresets;
424
925
  exports.executeUpdatePresenterNotes = executeUpdatePresenterNotes;
926
+ exports.executeValidateSlideDeck = executeValidateSlideDeck;
425
927
  exports.generateDeckOutlineSchema = generateDeckOutlineSchema;
928
+ exports.generateHtmlDeckSchema = generateHtmlDeckSchema;
929
+ exports.handleCreateHtmlSlide = handleCreateHtmlSlide;
930
+ exports.handleGenerateHtmlDeck = handleGenerateHtmlDeck;
931
+ exports.handleListHtmlSlidePresets = handleListHtmlSlidePresets;
932
+ exports.handleValidateSlideDeck = handleValidateSlideDeck;
933
+ exports.htmlSlideSlotDataSchema = htmlSlideSlotDataSchema;
934
+ exports.listHtmlSlidePresetsSchema = listHtmlSlidePresetsSchema;
426
935
  exports.listSlidePresetsSchema = listSlidePresetsSchema;
427
936
  exports.updatePresenterNotesSchema = updatePresenterNotesSchema;
937
+ exports.validateHtmlSlideDeck = validateHtmlSlideDeck;
938
+ exports.validateMarkdownSlideDeck = validateMarkdownSlideDeck;
939
+ exports.validateSlideDeckSchema = validateSlideDeckSchema;
428
940
  //# sourceMappingURL=index.cjs.map
429
941
  //# sourceMappingURL=index.cjs.map