Add promo components and screenshot images
- Add LiveActivityAnimation, LiveActivityCard, BackgroundStill components - Update Root.tsx composition - Add widget and voting screenshot images Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
BIN
feels-promo/public/timeline_dark_medium_voting.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
feels-promo/public/timeline_light_small_voting.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
feels-promo/public/voting_dark_large.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
feels-promo/public/voting_light_large.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
feels-promo/public/voting_light_medium.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
feels-promo/public/voting_light_small.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
52
feels-promo/src/BackgroundStill.tsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { AbsoluteFill, Img, staticFile } from "remotion";
|
||||
|
||||
// Static version of the tiled background (no animation)
|
||||
export const BackgroundStill: React.FC = () => {
|
||||
const width = 1080;
|
||||
const height = 1920;
|
||||
|
||||
const iconSize = 80;
|
||||
const gap = 40;
|
||||
const cellSize = iconSize + gap;
|
||||
|
||||
const cols = Math.ceil(width / cellSize) + 4;
|
||||
const rows = Math.ceil(height / cellSize) + 4;
|
||||
|
||||
return (
|
||||
<AbsoluteFill
|
||||
style={{
|
||||
background: "linear-gradient(180deg, #f59e0b 0%, #ef4444 100%)",
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
position: "absolute",
|
||||
top: -cellSize * 2,
|
||||
left: -cellSize * 2,
|
||||
}}
|
||||
>
|
||||
{[...Array(rows)].map((_, row) =>
|
||||
[...Array(cols)].map((_, col) => {
|
||||
const staggerX = row % 2 === 0 ? 0 : cellSize / 2;
|
||||
return (
|
||||
<Img
|
||||
key={`${row}-${col}`}
|
||||
src={staticFile("app-icon.png")}
|
||||
style={{
|
||||
position: "absolute",
|
||||
width: iconSize,
|
||||
height: iconSize,
|
||||
left: col * cellSize + staggerX,
|
||||
top: row * cellSize,
|
||||
opacity: 0.08,
|
||||
borderRadius: iconSize * 0.22,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
})
|
||||
)}
|
||||
</div>
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
280
feels-promo/src/LiveActivityAnimation.tsx
Normal file
@@ -0,0 +1,280 @@
|
||||
import React from "react";
|
||||
import {
|
||||
AbsoluteFill,
|
||||
interpolate,
|
||||
useCurrentFrame,
|
||||
useVideoConfig,
|
||||
spring,
|
||||
Easing,
|
||||
} from "remotion";
|
||||
|
||||
// Mood colors matching the app
|
||||
const MOOD_COLORS = {
|
||||
horrible: "#F44336",
|
||||
bad: "#FF9800",
|
||||
average: "#FFC107",
|
||||
good: "#8BC34A",
|
||||
great: "#4CAF50",
|
||||
};
|
||||
|
||||
// Get mood based on progress
|
||||
const getMoodForProgress = (progress: number): { name: string; color: string } => {
|
||||
if (progress < 0.2) return { name: "Horrible", color: MOOD_COLORS.horrible };
|
||||
if (progress < 0.4) return { name: "Bad", color: MOOD_COLORS.bad };
|
||||
if (progress < 0.6) return { name: "Average", color: MOOD_COLORS.average };
|
||||
if (progress < 0.8) return { name: "Good", color: MOOD_COLORS.good };
|
||||
return { name: "Great", color: MOOD_COLORS.great };
|
||||
};
|
||||
|
||||
// Flame SVG icon
|
||||
const FlameIcon: React.FC<{ size: number; color: string }> = ({ size, color }) => (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 24 24"
|
||||
fill={color}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M12 23C16.1421 23 19.5 19.6421 19.5 15.5C19.5 14.1183 19.1425 12.8052 18.5 11.6447C18.5 11.6447 18 12.5 17 12.5C17 12.5 18 9.5 16 6C14.5 7.5 13.5 8 12.5 8C12.5 8 13.5 5 12 2C10.5 4 9.5 5 8 6.5C6.5 8 5 10 5 12.5C5 12.5 4.5 12 4 11.5C4 11.5 3.5 13 3.5 14.5C3.5 19.1944 7.30558 23 12 23ZM12 20C9.79086 20 8 18.2091 8 16C8 15.3504 8.15822 14.7369 8.43721 14.1967C8.43721 14.1967 9 15 10 15C10 15 9 13 10 11C10.75 11.75 11.25 12 11.75 12C11.75 12 11.25 10.5 12 9C12.75 10 13.25 10.5 14 11.25C14.75 12 15.5 13 15.5 14.5C15.5 14.5 16 14 16.25 13.75C16.25 13.75 16.5 14.5 16.5 15.25C16.5 17.8734 14.5 20 12 20Z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
export const LiveActivityAnimation: React.FC = () => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps, durationInFrames, width, height } = useVideoConfig();
|
||||
|
||||
const targetStreak = 365;
|
||||
|
||||
// Animation timing
|
||||
const animationStartFrame = fps * 1; // Start after 1 second
|
||||
const animationEndFrame = durationInFrames - fps * 1; // End 1 second before end
|
||||
const animationDuration = animationEndFrame - animationStartFrame;
|
||||
|
||||
// Calculate current streak with easing
|
||||
const rawProgress = interpolate(
|
||||
frame,
|
||||
[animationStartFrame, animationEndFrame],
|
||||
[0, 1],
|
||||
{
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.out(Easing.cubic),
|
||||
}
|
||||
);
|
||||
|
||||
const currentStreak = Math.round(rawProgress * targetStreak);
|
||||
const progressPercent = currentStreak / targetStreak;
|
||||
const mood = getMoodForProgress(progressPercent);
|
||||
|
||||
// Spring animation for the flame icon
|
||||
const flameScale = spring({
|
||||
frame: frame % 15, // Pulse every 15 frames
|
||||
fps,
|
||||
config: {
|
||||
damping: 10,
|
||||
stiffness: 200,
|
||||
mass: 0.5,
|
||||
},
|
||||
});
|
||||
|
||||
const flameScaleValue = interpolate(flameScale, [0, 1], [1, 1.1]);
|
||||
|
||||
// Fade in animation
|
||||
const fadeIn = interpolate(frame, [0, fps * 0.5], [0, 1], {
|
||||
extrapolateRight: "clamp",
|
||||
});
|
||||
|
||||
return (
|
||||
<AbsoluteFill
|
||||
style={{
|
||||
backgroundColor: "transparent",
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
fontFamily: "-apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif",
|
||||
opacity: fadeIn,
|
||||
}}
|
||||
>
|
||||
{/* Live Activity Card */}
|
||||
<div
|
||||
style={{
|
||||
width: width * 0.9,
|
||||
backgroundColor: "rgba(44, 44, 46, 0.95)",
|
||||
borderRadius: 24,
|
||||
padding: 24,
|
||||
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 24,
|
||||
}}
|
||||
>
|
||||
{/* Streak Indicator */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<div style={{ transform: `scale(${flameScaleValue})` }}>
|
||||
<FlameIcon size={64} color="#FF9500" />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 56,
|
||||
fontWeight: 700,
|
||||
color: "#FFFFFF",
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
{currentStreak}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
day streak
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div
|
||||
style={{
|
||||
width: 1,
|
||||
height: 100,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.2)",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Status Section */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 12,
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{currentStreak > 0 ? (
|
||||
<>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{/* Mood Color Circle */}
|
||||
<div
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: mood.color,
|
||||
boxShadow: `0 0 20px ${mood.color}80`,
|
||||
}}
|
||||
/>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
Today's mood
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 24,
|
||||
fontWeight: 600,
|
||||
color: "#FFFFFF",
|
||||
}}
|
||||
>
|
||||
{mood.name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
) : (
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 24,
|
||||
fontWeight: 600,
|
||||
color: "#FFFFFF",
|
||||
}}
|
||||
>
|
||||
Start your streak!
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
Tap to log your mood
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar Section */}
|
||||
<div
|
||||
style={{
|
||||
marginTop: 24,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{/* Progress Bar */}
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 12,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
borderRadius: 6,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: `${progressPercent * 100}%`,
|
||||
height: "100%",
|
||||
background: `linear-gradient(90deg, ${MOOD_COLORS.horrible}, ${MOOD_COLORS.bad}, ${MOOD_COLORS.average}, ${MOOD_COLORS.good}, ${MOOD_COLORS.great})`,
|
||||
borderRadius: 6,
|
||||
transition: "width 0.1s ease-out",
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
{/* Progress Label */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
fontSize: 18,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
<span>0</span>
|
||||
<span style={{ color: "#FFFFFF", fontWeight: 600 }}>
|
||||
{currentStreak} / {targetStreak} days
|
||||
</span>
|
||||
<span>{targetStreak}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</AbsoluteFill>
|
||||
);
|
||||
};
|
||||
261
feels-promo/src/LiveActivityCard.tsx
Normal file
@@ -0,0 +1,261 @@
|
||||
import { interpolate, useCurrentFrame, useVideoConfig, spring, Easing } from "remotion";
|
||||
|
||||
// Mood colors matching the app
|
||||
const MOOD_COLORS = {
|
||||
horrible: "#F44336",
|
||||
bad: "#FF9800",
|
||||
average: "#FFC107",
|
||||
good: "#8BC34A",
|
||||
great: "#4CAF50",
|
||||
};
|
||||
|
||||
// Get mood based on progress
|
||||
const getMoodForProgress = (progress: number): { name: string; color: string } => {
|
||||
if (progress < 0.2) return { name: "Horrible", color: MOOD_COLORS.horrible };
|
||||
if (progress < 0.4) return { name: "Bad", color: MOOD_COLORS.bad };
|
||||
if (progress < 0.6) return { name: "Average", color: MOOD_COLORS.average };
|
||||
if (progress < 0.8) return { name: "Good", color: MOOD_COLORS.good };
|
||||
return { name: "Great", color: MOOD_COLORS.great };
|
||||
};
|
||||
|
||||
// Flame SVG icon
|
||||
const FlameIcon: React.FC<{ size: number; color: string }> = ({ size, color }) => (
|
||||
<svg
|
||||
width={size}
|
||||
height={size}
|
||||
viewBox="0 0 24 24"
|
||||
fill={color}
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path d="M12 23C16.1421 23 19.5 19.6421 19.5 15.5C19.5 14.1183 19.1425 12.8052 18.5 11.6447C18.5 11.6447 18 12.5 17 12.5C17 12.5 18 9.5 16 6C14.5 7.5 13.5 8 12.5 8C12.5 8 13.5 5 12 2C10.5 4 9.5 5 8 6.5C6.5 8 5 10 5 12.5C5 12.5 4.5 12 4 11.5C4 11.5 3.5 13 3.5 14.5C3.5 19.1944 7.30558 23 12 23ZM12 20C9.79086 20 8 18.2091 8 16C8 15.3504 8.15822 14.7369 8.43721 14.1967C8.43721 14.1967 9 15 10 15C10 15 9 13 10 11C10.75 11.75 11.25 12 11.75 12C11.75 12 11.25 10.5 12 9C12.75 10 13.25 10.5 14 11.25C14.75 12 15.5 13 15.5 14.5C15.5 14.5 16 14 16.25 13.75C16.25 13.75 16.5 14.5 16.5 15.25C16.5 17.8734 14.5 20 12 20Z" />
|
||||
</svg>
|
||||
);
|
||||
|
||||
interface LiveActivityCardProps {
|
||||
width: number;
|
||||
targetStreak?: number;
|
||||
animationSpeed?: number; // multiplier for animation speed
|
||||
showProgressBar?: boolean;
|
||||
}
|
||||
|
||||
export const LiveActivityCard: React.FC<LiveActivityCardProps> = ({
|
||||
width,
|
||||
targetStreak = 365,
|
||||
animationSpeed = 1,
|
||||
showProgressBar = false,
|
||||
}) => {
|
||||
const frame = useCurrentFrame();
|
||||
const { fps, durationInFrames } = useVideoConfig();
|
||||
|
||||
// Animation timing - use full scene duration
|
||||
const animationStartFrame = Math.round(fps * 0.3); // Start after 0.3 seconds
|
||||
const animationEndFrame = durationInFrames - Math.round(fps * 0.2);
|
||||
|
||||
// Calculate current streak with easing
|
||||
const rawProgress = interpolate(
|
||||
frame * animationSpeed,
|
||||
[animationStartFrame, animationEndFrame],
|
||||
[0, 1],
|
||||
{
|
||||
extrapolateLeft: "clamp",
|
||||
extrapolateRight: "clamp",
|
||||
easing: Easing.out(Easing.cubic),
|
||||
}
|
||||
);
|
||||
|
||||
const currentStreak = Math.round(rawProgress * targetStreak);
|
||||
const progressPercent = currentStreak / targetStreak;
|
||||
const mood = getMoodForProgress(progressPercent);
|
||||
|
||||
// Spring animation for the flame icon
|
||||
const flameScale = spring({
|
||||
frame: frame % 15,
|
||||
fps,
|
||||
config: {
|
||||
damping: 10,
|
||||
stiffness: 200,
|
||||
mass: 0.5,
|
||||
},
|
||||
});
|
||||
|
||||
const flameScaleValue = interpolate(flameScale, [0, 1], [1, 1.1]);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: width,
|
||||
backgroundColor: "rgba(44, 44, 46, 0.95)",
|
||||
borderRadius: 24,
|
||||
padding: 24,
|
||||
boxShadow: "0 8px 32px rgba(0, 0, 0, 0.4)",
|
||||
fontFamily: "-apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 24,
|
||||
}}
|
||||
>
|
||||
{/* Streak Indicator */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
alignItems: "center",
|
||||
gap: 8,
|
||||
}}
|
||||
>
|
||||
<div style={{ transform: `scale(${flameScaleValue})` }}>
|
||||
<FlameIcon size={64} color="#FF9500" />
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 56,
|
||||
fontWeight: 700,
|
||||
color: "#FFFFFF",
|
||||
lineHeight: 1,
|
||||
}}
|
||||
>
|
||||
{currentStreak}
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 18,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
day streak
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Divider */}
|
||||
<div
|
||||
style={{
|
||||
width: 1,
|
||||
height: 100,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.2)",
|
||||
}}
|
||||
/>
|
||||
|
||||
{/* Status Section */}
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 12,
|
||||
flex: 1,
|
||||
}}
|
||||
>
|
||||
{currentStreak > 0 ? (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
{/* Mood Color Circle */}
|
||||
<div
|
||||
style={{
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
backgroundColor: mood.color,
|
||||
boxShadow: `0 0 20px ${mood.color}80`,
|
||||
}}
|
||||
/>
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
Today's mood
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 24,
|
||||
fontWeight: 600,
|
||||
color: "#FFFFFF",
|
||||
}}
|
||||
>
|
||||
{mood.name}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 24,
|
||||
fontWeight: 600,
|
||||
color: "#FFFFFF",
|
||||
}}
|
||||
>
|
||||
Start your streak!
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
fontSize: 16,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
Tap to log your mood
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Progress Bar Section */}
|
||||
{showProgressBar && (
|
||||
<div
|
||||
style={{
|
||||
marginTop: 24,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 12,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: 12,
|
||||
backgroundColor: "rgba(255, 255, 255, 0.1)",
|
||||
borderRadius: 6,
|
||||
overflow: "hidden",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
width: `${progressPercent * 100}%`,
|
||||
height: "100%",
|
||||
background: `linear-gradient(90deg, ${MOOD_COLORS.horrible}, ${MOOD_COLORS.bad}, ${MOOD_COLORS.average}, ${MOOD_COLORS.good}, ${MOOD_COLORS.great})`,
|
||||
borderRadius: 6,
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
justifyContent: "space-between",
|
||||
fontSize: 18,
|
||||
color: "rgba(255, 255, 255, 0.6)",
|
||||
}}
|
||||
>
|
||||
<span>0</span>
|
||||
<span style={{ color: "#FFFFFF", fontWeight: 600 }}>
|
||||
{currentStreak} / {targetStreak} days
|
||||
</span>
|
||||
<span>{targetStreak}</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Composition } from "remotion";
|
||||
import { Composition, Still } from "remotion";
|
||||
import { FeelsPromoV1 } from "./FeelsPromo";
|
||||
import { ConceptASelfAwareness } from "./ConceptA-SelfAwareness";
|
||||
import { ConceptBNoJournalJournal } from "./ConceptB-NoJournalJournal";
|
||||
@@ -13,6 +13,9 @@ import { ConceptIRetroArcade } from "./ConceptI-RetroArcade";
|
||||
import { ConceptJConspiracy } from "./ConceptJ-Conspiracy";
|
||||
import { ConceptKSportsCenter } from "./ConceptK-SportsCenter";
|
||||
import { ConceptLMusical } from "./ConceptL-Musical";
|
||||
// Utility animations
|
||||
import { LiveActivityAnimation } from "./LiveActivityAnimation";
|
||||
import { BackgroundStill } from "./BackgroundStill";
|
||||
|
||||
export const RemotionRoot: React.FC = () => {
|
||||
const fps = 30;
|
||||
@@ -52,11 +55,11 @@ export const RemotionRoot: React.FC = () => {
|
||||
height={1920}
|
||||
/>
|
||||
|
||||
{/* Concept B: The No-Journal Journal (20s) */}
|
||||
{/* Concept B: The No-Journal Journal (15s) */}
|
||||
<Composition
|
||||
id="ConceptB-NoJournalJournal"
|
||||
component={ConceptBNoJournalJournal}
|
||||
durationInFrames={Math.round(20 * fps)}
|
||||
durationInFrames={Math.round(15 * fps)}
|
||||
fps={fps}
|
||||
width={1080}
|
||||
height={1920}
|
||||
@@ -102,11 +105,11 @@ export const RemotionRoot: React.FC = () => {
|
||||
height={1920}
|
||||
/>
|
||||
|
||||
{/* Concept G: The Streak Effect (20s) */}
|
||||
{/* Concept G: The Streak Effect (12s) */}
|
||||
<Composition
|
||||
id="ConceptG-StreakEffect"
|
||||
component={ConceptGStreakEffect}
|
||||
durationInFrames={Math.round(20 * fps)}
|
||||
durationInFrames={Math.round(12 * fps)}
|
||||
fps={fps}
|
||||
width={1080}
|
||||
height={1920}
|
||||
@@ -165,6 +168,28 @@ export const RemotionRoot: React.FC = () => {
|
||||
width={1080}
|
||||
height={1920}
|
||||
/>
|
||||
|
||||
{/* ═══════════════════════════════════════════════════════════════
|
||||
UTILITY ANIMATIONS
|
||||
═══════════════════════════════════════════════════════════════ */}
|
||||
|
||||
{/* Live Activity Preview - Streak 0 to 365 animation (12s) */}
|
||||
<Composition
|
||||
id="LiveActivityAnimation"
|
||||
component={LiveActivityAnimation}
|
||||
durationInFrames={Math.round(12 * fps)}
|
||||
fps={fps}
|
||||
width={1080}
|
||||
height={1920}
|
||||
/>
|
||||
|
||||
{/* Background Still for export */}
|
||||
<Still
|
||||
id="BackgroundStill"
|
||||
component={BackgroundStill}
|
||||
width={1080}
|
||||
height={1920}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
BIN
screens/ai_dark.png
Normal file
|
After Width: | Height: | Size: 391 KiB |
BIN
screens/aj_light.png
Normal file
|
After Width: | Height: | Size: 378 KiB |
BIN
screens/insights_dark.png
Normal file
|
After Width: | Height: | Size: 338 KiB |
BIN
screens/insights_light.png
Normal file
|
After Width: | Height: | Size: 369 KiB |
BIN
screens/timeline_dark_large_voting.png
Normal file
|
After Width: | Height: | Size: 162 KiB |
BIN
screens/timeline_dark_medium_voting.png
Normal file
|
After Width: | Height: | Size: 72 KiB |
BIN
screens/timeline_light_large_voting.png
Normal file
|
After Width: | Height: | Size: 163 KiB |
BIN
screens/timeline_light_medium_voting.png
Normal file
|
After Width: | Height: | Size: 122 KiB |
BIN
screens/voting_dark_large.png
Normal file
|
After Width: | Height: | Size: 131 KiB |
BIN
screens/voting_header.png
Normal file
|
After Width: | Height: | Size: 67 KiB |
BIN
screens/voting_light_large.png
Normal file
|
After Width: | Height: | Size: 132 KiB |
BIN
screens/voting_light_medium.png
Normal file
|
After Width: | Height: | Size: 73 KiB |
BIN
screens/voting_light_small.png
Normal file
|
After Width: | Height: | Size: 68 KiB |
BIN
screens/watch.png
Normal file
|
After Width: | Height: | Size: 428 KiB |
BIN
screens/watch_voting_light.png
Normal file
|
After Width: | Height: | Size: 76 KiB |