Enable content blocks to reference named Remark.js layouts (e.g., left-aligned) and add standard layout definitions to generated slides.
- Reference existing template layouts (not custom definitions)
- Rename
slides.layout→slides.classfor semantic clarity - Place layout blocks at top of slides (before title)
Update SlideRenderConfig (lines 132-142):
class SlideRenderConfig(BaseModel):
render: bool = True
class_: Optional[str] = Field(
default=None,
description="CSS classes to apply to slides (e.g., 'center', 'reduce90')"
)
layout_name: Optional[str] = Field(
default=None,
description="Named layout to reference (e.g., 'left-aligned')"
)Update ContentBlock propagation logic (lines 198-202):
- Keep
class_convenience field - Map it to
slides.class_(notslides.layout) - Update field name:
class_→ maps toslides.class_
Validation:
- Add validator to ensure
layout_namereferences valid layouts - Valid values:
left-alignedor None
Update generate_slides() function (lines 185-307):
Step 2a: Apply layout references (update lines 207-212):
if block.slides.layout_name:
for slide in slides:
# Set layout reference if not already set
if not slide.get('layout_ref'):
slide['layout_ref'] = block.slides.layout_name
if block.slides.class_:
for slide in slides:
if not slide.get('class'):
slide['class'] = f"class: {block.slides.class_}"Step 2b: Format slides with layout references (update lines 214-231):
formatted_slides = []
for slide in all_slides:
slide_content = slide['content']
slide_content = process_code_wrappers(slide_content)
lines = []
# Add layout reference if present
if slide.get('layout_ref'):
lines.append(f"layout: {slide['layout_ref']}")
# Add class directive if present
if slide['class']:
lines.append(slide['class'])
elif lines: # Has layout but no class, add separator
lines.append('')
# Add content
lines.append(slide_content)
formatted_slides.append('\n'.join(lines))Step 2c: Add layout definitions at top (update template rendering around line 244):
# Standard Remark.js layout definitions
layout_definitions = [
"---",
"layout: true",
"name: left-aligned",
"class: left, middle",
"---",
"",
"---",
"layout: true",
"class: center, middle",
"---",
]
# Prepend to slides
formatted_slides = layout_definitions + formatted_slidesRemove existing layout definitions (lines 19-37):
- Delete the hardcoded layout blocks
- They'll now be generated dynamically via build.py
Rationale: Build script has more context and can conditionally include layouts.
Add layout definitions in markdown assembly (around line 268 in build.py):
# For HTML slides
layout_blocks = [
"---",
"layout: true",
"name: left-aligned",
"class: left, middle",
"---",
"",
"---",
"layout: true",
"class: center, middle",
"---",
]
# Build markdown for HTML
markdown_parts = layout_blocks + [title_slide] + [questions_md] + ...Update all 13 topics to use new field name:
- Find:
class: center(convenience field) - Keep: This still works, but now maps to
slides.class_ - Find:
slides:\n layout: center(explicit field) - Replace with:
slides:\n class: center
Example migration:
# Before
- type: slide
class: center
content: |

# After (no change needed - convenience field still works)
- type: slide
class: center
content: |
Example with layout reference:
# New capability
- type: slide
slides:
layout_name: left-aligned
class: reduce90
content: |
### Some Heading
Content hereUpdate docs/SCHEMA.md:
- Document
slides.class_field - Document
slides.layout_namefield with valid values - Add examples of layout references
- Regenerate from models.py:
uv run python scripts/generate_schema_docs.py
-
scripts/models.py - Schema changes
- SlideRenderConfig class (lines 132-142)
- ContentBlock propagation (lines 198-202)
-
outputs/training-slides/build.py - Generation logic
- generate_slides() layout reference application (lines 207-212)
- Slide formatting with layout/class (lines 214-231)
- Layout definition injection (around line 244 for GTN, line 268 for HTML)
-
outputs/training-slides/template.html - Remove hardcoded layouts
- Delete lines 19-37 (layout definitions)
-
topics/*/content.yaml - Field migration (13 files)
- Update explicit
slides.layout→slides.class - Convenience field
class:unchanged
- Update explicit
-
docs/SCHEMA.md - Documentation update
- Regenerate via generate_schema_docs.py
-
Validate schema changes:
- Run
make validateto ensure all topics parse correctly - Check that
layout_namevalidation works
- Run
-
Test slide generation:
- Build slides:
make build-slides - Verify layout blocks appear at top of generated .md files
- Check that layout references are properly formatted
- Build slides:
-
Visual verification:
- Open generated slides.html for a topic
- Verify slides with
layout_namereference apply correct classes - Check that layout definitions don't create extra blank slides
-
Test both output formats:
- GTN markdown (.md files)
- Standalone HTML (.html files)
- Update schema (models.py)
- Update build script (build.py)
- Update template (template.html)
- Regenerate schema docs
- Run validation to catch issues
- Migrate content.yaml files (automated with sed/scripts)
- Test build and visual output
- Commit changes
class:convenience field continues to work- Existing content.yaml files work after migration
- Generated output format unchanged (except layout blocks at top)
- Training-material sync unaffected (uses .md files)
None - all clarified with user.