mirror of
https://github.com/R0m1k3/Socialflow.git
synced 2026-10-23 23:18:12 +02:00
feat: show 3 words at a time in text overlay (TikTok style)
Groups word timings by chunks of 3. The active word is highlighted in yellow/scaled; the 2 surrounding words show in white. Gives enough reading time while staying in sync with the voice. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
1 parent
4072f8954f
commit
36fe05c04b
1 file changed
+46
-40
@@ -120,47 +120,53 @@ export const ImageComposition = ({
|
|||||||
{/* Background music */}
|
{/* Background music */}
|
||||||
{musicUrl && <Html5Audio src={musicUrl} volume={musicVolume} />}
|
{musicUrl && <Html5Audio src={musicUrl} volume={musicVolume} />}
|
||||||
|
|
||||||
{/* TikTok-style word-by-word text overlay (content section only) */}
|
{/* TikTok-style 3-words-at-a-time overlay (content section only) */}
|
||||||
{frame < endingStart && (
|
{frame < endingStart && (
|
||||||
wordTimings && wordTimings.length > 0 ? (
|
wordTimings && wordTimings.length > 0 && activeWordIdx >= 0 ? (() => {
|
||||||
<AbsoluteFill style={{ justifyContent: "flex-end", alignItems: "center", paddingBottom: 160 }}>
|
// Group index: which chunk of 3 is currently active
|
||||||
<div
|
const groupIdx = Math.floor(activeWordIdx / 3);
|
||||||
style={{
|
const groupStart = groupIdx * 3;
|
||||||
maxWidth: "88%",
|
const groupWords = wordTimings.slice(groupStart, groupStart + 3);
|
||||||
textAlign: "center",
|
return (
|
||||||
display: "flex",
|
<AbsoluteFill style={{ justifyContent: "flex-end", alignItems: "center", paddingBottom: 160 }}>
|
||||||
flexWrap: "wrap",
|
<div
|
||||||
justifyContent: "center",
|
style={{
|
||||||
gap: "0 14px",
|
maxWidth: "88%",
|
||||||
alignItems: "baseline",
|
textAlign: "center",
|
||||||
filter: "drop-shadow(0 2px 12px rgba(0,0,0,0.7))",
|
display: "flex",
|
||||||
}}
|
flexWrap: "wrap",
|
||||||
>
|
justifyContent: "center",
|
||||||
{wordTimings.map((w, i) => {
|
gap: "0 18px",
|
||||||
const isActive = i === activeWordIdx;
|
alignItems: "baseline",
|
||||||
if (!isActive) return null;
|
filter: "drop-shadow(0 2px 12px rgba(0,0,0,0.7))",
|
||||||
return (
|
}}
|
||||||
<span
|
>
|
||||||
key={i}
|
{groupWords.map((w, gi) => {
|
||||||
style={{
|
const isActive = groupStart + gi === activeWordIdx;
|
||||||
color: "#FFE600",
|
return (
|
||||||
fontFamily: "'Arial Black', 'Impact', sans-serif",
|
<span
|
||||||
fontSize: 80,
|
key={groupStart + gi}
|
||||||
fontWeight: 900,
|
style={{
|
||||||
lineHeight: 1.2,
|
color: isActive ? "#FFE600" : "white",
|
||||||
WebkitTextStroke: "3px rgba(0,0,0,0.8)",
|
fontFamily: "'Arial Black', 'Impact', sans-serif",
|
||||||
textShadow: "0 4px 20px rgba(0,0,0,0.9)",
|
fontSize: 76,
|
||||||
display: "inline-block",
|
fontWeight: 900,
|
||||||
textTransform: "uppercase",
|
lineHeight: 1.2,
|
||||||
}}
|
WebkitTextStroke: isActive ? "3px rgba(0,0,0,0.8)" : "2px rgba(0,0,0,0.7)",
|
||||||
>
|
textShadow: "0 4px 20px rgba(0,0,0,0.9)",
|
||||||
{w.word}
|
display: "inline-block",
|
||||||
</span>
|
textTransform: "uppercase",
|
||||||
);
|
transform: isActive ? "scale(1.08)" : "scale(1)",
|
||||||
})}
|
}}
|
||||||
</div>
|
>
|
||||||
</AbsoluteFill>
|
{w.word}
|
||||||
) : overlayText ? (
|
</span>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</AbsoluteFill>
|
||||||
|
);
|
||||||
|
})() : overlayText ? (
|
||||||
<AbsoluteFill style={{ justifyContent: "flex-end", alignItems: "center", paddingBottom: 160 }}>
|
<AbsoluteFill style={{ justifyContent: "flex-end", alignItems: "center", paddingBottom: 160 }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|||||||
Reference in new issue
Block a user