Skip to content

Using Templates

Guide to using Fluvie's pre-built templates

Templates provide ready-to-use scene compositions that you customize with your data, theme, and timing. This guide covers everything you need to know.

Table of Contents


Basic Usage

1. Choose a Template

Templates are organized by category:

  • Intro: Opening scenes (TheNeonGate, DigitalMirror, TheMixtape)
  • Ranking: List displays (StackClimb, SlotMachine, TheSpotlight)
  • DataViz: Statistics (LiquidMinutes, OrbitalMetrics, TheGrowthTree)
  • Collage: Photo grids (TheGridShuffle, MosaicReveal, BentoRecap)
  • Thematic: Mood/vibe (LofiWindow, GlitchReality, Kaleidoscope)
  • Conclusion: Endings (TheSummaryPoster, ParticleFarewell, WrappedReceipt)

2. Create Data

Each template requires specific data:

final introData = IntroData(
  title: 'Your 2024',
  subtitle: 'Wrapped',
  year: 2024,
);

3. Create Template

final template = TheNeonGate(
  data: introData,
  theme: TemplateTheme.neon,
  timing: TemplateTiming.dramatic,
);

4. Convert to Scene

final scene = template.toScene();

// Or with transitions
final scene = template.toSceneWithCrossFade();

5. Add to Video

Video(
  fps: 30,
  width: 1080,
  height: 1920,
  scenes: [scene],
)

Data Contracts

IntroData

For intro/identity templates:

IntroData(
  title: 'Your 2024',           // Required: main title
  subtitle: 'Wrapped',          // Optional: subtitle text
  year: 2024,                   // Optional: year number
  logoPath: 'assets/logo.png',  // Optional: logo image
  userName: 'John',             // Optional: user name
  profileImagePath: 'path.jpg', // Optional: profile image
)

RankingData

For ranking/list templates:

RankingData(
  items: [                      // Required: list of items
    RankingItem(
      rank: 1,                  // Required: position (1 = first)
      label: 'Item Name',       // Required: display text
      subtitle: 'Details',      // Optional: secondary text
      value: 1234,              // Optional: numeric value
      imagePath: 'path.jpg',    // Optional: item image
      metadata: {'key': value}, // Optional: extra data
    ),
  ],
  title: 'Top Songs',           // Optional: section title
  subtitle: 'This Year',        // Optional: subtitle
  isTopList: true,              // Optional: is this a "top N" list?
)

DataVizData

For data visualization templates:

DataVizData(
  metrics: [                    // Required: list of metrics
    MetricData(
      label: 'Hours Listened',  // Required: metric name
      value: 1234,              // Required: numeric value
      unit: 'hrs',              // Optional: unit suffix
      icon: Icons.timer,        // Optional: icon
      color: Colors.blue,       // Optional: color
      percentage: 0.75,         // Optional: percentage (0-1)
      trend: 1.0,               // Optional: trend (-1 to 1)
    ),
  ],
  title: 'Your Stats',          // Optional: title
  subtitle: 'In Numbers',       // Optional: subtitle
  maxValue: 2000,               // Optional: scale max
  categories: {'Pop': 45.0},    // Optional: category breakdown
  timeSeries: {0: 100, 60: 200}, // Optional: time data
)

MetricData Factories:

// Percentage with % suffix
MetricData.percentage(label: 'Growth', value: 45)

// Duration in minutes
MetricData.minutes(label: 'Daily', minutes: 120)

// Simple count
MetricData.count(label: 'Songs', count: 5000)

CollageData

For collage/grid templates:

CollageData(
  images: [                     // Required: image paths
    'assets/photo1.jpg',
    'assets/photo2.jpg',
    'assets/photo3.jpg',
  ],
  title: 'Your Moments',        // Optional: title
  subtitle: '2024 Gallery',     // Optional: subtitle
  description: 'A year in...',  // Optional: description
  captions: ['One', 'Two'],     // Optional: per-image captions
  featuredIndex: 0,             // Optional: featured image index
  layout: TemplateCollageLayout.grid, // Optional: layout hint
  stats: {'Photos': 100},       // Optional: statistics
)

Layout Options:

TemplateCollageLayout.grid      // Standard grid
TemplateCollageLayout.masonry   // Pinterest-style
TemplateCollageLayout.featured  // One large + thumbnails
TemplateCollageLayout.strip     // Horizontal scroll
TemplateCollageLayout.diagonal  // Diagonal arrangement

ThematicData

For thematic/vibe templates:

ThematicData(
  text: 'Your Music Journey',   // Required: main text
  title: 'The Vibe',            // Optional: title
  subtitle: '2024 Edition',     // Optional: subtitle
  description: 'Longer text',   // Optional: description
  images: ['path1.jpg'],        // Optional: image paths
  statValue: '1,234',           // Optional: main stat
  statLabel: 'hours',           // Optional: stat label
  theme: 'lofi',                // Optional: theme hint
  accentColor: Colors.purple,   // Optional: accent color
  metadata: {'key': value},     // Optional: extra data
)

SummaryData

For conclusion/summary templates:

SummaryData(
  title: 'That\'s a Wrap!',     // Optional: title
  subtitle: 'See You Next Year', // Optional: subtitle
  name: 'John',                 // Optional: user name
  year: 2024,                   // Optional: year
  stats: {                      // Optional: key statistics
    'Hours': '1,234',
    'Songs': '5,678',
    'Artists': '234',
  },
  highlights: [                 // Optional: achievements
    HighlightItem(
      title: 'Top Fan',
      description: 'Top 1% of listeners',
      icon: Icons.star,
    ),
  ],
  message: 'Thanks for...',     // Optional: closing message
  ctaText: 'Share',             // Optional: button text
  shareUrl: 'https://...',      // Optional: share link
  qrData: 'https://...',        // Optional: QR code data
)

Theming

TemplateTheme

Customize colors and styling:

TemplateTheme(
  primaryColor: Colors.cyan,      // Main accent color
  secondaryColor: Colors.pink,    // Secondary accent
  backgroundColor: Colors.black,  // Background color
  textColor: Colors.white,        // Primary text color
  accentColor: Colors.purple,     // Additional accent
  surfaceColor: Color(0xFF222222), // Surface/card color
)

Built-in Themes

// Neon/cyberpunk (bright colors on dark)
theme: TemplateTheme.neon

// Spotify-inspired (green on dark)
theme: TemplateTheme.spotify

// Clean minimal (subtle colors)
theme: TemplateTheme.minimal

// Warm sunset (orange/pink/purple)
theme: TemplateTheme.sunset

// Cool ocean (blues and teals)
theme: TemplateTheme.ocean

Theme Merging

Themes merge with template defaults:

// Template has default neon theme
// Your custom colors override specific values
TheNeonGate(
  data: introData,
  theme: TemplateTheme(
    primaryColor: Colors.green,  // Overrides neon's cyan
    // Other colors use neon defaults
  ),
)

Timing

TemplateTiming

Control animation pacing:

TemplateTiming(
  entryDelay: 0,        // Frames before first animation
  entryDuration: 30,    // Entry animation length
  staggerDelay: 10,     // Delay between elements
  holdDuration: 60,     // Time at full visibility
  exitDelay: 0,         // Frames before exit starts
  exitDuration: 20,     // Exit animation length
)

Built-in Timings

// Standard pacing (good default)
timing: TemplateTiming.standard

// Slower, more dramatic (for emphasis)
timing: TemplateTiming.dramatic

// Faster, snappier (for quick reveals)
timing: TemplateTiming.snappy

// Very quick (for rapid sequences)
timing: TemplateTiming.quick

Transitions

toScene() Options

template.toScene(
  durationInFrames: 180,                    // Override recommended length
  transitionIn: SceneTransition.crossFade(durationInFrames: 20),
  transitionOut: SceneTransition.slideLeft(durationInFrames: 15),
  fadeInFrames: 10,               // Scene fade in
  fadeOutFrames: 10,              // Scene fade out
)

Convenience Methods

// Cross-fade both directions
template.toSceneWithCrossFade(
  length: 180,
  fadeDuration: 20,
)

// Slide transition
template.toSceneWithSlide(
  length: 180,
  direction: TransitionSlideDirection.left,
  slideDuration: 25,
)

Slide Directions

TransitionSlideDirection.left   // From right
TransitionSlideDirection.right  // From left
TransitionSlideDirection.up     // From bottom
TransitionSlideDirection.down   // From top

Examples

Full Video with Templates

Video(
  fps: 30,
  width: 1080,
  height: 1920,
  backgroundMusicAsset: 'assets/music.mp3',
  musicFadeInFrames: 60,
  musicFadeOutFrames: 90,
  scenes: [
    // Intro
    TheNeonGate(
      data: IntroData(
        title: 'Your 2024',
        subtitle: 'Wrapped',
        year: 2024,
      ),
      theme: TemplateTheme.neon,
    ).toSceneWithCrossFade(),

    // Top Songs
    StackClimb(
      data: RankingData(
        title: 'Top Songs',
        items: topSongs,
      ),
    ).toSceneWithSlide(direction: TransitionSlideDirection.left),

    // Stats
    LiquidMinutes(
      data: DataVizData(
        title: 'Your Stats',
        metrics: statsMetrics,
      ),
    ).toSceneWithCrossFade(),

    // Photo Memories
    TheGridShuffle(
      data: CollageData(
        title: 'Moments',
        images: photoList,
      ),
    ).toSceneWithSlide(direction: TransitionSlideDirection.up),

    // Conclusion
    TheSummaryPoster(
      data: SummaryData(
        title: 'That\'s a Wrap!',
        stats: finalStats,
        message: 'See you in 2025!',
      ),
    ).toSceneWithCrossFade(fadeDuration: 30),
  ],
)

Consistent Theming

final myTheme = TemplateTheme(
  primaryColor: Color(0xFF1DB954),
  secondaryColor: Color(0xFF191414),
  backgroundColor: Color(0xFF121212),
  textColor: Colors.white,
);

Video(
  scenes: [
    TheNeonGate(data: introData, theme: myTheme).toScene(),
    StackClimb(data: rankingData, theme: myTheme).toScene(),
    TheSummaryPoster(data: summaryData, theme: myTheme).toScene(),
  ],
)

Custom Timing

final slowTiming = TemplateTiming(
  entryDelay: 15,
  entryDuration: 45,
  staggerDelay: 20,
  holdDuration: 90,
  exitDuration: 30,
);

TheNeonGate(
  data: introData,
  timing: slowTiming,
).toScene(durationInFrames: 240)  // Longer scene for slow timing

Best Practices

1. Match Length to Timing

Ensure scene length accommodates all animations:

final template = TheNeonGate(data: introData);

// Use recommended length
template.toScene()  // Uses template.recommendedLength

// Or calculate based on timing
template.toScene(durationInFrames: template.recommendedLength + 30)

2. Consistent Themes

Create a theme and reuse it:

final appTheme = TemplateTheme.neon.copyWith(
  primaryColor: myBrandColor,
);

// Apply to all templates

3. Smooth Transitions

Use matching transitions for flow:

// Good: Consistent direction
scene1.toSceneWithSlide(direction: TransitionSlideDirection.left)
scene2.toSceneWithSlide(direction: TransitionSlideDirection.left)

// Good: Alternating for variety
scene1.toSceneWithCrossFade()
scene2.toSceneWithSlide()
scene3.toSceneWithCrossFade()

Templates have recommendedLength for a reason:

print(template.recommendedLength);  // Check what's recommended

// Override only if needed
template.toScene(durationInFrames: 200)