taleem-slides 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +224 -0
  2. package/decks/angles_and_transversals.json +85 -0
  3. package/decks/congruent_triangles.json +169 -0
  4. package/decks/demo_deck.json +22 -0
  5. package/decks/eq_28aug2025.json +67 -0
  6. package/decks/goldstandar_eq_28aug25.json +69 -0
  7. package/decks/parallelogram_properties.json +164 -0
  8. package/decks/parallelogram_properties_no_sound.json +164 -0
  9. package/decks/posultate_and_SAS_postulate.json +76 -0
  10. package/decks/qanoon.md +136 -0
  11. package/decks/theorem_revision_ch10_11.fixed.json +265 -0
  12. package/decks/theorem_revision_ch10_11.json +269 -0
  13. package/decks/theorems9old_11.1.1.json +382 -0
  14. package/decks/theorems9old_11.1.2.json +162 -0
  15. package/decks/theorems9old_11.1.3.json +857 -0
  16. package/index.html +88 -0
  17. package/package.json +22 -0
  18. package/src/index.js +5 -0
  19. package/src/interpreter/slideBuilder.js +65 -0
  20. package/src/registry.js +57 -0
  21. package/src/slideManager/SlideManager.js +62 -0
  22. package/src/slides/BarChartSlide.js +44 -0
  23. package/src/slides/BigNumberSlide.js +24 -0
  24. package/src/slides/BulletListSlide.js +26 -0
  25. package/src/slides/ContactSlide.js +22 -0
  26. package/src/slides/CornerWordsSlide.js +27 -0
  27. package/src/slides/DonutChartSlide.js +28 -0
  28. package/src/slides/EqSlide.js +22 -0
  29. package/src/slides/FillImageSlide.js +24 -0
  30. package/src/slides/ImageLeftBulletsRightSlide.js +28 -0
  31. package/src/slides/ImageRightBulletsLeftSlide.js +28 -0
  32. package/src/slides/ImageSlide.js +22 -0
  33. package/src/slides/ImageWithCaptionSlide.js +26 -0
  34. package/src/slides/ImageWithTitleSlide.js +26 -0
  35. package/src/slides/QuoteSlide.js +24 -0
  36. package/src/slides/QuoteWithImageSlide.js +30 -0
  37. package/src/slides/StatisticSlide.js +26 -0
  38. package/src/slides/SvgPointerSlide.js +22 -0
  39. package/src/slides/TableSlide.js +27 -0
  40. package/src/slides/TitleAndParaSlide.js +26 -0
  41. package/src/slides/TitleAndSubtitleSlide.js +27 -0
  42. package/src/slides/TitleSlide.js +41 -0
  43. package/src/slides/TwoColumnTextSlide.js +27 -0
  44. package/tests/interpreter.test.js +47 -0
  45. package/tests/slides.barChart.test.js +64 -0
  46. package/tests/slides.bigNumber.test.js +28 -0
  47. package/tests/slides.bulletList.test.js +32 -0
  48. package/tests/slides.contactSlide.test.js +48 -0
  49. package/tests/slides.cornerWordsSlide.test.js +28 -0
  50. package/tests/slides.donutChart.test.js +28 -0
  51. package/tests/slides.eq.test.js +26 -0
  52. package/tests/slides.fillImage.test.js +28 -0
  53. package/tests/slides.imageLeftBulletsRight.test.js +28 -0
  54. package/tests/slides.imageRightBulletsLeft.test.js +26 -0
  55. package/tests/slides.imageSlide.test.js +28 -0
  56. package/tests/slides.imageWithCaption.test.js +44 -0
  57. package/tests/slides.imageWithTitle.test.js +45 -0
  58. package/tests/slides.quoteSlide.test.js +28 -0
  59. package/tests/slides.quoteWithImage.test.js +46 -0
  60. package/tests/slides.statistic.test.js +44 -0
  61. package/tests/slides.svgPointer.test.js +37 -0
  62. package/tests/slides.table.test.js +41 -0
  63. package/tests/slides.test.js +42 -0
  64. package/tests/slides.titleAndPara.test.js +35 -0
  65. package/tests/slides.titleAndSubtitle.test.js +32 -0
  66. package/tests/slides.twoColumnText.test.js +35 -0
package/README.md ADDED
@@ -0,0 +1,224 @@
1
+
2
+ # 📦 taleem-slides
3
+
4
+ > **Deterministic slide interpretation & rendering engine for deck-v1**
5
+
6
+ `taleem-slides` is a **pure, test-locked rendering layer**.
7
+ It takes a validated `deck-v1` JSON and produces **deterministic HTML output** through a strict public API.
8
+
9
+ This project does **not**:
10
+
11
+ * build decks
12
+ * mutate data
13
+ * manage timing state
14
+ * expose slide internals
15
+
16
+ It only **interprets** and **renders**.
17
+
18
+ ---
19
+
20
+ ## 🧠 Mental Model
21
+
22
+ ```
23
+ deck-v1 JSON
24
+
25
+ slideBuilder()
26
+
27
+ SlideManager
28
+
29
+ renderSlide(index [, showAt])
30
+ ```
31
+
32
+ Key idea:
33
+ **Slides are private. Rendering is the only contract.**
34
+
35
+ ---
36
+
37
+ ## ✅ What This Project Guarantees
38
+
39
+ * Deterministic rendering (same input → same HTML)
40
+ * Strict validation per slide type
41
+ * Zero mutation after build
42
+ * No access to internal slide objects
43
+ * Full test coverage across all slide types
44
+
45
+ ---
46
+
47
+ ## 🔑 Public API
48
+
49
+ ### `slideBuilder(deckV1Json) → SlideManager`
50
+
51
+ Builds and validates a deck, returning a `SlideManager`.
52
+
53
+ ```js
54
+ import { slideBuilder } from "taleem-slides";
55
+
56
+ const manager = slideBuilder(deckJson);
57
+ ```
58
+
59
+ Throws immediately on:
60
+
61
+ * invalid deck structure
62
+ * unsupported slide types
63
+ * invalid slide data
64
+
65
+ ---
66
+
67
+ ### `SlideManager.renderSlide(index, showAt?) → string`
68
+
69
+ Renders **one slide** to HTML.
70
+
71
+ ```js
72
+ const html = manager.renderSlide(0);
73
+ ```
74
+
75
+ Notes:
76
+
77
+ * `index` is zero-based
78
+ * `showAt` is optional (for time-aware slides)
79
+ * return value is **plain HTML string**
80
+
81
+ ---
82
+
83
+ ### `SlideManager.renderAll() → string`
84
+
85
+ Renders **all slides** as a static HTML dump.
86
+
87
+ ```js
88
+ const fullHtml = manager.renderAll();
89
+ ```
90
+
91
+ ---
92
+
93
+ ## 🔒 Encapsulation Rules (By Design)
94
+
95
+ * `SlideManager` does **not** expose slides
96
+ * Slides are frozen internally
97
+ * Rendered output is a string (immutable by nature)
98
+
99
+ If you want to *inspect structure*, that belongs in **taleem-core**, not here.
100
+
101
+ ---
102
+
103
+ ## 🧪 Testing Philosophy
104
+
105
+ This project has **56 passing tests** covering:
106
+
107
+ * slideBuilder validation
108
+ * every slide type
109
+ * deterministic rendering
110
+ * error handling
111
+ * edge cases
112
+
113
+ Tests assert **behavior**, not snapshots.
114
+
115
+ This test suite is the **living specification**.
116
+
117
+ ---
118
+
119
+ ## 🎞️ Supported Slide Types
120
+
121
+ `taleem-slides` supports all canonical `deck-v1` slide types, including:
122
+
123
+ * titleSlide
124
+ * titleAndSubtitle
125
+ * titleAndPara
126
+ * bulletList
127
+ * twoColumnText
128
+ * imageSlide
129
+ * imageWithTitle
130
+ * imageWithCaption
131
+ * imageLeftBulletsRight
132
+ * imageRightBulletsLeft
133
+ * table
134
+ * statistic
135
+ * donutChart
136
+ * barChart
137
+ * bigNumber
138
+ * quoteSlide
139
+ * quoteWithImage
140
+ * cornerWordsSlide
141
+ * contactSlide
142
+ * fillImage
143
+ * eq
144
+ * svgPointer
145
+
146
+ All validation rules are enforced at build time.
147
+
148
+ ---
149
+
150
+ ## 🧊 Versioning & Stability
151
+
152
+ * This project targets **deck-v1 only**
153
+ * No breaking changes without `deck-v2`
154
+ * Rendering output is intentionally simple HTML
155
+ * Styling is the responsibility of the consuming app
156
+
157
+ ---
158
+
159
+ ## 📍 When to Use This
160
+
161
+ Use `taleem-slides` when you want:
162
+
163
+ * a **trustworthy rendering engine**
164
+ * clean separation from content generation
165
+ * confidence that slides behave exactly as specified
166
+
167
+ Do **not** use it for:
168
+
169
+ * authoring decks
170
+ * editing slides
171
+ * managing playback state
172
+
173
+ ---
174
+
175
+ ---
176
+
177
+ # 🧠 taleem-core (Contextual Overview)
178
+
179
+ > **Authoring & specification layer for deck-v1**
180
+
181
+ `taleem-core` is responsible for **creating valid decks**.
182
+ `taleem-slides` is responsible for **rendering them**.
183
+
184
+ They are intentionally separate.
185
+
186
+ ---
187
+
188
+ ## Responsibility Split
189
+
190
+ | Concern | taleem-core | taleem-slides |
191
+ | ------------------- | ----------- | ------------- |
192
+ | Deck creation | ✅ | ❌ |
193
+ | Schema validation | ✅ | ❌ |
194
+ | EQ expansion | ✅ | ❌ |
195
+ | Timing rules | ✅ | ❌ |
196
+ | Rendering HTML | ❌ | ✅ |
197
+ | Slide encapsulation | ❌ | ✅ |
198
+
199
+ ---
200
+
201
+ ## Core Artifacts
202
+
203
+ From the docs you uploaded:
204
+
205
+ * `api.md` → defines **deck-v1 contract**
206
+ * `eq.md` → defines **EQ slide expansion rules**
207
+ * `timings.md` → defines **global timing semantics**
208
+
209
+ `taleem-slides` **trusts** these documents.
210
+ It does not reinterpret them.
211
+
212
+ ---
213
+
214
+ ## Architectural Law (Important)
215
+
216
+ > **Authoring and rendering must never mix**
217
+
218
+ Once a deck enters `taleem-slides`, it is:
219
+
220
+ * assumed valid
221
+ * treated as immutable
222
+ * rendered deterministically
223
+
224
+ This is why the system scales cleanly.
@@ -0,0 +1,85 @@
1
+ {
2
+ "name": "Angles and Transversals",
3
+ "description": "Intro to angle types formed by a transversal — with memory trick",
4
+ "tags": [
5
+ "geometry",
6
+ "angles",
7
+ "class9"
8
+ ],
9
+ "status": "ready",
10
+ "createdAt": "2025-07-25T16:04:36.820Z",
11
+ "editedAt": "2025-07-25T16:04:36.820Z",
12
+ "version": "deck-v1",
13
+ "background": {
14
+ "backgroundColor": "#F3E5AB",
15
+ "backgroundImage": "/media/images/taleem.webp",
16
+ "backgroundImageOpacity": 0.1
17
+ },
18
+ "deck": [
19
+ {
20
+ "start": 0,
21
+ "end": 9.02,
22
+ "type": "titleSlide",
23
+ "data": [
24
+ {
25
+ "name": "title",
26
+ "content": "Angles and Transversals",
27
+ "showAt": 0
28
+ }
29
+ ]
30
+ },
31
+ {
32
+ "start": 9.02,
33
+ "end": 33.87,
34
+ "type": "imageSlide",
35
+ "data": [
36
+ {
37
+ "name": "image",
38
+ "content": "/media/images/traversal.webp",
39
+ "showAt": 0
40
+ }
41
+ ]
42
+ },
43
+ {
44
+ "start": 33.87,
45
+ "end": 52.85,
46
+ "type": "titleAndSubtitle",
47
+ "data": [
48
+ {
49
+ "name": "title",
50
+ "content": "Memory Line",
51
+ "showAt": 0
52
+ },
53
+ {
54
+ "name": "subtitle",
55
+ "content": "Jahan angles milay — Alternate aur Corresponding barabar, Interior mil ke 180!",
56
+ "showAt": 0
57
+ }
58
+ ]
59
+ },
60
+ {
61
+ "start": 52.85,
62
+ "end": 188.09,
63
+ "type": "imageSlide",
64
+ "data": [
65
+ {
66
+ "name": "image",
67
+ "content": "/media/images/angles.jpg",
68
+ "showAt": 0
69
+ }
70
+ ]
71
+ },
72
+ {
73
+ "start": 188.09,
74
+ "end": 196.18,
75
+ "type": "titleSlide",
76
+ "data": [
77
+ {
78
+ "name": "title",
79
+ "content": "Jahan angles milay — Alternate aur Corresponding barabar, Interior mil ke 180!",
80
+ "showAt": 0
81
+ }
82
+ ]
83
+ }
84
+ ]
85
+ }
@@ -0,0 +1,169 @@
1
+ {
2
+ "name": "congruent_triangles",
3
+ "description": "Class 9 Geometry — Congruent Triangles Summary",
4
+ "tags": [
5
+ "math",
6
+ "geometry",
7
+ "triangles"
8
+ ],
9
+ "status": "draft",
10
+ "createdAt": "2025-07-21T00:00:00Z",
11
+ "editedAt": "2025-07-21T00:00:00Z",
12
+ "version": "deck-v1",
13
+ "background": {
14
+ "backgroundColor": "#F3E5AB",
15
+ "backgroundImage": "/images/taleem.webp",
16
+ "backgroundImageOpacity": 0.07
17
+ },
18
+ "deck": [
19
+ {
20
+ "start": 0,
21
+ "end": 10,
22
+ "type": "imageWithTitle",
23
+ "data": [
24
+ {
25
+ "name": "image",
26
+ "content": "/images/congruent_triangle.webp",
27
+ "showAt": 0
28
+ },
29
+ {
30
+ "name": "title",
31
+ "content": "Congruent Triangles",
32
+ "showAt": 2
33
+ }
34
+ ]
35
+ },
36
+ {
37
+ "start": 10,
38
+ "end": 30,
39
+ "type": "imageLeftBulletsRight",
40
+ "data": [
41
+ {
42
+ "name": "image",
43
+ "content": "/images/congruent_triangle2.webp",
44
+ "showAt": 10
45
+ },
46
+ {
47
+ "name": "bullet",
48
+ "content": "Same shape and same size",
49
+ "showAt": 13
50
+ },
51
+ {
52
+ "name": "bullet",
53
+ "content": "All sides and angles are equal",
54
+ "showAt": 16
55
+ },
56
+ {
57
+ "name": "bullet",
58
+ "content": "Can fit exactly on top of each other",
59
+ "showAt": 19
60
+ }
61
+ ]
62
+ },
63
+ {
64
+ "start": 30,
65
+ "end": 35,
66
+ "type": "titleAndSubtitle",
67
+ "data": [
68
+ {
69
+ "name": "title",
70
+ "content": "4 Rules to Prove Congruence",
71
+ "showAt": 30
72
+ },
73
+ {
74
+ "name": "subtitle",
75
+ "content": "SAS, ASA, SSS, RHS",
76
+ "showAt": 32
77
+ }
78
+ ]
79
+ },
80
+ {
81
+ "start": 35,
82
+ "end": 50,
83
+ "type": "bulletList",
84
+ "data": [
85
+ {
86
+ "name": "bullet",
87
+ "content": "SAS: Side–Angle–Side",
88
+ "showAt": 36
89
+ },
90
+ {
91
+ "name": "bullet",
92
+ "content": "ASA: Angle–Side–Angle",
93
+ "showAt": 38
94
+ },
95
+ {
96
+ "name": "bullet",
97
+ "content": "SSS: Side–Side–Side",
98
+ "showAt": 41
99
+ },
100
+ {
101
+ "name": "bullet",
102
+ "content": "RHS: Right-angle–Hypotenuse–Side",
103
+ "showAt": 44
104
+ }
105
+ ]
106
+ },
107
+ {
108
+ "start": 50,
109
+ "end": 55,
110
+ "type": "titleAndSubtitle",
111
+ "data": [
112
+ {
113
+ "name": "title",
114
+ "content": "Similar vs Congruent",
115
+ "showAt": 50
116
+ },
117
+ {
118
+ "name": "subtitle",
119
+ "content": "Not all triangles that look alike are congruent",
120
+ "showAt": 52
121
+ }
122
+ ]
123
+ },
124
+ {
125
+ "start": 55,
126
+ "end": 75,
127
+ "type": "imageLeftBulletsRight",
128
+ "data": [
129
+ {
130
+ "name": "image",
131
+ "content": "/images/congruent_triangle2.webp",
132
+ "showAt": 55
133
+ },
134
+ {
135
+ "name": "bullet",
136
+ "content": "Congruent: exact match in size and shape",
137
+ "showAt": 58
138
+ },
139
+ {
140
+ "name": "bullet",
141
+ "content": "Similar: same shape, different size",
142
+ "showAt": 61
143
+ },
144
+ {
145
+ "name": "bullet",
146
+ "content": "Similar ≠ Congruent (they don’t “fit”)",
147
+ "showAt": 64
148
+ }
149
+ ]
150
+ },
151
+ {
152
+ "start": 75,
153
+ "end": 85,
154
+ "type": "quoteSlide",
155
+ "data": [
156
+ {
157
+ "name": "quoteLine",
158
+ "content": "Congruent triangles are the building blocks of geometric proof.",
159
+ "showAt": 75
160
+ },
161
+ {
162
+ "name": "author",
163
+ "content": "— Taleem.Help",
164
+ "showAt": 78
165
+ }
166
+ ]
167
+ }
168
+ ]
169
+ }
@@ -0,0 +1,22 @@
1
+ {
2
+ "version": "deck-v1",
3
+ "name": "demo-minimal",
4
+ "deck": [
5
+ {
6
+ "start": 0,
7
+ "end": 10,
8
+ "type": "titleSlide",
9
+ "data": [
10
+ { "name": "title", "content": "Angles and Transversals", "showAt": 0 }
11
+ ]
12
+ },
13
+ {
14
+ "start": 10,
15
+ "end": 20,
16
+ "type": "titleSlide",
17
+ "data": [
18
+ { "name": "title", "content": "Parallel Lines and Transversals", "showAt": 0 }
19
+ ]
20
+ }
21
+ ]
22
+ }
@@ -0,0 +1,67 @@
1
+ {
2
+ "name": "eq_long_test",
3
+ "description": "Title + 1 long eq slide with 15 lines",
4
+ "tags": ["test", "eq"],
5
+ "status": "draft",
6
+ "version": "deck-v1",
7
+ "background": {
8
+ "backgroundColor": "#F3E5AB",
9
+ "backgroundImage": "/images/taleem.webp",
10
+ "backgroundImageOpacity": 0.07
11
+ },
12
+ "deck": [
13
+ {
14
+ "type": "imageWithTitle",
15
+ "start": 0,
16
+ "end": 5,
17
+ "data": [
18
+ {
19
+ "name": "image",
20
+ "content": "/images/box.webp",
21
+ "showAt": 0
22
+ },
23
+ {
24
+ "name": "title",
25
+ "content": "Equations Test Deck",
26
+ "showAt": 0
27
+ }
28
+ ]
29
+ },
30
+ {
31
+ "type": "eq",
32
+ "start": 5,
33
+ "end": 50,
34
+ "data": [
35
+ { "name": "line", "type": "heading", "content": "Algebra & Physics Equations", "showAt": 5 },
36
+
37
+ { "name": "line", "type": "math", "content": "a^2 + b^2 = c^2", "showAt": 7, "spItems": [{ "type": "spText", "content": "Pythagoras theorem" }] },
38
+ { "name": "line", "type": "text", "content": "This relates the sides of a right triangle.", "showAt": 9 },
39
+
40
+ { "name": "line", "type": "math", "content": "F = m \\times a", "showAt": 11, "spItems": [{ "type": "spHeading", "content": "Newton's Second Law" }] },
41
+ { "name": "line", "type": "text", "content": "Force equals mass times acceleration.", "showAt": 13 },
42
+
43
+ { "name": "line", "type": "math", "content": "E = m c^2", "showAt": 15, "spItems": [{ "type": "spMath", "content": "c = speed of light" }] },
44
+ { "name": "line", "type": "text", "content": "Energy-mass equivalence from Einstein.", "showAt": 17 },
45
+
46
+ { "name": "line", "type": "math", "content": "V = I R", "showAt": 19 },
47
+ { "name": "line", "type": "text", "content": "Ohm's Law: voltage, current, resistance.", "showAt": 21 },
48
+
49
+ { "name": "line", "type": "math", "content": "p = m v", "showAt": 23 },
50
+ { "name": "line", "type": "text", "content": "Momentum equals mass times velocity.", "showAt": 25 },
51
+
52
+ { "name": "line", "type": "math", "content": "KE = 1/2 m v^2", "showAt": 27 },
53
+ { "name": "line", "type": "text", "content": "Kinetic energy formula.", "showAt": 29 },
54
+
55
+ { "name": "line", "type": "math", "content": "PE = m g h", "showAt": 31 },
56
+ { "name": "line", "type": "text", "content": "Potential energy at height h.", "showAt": 33 },
57
+
58
+ { "name": "line", "type": "math", "content": "Q = m c ΔT", "showAt": 35 },
59
+ { "name": "line", "type": "text", "content": "Heat energy gained or lost.", "showAt": 37 },
60
+
61
+ { "name": "line", "type": "math", "content": "v = d / t", "showAt": 39 },
62
+ { "name": "line", "type": "text", "content": "Velocity is distance over time.", "showAt": 41 }
63
+ ]
64
+ }
65
+ ]
66
+ }
67
+
@@ -0,0 +1,69 @@
1
+ {
2
+ "name": "goldstandard_eq_28aug25",
3
+ "description": "Title + one long EQ slide (FLAT authoring) covering all sidebar types",
4
+ "tags": ["eq", "gold-standard", "flat-authoring"],
5
+ "status": "draft",
6
+ "version": "deck-v1",
7
+ "background": {
8
+ "backgroundColor": "#0e0f14",
9
+ "backgroundImage": "/media/images/box.webp",
10
+ "backgroundImageOpacity": 0.07
11
+ },
12
+ "deck": [
13
+ {
14
+ "type": "imageWithTitle",
15
+ "start": 0,
16
+ "end": 5,
17
+ "data": [
18
+ { "name": "image", "content": "/media/images/box.webp", "showAt": 0 },
19
+ { "name": "title", "content": "EQ Sidebar Gold Standard", "showAt": 0 }
20
+ ]
21
+ },
22
+ {
23
+ "type": "eq",
24
+ "start": 5,
25
+ "end": 55,
26
+ "data": [
27
+ { "name": "heading", "content": "Test All Sidebar Types", "showAt": 5 },
28
+
29
+ { "name": "spHeading", "content": "SP Heading" },
30
+ { "name": "spText", "content": "This is a sidebar comment." },
31
+ { "name": "spMath", "content": "a^2 + b^2 = c^2" },
32
+ { "name": "spImage", "content": "/media/images/box.webp" },
33
+
34
+ { "name": "math", "content": "E = mc^2", "showAt": 12 },
35
+ { "name": "spHeading", "content": "Einstein's Law" },
36
+ { "name": "spText", "content": "Energy–mass equivalence" },
37
+ { "name": "spImage", "content": "/media/images/box.webp" },
38
+
39
+ { "name": "math", "content": "\\int_0^\\pi \\sin x \\,dx = 2", "showAt": 20 },
40
+ { "name": "spHeading", "content": "Integral Result" },
41
+ { "name": "spText", "content": "Area under sine from 0 to π" },
42
+ { "name": "spMath", "content": "\\int_0^\\pi \\sin x \\,dx = 2" },
43
+
44
+ { "name": "math", "content": "\\sum_{n=1}^{\\infty} \\frac{1}{n^2} = \\frac{\\pi^2}{6}", "showAt": 28 },
45
+ { "name": "spHeading", "content": "Basel Problem" },
46
+ { "name": "spText", "content": "Euler's celebrated result" },
47
+ { "name": "spImage", "content": "/media/images/box.webp" },
48
+
49
+ { "name": "text", "content": "Ohm’s Law", "showAt": 36 },
50
+ { "name": "spMath", "content": "V = I R" },
51
+ { "name": "spText", "content": "Voltage = Current × Resistance" },
52
+
53
+ { "name": "math", "content": "p = m v", "showAt": 42 },
54
+ { "name": "spText", "content": "Momentum = mass × velocity" },
55
+
56
+ { "name": "math", "content": "KE = ½ m v^2", "showAt": 46 },
57
+ { "name": "spText", "content": "Kinetic energy formula" },
58
+
59
+ { "name": "math", "content": "PE = m g h", "showAt": 50 },
60
+ { "name": "spText", "content": "Potential energy at height h" },
61
+
62
+ { "name": "text", "content": "End of test. All sidebar types shown.", "showAt": 54 },
63
+ { "name": "spText", "content": "Thanks for testing EQ format!" }
64
+
65
+ ]
66
+ }
67
+ ]
68
+ }
69
+