# 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…

Page: https://fframes-kit.pages.dev/docs/slides/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.

```rust
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:

```rust
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);
```
