@@ -566,14 +566,31 @@ INCORRECT: Putting the better option on the left will show it with RED ✗ styli
566566 ]
567567}
568568
569+ KEY TAKEAWAYS GENERATION (TWO-STEP PROCESS):
570+
571+ When creating the "takeaway" slide at the end of the presentation:
572+
573+ STEP 1: First, review the lesson and mentally list ALL significant takeaways
574+ - Identify every important concept, pattern, or insight from the lesson
575+ - Don't filter yet—just enumerate everything worth remembering
576+
577+ STEP 2: Then, condense to the 3-5 MOST critical takeaways
578+ - Prioritize by impact and generality (what will matter most in production?)
579+ - Combine related points into higher-level insights when possible
580+ - Remove redundant or overly specific points
581+ - Ensure each takeaway is actionable and memorable
582+
583+ IMPORTANT: The final takeaway slide MUST have exactly 3-5 items, even if the source material lists more.
584+ Quality over quantity—choose the most impactful insights.
585+
569586CRITICAL REQUIREMENTS:
570587
5715881. The output MUST be valid JSON - no preamble, no explanation, just the JSON object
5725892. Write the JSON directly to the file: ${ outputPath }
5735903. Include 8-15 slides (no more, no less)
5745914. Every slide MUST have speakerNotes with all fields
5755925. Code examples must be actual code from the lesson, not pseudocode
576- 6. Content arrays must have 3-5 items (except title slide)
593+ 6. Content arrays MUST have 3-5 items (except title slide) - THIS IS STRICTLY ENFORCED
5775947. PROMPT EXAMPLES: Use "code" or "codeComparison" slide types, NEVER bullet points
578595
579596BEFORE YOU GENERATE - CHECKLIST:
@@ -842,6 +859,85 @@ function validateComparisonSemantics(presentation) {
842859 } ;
843860}
844861
862+ /**
863+ * Validate that content arrays have 3-5 items maximum
864+ * @param {object } presentation - Generated presentation object
865+ * @returns {object } Validation result with issues
866+ */
867+ function validateContentArrayLengths ( presentation ) {
868+ const issues = [ ] ;
869+ const MIN_ITEMS = 3 ;
870+ const MAX_ITEMS = 5 ;
871+
872+ // Slide types that must have content arrays with 3-5 items
873+ const slidesWithContent = presentation . slides . filter ( slide => {
874+ // Skip title slide (different rules)
875+ if ( slide . type === 'title' ) return false ;
876+
877+ // Check slides with content arrays
878+ return slide . content && Array . isArray ( slide . content ) ;
879+ } ) ;
880+
881+ for ( const slide of slidesWithContent ) {
882+ const contentLength = slide . content . length ;
883+
884+ if ( contentLength < MIN_ITEMS || contentLength > MAX_ITEMS ) {
885+ issues . push ( {
886+ slide : slide . title || slide . type ,
887+ type : slide . type ,
888+ count : contentLength ,
889+ reason : contentLength < MIN_ITEMS
890+ ? `Only ${ contentLength } item(s), need at least ${ MIN_ITEMS } `
891+ : `Has ${ contentLength } item(s), maximum is ${ MAX_ITEMS } `
892+ } ) ;
893+ }
894+ }
895+
896+ // Check comparison slides (left/right content)
897+ const comparisonSlides = presentation . slides . filter ( s =>
898+ s . type === 'comparison' || s . type === 'marketingReality'
899+ ) ;
900+
901+ for ( const slide of comparisonSlides ) {
902+ const leftContent = slide . left ?. content || slide . metaphor ?. content ;
903+ const rightContent = slide . right ?. content || slide . reality ?. content ;
904+
905+ if ( leftContent && Array . isArray ( leftContent ) ) {
906+ const leftLength = leftContent . length ;
907+ if ( leftLength < MIN_ITEMS || leftLength > MAX_ITEMS ) {
908+ issues . push ( {
909+ slide : `${ slide . title } (LEFT)` ,
910+ type : slide . type ,
911+ count : leftLength ,
912+ reason : leftLength < MIN_ITEMS
913+ ? `Only ${ leftLength } item(s), need at least ${ MIN_ITEMS } `
914+ : `Has ${ leftLength } item(s), maximum is ${ MAX_ITEMS } `
915+ } ) ;
916+ }
917+ }
918+
919+ if ( rightContent && Array . isArray ( rightContent ) ) {
920+ const rightLength = rightContent . length ;
921+ if ( rightLength < MIN_ITEMS || rightLength > MAX_ITEMS ) {
922+ issues . push ( {
923+ slide : `${ slide . title } (RIGHT)` ,
924+ type : slide . type ,
925+ count : rightLength ,
926+ reason : rightLength < MIN_ITEMS
927+ ? `Only ${ rightLength } item(s), need at least ${ MIN_ITEMS } `
928+ : `Has ${ rightLength } item(s), maximum is ${ MAX_ITEMS } `
929+ } ) ;
930+ }
931+ }
932+ }
933+
934+ return {
935+ valid : issues . length === 0 ,
936+ issues,
937+ totalSlidesChecked : slidesWithContent . length + comparisonSlides . length
938+ } ;
939+ }
940+
845941/**
846942 * Validate that prompt examples are preserved as code blocks
847943 * @param {string } content - Parsed markdown content
@@ -987,6 +1083,24 @@ async function generatePresentation(filePath, manifest, config) {
9871083 console . log ( ` ✅ All ${ semanticValidation . totalComparisons } comparison slide(s) follow correct convention` ) ;
9881084 }
9891085
1086+ // Validate content array lengths (3-5 items)
1087+ // CRITICAL: This validation is intentionally strict and throws an error because
1088+ // slides with too many bullets become unreadable and overflow the layout.
1089+ // The two-step condensation process in the prompt should prevent this.
1090+ const contentValidation = validateContentArrayLengths ( presentation ) ;
1091+ if ( ! contentValidation . valid ) {
1092+ console . log ( ` ❌ BUILD FAILURE: ${ contentValidation . issues . length } content array violation(s):` ) ;
1093+ contentValidation . issues . forEach ( issue => {
1094+ console . log ( ` - Slide "${ issue . slide } " (${ issue . type } ): ${ issue . reason } ` ) ;
1095+ } ) ;
1096+ console . log ( ` ℹ️ All content arrays MUST have 3-5 items (except title slide)` ) ;
1097+ console . log ( ` ℹ️ For takeaway slides: use the two-step condensation process` ) ;
1098+ console . log ( ` ℹ️ The presentation was not saved. Fix the generation and try again.` ) ;
1099+ throw new Error ( 'Content array validation failed - slides have too many or too few items' ) ;
1100+ } else if ( contentValidation . totalSlidesChecked > 0 ) {
1101+ console . log ( ` ✅ All ${ contentValidation . totalSlidesChecked } content array(s) have 3-5 items` ) ;
1102+ }
1103+
9901104 // Validate prompt examples are preserved as code
9911105 // CRITICAL: This validation is intentionally strict and throws an error because
9921106 // prompt examples are core educational content that must be preserved exactly.
0 commit comments