@@ -115,6 +115,16 @@ def seg_end(i: int) -> float:
115115
116116 self .timed_play (Write (title ), run_time = 1.2 )
117117 self .timed_play (FadeIn (subtitle , shift = UP * 0.2 ), run_time = 0.8 )
118+
119+ tagline = Text (
120+ "Reproducible · version-controlled · fully automated" ,
121+ font_size = 16 , color = GREY_B ,
122+ )
123+ tagline .next_to (subtitle , DOWN , buff = 0.4 )
124+ self .wait_until (seg_start (1 ))
125+ self .timed_play (FadeIn (tagline , shift = UP * 0.15 ), run_time = 0.7 )
126+ title_group .add (tagline )
127+
118128 self .wait_until (seg_start (2 ))
119129
120130 # ── Beat 2: Title shrinks; show inputs ────────────────────────
@@ -188,7 +198,17 @@ def seg_end(i: int) -> float:
188198 out_group .add (ot )
189199
190200 self .timed_play (FadeIn (outputs_label ), run_time = 0.4 )
191- self .timed_play (* [FadeIn (o , shift = UP * 0.15 ) for o in out_group ], run_time = 0.6 )
201+
202+ out_per = max (0.3 , (seg_start (9 ) - self ._clock - 1.0 ) / len (out_group ))
203+ for o in out_group :
204+ self .timed_play (FadeIn (o , shift = UP * 0.15 ), run_time = out_per )
205+
206+ output_arrows = VGroup ()
207+ for sb in [stage_boxes [- 1 ]]:
208+ arr = _arrow (sb [0 ].get_bottom (), outputs_label .get_top (), color = C_ACCENT )
209+ output_arrows .add (arr )
210+ self .timed_play (Create (output_arrows [0 ]), run_time = 0.5 )
211+
192212 self .wait_until (seg_start (9 ))
193213
194214 # ── Beats 9-10: Concat + Pages ────────────────────────────────
@@ -208,6 +228,23 @@ def seg_end(i: int) -> float:
208228
209229 self .timed_play (Create (val_to_concat ), FadeIn (concat_box ), run_time = 0.5 )
210230 self .timed_play (Create (concat_to_pages ), FadeIn (pages_box ), run_time = 0.5 )
231+
232+ checks_group = VGroup ()
233+ check_items = [
234+ ("✓ stream presence" , C_GREEN ),
235+ ("✓ A/V drift < 2.75s" , C_GREEN ),
236+ ("✓ no blank frames" , C_GREEN ),
237+ ("✓ narration lint clean" , C_GREEN ),
238+ ]
239+ for ci , (cl , cc ) in enumerate (check_items ):
240+ ct = Text (cl , font_size = 12 , color = cc )
241+ ct .move_to (LEFT * 5.0 + DOWN * (1.8 + ci * 0.35 ))
242+ checks_group .add (ct )
243+
244+ check_per = max (0.3 , (seg_start (11 ) - self ._clock - 0.5 ) / len (check_items ))
245+ for ct in checks_group :
246+ self .timed_play (FadeIn (ct , shift = RIGHT * 0.2 ), run_time = check_per )
247+
211248 self .wait_until (seg_start (11 ))
212249
213250 # ── Beat 11: Single command highlight ─────────────────────────
@@ -223,6 +260,28 @@ def seg_end(i: int) -> float:
223260
224261 self .timed_play (FadeIn (cmd_group , shift = UP * 0.3 ), run_time = 0.7 )
225262 self .timed_play (Indicate (cmd_group , color = C_ACCENT , scale_factor = 1.05 ), run_time = 0.8 )
263+
264+ config_items = VGroup ()
265+ cfg_entries = [
266+ ("segments:" , C_ACCENT ),
267+ (" visual_map:" , C_TEAL ),
268+ (" tts:" , C_PURPLE ),
269+ (" validation:" , C_RED ),
270+ (" wizard:" , C_ORANGE ),
271+ ]
272+ for ci , (cl , cc ) in enumerate (cfg_entries ):
273+ ct = Text (cl , font_size = 12 , color = cc , font = "Monospace" )
274+ ct .move_to (RIGHT * 4.0 + DOWN * (1.8 + ci * 0.3 ))
275+ config_items .add (ct )
276+
277+ cfg_label = Text ("docgen.yaml" , font_size = 14 , color = C_ORANGE , weight = BOLD )
278+ cfg_label .move_to (RIGHT * 4.0 + DOWN * 1.4 )
279+ self .timed_play (FadeIn (cfg_label ), run_time = 0.3 )
280+
281+ cfg_per = max (0.2 , (seg_start (12 ) - self ._clock - 0.3 ) / len (config_items ))
282+ for ct in config_items :
283+ self .timed_play (FadeIn (ct , shift = RIGHT * 0.15 ), run_time = cfg_per )
284+
226285 self .wait_until (seg_start (12 ))
227286
228287 # ── Beat 12: Final + fade out ─────────────────────────────────
@@ -352,6 +411,36 @@ def seg_end(i: int) -> float:
352411 * [FadeIn (c , shift = LEFT * 0.1 ) for c in checks ],
353412 run_time = 0.5 ,
354413 )
414+ self .wait_until (seg_start (6 ))
415+
416+ # ── Beats 6-7: Exclude patterns filter animation ─────────
417+ exclude_title = Text ("Excluded by docgen.yaml:" , font_size = 13 , color = C_ORANGE )
418+ exclude_title .move_to (RIGHT * 2.5 + UP * 0.8 )
419+
420+ excluded_dirs = [
421+ "node_modules/" ,
422+ "__pycache__/" ,
423+ ".pytest_cache/" ,
424+ ".venv/" ,
425+ ]
426+ excl_group = VGroup ()
427+ for ei , edir in enumerate (excluded_dirs ):
428+ et = Text (edir , font_size = 11 , color = C_RED , font = "Monospace" )
429+ cross = Text ("✗" , font_size = 13 , color = C_RED )
430+ et .move_to (RIGHT * 3.0 + UP * (0.3 - ei * 0.35 ))
431+ cross .move_to (RIGHT * 1.8 + UP * (0.3 - ei * 0.35 ))
432+ excl_group .add (VGroup (cross , et ))
433+
434+ self .timed_play (FadeIn (exclude_title ), run_time = 0.4 )
435+
436+ excl_per = max (0.3 , (seg_start (8 ) - self ._clock - 0.5 ) / len (excl_group ))
437+ for eg in excl_group :
438+ self .timed_play (FadeIn (eg , shift = LEFT * 0.15 ), run_time = excl_per )
439+
440+ self .wait_until (seg_start (8 ) - 0.3 )
441+ self .timed_play (
442+ FadeOut (exclude_title ), FadeOut (excl_group ), run_time = 0.3 ,
443+ )
355444 self .wait_until (seg_start (8 ))
356445
357446 # ── Beat 8: Switch to Production tab ─────────────────────────
0 commit comments