1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Serialize, Deserialize)]
5#[serde(rename_all = "snake_case")]
6pub struct Presentation {
7 #[serde(default = "default_format_version")]
9 pub format_version: String,
10 pub title: String,
11 #[serde(skip_serializing_if = "Option::is_none")]
12 pub author: Option<String>,
13 #[serde(skip_serializing_if = "Option::is_none")]
15 pub description: Option<String>,
16 #[serde(skip_serializing_if = "Option::is_none")]
18 pub date: Option<String>,
19 #[serde(skip_serializing_if = "Option::is_none")]
21 pub language: Option<String>,
22 #[serde(skip_serializing_if = "Option::is_none")]
25 pub audio_track: Option<String>,
26 #[serde(skip_serializing_if = "Option::is_none")]
29 pub typst_source: Option<String>,
30 pub slides: Vec<Slide>,
31 #[serde(default, skip_serializing_if = "Vec::is_empty")]
33 pub annotations: Vec<Annotation>,
34 #[serde(skip_serializing_if = "Option::is_none")]
37 pub transcript: Option<Transcript>,
38}
39
40fn default_format_version() -> String {
41 "1.0".into()
42}
43
44#[derive(Debug, Clone, Serialize, Deserialize)]
45#[serde(rename_all = "snake_case")]
46pub struct Slide {
47 pub id: String,
49 pub time_start: u64,
51 #[serde(skip_serializing_if = "Option::is_none")]
55 pub svg_file: Option<String>,
56 #[serde(skip_serializing_if = "Option::is_none")]
58 pub typst_file: Option<String>,
59 #[serde(skip_serializing_if = "Option::is_none")]
61 pub typst_inline: Option<String>,
62 #[serde(default, skip_serializing_if = "Vec::is_empty")]
63 pub animations: Vec<Animation>,
64 #[serde(skip_serializing_if = "Option::is_none")]
65 pub pointer_trail: Option<PointerTrail>,
66 #[serde(skip_serializing_if = "Option::is_none")]
67 pub transition: Option<TransitionKind>,
68}
69
70#[derive(Debug, Clone, Serialize, Deserialize)]
71#[serde(rename_all = "snake_case")]
72pub struct Animation {
73 pub element_id: String,
75 pub time_start: u64,
77 pub duration: u64,
79 pub kind: String,
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(rename_all = "snake_case")]
85pub struct PointerTrail {
86 pub points: Vec<TrailPoint>,
87}
88
89#[derive(Debug, Clone, Serialize, Deserialize)]
90#[serde(rename_all = "snake_case")]
91pub struct TrailPoint {
92 pub time_ms: u64,
94 pub x: f32,
95 pub y: f32,
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize)]
100#[serde(rename_all = "snake_case")]
101pub struct Annotation {
102 pub slide_id: String,
103 #[serde(flatten)]
104 pub kind: AnnotationType,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize)]
108#[serde(tag = "type", rename_all = "snake_case")]
109pub enum AnnotationType {
110 Highlight {
111 rect: Rect,
112 color: String,
113 #[serde(skip_serializing_if = "Option::is_none")]
114 author_note: Option<String>,
115 },
116 Comment {
117 position: Point,
118 text: String,
119 },
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
123pub struct Rect {
124 pub x: f32,
125 pub y: f32,
126 pub w: f32,
127 pub h: f32,
128}
129
130#[derive(Debug, Clone, Serialize, Deserialize)]
131pub struct Point {
132 pub x: f32,
133 pub y: f32,
134}
135
136#[derive(Debug, Clone, Serialize, Deserialize)]
137#[serde(rename_all = "snake_case")]
138pub enum TransitionKind {
139 Cut,
140 Fade,
141 SlideLeft,
142 SlideRight,
143}
144
145#[derive(Debug, Clone, Serialize, Deserialize)]
149#[serde(rename_all = "snake_case")]
150pub struct Transcript {
151 pub mode: TranscriptMode,
152 pub language: String,
154 pub segments: Vec<TranscriptSegment>,
155}
156
157#[derive(Debug, Clone, Serialize, Deserialize)]
159#[serde(rename_all = "snake_case")]
160pub enum TranscriptMode {
161 Synchronized,
163 Standalone,
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize)]
169#[serde(rename_all = "snake_case")]
170pub struct TranscriptSegment {
171 pub start_ms: u64,
173 pub end_ms: u64,
175 pub text: String,
176 #[serde(skip_serializing_if = "Option::is_none")]
178 pub slide_ref: Option<String>,
179 #[serde(default, skip_serializing_if = "Vec::is_empty")]
181 pub words: Vec<TranscriptWord>,
182}
183
184#[derive(Debug, Clone, Serialize, Deserialize)]
186#[serde(rename_all = "snake_case")]
187pub struct TranscriptWord {
188 pub text: String,
189 pub start_ms: u64,
190 pub end_ms: u64,
191}