Created
January 30, 2026 17:08
-
-
Save JonnyBurger/0e804eefbb8f096a71df6d8b5a7feb2e to your computer and use it in GitHub Desktop.
Claude Code Lower Third prompt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| ❯ use remotion best practices. this is our youtube channel: https://www.youtube.com/@remotion_dev. use curl scrape youtube to find the avatar and the subscriber count. multiple subscriber | |
| counts appear on the page, find the right one. make a white lower third that slides in from the bottom center. show the name, subscriber count and avatar. display a typical fixed width | |
| black youtube subscribe button that changes from "Subscribe" to "Subscribed". use a ease-out animation and for pressing in the button and a spring animation with a slight bounce once the | |
| button is released. fade out the lower third. render it as a transparent prores video. | |
| ⏺ Skill(remotion-best-practices) | |
| ⎿ Successfully loaded skill | |
| ⏺ Bash(curl -s 'https://www.youtube.com/@remotion_dev' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' -H 'Accept-Language: en-US,e…) | |
| ⎿ grep: invalid option -- P | |
| usage: grep [-abcdDEFGHhIiJLlMmnOopqRSsUVvwXxZz] [-A num] [-B num] [-C[num]] | |
| [-e pattern] [-f file] [--binary-files=value] [--color=when] | |
| … +2 lines (ctrl+o to expand) | |
| ⏺ Bash(curl -s 'https://www.youtube.com/@remotion_dev' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' -H 'Accept-Language: en-US,e…) | |
| ⎿ grep: invalid option -- P | |
| usage: grep [-abcdDEFGHhIiJLlMmnOopqRSsUVvwXxZz] [-A num] [-B num] [-C[num]] | |
| [-e pattern] [-f file] [--binary-files=value] [--color=when] | |
| … +2 lines (ctrl+o to expand) | |
| ⏺ Searched for 1 pattern (ctrl+o to expand) | |
| ⏺ Let me scrape YouTube properly and read the relevant skill files. | |
| ⏺ Bash(curl -s 'https://www.youtube.com/@remotion_dev' -H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36' -H 'Accept-Language: en-US,e…) | |
| ⎿ (No content) | |
| ⏺ Bash(cd /private/tmp/claude-501/-Users-jonathanburger-lower-third/12024f83-f9c6-44a3-ad9d-583e9ce5f156/scratchpad && python3 -c " | |
| import re, json…) | |
| ⎿ Subscriber counts: [] | |
| Avatar: {"url":"https://yt3.googleusercontent.com/U1odzKpyZw7s4kcP0O1LwLXqmvoho1jqVxZ7EABsT8IRIEuzTF4Vwu-cdq3387GmzmQq9Fxhi4c=s900-c-k-c0x00ffffff-no-rj","width":900,"height":900} | |
| Channel name: [] | |
| ⎿ Shell cwd was reset to /Users/jonathanburger/lower-third | |
| ⏺ Read 5 files (ctrl+o to expand) | |
| ⏺ Now let me get the subscriber count text properly and the channel name. | |
| ⏺ Bash(cd /private/tmp/claude-501/-Users-jonathanburger-lower-third/12024f83-f9c6-44a3-ad9d-583e9ce5f156/scratchpad && python3 -c " | |
| import re…) | |
| ⎿ Sub text: [] | |
| Sub accessible: [] | |
| Titles: ['Home', 'Videos', 'Shorts', 'Playlists', 'Posts'] | |
| ⎿ Shell cwd was reset to /Users/jonathanburger/lower-third | |
| ⏺ Read 1 file (ctrl+o to expand) | |
| ⏺ Bash(cd /private/tmp/claude-501/-Users-jonathanburger-lower-third/12024f83-f9c6-44a3-ad9d-583e9ce5f156/scratchpad && python3 -c " | |
| import re…) | |
| ⎿ r":4279440147},{"weightLabel":"FONT_WEIGHT_BOLD"}]},"subtitle":{"content":"@JonnyBurger • 4.11K subscribers"},"trailingImage":{"sources":[{"clientResource":{"imageName":"yt-sys-icons: | |
| chevron_righ | |
| --- | |
| href="https://m.youtube.com/@remotion_dev"><title>Remotion - YouTube</title><meta name="description" content="Make videos programmatically."><meta nam | |
| ⎿ Shell cwd was reset to /Users/jonathanburger/lower-third | |
| ⏺ I see the data but it's showing a different channel reference. Let me find the main channel subscriber count. | |
| ⏺ Bash(cd /private/tmp/claude-501/-Users-jonathanburger-lower-third/12024f83-f9c6-44a3-ad9d-583e9ce5f156/scratchpad && python3 -c " | |
| import re…) | |
| ⎿ '4.11K subscribers' | |
| Remotion nearby: False | |
| … +11 lines (ctrl+o to expand) | |
| ⎿ Shell cwd was reset to /Users/jonathanburger/lower-third | |
| ⏺ The Remotion channel has 2.26K subscribers. Avatar URL was already found. Now let me build everything. | |
| ⏺ Read 2 files (ctrl+o to expand) | |
| ⏺ Now let me write the composition and root files. | |
| ⏺ Write(src/Composition.tsx) | |
| ⎿ Added 159 lines, removed 1 line | |
| 1 +import { | |
| 2 + AbsoluteFill, | |
| 3 + Img, | |
| 4 + interpolate, | |
| 5 + spring, | |
| 6 + useCurrentFrame, | |
| 7 + useVideoConfig, | |
| 8 + Easing, | |
| 9 +} from "remotion"; | |
| 10 + | |
| 11 +const AVATAR_URL = | |
| 12 + "https://yt3.googleusercontent.com/U1odzKpyZw7s4kcP0O1LwLXqmvoho1jqVxZ7EABsT8IRIEuzTF4Vwu-cdq3387GmzmQq9Fxhi4c=s900-c-k-c0x00ffffff-no-rj"; | |
| 13 +const CHANNEL_NAME = "Remotion"; | |
| 14 +const SUBSCRIBER_COUNT = "2.26K subscribers"; | |
| 15 + | |
| 16 +const SUBSCRIBE_PRESS_FRAME = 45; // 1.5s in | |
| 17 +const CARD_PADDING = 20; | |
| 18 + | |
| 19 export const MyComposition = () => { | |
| 2 - return null; | |
| 20 + const frame = useCurrentFrame(); | |
| 21 + const { fps, durationInFrames } = useVideoConfig(); | |
| 22 + | |
| 23 + // Slide in from bottom (ease-out) | |
| 24 + const slideIn = interpolate(frame, [0, 0.5 * fps], [200, 0], { | |
| 25 + extrapolateRight: "clamp", | |
| 26 + extrapolateLeft: "clamp", | |
| 27 + easing: Easing.out(Easing.quad), | |
| 28 + }); | |
| 29 + | |
| 30 + // Fade out near the end | |
| 31 + const fadeOut = interpolate( | |
| 32 + frame, | |
| 33 + [durationInFrames - 0.5 * fps, durationInFrames], | |
| 34 + [1, 0], | |
| 35 + { | |
| 36 + extrapolateRight: "clamp", | |
| 37 + extrapolateLeft: "clamp", | |
| 38 + }, | |
| 39 + ); | |
| 40 + | |
| 41 + // Subscribe button press animation | |
| 42 + // Ease-out for pressing in | |
| 43 + const pressIn = interpolate( | |
| 44 + frame, | |
| 45 + [SUBSCRIBE_PRESS_FRAME, SUBSCRIBE_PRESS_FRAME + 4], | |
| 46 + [1, 0.92], | |
| 47 + { | |
| 48 + extrapolateRight: "clamp", | |
| 49 + extrapolateLeft: "clamp", | |
| 50 + easing: Easing.out(Easing.quad), | |
| 51 + }, | |
| 52 + ); | |
| 53 + | |
| 54 + // Spring bounce back on release | |
| 55 + const releaseSpring = spring({ | |
| 56 + frame: frame - (SUBSCRIBE_PRESS_FRAME + 4), | |
| 57 + fps, | |
| 58 + config: { damping: 8, stiffness: 200 }, | |
| 59 + }); | |
| 60 + | |
| 61 + const pressOut = interpolate(releaseSpring, [0, 1], [0.92, 1]); | |
| 62 + | |
| 63 + const buttonScale = | |
| 64 + frame < SUBSCRIBE_PRESS_FRAME | |
| 65 + ? 1 | |
| 66 + : frame < SUBSCRIBE_PRESS_FRAME + 4 | |
| 67 + ? pressIn | |
| 68 + : pressOut; | |
| 69 + | |
| 70 + const isSubscribed = frame >= SUBSCRIBE_PRESS_FRAME + 4; | |
| 71 + | |
| 72 + return ( | |
| 73 + <AbsoluteFill> | |
| 74 + <div | |
| 75 + style={{ | |
| 76 + position: "absolute", | |
| 77 + bottom: 60, | |
| 78 + left: "50%", | |
| 79 + transform: `translateX(-50%) translateY(${slideIn}px)`, | |
| 80 + opacity: fadeOut, | |
| 81 + display: "flex", | |
| 82 + alignItems: "center", | |
| 83 + gap: 16, | |
| 84 + backgroundColor: "white", | |
| 85 + borderRadius: 12, | |
| 86 + padding: CARD_PADDING, | |
| 87 + boxShadow: "0 4px 24px rgba(0,0,0,0.12)", | |
| 88 + }} | |
| 89 + > | |
| 90 + {/* Avatar */} | |
| 91 + <Img | |
| 92 + src={AVATAR_URL} | |
| 93 + style={{ | |
| 94 + width: 56, | |
| 95 + height: 56, | |
| 96 + borderRadius: "50%", | |
| 97 + }} | |
| 98 + /> | |
| 99 + | |
| 100 + {/* Name and subscribers */} | |
| 101 + <div | |
| 102 + style={{ | |
| 103 + display: "flex", | |
| 104 + flexDirection: "column", | |
| 105 + gap: 2, | |
| 106 + marginRight: 16, | |
| 107 + }} | |
| 108 + > | |
| 109 + <span | |
| 110 + style={{ | |
| 111 + fontSize: 18, | |
| 112 + fontWeight: 600, | |
| 113 + fontFamily: "sans-serif", | |
| 114 + color: "#0f0f0f", | |
| 115 + whiteSpace: "nowrap", | |
| 116 + }} | |
| 117 + > | |
| 118 + {CHANNEL_NAME} | |
| 119 + </span> | |
| 120 + <span | |
| 121 + style={{ | |
| 122 + fontSize: 13, | |
| 123 + fontFamily: "sans-serif", | |
| 124 + color: "#606060", | |
| 125 + whiteSpace: "nowrap", | |
| 126 + }} | |
| 127 + > | |
| 128 + {SUBSCRIBER_COUNT} | |
| 129 + </span> | |
| 130 + </div> | |
| 131 + | |
| 132 + {/* Subscribe button */} | |
| 133 + <div | |
| 134 + style={{ | |
| 135 + transform: `scale(${buttonScale})`, | |
| 136 + width: 110, | |
| 137 + height: 36, | |
| 138 + borderRadius: 18, | |
| 139 + backgroundColor: isSubscribed ? "#f2f2f2" : "#0f0f0f", | |
| 140 + display: "flex", | |
| 141 + alignItems: "center", | |
| 142 + justifyContent: "center", | |
| 143 + cursor: "pointer", | |
| 144 + }} | |
| 145 + > | |
| 146 + <span | |
| 147 + style={{ | |
| 148 + fontSize: 14, | |
| 149 + fontWeight: 500, | |
| 150 + fontFamily: "sans-serif", | |
| 151 + color: isSubscribed ? "#0f0f0f" : "white", | |
| 152 + whiteSpace: "nowrap", | |
| 153 + }} | |
| 154 + > | |
| 155 + {isSubscribed ? "Subscribed" : "Subscribe"} | |
| 156 + </span> | |
| 157 + </div> | |
| 158 + </div> | |
| 159 + </AbsoluteFill> | |
| 160 + ); | |
| 161 }; | |
| ⏺ Now update Root.tsx to configure for transparent ProRes and extend the duration. | |
| ⏺ Write(src/Root.tsx) | |
| ⎿ Added 16 lines, removed 3 lines | |
| 1 import "./index.css"; | |
| 2 import { Composition } from "remotion"; | |
| 3 import { MyComposition } from "./Composition"; | |
| 4 +import type { CalculateMetadataFunction } from "remotion"; | |
| 5 | |
| 6 +const calculateMetadata: CalculateMetadataFunction< | |
| 7 + Record<string, unknown> | |
| 8 +> = async () => { | |
| 9 + return { | |
| 10 + defaultCodec: "prores", | |
| 11 + defaultVideoImageFormat: "png", | |
| 12 + defaultPixelFormat: "yuva444p10le", | |
| 13 + defaultProResProfile: "4444", | |
| 14 + }; | |
| 15 +}; | |
| 16 + | |
| 17 export const RemotionRoot: React.FC = () => { | |
| 18 return ( | |
| 19 <> | |
| 20 <Composition | |
| 21 id="MyComp" | |
| 22 component={MyComposition} | |
| 11 - durationInFrames={60} | |
| 23 + durationInFrames={120} | |
| 24 fps={30} | |
| 13 - width={1280} | |
| 14 - height={720} | |
| 25 + width={1920} | |
| 26 + height={1080} | |
| 27 + calculateMetadata={calculateMetadata} | |
| 28 /> | |
| 29 </> | |
| 30 ); | |
| ⏺ Now let me render it. | |
| ⏺ Bash(npx remotion render --image-format=png --pixel-format=yuva444p10le --codec=prores --prores-profile=4444 MyComp out/lower-third.mov 2>&1) | |
| ⎿ Bundling 6% | |
| Bundling 19% | |
| Bundling 58% | |
| … +140 lines (ctrl+o to expand) | |
| ⎿ (timeout 5m) | |
| ⏺ Done. Here's what was built: | |
| Scraped from YouTube (@remotion_dev): | |
| - Avatar: YouTube profile image (900x900) | |
| - Subscriber count: 2.26K subscribers | |
| - Channel name: Remotion | |
| Animation timeline (4 seconds at 30fps, 120 frames): | |
| 1. Frames 0-15: White card slides up from bottom center with Easing.out(Easing.quad) | |
| 2. Frame 45-49: Subscribe button scales down to 0.92 with ease-out (press effect) | |
| 3. Frame 49+: Spring bounce back (damping: 8, stiffness: 200) — button releases with slight bounce, text changes from "Subscribe" to "Subscribed" (black bg to gray bg) | |
| 4. Final 15 frames: Fade out opacity to 0 | |
| Output: out/lower-third.mov — 7.5 MB transparent ProRes 4444 (yuva444p10le, png image format) ready for import into video editing software. | |
| ✻ Cogitated for 1m 41s |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment