Skip to content

A complete deck

A whole video: the pitch template, renamed and extended with a slide of your own, in the sunset theme over a glow, with a footer and a slide transition between the slides. Render it with the fframes command line, or step through it in fframes Studio, which stops at the slides’ reveal times.

use fframes_kit::prelude::*;
#[derive(Debug)]
struct Pitch {
deck: Deck<'static>,
}
impl Pitch {
fn new() -> Self {
let mut slides = slides::templates::pitch_deck();
slides[0].layout = SlideLayout::Title {
title: "Lumen",
subtitle: Some("Lighting design in an afternoon"),
};
// one more slide before the closing page
let team = slides::Slide {
hold: 4.0,
notes: Some("Who we are, in one breath each."),
..slides::Slide::new(
"pitch-team",
SlideLayout::FeatureCards {
title: "The team",
items: vec![
("Ana", "CEO, ten years in lighting design."),
("Ben", "CTO, built rendering engines."),
("Chloe", "Design, ran a studio of twenty."),
],
},
)
};
let close = slides.len() - 1;
slides.insert(close, team);
let deck = Deck::new(slides::themes::sunset(), slides)
.backdrop(slides::Backdrop::Glow)
.footer("Lumen · Seed round")
.transition(Slide::default(), Timing::default());
Self { deck }
}
}
impl Video for Pitch {
const FPS: usize = 30;
const WIDTH: usize = 1920;
const HEIGHT: usize = 1080;
fn duration(&self) -> Duration<'_> {
Duration::Auto
}
fn audio(&self) -> AudioMap<'_> {
AudioMap::none()
}
fn define_scenes(&self) -> Scenes<'_> {
self.deck.scenes()
}
fn render_frame<'a>(&'a self, frame: Frame, ctx: &FFramesContext<'a, '_>) -> Svgr<'a> {
svgr!(
<svg viewBox="0 0 1920 1080" width={Self::WIDTH} height={Self::HEIGHT}>
{ctx.render_scenes(&frame)}
</svg>
)
}
}
let pitch = Pitch::new();
assert_eq!(pitch.deck.slides().count(), 11);
// the title page has no footer; the team slide is number 10 of 11
let footers: Vec<_> = pitch.deck.slides().map(|s| s.footer.and_then(|f| f.page)).collect();
assert_eq!(footers[0], None);
assert_eq!(footers[9], Some((10, 11)));
// the presenter's script
let script: Vec<&str> = pitch.deck.slides().filter_map(|s| s.notes()).collect();
assert_eq!(script.len(), 11);

The quarterly review and the talk are built the same way:

use fframes_kit::prelude::*;
let review = Deck::new(slides::themes::paper(), slides::templates::quarterly_review())
.backdrop(slides::Backdrop::Gradient)
.footer("Q3 review");
let talk = Deck::new(slides::themes::midnight(), slides::templates::conference_talk())
.backdrop(slides::Backdrop::Grid)
.footer("Video as code")
.transition(Fade::default(), Timing::default());
let minutes = |deck: &Deck| deck.slides().map(slides::Slide::seconds).sum::<f32>() / 60.0;
assert!(minutes(&review) > 0.5 && minutes(&talk) > 0.5);