index.tsx 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. import React from "react";
  2. import {
  3. useCurrentFrame,
  4. useVideoConfig,
  5. AbsoluteFill,
  6. interpolate,
  7. Easing,
  8. } from "remotion";
  9. import type { RemotionScene } from "../Root";
  10. import { THEMES } from "../base/theme/colors";
  11. import { Background } from "../base/components/background";
  12. import { SubtitleBar } from "../base/components/subtitle-bar";
  13. import { AnimatedText } from "../base/components/animated-text";
  14. import { Watermark } from "../base/components/watermark";
  15. import { StepIndicator } from "./components/step-indicator";
  16. import { KeyPointCard } from "./components/key-point-card";
  17. interface KnowledgeSceneProps {
  18. scene: RemotionScene;
  19. sceneIndex: number;
  20. totalScenes: number;
  21. totalFrames: number;
  22. title: string;
  23. channelName?: string;
  24. }
  25. const KnowledgeScene: React.FC<KnowledgeSceneProps> = ({
  26. scene,
  27. sceneIndex,
  28. totalScenes,
  29. totalFrames,
  30. title,
  31. channelName,
  32. }) => {
  33. const frame = useCurrentFrame();
  34. const colors = THEMES.knowledge;
  35. const visualText = scene.displayText ?? scene.narration;
  36. const fadeOpacity = interpolate(
  37. frame,
  38. [0, 10, scene.endFrame - scene.startFrame - 10, scene.endFrame - scene.startFrame],
  39. [0, 1, 1, 0],
  40. { extrapolateLeft: "clamp", extrapolateRight: "clamp" }
  41. );
  42. return (
  43. <AbsoluteFill style={{ opacity: fadeOpacity }}>
  44. <Background
  45. colors={colors}
  46. sceneIndex={sceneIndex}
  47. totalScenes={totalScenes}
  48. />
  49. {/* Step indicator */}
  50. <div
  51. style={{
  52. position: "absolute",
  53. top: 48,
  54. left: 80,
  55. }}
  56. >
  57. <StepIndicator
  58. currentStep={sceneIndex}
  59. totalSteps={totalScenes}
  60. color={colors.primaryLight}
  61. />
  62. </div>
  63. {/* Title label */}
  64. <div
  65. style={{
  66. position: "absolute",
  67. top: 48,
  68. right: 80,
  69. fontSize: 18,
  70. color: "#94a3b8",
  71. fontFamily: "Noto Sans SC",
  72. }}
  73. >
  74. {title}
  75. </div>
  76. {/* Content */}
  77. <div
  78. style={{
  79. position: "absolute",
  80. top: 120,
  81. left: 80,
  82. right: 80,
  83. bottom: 160,
  84. display: "flex",
  85. flexDirection: "column",
  86. justifyContent: "center",
  87. gap: 32,
  88. overflow: "hidden",
  89. }}
  90. >
  91. <AnimatedText
  92. text={visualText}
  93. fontSize={44}
  94. color="white"
  95. fontWeight={600}
  96. delay={5}
  97. />
  98. {scene.keyframes.length > 0 && (
  99. <KeyPointCard
  100. points={scene.keyframes
  101. .filter((kf) => kf.type === "text" || kf.type === "highlight")
  102. .map((kf) => kf.content)}
  103. color={colors.primaryLight}
  104. />
  105. )}
  106. </div>
  107. {scene.wordTimestamps.length > 0 && (
  108. <SubtitleBar wordTimestamps={scene.wordTimestamps} />
  109. )}
  110. <Watermark text={channelName} />
  111. </AbsoluteFill>
  112. );
  113. };
  114. export default KnowledgeScene;