@rdna/radiants 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 (44) hide show
  1. package/LICENSE +674 -0
  2. package/README.md +125 -0
  3. package/animations.css +68 -0
  4. package/assets/scrollbar-background.svg +9 -0
  5. package/base.css +144 -0
  6. package/dark.css +117 -0
  7. package/dist/chunk-SR2T7OEJ.mjs +46 -0
  8. package/dist/chunk-SR2T7OEJ.mjs.map +1 -0
  9. package/dist/components/core/index.d.mts +911 -0
  10. package/dist/components/core/index.mjs +2475 -0
  11. package/dist/components/core/index.mjs.map +1 -0
  12. package/dist/hooks/index.d.mts +22 -0
  13. package/dist/hooks/index.mjs +3 -0
  14. package/dist/hooks/index.mjs.map +1 -0
  15. package/dist/remotion/index.d.mts +252 -0
  16. package/dist/remotion/index.mjs +170 -0
  17. package/dist/remotion/index.mjs.map +1 -0
  18. package/dna.config.json +8 -0
  19. package/fonts/Joystix.woff2 +0 -0
  20. package/fonts/PixelCode-Black-Italic.woff2 +0 -0
  21. package/fonts/PixelCode-Black.woff2 +0 -0
  22. package/fonts/PixelCode-Bold-Italic.woff2 +0 -0
  23. package/fonts/PixelCode-Bold.woff2 +0 -0
  24. package/fonts/PixelCode-DemiBold-Italic.woff2 +0 -0
  25. package/fonts/PixelCode-DemiBold.woff2 +0 -0
  26. package/fonts/PixelCode-ExtraBlack-Italic.woff2 +0 -0
  27. package/fonts/PixelCode-ExtraBlack.woff2 +0 -0
  28. package/fonts/PixelCode-ExtraBold-Italic.woff2 +0 -0
  29. package/fonts/PixelCode-ExtraBold.woff2 +0 -0
  30. package/fonts/PixelCode-ExtraLight-Italic.woff2 +0 -0
  31. package/fonts/PixelCode-ExtraLight.woff2 +0 -0
  32. package/fonts/PixelCode-Italic.woff2 +0 -0
  33. package/fonts/PixelCode-Light-Italic.woff2 +0 -0
  34. package/fonts/PixelCode-Light.woff2 +0 -0
  35. package/fonts/PixelCode-Medium-Italic.woff2 +0 -0
  36. package/fonts/PixelCode-Medium.woff2 +0 -0
  37. package/fonts/PixelCode-Thin-Italic.woff2 +0 -0
  38. package/fonts/PixelCode-Thin.woff2 +0 -0
  39. package/fonts/PixelCode.woff2 +0 -0
  40. package/fonts.css +115 -0
  41. package/index.css +25 -0
  42. package/package.json +88 -0
  43. package/tokens.css +202 -0
  44. package/typography.css +175 -0
@@ -0,0 +1,252 @@
1
+ import { Easing, SpringConfig } from 'remotion';
2
+
3
+ /**
4
+ * @dna/radiants - Remotion Duration Utilities
5
+ *
6
+ * Maps DNA motion tokens to Remotion frame counts.
7
+ * Aligns with CSS duration tokens from animations.css.
8
+ */
9
+ /** Duration tokens in milliseconds, matching DNA motion spec */
10
+ declare const DURATION_MS: {
11
+ readonly instant: 0;
12
+ readonly fast: 100;
13
+ readonly base: 150;
14
+ readonly moderate: 200;
15
+ readonly slow: 300;
16
+ };
17
+ type DurationToken = keyof typeof DURATION_MS;
18
+ /**
19
+ * Convert a DNA duration token to frame count for Remotion.
20
+ *
21
+ * @param token - DNA duration token or milliseconds
22
+ * @param fps - Frames per second (default: 30)
23
+ * @returns Number of frames
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * durationToFrames('fast', 30); // 3 frames
28
+ * durationToFrames('base', 60); // 9 frames
29
+ * durationToFrames(200, 30); // 6 frames (raw ms)
30
+ * ```
31
+ */
32
+ declare function durationToFrames(token: DurationToken | number, fps?: number): number;
33
+ /**
34
+ * Convert frame count back to milliseconds.
35
+ *
36
+ * @param frames - Number of frames
37
+ * @param fps - Frames per second (default: 30)
38
+ * @returns Duration in milliseconds
39
+ */
40
+ declare function framesToMs(frames: number, fps?: number): number;
41
+ /**
42
+ * Get the closest DNA duration token for a given millisecond value.
43
+ *
44
+ * @param ms - Duration in milliseconds
45
+ * @returns Closest DNA duration token
46
+ */
47
+ declare function msToToken(ms: number): DurationToken;
48
+
49
+ /**
50
+ * @dna/radiants - Remotion Easing Curves
51
+ *
52
+ * DNA easing curves implemented via Remotion's Easing.bezier().
53
+ * Matches CSS custom properties: --easing-default, --easing-out, --easing-in
54
+ */
55
+
56
+ /**
57
+ * DNA easing curves for Remotion interpolations.
58
+ *
59
+ * These match the CSS custom properties defined in the DNA spec:
60
+ * - default/out: cubic-bezier(0, 0, 0.2, 1) - ease-out curve for most animations
61
+ * - in: cubic-bezier(0.4, 0, 1, 1) - ease-in for exit animations
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * import { interpolate } from 'remotion';
66
+ * import { dnaEasing } from '@dna/radiants/remotion';
67
+ *
68
+ * const opacity = interpolate(frame, [0, 30], [0, 1], {
69
+ * easing: dnaEasing.default,
70
+ * });
71
+ * ```
72
+ */
73
+ declare const dnaEasing: {
74
+ /** Standard ease-out curve (--easing-default) */
75
+ readonly default: (t: number) => number;
76
+ /** Ease-out curve for enter animations (--easing-out) */
77
+ readonly out: (t: number) => number;
78
+ /** Ease-in curve for exit animations (--easing-in) */
79
+ readonly in: (t: number) => number;
80
+ /** Linear easing for constant-rate animations */
81
+ readonly linear: typeof Easing.linear;
82
+ };
83
+ type EasingToken = keyof typeof dnaEasing;
84
+ /**
85
+ * Get an easing function by token name.
86
+ *
87
+ * @param token - Easing token name
88
+ * @returns Remotion easing function
89
+ */
90
+ declare function getEasing(token: EasingToken): (t: number) => number;
91
+
92
+ /**
93
+ * @dna/radiants - Remotion Spring Presets
94
+ *
95
+ * Pre-configured spring configurations for physics-based animations.
96
+ * These provide natural motion that aligns with DNA timing guidelines.
97
+ */
98
+
99
+ /**
100
+ * DNA spring presets for Remotion's spring() function.
101
+ *
102
+ * Each preset is tuned to approximate DNA duration tokens:
103
+ * - snappy: ~100-150ms feel, for quick micro-interactions
104
+ * - gentle: ~150-200ms feel, for standard UI transitions
105
+ * - stiff: ~200-300ms feel, for deliberate/heavy elements
106
+ *
107
+ * @example
108
+ * ```ts
109
+ * import { spring, useCurrentFrame, useVideoConfig } from 'remotion';
110
+ * import { dnaSpring } from '@dna/radiants/remotion';
111
+ *
112
+ * const { fps } = useVideoConfig();
113
+ * const frame = useCurrentFrame();
114
+ *
115
+ * const scale = spring({
116
+ * frame,
117
+ * fps,
118
+ * config: dnaSpring.snappy,
119
+ * });
120
+ * ```
121
+ */
122
+ declare const dnaSpring: {
123
+ /** Fast, responsive spring (~100-150ms) for micro-interactions */
124
+ readonly snappy: {
125
+ damping: number;
126
+ mass: number;
127
+ stiffness: number;
128
+ overshootClamping: false;
129
+ };
130
+ /** Balanced spring (~150-200ms) for standard transitions */
131
+ readonly gentle: {
132
+ damping: number;
133
+ mass: number;
134
+ stiffness: number;
135
+ overshootClamping: false;
136
+ };
137
+ /** Slower spring (~200-300ms) for deliberate, weighty motion */
138
+ readonly stiff: {
139
+ damping: number;
140
+ mass: number;
141
+ stiffness: number;
142
+ overshootClamping: false;
143
+ };
144
+ /** Bouncy spring for playful, attention-grabbing animations */
145
+ readonly bouncy: {
146
+ damping: number;
147
+ mass: number;
148
+ stiffness: number;
149
+ overshootClamping: false;
150
+ };
151
+ };
152
+ type SpringPreset = keyof typeof dnaSpring;
153
+ /**
154
+ * Get a spring configuration by preset name.
155
+ *
156
+ * @param preset - Spring preset name
157
+ * @returns Remotion SpringConfig object
158
+ */
159
+ declare function getSpringConfig(preset: SpringPreset): SpringConfig;
160
+
161
+ /**
162
+ * @dna/radiants - useMotion Hook
163
+ *
164
+ * High-level animation hook that provides DNA-styled motion for Remotion compositions.
165
+ * Supports both easing-based and spring-based animations.
166
+ */
167
+
168
+ /** Supported animation types */
169
+ type MotionType = 'fade' | 'slideUp' | 'slideDown' | 'slideLeft' | 'slideRight' | 'scale' | 'scaleUp';
170
+ /** Configuration for useMotion hook */
171
+ interface UseMotionConfig {
172
+ /** Animation type to apply */
173
+ type: MotionType;
174
+ /** Duration as DNA token or milliseconds (default: 'base') */
175
+ duration?: DurationToken | number;
176
+ /** Easing curve token (default: 'default') */
177
+ easing?: EasingToken;
178
+ /** Spring preset for physics-based motion */
179
+ spring?: SpringPreset;
180
+ /** Animation mode: 'easing' for bezier curves, 'spring' for physics (default: 'easing') */
181
+ mode?: 'easing' | 'spring';
182
+ /** Delay in frames before animation starts (default: 0) */
183
+ delay?: number;
184
+ /** Custom start frame (default: uses delay) */
185
+ from?: number;
186
+ }
187
+ /** Return type for useMotion hook */
188
+ interface UseMotionResult {
189
+ /** Current opacity value (0-1) */
190
+ opacity: number;
191
+ /** Current transform string */
192
+ transform: string;
193
+ /** Combined style object ready for use */
194
+ style: React.CSSProperties;
195
+ /** Current animation progress (0-1) */
196
+ progress: number;
197
+ /** Whether animation has completed */
198
+ isComplete: boolean;
199
+ }
200
+ /**
201
+ * High-level animation hook for DNA-styled motion in Remotion.
202
+ *
203
+ * Provides pre-configured animation patterns that match DNA motion guidelines.
204
+ * Supports both easing-based (bezier curves) and spring-based (physics) animations.
205
+ *
206
+ * @example
207
+ * ```tsx
208
+ * // Simple fade animation
209
+ * const { style } = useMotion({ type: 'fade' });
210
+ * return <div style={style}>Content</div>;
211
+ *
212
+ * // Slide up with custom duration
213
+ * const { style } = useMotion({
214
+ * type: 'slideUp',
215
+ * duration: 'slow',
216
+ * easing: 'out',
217
+ * });
218
+ *
219
+ * // Spring-based scale animation
220
+ * const { style } = useMotion({
221
+ * type: 'scale',
222
+ * mode: 'spring',
223
+ * spring: 'snappy',
224
+ * });
225
+ *
226
+ * // Staggered list items
227
+ * const delay = durationToFrames('fast', fps);
228
+ * items.map((item, i) => (
229
+ * <Item style={useMotion({ type: 'slideUp', delay: i * delay }).style} />
230
+ * ));
231
+ * ```
232
+ */
233
+ declare function useMotion(config: UseMotionConfig): UseMotionResult;
234
+ /**
235
+ * Create a stagger delay calculator for list animations.
236
+ *
237
+ * @param staggerMs - Delay between each item in milliseconds
238
+ * @param fps - Frames per second
239
+ * @returns Function that returns delay in frames for a given index
240
+ *
241
+ * @example
242
+ * ```tsx
243
+ * const getDelay = createStagger(50, fps);
244
+ *
245
+ * items.map((item, i) => (
246
+ * <Item style={useMotion({ type: 'slideUp', delay: getDelay(i) }).style} />
247
+ * ));
248
+ * ```
249
+ */
250
+ declare function createStagger(staggerMs: number, fps: number): (index: number) => number;
251
+
252
+ export { DURATION_MS, type DurationToken, type EasingToken, type MotionType, type SpringPreset, type UseMotionConfig, type UseMotionResult, createStagger, dnaEasing, dnaSpring, durationToFrames, framesToMs, getEasing, getSpringConfig, msToToken, useMotion };
@@ -0,0 +1,170 @@
1
+ import { Easing, useCurrentFrame, useVideoConfig, spring, interpolate } from 'remotion';
2
+
3
+ // remotion/durations.ts
4
+ var DURATION_MS = {
5
+ instant: 0,
6
+ fast: 100,
7
+ base: 150,
8
+ moderate: 200,
9
+ slow: 300
10
+ };
11
+ function durationToFrames(token, fps = 30) {
12
+ const ms = typeof token === "number" ? token : DURATION_MS[token];
13
+ return Math.round(ms / 1e3 * fps);
14
+ }
15
+ function framesToMs(frames, fps = 30) {
16
+ return Math.round(frames / fps * 1e3);
17
+ }
18
+ function msToToken(ms) {
19
+ const tokens = Object.entries(DURATION_MS);
20
+ let closest = tokens[0];
21
+ for (const [token, value] of tokens) {
22
+ if (Math.abs(value - ms) < Math.abs(closest[1] - ms)) {
23
+ closest = [token, value];
24
+ }
25
+ }
26
+ return closest[0];
27
+ }
28
+ var dnaEasing = {
29
+ /** Standard ease-out curve (--easing-default) */
30
+ default: Easing.bezier(0, 0, 0.2, 1),
31
+ /** Ease-out curve for enter animations (--easing-out) */
32
+ out: Easing.bezier(0, 0, 0.2, 1),
33
+ /** Ease-in curve for exit animations (--easing-in) */
34
+ in: Easing.bezier(0.4, 0, 1, 1),
35
+ /** Linear easing for constant-rate animations */
36
+ linear: Easing.linear
37
+ };
38
+ function getEasing(token) {
39
+ return dnaEasing[token];
40
+ }
41
+
42
+ // remotion/springs.ts
43
+ var dnaSpring = {
44
+ /** Fast, responsive spring (~100-150ms) for micro-interactions */
45
+ snappy: {
46
+ damping: 20,
47
+ mass: 0.5,
48
+ stiffness: 400,
49
+ overshootClamping: false
50
+ },
51
+ /** Balanced spring (~150-200ms) for standard transitions */
52
+ gentle: {
53
+ damping: 25,
54
+ mass: 1,
55
+ stiffness: 200,
56
+ overshootClamping: false
57
+ },
58
+ /** Slower spring (~200-300ms) for deliberate, weighty motion */
59
+ stiff: {
60
+ damping: 30,
61
+ mass: 1.2,
62
+ stiffness: 150,
63
+ overshootClamping: false
64
+ },
65
+ /** Bouncy spring for playful, attention-grabbing animations */
66
+ bouncy: {
67
+ damping: 12,
68
+ mass: 0.8,
69
+ stiffness: 300,
70
+ overshootClamping: false
71
+ }
72
+ };
73
+ function getSpringConfig(preset) {
74
+ return dnaSpring[preset];
75
+ }
76
+ var SLIDE_DISTANCE = 20;
77
+ var SCALE_FROM = 0.95;
78
+ function useMotion(config) {
79
+ const {
80
+ type,
81
+ duration = "base",
82
+ easing = "default",
83
+ spring: springPreset = "gentle",
84
+ mode = "easing",
85
+ delay = 0,
86
+ from
87
+ } = config;
88
+ const frame = useCurrentFrame();
89
+ const { fps } = useVideoConfig();
90
+ const startFrame = from ?? delay;
91
+ const adjustedFrame = Math.max(0, frame - startFrame);
92
+ let progress;
93
+ if (mode === "spring") {
94
+ progress = spring({
95
+ frame: adjustedFrame,
96
+ fps,
97
+ config: dnaSpring[springPreset]
98
+ });
99
+ } else {
100
+ const durationFrames = durationToFrames(duration, fps);
101
+ progress = interpolate(adjustedFrame, [0, durationFrames], [0, 1], {
102
+ easing: dnaEasing[easing],
103
+ extrapolateRight: "clamp"
104
+ });
105
+ }
106
+ const { opacity, transform } = getAnimationValues(type, progress);
107
+ const isComplete = progress >= 1;
108
+ return {
109
+ opacity,
110
+ transform,
111
+ style: {
112
+ opacity,
113
+ transform
114
+ },
115
+ progress,
116
+ isComplete
117
+ };
118
+ }
119
+ function getAnimationValues(type, progress) {
120
+ switch (type) {
121
+ case "fade":
122
+ return {
123
+ opacity: progress,
124
+ transform: "none"
125
+ };
126
+ case "slideUp":
127
+ return {
128
+ opacity: progress,
129
+ transform: `translateY(${interpolate(progress, [0, 1], [SLIDE_DISTANCE, 0])}px)`
130
+ };
131
+ case "slideDown":
132
+ return {
133
+ opacity: progress,
134
+ transform: `translateY(${interpolate(progress, [0, 1], [-SLIDE_DISTANCE, 0])}px)`
135
+ };
136
+ case "slideLeft":
137
+ return {
138
+ opacity: progress,
139
+ transform: `translateX(${interpolate(progress, [0, 1], [SLIDE_DISTANCE, 0])}px)`
140
+ };
141
+ case "slideRight":
142
+ return {
143
+ opacity: progress,
144
+ transform: `translateX(${interpolate(progress, [0, 1], [-SLIDE_DISTANCE, 0])}px)`
145
+ };
146
+ case "scale":
147
+ return {
148
+ opacity: progress,
149
+ transform: `scale(${interpolate(progress, [0, 1], [SCALE_FROM, 1])})`
150
+ };
151
+ case "scaleUp":
152
+ return {
153
+ opacity: progress,
154
+ transform: `scale(${interpolate(progress, [0, 1], [SCALE_FROM, 1])}) translateY(${interpolate(progress, [0, 1], [SLIDE_DISTANCE / 2, 0])}px)`
155
+ };
156
+ default:
157
+ return {
158
+ opacity: 1,
159
+ transform: "none"
160
+ };
161
+ }
162
+ }
163
+ function createStagger(staggerMs, fps) {
164
+ const staggerFrames = durationToFrames(staggerMs, fps);
165
+ return (index) => index * staggerFrames;
166
+ }
167
+
168
+ export { DURATION_MS, createStagger, dnaEasing, dnaSpring, durationToFrames, framesToMs, getEasing, getSpringConfig, msToToken, useMotion };
169
+ //# sourceMappingURL=index.mjs.map
170
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../remotion/durations.ts","../../remotion/easing.ts","../../remotion/springs.ts","../../remotion/useMotion.ts"],"names":[],"mappings":"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","file":"index.mjs","sourcesContent":["/**\n * @dna/radiants - Remotion Duration Utilities\n *\n * Maps DNA motion tokens to Remotion frame counts.\n * Aligns with CSS duration tokens from animations.css.\n */\n\n/** Duration tokens in milliseconds, matching DNA motion spec */\nexport const DURATION_MS = {\n instant: 0,\n fast: 100,\n base: 150,\n moderate: 200,\n slow: 300,\n} as const;\n\nexport type DurationToken = keyof typeof DURATION_MS;\n\n/**\n * Convert a DNA duration token to frame count for Remotion.\n *\n * @param token - DNA duration token or milliseconds\n * @param fps - Frames per second (default: 30)\n * @returns Number of frames\n *\n * @example\n * ```ts\n * durationToFrames('fast', 30); // 3 frames\n * durationToFrames('base', 60); // 9 frames\n * durationToFrames(200, 30); // 6 frames (raw ms)\n * ```\n */\nexport function durationToFrames(\n token: DurationToken | number,\n fps: number = 30\n): number {\n const ms = typeof token === 'number' ? token : DURATION_MS[token];\n return Math.round((ms / 1000) * fps);\n}\n\n/**\n * Convert frame count back to milliseconds.\n *\n * @param frames - Number of frames\n * @param fps - Frames per second (default: 30)\n * @returns Duration in milliseconds\n */\nexport function framesToMs(frames: number, fps: number = 30): number {\n return Math.round((frames / fps) * 1000);\n}\n\n/**\n * Get the closest DNA duration token for a given millisecond value.\n *\n * @param ms - Duration in milliseconds\n * @returns Closest DNA duration token\n */\nexport function msToToken(ms: number): DurationToken {\n const tokens = Object.entries(DURATION_MS) as [DurationToken, number][];\n let closest = tokens[0];\n\n for (const [token, value] of tokens) {\n if (Math.abs(value - ms) < Math.abs(closest[1] - ms)) {\n closest = [token, value];\n }\n }\n\n return closest[0];\n}\n","/**\n * @dna/radiants - Remotion Easing Curves\n *\n * DNA easing curves implemented via Remotion's Easing.bezier().\n * Matches CSS custom properties: --easing-default, --easing-out, --easing-in\n */\n\nimport { Easing } from 'remotion';\n\n/**\n * DNA easing curves for Remotion interpolations.\n *\n * These match the CSS custom properties defined in the DNA spec:\n * - default/out: cubic-bezier(0, 0, 0.2, 1) - ease-out curve for most animations\n * - in: cubic-bezier(0.4, 0, 1, 1) - ease-in for exit animations\n *\n * @example\n * ```ts\n * import { interpolate } from 'remotion';\n * import { dnaEasing } from '@dna/radiants/remotion';\n *\n * const opacity = interpolate(frame, [0, 30], [0, 1], {\n * easing: dnaEasing.default,\n * });\n * ```\n */\nexport const dnaEasing = {\n /** Standard ease-out curve (--easing-default) */\n default: Easing.bezier(0, 0, 0.2, 1),\n\n /** Ease-out curve for enter animations (--easing-out) */\n out: Easing.bezier(0, 0, 0.2, 1),\n\n /** Ease-in curve for exit animations (--easing-in) */\n in: Easing.bezier(0.4, 0, 1, 1),\n\n /** Linear easing for constant-rate animations */\n linear: Easing.linear,\n} as const;\n\nexport type EasingToken = keyof typeof dnaEasing;\n\n/**\n * Get an easing function by token name.\n *\n * @param token - Easing token name\n * @returns Remotion easing function\n */\nexport function getEasing(token: EasingToken): (t: number) => number {\n return dnaEasing[token];\n}\n","/**\n * @dna/radiants - Remotion Spring Presets\n *\n * Pre-configured spring configurations for physics-based animations.\n * These provide natural motion that aligns with DNA timing guidelines.\n */\n\nimport type { SpringConfig } from 'remotion';\n\n/**\n * DNA spring presets for Remotion's spring() function.\n *\n * Each preset is tuned to approximate DNA duration tokens:\n * - snappy: ~100-150ms feel, for quick micro-interactions\n * - gentle: ~150-200ms feel, for standard UI transitions\n * - stiff: ~200-300ms feel, for deliberate/heavy elements\n *\n * @example\n * ```ts\n * import { spring, useCurrentFrame, useVideoConfig } from 'remotion';\n * import { dnaSpring } from '@dna/radiants/remotion';\n *\n * const { fps } = useVideoConfig();\n * const frame = useCurrentFrame();\n *\n * const scale = spring({\n * frame,\n * fps,\n * config: dnaSpring.snappy,\n * });\n * ```\n */\nexport const dnaSpring = {\n /** Fast, responsive spring (~100-150ms) for micro-interactions */\n snappy: {\n damping: 20,\n mass: 0.5,\n stiffness: 400,\n overshootClamping: false,\n } satisfies SpringConfig,\n\n /** Balanced spring (~150-200ms) for standard transitions */\n gentle: {\n damping: 25,\n mass: 1,\n stiffness: 200,\n overshootClamping: false,\n } satisfies SpringConfig,\n\n /** Slower spring (~200-300ms) for deliberate, weighty motion */\n stiff: {\n damping: 30,\n mass: 1.2,\n stiffness: 150,\n overshootClamping: false,\n } satisfies SpringConfig,\n\n /** Bouncy spring for playful, attention-grabbing animations */\n bouncy: {\n damping: 12,\n mass: 0.8,\n stiffness: 300,\n overshootClamping: false,\n } satisfies SpringConfig,\n} as const;\n\nexport type SpringPreset = keyof typeof dnaSpring;\n\n/**\n * Get a spring configuration by preset name.\n *\n * @param preset - Spring preset name\n * @returns Remotion SpringConfig object\n */\nexport function getSpringConfig(preset: SpringPreset): SpringConfig {\n return dnaSpring[preset];\n}\n","/**\n * @dna/radiants - useMotion Hook\n *\n * High-level animation hook that provides DNA-styled motion for Remotion compositions.\n * Supports both easing-based and spring-based animations.\n */\n\nimport { useCurrentFrame, useVideoConfig, spring, interpolate } from 'remotion';\nimport { DURATION_MS, durationToFrames, type DurationToken } from './durations';\nimport { dnaEasing, type EasingToken } from './easing';\nimport { dnaSpring, type SpringPreset } from './springs';\n\n/** Supported animation types */\nexport type MotionType =\n | 'fade'\n | 'slideUp'\n | 'slideDown'\n | 'slideLeft'\n | 'slideRight'\n | 'scale'\n | 'scaleUp';\n\n/** Configuration for useMotion hook */\nexport interface UseMotionConfig {\n /** Animation type to apply */\n type: MotionType;\n /** Duration as DNA token or milliseconds (default: 'base') */\n duration?: DurationToken | number;\n /** Easing curve token (default: 'default') */\n easing?: EasingToken;\n /** Spring preset for physics-based motion */\n spring?: SpringPreset;\n /** Animation mode: 'easing' for bezier curves, 'spring' for physics (default: 'easing') */\n mode?: 'easing' | 'spring';\n /** Delay in frames before animation starts (default: 0) */\n delay?: number;\n /** Custom start frame (default: uses delay) */\n from?: number;\n}\n\n/** Return type for useMotion hook */\nexport interface UseMotionResult {\n /** Current opacity value (0-1) */\n opacity: number;\n /** Current transform string */\n transform: string;\n /** Combined style object ready for use */\n style: React.CSSProperties;\n /** Current animation progress (0-1) */\n progress: number;\n /** Whether animation has completed */\n isComplete: boolean;\n}\n\n/** Transform distances for slide animations */\nconst SLIDE_DISTANCE = 20;\n\n/** Scale values for scale animations */\nconst SCALE_FROM = 0.95;\n\n/**\n * High-level animation hook for DNA-styled motion in Remotion.\n *\n * Provides pre-configured animation patterns that match DNA motion guidelines.\n * Supports both easing-based (bezier curves) and spring-based (physics) animations.\n *\n * @example\n * ```tsx\n * // Simple fade animation\n * const { style } = useMotion({ type: 'fade' });\n * return <div style={style}>Content</div>;\n *\n * // Slide up with custom duration\n * const { style } = useMotion({\n * type: 'slideUp',\n * duration: 'slow',\n * easing: 'out',\n * });\n *\n * // Spring-based scale animation\n * const { style } = useMotion({\n * type: 'scale',\n * mode: 'spring',\n * spring: 'snappy',\n * });\n *\n * // Staggered list items\n * const delay = durationToFrames('fast', fps);\n * items.map((item, i) => (\n * <Item style={useMotion({ type: 'slideUp', delay: i * delay }).style} />\n * ));\n * ```\n */\nexport function useMotion(config: UseMotionConfig): UseMotionResult {\n const {\n type,\n duration = 'base',\n easing = 'default',\n spring: springPreset = 'gentle',\n mode = 'easing',\n delay = 0,\n from,\n } = config;\n\n const frame = useCurrentFrame();\n const { fps } = useVideoConfig();\n\n const startFrame = from ?? delay;\n const adjustedFrame = Math.max(0, frame - startFrame);\n\n let progress: number;\n\n if (mode === 'spring') {\n // Spring-based animation\n progress = spring({\n frame: adjustedFrame,\n fps,\n config: dnaSpring[springPreset],\n });\n } else {\n // Easing-based animation\n const durationFrames = durationToFrames(duration, fps);\n progress = interpolate(adjustedFrame, [0, durationFrames], [0, 1], {\n easing: dnaEasing[easing],\n extrapolateRight: 'clamp',\n });\n }\n\n // Calculate animation values based on type\n const { opacity, transform } = getAnimationValues(type, progress);\n\n const isComplete = progress >= 1;\n\n return {\n opacity,\n transform,\n style: {\n opacity,\n transform,\n },\n progress,\n isComplete,\n };\n}\n\n/**\n * Calculate opacity and transform values for a given animation type and progress.\n */\nfunction getAnimationValues(\n type: MotionType,\n progress: number\n): { opacity: number; transform: string } {\n switch (type) {\n case 'fade':\n return {\n opacity: progress,\n transform: 'none',\n };\n\n case 'slideUp':\n return {\n opacity: progress,\n transform: `translateY(${interpolate(progress, [0, 1], [SLIDE_DISTANCE, 0])}px)`,\n };\n\n case 'slideDown':\n return {\n opacity: progress,\n transform: `translateY(${interpolate(progress, [0, 1], [-SLIDE_DISTANCE, 0])}px)`,\n };\n\n case 'slideLeft':\n return {\n opacity: progress,\n transform: `translateX(${interpolate(progress, [0, 1], [SLIDE_DISTANCE, 0])}px)`,\n };\n\n case 'slideRight':\n return {\n opacity: progress,\n transform: `translateX(${interpolate(progress, [0, 1], [-SLIDE_DISTANCE, 0])}px)`,\n };\n\n case 'scale':\n return {\n opacity: progress,\n transform: `scale(${interpolate(progress, [0, 1], [SCALE_FROM, 1])})`,\n };\n\n case 'scaleUp':\n return {\n opacity: progress,\n transform: `scale(${interpolate(progress, [0, 1], [SCALE_FROM, 1])}) translateY(${interpolate(progress, [0, 1], [SLIDE_DISTANCE / 2, 0])}px)`,\n };\n\n default:\n return {\n opacity: 1,\n transform: 'none',\n };\n }\n}\n\n/**\n * Create a stagger delay calculator for list animations.\n *\n * @param staggerMs - Delay between each item in milliseconds\n * @param fps - Frames per second\n * @returns Function that returns delay in frames for a given index\n *\n * @example\n * ```tsx\n * const getDelay = createStagger(50, fps);\n *\n * items.map((item, i) => (\n * <Item style={useMotion({ type: 'slideUp', delay: getDelay(i) }).style} />\n * ));\n * ```\n */\nexport function createStagger(\n staggerMs: number,\n fps: number\n): (index: number) => number {\n const staggerFrames = durationToFrames(staggerMs, fps);\n return (index: number) => index * staggerFrames;\n}\n"]}
@@ -0,0 +1,8 @@
1
+ {
2
+ "name": "radiants",
3
+ "displayName": "Radiants",
4
+ "version": "1.0.0",
5
+ "description": "Retro pixel aesthetic with warm colors",
6
+ "colorModes": { "default": "light", "available": ["light", "dark"] },
7
+ "fonts": { "heading": "Joystix Monospace", "body": "Mondwest", "mono": "PixelCode" }
8
+ }
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
package/fonts.css ADDED
@@ -0,0 +1,115 @@
1
+ /* =============================================================================
2
+ fonts.css - @dna/radiants Font Definitions
3
+ ============================================================================= */
4
+
5
+ /* -----------------------------------------------------------------------------
6
+ @font-face Declarations
7
+ ----------------------------------------------------------------------------- */
8
+
9
+ /* Mondwest - Body font (must be downloaded separately)
10
+ Get it at: https://pangrampangram.com/products/bitmap-mondwest
11
+ ----------------------------------------------------------------------------- */
12
+
13
+ @font-face {
14
+ font-family: 'Mondwest';
15
+ src: url('./fonts/Mondwest.woff2') format('woff2');
16
+ font-weight: 400;
17
+ font-style: normal;
18
+ font-display: swap;
19
+ }
20
+
21
+ @font-face {
22
+ font-family: 'Mondwest';
23
+ src: url('./fonts/Mondwest-Bold.woff2') format('woff2');
24
+ font-weight: 700;
25
+ font-style: normal;
26
+ font-display: swap;
27
+ }
28
+
29
+ /* Joystix - Heading font
30
+ ----------------------------------------------------------------------------- */
31
+
32
+ @font-face {
33
+ font-family: 'Joystix Monospace';
34
+ src: url('./fonts/Joystix.woff2') format('woff2');
35
+ font-weight: 400;
36
+ font-style: normal;
37
+ font-display: swap;
38
+ }
39
+
40
+ /* PixelCode - Monospace font
41
+ ----------------------------------------------------------------------------- */
42
+
43
+ @font-face {
44
+ font-family: 'PixelCode';
45
+ src: url('./fonts/PixelCode.woff2') format('woff2');
46
+ font-weight: 400;
47
+ font-style: normal;
48
+ font-display: swap;
49
+ }
50
+
51
+ @font-face {
52
+ font-family: 'PixelCode';
53
+ src: url('./fonts/PixelCode-Italic.woff2') format('woff2');
54
+ font-weight: 400;
55
+ font-style: italic;
56
+ font-display: swap;
57
+ }
58
+
59
+ @font-face {
60
+ font-family: 'PixelCode';
61
+ src: url('./fonts/PixelCode-Bold.woff2') format('woff2');
62
+ font-weight: 700;
63
+ font-style: normal;
64
+ font-display: swap;
65
+ }
66
+
67
+ @font-face {
68
+ font-family: 'PixelCode';
69
+ src: url('./fonts/PixelCode-Bold-Italic.woff2') format('woff2');
70
+ font-weight: 700;
71
+ font-style: italic;
72
+ font-display: swap;
73
+ }
74
+
75
+ @font-face {
76
+ font-family: 'PixelCode';
77
+ src: url('./fonts/PixelCode-Light.woff2') format('woff2');
78
+ font-weight: 300;
79
+ font-style: normal;
80
+ font-display: swap;
81
+ }
82
+
83
+ @font-face {
84
+ font-family: 'PixelCode';
85
+ src: url('./fonts/PixelCode-Light-Italic.woff2') format('woff2');
86
+ font-weight: 300;
87
+ font-style: italic;
88
+ font-display: swap;
89
+ }
90
+
91
+ @font-face {
92
+ font-family: 'PixelCode';
93
+ src: url('./fonts/PixelCode-Medium.woff2') format('woff2');
94
+ font-weight: 500;
95
+ font-style: normal;
96
+ font-display: swap;
97
+ }
98
+
99
+ @font-face {
100
+ font-family: 'PixelCode';
101
+ src: url('./fonts/PixelCode-Medium-Italic.woff2') format('woff2');
102
+ font-weight: 500;
103
+ font-style: italic;
104
+ font-display: swap;
105
+ }
106
+
107
+ /* -----------------------------------------------------------------------------
108
+ Font Family Theme Variables
109
+ ----------------------------------------------------------------------------- */
110
+
111
+ @theme {
112
+ --font-sans: 'Mondwest', system-ui, sans-serif;
113
+ --font-heading: 'Joystix Monospace', monospace;
114
+ --font-mono: 'PixelCode', monospace;
115
+ }
package/index.css ADDED
@@ -0,0 +1,25 @@
1
+ /* =============================================================================
2
+ @dna/radiants - Theme Entry Point
3
+ Import this file to use the Radiants theme with Tailwind CSS v4
4
+ ============================================================================= */
5
+
6
+ @import 'tailwindcss';
7
+
8
+ /* Theme tokens - semantic color mappings */
9
+ @import './tokens.css';
10
+
11
+ /* Font declarations and typography tokens */
12
+ @import './fonts.css';
13
+
14
+ /* Base element typography styles */
15
+ @import './typography.css';
16
+
17
+ /* Base styles - box-sizing, body defaults, scrollbars */
18
+ @import './base.css';
19
+
20
+ /* Animations - keyframes and utility classes */
21
+ @import './animations.css';
22
+
23
+ /* Note: dark.css is NOT auto-imported - consumers import it separately:
24
+ @import '@dna/radiants/dark';
25
+ */