capture-flow 0.0.0-stage → 0.1.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 (104) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +238 -2
  3. package/bin/capture-flow.mjs +12 -0
  4. package/package.json +55 -4
  5. package/src/build.ts +186 -0
  6. package/src/capture.ts +77 -0
  7. package/src/cli.ts +139 -0
  8. package/src/index.ts +11 -0
  9. package/src/manifest.ts +98 -0
  10. package/src/render.ts +75 -0
  11. package/src/verify.ts +90 -0
  12. package/vendor/wajha/LICENSE +21 -0
  13. package/vendor/wajha/NOTICE +21 -0
  14. package/vendor/wajha/engine/background.ts +55 -0
  15. package/vendor/wajha/engine/bidi.ts +589 -0
  16. package/vendor/wajha/engine/cache.ts +96 -0
  17. package/vendor/wajha/engine/color.ts +125 -0
  18. package/vendor/wajha/engine/devices/android.ts +53 -0
  19. package/vendor/wajha/engine/devices/browser.ts +170 -0
  20. package/vendor/wajha/engine/devices/finish.ts +154 -0
  21. package/vendor/wajha/engine/devices/geometry.ts +326 -0
  22. package/vendor/wajha/engine/devices/index.ts +143 -0
  23. package/vendor/wajha/engine/devices/ipad.ts +21 -0
  24. package/vendor/wajha/engine/devices/iphone.ts +55 -0
  25. package/vendor/wajha/engine/devices/macbook.ts +187 -0
  26. package/vendor/wajha/engine/devices/mock/apps/calendar.ts +145 -0
  27. package/vendor/wajha/engine/devices/mock/apps/chat.ts +213 -0
  28. package/vendor/wajha/engine/devices/mock/apps/finance.ts +164 -0
  29. package/vendor/wajha/engine/devices/mock/apps/fitness.ts +145 -0
  30. package/vendor/wajha/engine/devices/mock/apps/index.ts +14 -0
  31. package/vendor/wajha/engine/devices/mock/apps/meditation.ts +167 -0
  32. package/vendor/wajha/engine/devices/mock/apps/music.ts +152 -0
  33. package/vendor/wajha/engine/devices/mock/apps/shop.ts +116 -0
  34. package/vendor/wajha/engine/devices/mock/apps/social.ts +152 -0
  35. package/vendor/wajha/engine/devices/mock/apps/tasks.ts +131 -0
  36. package/vendor/wajha/engine/devices/mock/apps/travel.ts +121 -0
  37. package/vendor/wajha/engine/devices/mock/art.ts +557 -0
  38. package/vendor/wajha/engine/devices/mock/chrome.ts +337 -0
  39. package/vendor/wajha/engine/devices/mock/icons.ts +614 -0
  40. package/vendor/wajha/engine/devices/mock/kit.ts +213 -0
  41. package/vendor/wajha/engine/devices/mock/rng.ts +40 -0
  42. package/vendor/wajha/engine/devices/mock/theme.ts +133 -0
  43. package/vendor/wajha/engine/devices/mock/widgets.ts +231 -0
  44. package/vendor/wajha/engine/devices/paths.ts +113 -0
  45. package/vendor/wajha/engine/devices/screen.ts +75 -0
  46. package/vendor/wajha/engine/devices/shadow.ts +124 -0
  47. package/vendor/wajha/engine/devices/slab.ts +200 -0
  48. package/vendor/wajha/engine/devices/vision.ts +43 -0
  49. package/vendor/wajha/engine/devices/watch.ts +14 -0
  50. package/vendor/wajha/engine/geometry.ts +152 -0
  51. package/vendor/wajha/engine/images.ts +96 -0
  52. package/vendor/wajha/engine/index.ts +20 -0
  53. package/vendor/wajha/engine/linebreak.ts +226 -0
  54. package/vendor/wajha/engine/markup.ts +84 -0
  55. package/vendor/wajha/engine/mock.ts +158 -0
  56. package/vendor/wajha/engine/paint.ts +474 -0
  57. package/vendor/wajha/engine/patterns.ts +263 -0
  58. package/vendor/wajha/engine/render.ts +364 -0
  59. package/vendor/wajha/engine/shapes.ts +260 -0
  60. package/vendor/wajha/engine/testing/canvasNode.ts +121 -0
  61. package/vendor/wajha/engine/testing/fakeDevices.ts +85 -0
  62. package/vendor/wajha/engine/text.ts +694 -0
  63. package/vendor/wajha/engine/types.ts +190 -0
  64. package/vendor/wajha/export/paths.ts +197 -0
  65. package/vendor/wajha/export/png.ts +223 -0
  66. package/vendor/wajha/export/types.ts +60 -0
  67. package/vendor/wajha/model/adapt.ts +889 -0
  68. package/vendor/wajha/model/catalog.ts +369 -0
  69. package/vendor/wajha/model/clone.ts +58 -0
  70. package/vendor/wajha/model/colorMath.ts +128 -0
  71. package/vendor/wajha/model/defaults.ts +386 -0
  72. package/vendor/wajha/model/geometry.ts +95 -0
  73. package/vendor/wajha/model/ids.ts +13 -0
  74. package/vendor/wajha/model/instantiate.ts +280 -0
  75. package/vendor/wajha/model/mirror.ts +43 -0
  76. package/vendor/wajha/model/resolve.ts +87 -0
  77. package/vendor/wajha/model/rules.ts +249 -0
  78. package/vendor/wajha/model/stub.ts +4 -0
  79. package/vendor/wajha/model/types.ts +456 -0
  80. package/vendor/wajha/model/typography.ts +28 -0
  81. package/vendor/wajha/model/validate.ts +917 -0
  82. package/vendor/wajha/templates/builtin/aurora.ts +163 -0
  83. package/vendor/wajha/templates/builtin/bubblegum.ts +132 -0
  84. package/vendor/wajha/templates/builtin/citrusPop.ts +124 -0
  85. package/vendor/wajha/templates/builtin/clayGarden.ts +114 -0
  86. package/vendor/wajha/templates/builtin/desertDune.ts +97 -0
  87. package/vendor/wajha/templates/builtin/glassPrism.ts +139 -0
  88. package/vendor/wajha/templates/builtin/launchpad.ts +140 -0
  89. package/vendor/wajha/templates/builtin/loudAndClear.ts +109 -0
  90. package/vendor/wajha/templates/builtin/midnightNeon.ts +108 -0
  91. package/vendor/wajha/templates/builtin/monoSwiss.ts +149 -0
  92. package/vendor/wajha/templates/builtin/noirGold.ts +149 -0
  93. package/vendor/wajha/templates/builtin/noor.ts +107 -0
  94. package/vendor/wajha/templates/builtin/obsidian.ts +137 -0
  95. package/vendor/wajha/templates/builtin/panoramaPeaks.ts +145 -0
  96. package/vendor/wajha/templates/builtin/panoramaRibbon.ts +138 -0
  97. package/vendor/wajha/templates/builtin/panoramaWaves.ts +138 -0
  98. package/vendor/wajha/templates/builtin/paperAndInk.ts +98 -0
  99. package/vendor/wajha/templates/builtin/sage.ts +94 -0
  100. package/vendor/wajha/templates/builtin/splitTone.ts +129 -0
  101. package/vendor/wajha/templates/builtin/sunsetBoulevard.ts +127 -0
  102. package/vendor/wajha/templates/index.ts +55 -0
  103. package/vendor/wajha/templates/kit.ts +761 -0
  104. package/vendor/wajha/ui/sortShots.ts +239 -0
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Glass Prism: light through frosted glass. An iridescent pastel mesh,
3
+ * translucent glass cards floating behind white phones, crisp Plus Jakarta
4
+ * Sans headlines with violet highlights. Story: a calendar and planner.
5
+ */
6
+ import type { SlideElement } from '../../model/types';
7
+ import { ALL_CLASSES, F, METAL, background, copyAt, device, glow, linear, mesh, pattern, rect, ring, slide, template, theme, typeset, type Cls, type DeviceOptions } from '../kit';
8
+
9
+ const t = typeset({
10
+ heading: F.jakarta,
11
+ body: F.jakarta,
12
+ ink: '#15122b',
13
+ soft: '#4a4766',
14
+ accent: '#6a4dff',
15
+ head: { weight: 800, size: 0.088, lineHeight: 1.12, letterSpacing: -0.03 },
16
+ sub: { weight: 500, size: 0.04 },
17
+ });
18
+
19
+ const SHADOW = { color: '#3b2f8a38', blur: 0.08, x: 0, y: 0.035 };
20
+ const phone = (o: DeviceOptions) => device({ color: METAL.white, shadow: SHADOW, ...o });
21
+ const pad = (o: DeviceOptions) => device({ cls: 'tablet', frame: 'ipad', color: METAL.white, shadow: SHADOW, ...o });
22
+ const laptop = (o: DeviceOptions) => device({ cls: 'wide', frame: 'macbook', color: METAL.silver, shadow: SHADOW, ...o });
23
+
24
+ /** A frosted glass card. */
25
+ const card = (x: number, y: number, w: number, h: number, rotation: number) =>
26
+ rect({ name: 'Glass card', x, y, width: w, height: h, rotation, radius: 0.16, fill: linear(150, '#ffffffd9', '#ffffff4d'), opacity: 0.9 });
27
+
28
+ function copy(cls: Cls, seam?: number): SlideElement[] {
29
+ if (cls === 'wide') return copyAt(t, { cls, seam: seam ?? 0.215, width: 1.2, subWidth: 0.95, head: { size: 0.066 }, sub: { size: 0.03 } });
30
+ if (cls === 'tablet') return copyAt(t, { cls, seam: seam ?? 0.165, width: 0.8, subWidth: 0.64, head: { size: 0.066 }, sub: { size: 0.031 } });
31
+ return copyAt(t, { seam: seam ?? 0.15 });
32
+ }
33
+
34
+ function hero(cls: Cls): SlideElement[] {
35
+ if (cls === 'wide') return [card(0.17, 0.64, 0.42, 0.38, -8), card(0.84, 0.72, 0.36, 0.34, 7), ...copy(cls), laptop({ width: 1.04, top: 0.35 })];
36
+ if (cls === 'tablet') return [card(0.16, 0.62, 0.4, 0.5, -9), card(0.86, 0.78, 0.36, 0.44, 8), ...copy(cls), pad({ width: 0.74, top: 0.29 })];
37
+ return [card(0.17, 0.5, 0.44, 0.62, -10), card(0.85, 0.68, 0.4, 0.5, 8), ...copy(cls), phone({ width: 0.8, top: 0.25 })];
38
+ }
39
+
40
+ function pair(cls: Cls): SlideElement[] {
41
+ if (cls === 'wide') {
42
+ return [
43
+ card(0.2, 0.7, 0.4, 0.34, -6),
44
+ ...copy(cls),
45
+ laptop({ width: 0.92, top: 0.37, x: 0.43, slot: 'second' }),
46
+ device({ cls, frame: 'none', width: 0.5, x: 0.76, y: 0.68, cornerRadius: 0.03, shadow: SHADOW }),
47
+ ];
48
+ }
49
+ if (cls === 'tablet') return [card(0.5, 0.7, 0.8, 0.5, -4), ...copy(cls), pad({ width: 0.58, top: 0.36, x: 0.66, slot: 'second' }), pad({ width: 0.58, top: 0.3, x: 0.36 })];
50
+ return [card(0.5, 0.62, 0.86, 0.56, -5), ...copy(cls), phone({ width: 0.6, top: 0.3, x: 0.7, slot: 'second' }), phone({ width: 0.62, top: 0.26, x: 0.33 })];
51
+ }
52
+
53
+ function upside(cls: Cls): SlideElement[] {
54
+ if (cls !== 'tall') return hero(cls);
55
+ return [card(0.82, 0.3, 0.42, 0.56, 9), card(0.16, 0.5, 0.36, 0.46, -8), phone({ width: 0.82, bottom: 0.69 }), ...copy(cls, 0.81)];
56
+ }
57
+
58
+ function side(cls: Cls): SlideElement[] {
59
+ if (cls !== 'tall') return hero(cls);
60
+ return [
61
+ ring({ x: 0.2, y: 0.5, size: 0.5, stroke: 0.006, color: '#ffffff', opacity: 0.9 }),
62
+ card(0.22, 0.66, 0.4, 0.5, -10),
63
+ ...copy(cls),
64
+ phone({ width: 0.76, top: 0.27, x: 0.55, rotation: 6 }),
65
+ ];
66
+ }
67
+
68
+ function halo(cls: Cls): SlideElement[] {
69
+ const rings = (x: number, y: number, s: number) => [
70
+ glow({ x, y, size: 0.9 * s, color: '#ffffff', opacity: 0.7, blur: 0.1 }),
71
+ ring({ x, y, size: 1.04 * s, stroke: 0.006, color: '#ffffff', opacity: 0.85 }),
72
+ ];
73
+ // Low behind the laptop: the halo stays clear of the subtitle, also on the feature graphic where the copy grows.
74
+ if (cls === 'wide') return [...rings(0.5, 0.78, 0.76), ...copy(cls), laptop({ width: 1.04, top: 0.35 })];
75
+ if (cls === 'tablet') return [...rings(0.5, 0.72, 1.05), ...copy(cls), pad({ width: 0.74, top: 0.29 })];
76
+ return [...rings(0.5, 0.6, 1.05), ...copy(cls), phone({ width: 0.78, top: 0.255 })];
77
+ }
78
+
79
+ const o = { classes: ALL_CLASSES };
80
+
81
+ export const glassPrism = template({
82
+ id: 'glass-prism',
83
+ name: 'Glass Prism',
84
+ description: 'Light through frosted glass: an iridescent pastel mesh, translucent glass cards floating behind white phones and crisp headlines with violet highlights.',
85
+ category: 'gradient',
86
+ tags: ['pastel', 'glass', 'light', 'productivity', 'iridescent'],
87
+ apps: ['calendar', 'tasks', 'chat', 'meditation', 'finance', 'fitness', 'social', 'travel'],
88
+ theme: theme({
89
+ background: background(
90
+ mesh('#f3f0ff', [0.08, 0.06, '#d4c4ff', 0.55], [0.96, 0.28, '#bcdcff', 0.5], [0.1, 0.84, '#ffd3e6', 0.5], [0.92, 0.94, '#c4f1e2', 0.46]),
91
+ pattern('noise', '#4b3fb3', 0.03, 0.05),
92
+ ),
93
+ heading: F.jakarta,
94
+ body: F.jakarta,
95
+ palette: ['#6a4dff', '#ff7eb6', '#4cc9f0', '#2ec4a6', '#ffffff', '#15122b'],
96
+ }),
97
+ slides: [
98
+ slide(
99
+ {
100
+ en: { headline: 'Your week, *beautifully* planned', subtitle: 'Calendar, tasks and notes in one calm, colorful space.' },
101
+ ar: { headline: 'أسبوعك *منظّم* بأناقة', subtitle: 'التقويم والمهام والملاحظات في مساحة واحدة هادئة وملوّنة.' },
102
+ },
103
+ hero,
104
+ o,
105
+ ),
106
+ slide(
107
+ {
108
+ en: { headline: 'Time blocks that *flow*', subtitle: 'Drag tasks into your day and watch the plan come together.' },
109
+ ar: { headline: 'جدول يومك *بسلاسة*', subtitle: 'اسحب مهامك إلى يومك وشاهد خطتك تكتمل أمامك.' },
110
+ },
111
+ pair,
112
+ o,
113
+ ),
114
+ slide(
115
+ {
116
+ en: { headline: 'Focus on what *matters*', subtitle: 'Smart priorities surface the next right thing to do.' },
117
+ ar: { headline: 'ركّز على *الأهم*', subtitle: 'أولويات ذكية تُبرز لك الخطوة التالية الصحيحة.' },
118
+ },
119
+ upside,
120
+ o,
121
+ ),
122
+ slide(
123
+ {
124
+ en: { headline: 'Plan *together*', subtitle: 'Shared calendars keep the whole team in sync.' },
125
+ ar: { headline: 'خطّطوا *معًا*', subtitle: 'تقاويم مشتركة تُبقي الفريق بأكمله على تواصل.' },
126
+ },
127
+ side,
128
+ o,
129
+ ),
130
+ slide(
131
+ {
132
+ en: { headline: 'Always *in sync*', subtitle: 'iPhone, iPad and Mac, updated the moment plans change.' },
133
+ ar: { headline: 'متزامن *دائمًا*', subtitle: 'على آيفون وآيباد وماك، تتحدّث خطتك فور تعديلها.' },
134
+ },
135
+ halo,
136
+ o,
137
+ ),
138
+ ],
139
+ });
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Launchpad: a clean product page for web apps. Cool paper grey with a dot
3
+ * grid, Space Grotesk headlines with electric-blue highlights, light
4
+ * browser windows (a phone beside them where it helps). Story: a privacy
5
+ * friendly web analytics tool.
6
+ */
7
+ import type { SlideElement } from '../../model/types';
8
+ import { ALL_CLASSES, F, METAL, background, copyAt, device, glow, pattern, ring, slide, solid, template, theme, typeset, type Cls, type DeviceOptions } from '../kit';
9
+
10
+ const BLUE = '#2563eb';
11
+ const t = typeset({
12
+ heading: F.spaceGrotesk,
13
+ body: F.inter,
14
+ ink: '#0b1220',
15
+ soft: '#475266',
16
+ accent: BLUE,
17
+ head: { weight: 700, size: 0.088, lineHeight: 1.1, letterSpacing: -0.035 },
18
+ sub: { weight: 450, size: 0.039, lineHeight: 1.38 },
19
+ });
20
+
21
+ const SHADOW = { color: '#0f172a33', blur: 0.07, x: 0, y: 0.03 };
22
+ const browser = (o: DeviceOptions) => device({ frame: 'browser', color: '#ffffff', finish: 'matte', shadow: SHADOW, ...o });
23
+ const phone = (o: DeviceOptions) => device({ color: METAL.silver, shadow: SHADOW, ...o });
24
+
25
+ function copy(cls: Cls, seam?: number): SlideElement[] {
26
+ if (cls === 'wide') return copyAt(t, { cls, seam: seam ?? 0.5, x: 0.21, width: 0.46, align: 'start', head: { size: 0.068, maxLines: 3 }, sub: { size: 0.031, maxLines: 3 } });
27
+ if (cls === 'tablet') return copyAt(t, { cls, seam: seam ?? 0.165, width: 0.82, subWidth: 0.66, head: { size: 0.066 }, sub: { size: 0.031 } });
28
+ return copyAt(t, { seam: seam ?? 0.15 });
29
+ }
30
+
31
+ /** A faint blue light under the windows: depth on a flat page. */
32
+ const halo = (x: number, y: number, size: number) => glow({ x, y, size, color: BLUE, opacity: 0.16, blur: 0.16 });
33
+
34
+ function hero(cls: Cls): SlideElement[] {
35
+ if (cls === 'wide') return [halo(0.69, 0.55, 0.8), ...copy(cls), browser({ cls, width: 0.96, x: 0.69, y: 0.5 })];
36
+ if (cls === 'tablet') return [halo(0.5, 0.75, 0.9), ...copy(cls), browser({ cls, width: 0.84, top: 0.29 })];
37
+ return [halo(0.5, 0.62, 0.95), ...copy(cls), browser({ width: 0.8, top: 0.24 })];
38
+ }
39
+
40
+ function stacked(cls: Cls): SlideElement[] {
41
+ if (cls === 'wide') {
42
+ return [halo(0.7, 0.55, 0.8), ...copy(cls), browser({ cls, width: 0.74, x: 0.74, y: 0.58, slot: 'second' }), browser({ cls, width: 0.74, x: 0.635, y: 0.43 })];
43
+ }
44
+ if (cls === 'tablet') return [halo(0.5, 0.75, 0.9), ...copy(cls), browser({ cls, width: 0.66, top: 0.36, x: 0.62, slot: 'second' }), browser({ cls, width: 0.66, top: 0.3, x: 0.4 })];
45
+ return [halo(0.5, 0.62, 0.95), ...copy(cls), browser({ width: 0.62, top: 0.3, x: 0.66, slot: 'second' }), browser({ width: 0.64, top: 0.255, x: 0.36 })];
46
+ }
47
+
48
+ function upside(cls: Cls): SlideElement[] {
49
+ if (cls === 'wide') {
50
+ // Mirrored: the browser on the left, the copy in the right column.
51
+ return [
52
+ halo(0.31, 0.55, 0.8),
53
+ ...copyAt(t, { cls, seam: 0.5, x: 0.775, width: 0.46, align: 'start', head: { size: 0.07, maxLines: 3 }, sub: { size: 0.032, maxLines: 3 } }),
54
+ browser({ cls, width: 0.9, x: 0.31, y: 0.5 }),
55
+ ];
56
+ }
57
+ if (cls !== 'tall') return hero(cls);
58
+ return [halo(0.5, 0.36, 0.95), browser({ width: 0.82, bottom: 0.69 }), ...copy(cls, 0.81)];
59
+ }
60
+
61
+ /** Desktop and phone side by side: the same app on every screen. */
62
+ function everywhere(cls: Cls): SlideElement[] {
63
+ if (cls === 'wide') return [halo(0.66, 0.55, 0.8), ...copy(cls), browser({ cls, width: 0.88, x: 0.66, y: 0.47 }), device({ cls, frame: 'none', width: 0.36, x: 0.88, y: 0.72, cornerRadius: 0.04, shadow: SHADOW, slot: 'second' })];
64
+ if (cls === 'tablet') return [halo(0.5, 0.75, 0.9), ...copy(cls), browser({ cls, width: 0.8, top: 0.29, x: 0.44 }), device({ cls, frame: 'ipad', color: METAL.silver, width: 0.36, top: 0.52, x: 0.8, slot: 'second', shadow: SHADOW })];
65
+ return [halo(0.5, 0.62, 0.95), ...copy(cls), browser({ width: 0.76, top: 0.255, x: 0.42 }), phone({ width: 0.42, top: 0.48, x: 0.76, slot: 'second' })];
66
+ }
67
+
68
+ function orbit(cls: Cls): SlideElement[] {
69
+ const rings = (x: number, y: number, s: number) => [
70
+ ring({ name: 'Orbit', x, y, size: 1.1 * s, stroke: 0.003, color: BLUE, opacity: 0.22 }),
71
+ ring({ name: 'Orbit', x, y, size: 0.82 * s, stroke: 0.003, color: BLUE, opacity: 0.3 }),
72
+ ];
73
+ if (cls === 'wide') return [...rings(0.69, 0.5, 0.95), ...hero(cls)];
74
+ if (cls === 'tablet') return [...rings(0.5, 0.7, 1.1), ...hero(cls)];
75
+ return [...rings(0.5, 0.6, 1.05), ...hero(cls)];
76
+ }
77
+
78
+ const o = { classes: ALL_CLASSES };
79
+
80
+ export const launchpad = template({
81
+ id: 'launchpad',
82
+ name: 'Launchpad',
83
+ description: 'A clean product page for web apps: cool grey paper with a dot grid, Space Grotesk headlines with electric-blue highlights, and light browser windows that work on every canvas.',
84
+ category: 'minimal',
85
+ tags: ['web app', 'browser', 'saas', 'light', 'clean'],
86
+ apps: ['finance', 'fitness', 'tasks', 'calendar', 'chat', 'shop', 'social'],
87
+ theme: theme({
88
+ background: background(solid('#f5f6f8'), pattern('dots', '#0f172a', 0.09, 0.045)),
89
+ heading: F.spaceGrotesk,
90
+ body: F.inter,
91
+ palette: [BLUE, '#14b8a6', '#f59e0b', '#ef4444', '#ffffff', '#0b1220'],
92
+ }),
93
+ slides: [
94
+ slide(
95
+ {
96
+ en: { headline: 'Analytics, *simplified*', subtitle: 'Understand your traffic in seconds, without cookies.' },
97
+ ar: { headline: 'تحليلات *أبسط*', subtitle: 'افهم زيارات موقعك في ثوانٍ، دون ملفات تعريف الارتباط.' },
98
+ de: { headline: 'Analytics, *vereinfacht*', subtitle: 'Verstehe deinen Traffic in Sekunden, ganz ohne Cookies.' },
99
+ },
100
+ hero,
101
+ o,
102
+ ),
103
+ slide(
104
+ {
105
+ en: { headline: 'Real-time, *really*', subtitle: 'Watch visitors arrive the moment you launch.' },
106
+ ar: { headline: 'لحظةً *بلحظة*', subtitle: 'شاهد الزوّار يصلون فور إطلاق موقعك.' },
107
+ de: { headline: 'Echtzeit, *wirklich*', subtitle: 'Sieh deine Besucher, sobald du live gehst.' },
108
+ },
109
+ stacked,
110
+ o,
111
+ ),
112
+ slide(
113
+ {
114
+ en: { headline: 'Goals that *convert*', subtitle: 'Track sign-ups, sales and funnels with zero setup.' },
115
+ ar: { headline: 'أهداف *تحقق* النتائج', subtitle: 'تتبّع التسجيلات والمبيعات ومسارات التحويل دون أي إعداد.' },
116
+ de: { headline: 'Ziele, die *konvertieren*', subtitle: 'Verfolge Anmeldungen, Verkäufe und Funnels ohne Einrichtung.' },
117
+ },
118
+ upside,
119
+ o,
120
+ ),
121
+ slide(
122
+ {
123
+ en: { headline: 'Reports your team *loves*', subtitle: 'Live dashboards on every screen, shared with one link.' },
124
+ ar: { headline: 'تقارير *يحبها* فريقك', subtitle: 'لوحات بيانات مباشرة على كل شاشة، تشاركها برابط واحد.' },
125
+ de: { headline: 'Berichte, die dein Team *liebt*', subtitle: 'Live-Dashboards auf jedem Bildschirm, geteilt per Link.' },
126
+ },
127
+ everywhere,
128
+ o,
129
+ ),
130
+ slide(
131
+ {
132
+ en: { headline: 'Privacy *first*', subtitle: 'No cookies, no tracking, fully GDPR compliant.' },
133
+ ar: { headline: 'خصوصية *بلا تنازلات*', subtitle: 'بلا ملفات تعريف ارتباط ولا تتبّع، ومتوافق مع اللائحة الأوروبية.' },
134
+ de: { headline: 'Datenschutz *zuerst*', subtitle: 'Keine Cookies, kein Tracking, voll DSGVO-konform.' },
135
+ },
136
+ orbit,
137
+ o,
138
+ ),
139
+ ],
140
+ });
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Loud & Clear: poster energy. Cobalt and paper white slides in turn,
3
+ * oversized Outfit Black set in capitals, neon lime accents, compact black
4
+ * phones. Story: a training app.
5
+ */
6
+ import type { SlideElement } from '../../model/types';
7
+ import { ALL_CLASSES, F, background, circle, copyAt, device, slide, solid, template, theme, typeset, type Cls } from '../kit';
8
+
9
+ const COBALT = '#2340ff';
10
+ const LIME = '#d7ff3a';
11
+ const PAPER = '#f3f3ee';
12
+
13
+ const head = { weight: 900, size: 0.16, lineHeight: 1.0, letterSpacing: -0.01, transform: 'uppercase' as const, maxLines: 3, width: 0.92 };
14
+ const sub = { weight: 500, size: 0.04, lineHeight: 1.32 };
15
+
16
+ const blue = typeset({ heading: F.outfit, body: F.outfit, ink: '#ffffff', soft: '#e3e8ff', accent: LIME, head, sub });
17
+ const paper = typeset({ heading: F.outfit, body: F.outfit, ink: COBALT, soft: '#363b57', accent: LIME, mode: 'marker', head, sub });
18
+
19
+ const SHADOW = { color: '#0a0f4d59', blur: 0.06, x: 0, y: 0.03 };
20
+ const phone = (o: Parameters<typeof device>[0]) => device({ color: '#1b1b1d', finish: 'matte', width: 0.66, top: 0.4, shadow: SHADOW, ...o });
21
+
22
+ /** Big headline over a compact device, with one bold disc behind it. */
23
+ function poster(onPaper: boolean, o: { disc?: [number, number, number]; rotation?: number; x?: number } = {}) {
24
+ return (cls: Cls): SlideElement[] => {
25
+ const t = onPaper ? paper : blue;
26
+ const [dx, dy, ds] = o.disc ?? [0.84, 0.8, 0.72];
27
+ const disc = (x: number, y: number, size: number) => circle({ name: 'Disc', x, y, size, color: onPaper ? COBALT : LIME, opacity: onPaper ? 1 : 0.95 });
28
+ if (cls === 'wide') {
29
+ return [
30
+ disc(0.8, 0.84, 0.8),
31
+ ...copyAt(t, { cls, seam: 0.56, x: 0.26, width: 0.66, head: { size: 0.12 }, sub: { size: 0.032, width: 0.6 } }),
32
+ device({ cls, frame: 'macbook', color: '#2b2c31', width: 0.74, x: 0.745, y: 0.5, rotation: (o.rotation ?? 0) / 2, shadow: SHADOW }),
33
+ ];
34
+ }
35
+ if (cls === 'tablet') {
36
+ return [
37
+ disc(dx, dy, ds * 0.9),
38
+ ...copyAt(t, { cls, seam: 0.25, head: { size: 0.12 }, sub: { size: 0.032, width: 0.7 } }),
39
+ device({ cls, frame: 'ipad', color: '#1b1b1d', finish: 'matte', width: 0.68, top: 0.375, x: o.x ?? 0.5, rotation: (o.rotation ?? 0) / 2, shadow: SHADOW }),
40
+ ];
41
+ }
42
+ return [disc(dx, dy, ds), ...copyAt(t, { seam: 0.305 }), phone({ rotation: o.rotation ?? 0, x: o.x ?? 0.5 })];
43
+ };
44
+ }
45
+
46
+ const o3 = { classes: ALL_CLASSES };
47
+ const PAPER_BG = background(solid(PAPER));
48
+
49
+ export const loudAndClear = template({
50
+ id: 'loud-and-clear',
51
+ name: 'Loud & Clear',
52
+ description: 'Poster energy: cobalt and paper-white slides in turn, oversized Outfit Black capitals, neon lime accents and compact black phones.',
53
+ category: 'bold',
54
+ tags: ['bold', 'uppercase', 'poster', 'fitness', 'high contrast'],
55
+ apps: ['fitness', 'travel', 'music', 'calendar', 'social', 'chat', 'meditation', 'tasks'],
56
+ theme: theme({
57
+ background: background(solid(COBALT)),
58
+ heading: F.outfit,
59
+ body: F.outfit,
60
+ palette: [COBALT, LIME, '#ff4d2e', '#111111', PAPER],
61
+ }),
62
+ slides: [
63
+ slide(
64
+ {
65
+ en: { headline: 'Train *harder*', subtitle: 'Workouts that adapt to you, every single day.' },
66
+ ar: { headline: 'تمرّن *بقوة*', subtitle: 'تمارين تتكيّف معك يومًا بعد يوم.' },
67
+ de: { headline: 'Trainiere *härter*', subtitle: 'Workouts, die sich jeden Tag an dich anpassen.' },
68
+ },
69
+ poster(false),
70
+ o3,
71
+ ),
72
+ slide(
73
+ {
74
+ en: { headline: 'Lift. Run. *Repeat.*', subtitle: '500+ guided sessions for strength, cardio and mobility.' },
75
+ ar: { headline: 'ارفع. اركض. *كرّر.*', subtitle: 'أكثر من 500 جلسة موجّهة للقوة واللياقة والمرونة.' },
76
+ de: { headline: 'Heben. Laufen. *Wiederholen.*', subtitle: 'Über 500 geführte Einheiten für Kraft, Ausdauer und Mobilität.' },
77
+ },
78
+ poster(true, { disc: [0.14, 0.86, 0.62], rotation: -6, x: 0.53 }),
79
+ { ...o3, background: PAPER_BG },
80
+ ),
81
+ slide(
82
+ {
83
+ en: { headline: 'Every rep *counts*', subtitle: 'Live stats and form tips while you move.' },
84
+ ar: { headline: 'كل تكرار *يُحسب*', subtitle: 'إحصاءات مباشرة ونصائح للأداء الصحيح أثناء التمرين.' },
85
+ de: { headline: 'Jede Wiederholung *zählt*', subtitle: 'Live-Werte und Techniktipps, während du trainierst.' },
86
+ },
87
+ poster(false, { disc: [0.5, 0.92, 1.1] }),
88
+ o3,
89
+ ),
90
+ slide(
91
+ {
92
+ en: { headline: 'Beat your *best*', subtitle: 'Personal records, streaks and weekly goals.' },
93
+ ar: { headline: 'حطّم *أرقامك*', subtitle: 'أرقامك القياسية وسلاسل إنجازك وأهدافك الأسبوعية.' },
94
+ de: { headline: 'Schlag deine *Bestzeit*', subtitle: 'Persönliche Rekorde, Serien und Wochenziele.' },
95
+ },
96
+ poster(true, { disc: [0.86, 0.78, 0.7], rotation: 6, x: 0.47 }),
97
+ { ...o3, background: PAPER_BG },
98
+ ),
99
+ slide(
100
+ {
101
+ en: { headline: 'Join the *crew*', subtitle: 'Challenges with friends keep you coming back.' },
102
+ ar: { headline: 'انضم إلى *الفريق*', subtitle: 'تحديات مع الأصدقاء تُبقي حماسك متّقدًا.' },
103
+ de: { headline: 'Werde Teil der *Crew*', subtitle: 'Challenges mit Freunden halten dich motiviert.' },
104
+ },
105
+ poster(false, { disc: [0.18, 0.78, 0.64] }),
106
+ o3,
107
+ ),
108
+ ],
109
+ });
@@ -0,0 +1,108 @@
1
+ /**
2
+ * Midnight Neon: after dark. A violet night fading to black over a cyan
3
+ * synthwave grid, neon tube rings in magenta and cyan, Space Grotesk set in
4
+ * capitals, black phones. Story: a nightlife and live music app.
5
+ */
6
+ import type { SlideElement } from '../../model/types';
7
+ import { F, METAL, background, copyAt, device, glow, pattern, radial, ring, slide, template, theme, typeset } from '../kit';
8
+
9
+ const PINK = '#ff2bd6';
10
+ const CYAN = '#00e5ff';
11
+
12
+ const t = typeset({
13
+ heading: F.spaceGrotesk,
14
+ body: F.spaceGrotesk,
15
+ ink: '#ffffff',
16
+ soft: '#d8d1f4',
17
+ accent: '#ff5ddc',
18
+ head: { weight: 700, size: 0.084, lineHeight: 1.12, letterSpacing: 0.005, transform: 'uppercase' },
19
+ sub: { weight: 400, size: 0.04 },
20
+ });
21
+
22
+ const phone = (o: Parameters<typeof device>[0]) => device({ color: METAL.black, shadow: { color: '#000000b3', blur: 0.08, x: 0, y: 0.035 }, ...o });
23
+
24
+ /** A neon tube: a coloured glow with a hot white core. */
25
+ const neon = (x: number, y: number, size: number, color: string): SlideElement[] => [
26
+ ring({ name: 'Neon tube', x, y, size, stroke: 0.014, color, blur: 0.035, opacity: 0.95 }),
27
+ ring({ name: 'Neon core', x, y, size: size - 0.009, stroke: 0.004, color: '#fff4fd', opacity: 0.95 }),
28
+ ];
29
+
30
+ const lights = (flip = false): SlideElement[] => [
31
+ glow({ x: flip ? 0.86 : 0.14, y: 0.5, size: 0.7, color: PINK, opacity: 0.4 }),
32
+ glow({ x: flip ? 0.16 : 0.86, y: 0.78, size: 0.62, color: CYAN, opacity: 0.32 }),
33
+ ];
34
+
35
+ const top = () => copyAt(t, { seam: 0.15 });
36
+
37
+ const hero = (): SlideElement[] => [...lights(), ...neon(0.5, 0.6, 1.02, PINK), ...top(), phone({ width: 0.78, top: 0.255 })];
38
+
39
+ const tilted = (): SlideElement[] => [glow({ x: 0.1, y: 0.04, size: 0.34, color: PINK, opacity: 0.34 }), ...neon(0.84, 0.36, 0.42, CYAN), ...top(), phone({ width: 0.78, top: 0.265, x: 0.47, rotation: 8 })];
40
+
41
+ const crowd = (): SlideElement[] => [
42
+ ...lights(),
43
+ ...top(),
44
+ phone({ width: 0.6, top: 0.31, x: 0.7, rotation: 7, slot: 'second' }),
45
+ phone({ width: 0.63, top: 0.26, x: 0.33, rotation: -6 }),
46
+ ];
47
+
48
+ const hanging = (): SlideElement[] => [
49
+ glow({ x: 0.5, y: 0.34, size: 0.9, color: PINK, opacity: 0.36 }),
50
+ ...neon(0.5, 0.33, 1.0, CYAN),
51
+ phone({ width: 0.8, bottom: 0.68 }),
52
+ ...copyAt(t, { seam: 0.81 }),
53
+ ];
54
+
55
+ const pair = (): SlideElement[] => [...neon(0.36, 0.56, 0.9, PINK), ...neon(0.66, 0.68, 0.9, CYAN), ...top(), phone({ width: 0.76, top: 0.26 })];
56
+
57
+ export const midnightNeon = template({
58
+ id: 'midnight-neon',
59
+ name: 'Midnight Neon',
60
+ description: 'After dark: a violet night fading to black over a cyan synthwave grid, neon tube rings in magenta and cyan, capital Space Grotesk headlines and black phones.',
61
+ category: 'dark',
62
+ tags: ['neon', 'night', 'music', 'synthwave', 'glow'],
63
+ apps: ['music', 'social', 'chat', 'calendar', 'shop', 'travel', 'finance'],
64
+ theme: theme({
65
+ background: background(radial(0.5, 0, 1.05, ['#3a0f63', 0], ['#14072b', 0.5], ['#07050d', 1]), pattern('grid', CYAN, 0.07, 0.1)),
66
+ heading: F.spaceGrotesk,
67
+ body: F.spaceGrotesk,
68
+ palette: ['#ff4fd8', CYAN, '#7c4dff', '#ffd23f', '#ffffff', '#07050d'],
69
+ mockDark: true,
70
+ }),
71
+ slides: [
72
+ slide(
73
+ {
74
+ en: { headline: 'Find your *night*', subtitle: 'The best gigs, clubs and DJ sets in your city.' },
75
+ ar: { headline: 'اعثر على *سهرتك*', subtitle: 'أفضل الحفلات والعروض الموسيقية في مدينتك.' },
76
+ },
77
+ hero,
78
+ ),
79
+ slide(
80
+ {
81
+ en: { headline: 'Tickets in *one tap*', subtitle: 'Skip the line with passes that live in your wallet.' },
82
+ ar: { headline: 'تذكرتك *بلمسة*', subtitle: 'تجاوز الطوابير بتذاكر محفوظة في محفظتك الرقمية.' },
83
+ },
84
+ tilted,
85
+ ),
86
+ slide(
87
+ {
88
+ en: { headline: 'Go *together*', subtitle: 'See where friends are heading and join the plan.' },
89
+ ar: { headline: 'اذهبوا *معًا*', subtitle: 'اعرف وجهة أصدقائك وانضم إلى خطتهم.' },
90
+ },
91
+ crowd,
92
+ ),
93
+ slide(
94
+ {
95
+ en: { headline: 'Never miss a *drop*', subtitle: 'Alerts the moment your favorite artists announce.' },
96
+ ar: { headline: 'لا تفوّت أي *حفلة*', subtitle: 'تنبيهات فورية حين يعلن فنانوك المفضّلون عن عروضهم.' },
97
+ },
98
+ hanging,
99
+ ),
100
+ slide(
101
+ {
102
+ en: { headline: 'Relive the *set*', subtitle: 'Playlists from every show you go to.' },
103
+ ar: { headline: 'عِش *اللحظة* من جديد', subtitle: 'قوائم تشغيل من كل حفلة تحضرها.' },
104
+ },
105
+ pair,
106
+ ),
107
+ ],
108
+ });
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Mono Swiss: International Typographic Style. Warm paper white on a
3
+ * six-column hairline grid, flush-left Inter set tight and large, a single
4
+ * signal red, bare screenshots placed on the grid. Story: a notes app.
5
+ */
6
+ import type { SlideElement } from '../../model/types';
7
+ import { ALL_CLASSES, F, background, canvas, copyAt, device, pattern, rect, r5, slide, solid, template, theme, typeset, type Cls, type DeviceOptions } from '../kit';
8
+
9
+ const RED = '#cc2a18';
10
+ const t = typeset({
11
+ heading: F.inter,
12
+ body: F.inter,
13
+ ink: '#0e0e0e',
14
+ soft: '#3a3a3a',
15
+ accent: RED,
16
+ align: 'start',
17
+ head: { weight: 800, size: 0.108, lineHeight: 1.06, letterSpacing: -0.045, maxLines: 3 },
18
+ sub: { weight: 450, size: 0.038, lineHeight: 1.4 },
19
+ eyebrow: { color: '#0e0e0e', highlight: RED, size: 0.028, letterSpacing: 0.12, weight: 700 },
20
+ });
21
+
22
+ /** The grid: 0.168u modules with 0.084u margins (the background pattern draws the same lines). */
23
+ const M = 0.168;
24
+ const edge = (k: number) => 0.084 + M * k;
25
+
26
+ /** Element centre x (canvas fraction) of a box spanning grid lines a..b. */
27
+ const spanX = (cls: Cls, a: number, b: number) => r5((edge(a) + edge(b)) / 2 / canvas(cls).wu);
28
+ const spanW = (a: number, b: number) => r5(edge(b) - edge(a));
29
+ /** A grid line as a fraction of the canvas height. */
30
+ const row = (cls: Cls, k: number) => r5(edge(k) / canvas(cls).hu);
31
+
32
+ const SHADOW = { color: '#0000002e', blur: 0.035, x: 0, y: 0.018 };
33
+ const shot = (cls: Cls, a: number, b: number, topRow: number, o: DeviceOptions = {}) =>
34
+ device({ cls, frame: 'none', cornerRadius: 0.07, shadow: SHADOW, x: spanX(cls, a, b), width: spanW(a, b), top: row(cls, topRow), ...o });
35
+
36
+ /** A solid red module, the one loud element on the page. */
37
+ const block = (cls: Cls, col: number, rowK: number, size = 1) =>
38
+ rect({ name: 'Red block', x: spanX(cls, col, col + size), y: r5((edge(rowK) + (M * size) / 2) / canvas(cls).hu), size: M * size, radius: 0, color: RED });
39
+
40
+ /** Eyebrow on the top margin, headline + subtitle meeting at a grid line. */
41
+ function copy(cls: Cls, seamRow: number, o: { head?: number; subTo?: number } = {}): SlideElement[] {
42
+ const wide = cls === 'wide';
43
+ const to = wide ? 4 : 5;
44
+ return [
45
+ t.eyebrow({ x: spanX(cls, 0, to), width: spanW(0, to), y: row(cls, 0) }),
46
+ ...copyAt(t, {
47
+ cls,
48
+ seam: row(cls, seamRow),
49
+ x: spanX(cls, 0, to),
50
+ width: spanW(0, to),
51
+ head: { size: o.head ?? (cls === 'tall' ? 0.108 : 0.084) },
52
+ sub: { x: spanX(cls, 0, o.subTo ?? (wide ? 4 : 4)), width: spanW(0, o.subTo ?? 4), size: cls === 'tall' ? 0.038 : 0.03 },
53
+ }),
54
+ ];
55
+ }
56
+
57
+ function think(cls: Cls): SlideElement[] {
58
+ if (cls === 'wide') return [...copy(cls, 3, { head: 0.1 }), shot(cls, 5, 9, 1), block(cls, 0, 4.5)];
59
+ if (cls === 'tablet') return [...copy(cls, 2.5, { head: 0.11 }), shot(cls, 2, 5, 3.6), block(cls, 0, 6)];
60
+ return [...copy(cls, 3.5, { head: 0.135 }), shot(cls, 2, 5, 5.5), block(cls, 0, 11)];
61
+ }
62
+
63
+ function focus(cls: Cls): SlideElement[] {
64
+ if (cls === 'wide') return [...copy(cls, 3), shot(cls, 4.5, 9, 0.8)];
65
+ if (cls === 'tablet') return [...copy(cls, 2.5), shot(cls, 1, 5, 3.6)];
66
+ return [...copy(cls, 3), shot(cls, 1, 5, 4.4)];
67
+ }
68
+
69
+ function organize(cls: Cls): SlideElement[] {
70
+ if (cls === 'wide') return [...copy(cls, 3), shot(cls, 6, 9, 2, { slot: 'second' }), shot(cls, 4.5, 7.5, 0.8)];
71
+ if (cls === 'tablet') return [...copy(cls, 2.5), shot(cls, 2.5, 5, 4.4, { slot: 'second' }), shot(cls, 0, 2.5, 3.6)];
72
+ return [...copy(cls, 3), shot(cls, 2.5, 5, 5.4, { slot: 'second' }), shot(cls, 0, 2.5, 4.4)];
73
+ }
74
+
75
+ function search(cls: Cls): SlideElement[] {
76
+ if (cls === 'wide') return [...copy(cls, 3), shot(cls, 4.5, 9, 0.8), block(cls, 0, 4.5)];
77
+ if (cls === 'tablet') return [...copy(cls, 2.5), shot(cls, 0, 4, 3.6), block(cls, 4, 6)];
78
+ return [...copy(cls, 3), shot(cls, 0, 4, 4.4), block(cls, 4, 11)];
79
+ }
80
+
81
+ function secure(cls: Cls): SlideElement[] {
82
+ if (cls === 'wide') return [...copy(cls, 3), shot(cls, 4.5, 9, 0.8)];
83
+ if (cls === 'tablet') return [...copy(cls, 2.5), shot(cls, 1, 5, 3.6)];
84
+ return [...copy(cls, 3), shot(cls, 1, 5, 4.4)];
85
+ }
86
+
87
+ const o = { classes: ALL_CLASSES };
88
+
89
+ export const monoSwiss = template({
90
+ id: 'mono-swiss',
91
+ name: 'Mono Swiss',
92
+ description: 'International Typographic Style: paper white on a hairline grid, flush-left Inter set tight and large, one signal red, and bare screenshots placed on the grid.',
93
+ category: 'minimal',
94
+ tags: ['swiss', 'grid', 'typography', 'monochrome', 'notes'],
95
+ apps: ['tasks', 'calendar', 'chat', 'finance', 'meditation', 'social', 'shop'],
96
+ theme: theme({
97
+ background: background(solid('#f1f0eb'), pattern('grid', '#111111', 0.06, M)),
98
+ heading: F.inter,
99
+ body: F.inter,
100
+ palette: [RED, '#111111', '#7a7a7a', '#d9d7d0', '#f1f0eb'],
101
+ }),
102
+ slides: [
103
+ slide(
104
+ {
105
+ en: { eyebrow: '*01* — Capture', headline: 'Think *clearly.*', subtitle: 'Plain-text notes that stay out of your way.' },
106
+ ar: { eyebrow: '*01* — التدوين', headline: 'فكّر *بوضوح.*', subtitle: 'ملاحظات نصية بسيطة لا تشتّت انتباهك.' },
107
+ de: { eyebrow: '*01* — Notieren', headline: 'Denk *klar.*', subtitle: 'Schlichte Notizen, die dir nicht im Weg stehen.' },
108
+ },
109
+ think,
110
+ o,
111
+ ),
112
+ slide(
113
+ {
114
+ en: { eyebrow: '*02* — Focus', headline: 'Write without *noise*', subtitle: 'A distraction-free editor with nothing but your words.' },
115
+ ar: { eyebrow: '*02* — التركيز', headline: 'اكتب *بلا ضجيج*', subtitle: 'محرّر خالٍ من المشتّتات، لا شيء فيه سوى كلماتك.' },
116
+ de: { eyebrow: '*02* — Fokus', headline: 'Schreiben ohne *Lärm*', subtitle: 'Ein ablenkungsfreier Editor, nur du und deine Worte.' },
117
+ },
118
+ focus,
119
+ o,
120
+ ),
121
+ slide(
122
+ {
123
+ en: { eyebrow: '*03* — Organize', headline: 'Everything in its *place*', subtitle: 'Tags, folders and links that connect your ideas.' },
124
+ ar: { eyebrow: '*03* — التنظيم', headline: 'كل شيء في *مكانه*', subtitle: 'وسوم ومجلدات وروابط تصل أفكارك ببعضها.' },
125
+ de: { eyebrow: '*03* — Ordnen', headline: 'Alles an seinem *Platz*', subtitle: 'Tags, Ordner und Links, die deine Ideen verbinden.' },
126
+ },
127
+ organize,
128
+ o,
129
+ ),
130
+ slide(
131
+ {
132
+ en: { eyebrow: '*04* — Search', headline: 'Find *anything* in seconds', subtitle: 'Instant search across every note you have ever written.' },
133
+ ar: { eyebrow: '*04* — البحث', headline: 'اعثر على *أي شيء* في ثوانٍ', subtitle: 'بحث فوري في كل ملاحظة كتبتها يومًا.' },
134
+ de: { eyebrow: '*04* — Suchen', headline: 'Finde *alles* in Sekunden', subtitle: 'Sofortsuche in jeder Notiz, die du je geschrieben hast.' },
135
+ },
136
+ search,
137
+ o,
138
+ ),
139
+ slide(
140
+ {
141
+ en: { eyebrow: '*05* — Sync', headline: 'Private by *design*', subtitle: 'End-to-end encrypted and synced across your devices.' },
142
+ ar: { eyebrow: '*05* — المزامنة', headline: 'الخصوصية *أولًا*', subtitle: 'تشفير تام بين الطرفين ومزامنة على جميع أجهزتك.' },
143
+ de: { eyebrow: '*05* — Sync', headline: 'Privat aus *Prinzip*', subtitle: 'Ende-zu-Ende-verschlüsselt und auf allen Geräten synchron.' },
144
+ },
145
+ secure,
146
+ o,
147
+ ),
148
+ ],
149
+ });