@@ -7,10 +7,10 @@ import {
77 DownloadOutlined ,
88 ExpandOutlined ,
99 ExportOutlined ,
10+ FontSizeOutlined ,
1011 LoadingOutlined ,
1112 PauseOutlined ,
1213 ThunderboltOutlined ,
13- VideoCameraOutlined ,
1414} from '@ant-design/icons' ;
1515import { Player as RemotionPlayer } from '@remotion/player' ;
1616import type {
@@ -74,8 +74,8 @@ export function Player(props?: {
7474 setAutoZoom,
7575 playbackSpeed,
7676 setPlaybackSpeed,
77- effectsEnabled ,
78- setEffectsEnabled ,
77+ subtitleEnabled ,
78+ setSubtitleEnabled ,
7979 } = useGlobalPreference ( ) ;
8080
8181 useEffect ( ( ) => {
@@ -88,11 +88,8 @@ export function Player(props?: {
8888 const deviceType = props ?. deviceType ;
8989 const frameMap = useMemo < FrameMap | null > ( ( ) => {
9090 if ( ! scripts || scripts . length === 0 ) return null ;
91- return calculateFrameMap ( scripts , {
92- effects : effectsEnabled ,
93- deviceType,
94- } ) ;
95- } , [ scripts , effectsEnabled , deviceType ] ) ;
91+ return calculateFrameMap ( scripts , { deviceType } ) ;
92+ } , [ scripts , deviceType ] ) ;
9693
9794 const playerRef = useRef < PlayerRef > ( null ) ;
9895 const lastTaskIdRef = useRef < string | null > ( null ) ;
@@ -192,11 +189,7 @@ export function Player(props?: {
192189 const player = playerRef . current ;
193190 if ( ! player ) return ;
194191 const frame = player . getCurrentFrame ( ) ?? 0 ;
195- const stepsFrame = frame - frameMap . openingDurationInFrames ;
196- const taskId =
197- stepsFrame >= 0
198- ? deriveTaskId ( frameMap . scriptFrames , stepsFrame )
199- : null ;
192+ const taskId = deriveTaskId ( frameMap . scriptFrames , frame ) ;
200193 if ( taskId !== lastTaskIdRef . current ) {
201194 lastTaskIdRef . current = taskId ;
202195 props . onTaskChange ! ( taskId ) ;
@@ -214,7 +207,7 @@ export function Player(props?: {
214207 setIsExporting ( true ) ;
215208 setExportProgress ( 0 ) ;
216209 try {
217- await exportBrandedVideo ( frameMap , effectsEnabled , ( pct ) =>
210+ await exportBrandedVideo ( frameMap , ( pct ) =>
218211 setExportProgress ( Math . round ( pct * 100 ) ) ,
219212 ) ;
220213 message . success ( 'Video exported' ) ;
@@ -225,30 +218,29 @@ export function Player(props?: {
225218 setIsExporting ( false ) ;
226219 setExportProgress ( 0 ) ;
227220 }
228- } , [ frameMap , effectsEnabled , isExporting ] ) ;
229-
230- const [ mouseOverSettingsIcon , setMouseOverSettingsIcon ] = useState ( false ) ;
221+ } , [ frameMap , isExporting ] ) ;
231222
232223 const renderPlayPauseButton : RenderPlayPauseButton = useCallback (
233- ( { playing, isBuffering } ) => {
234- if ( isBuffering )
235- return < LoadingOutlined spin style = { { color : '#fff' } } /> ;
236- return playing ? (
237- < PauseOutlined style = { { color : '#fff' } } />
238- ) : (
239- < CaretRightOutlined style = { { color : '#fff' } } />
240- ) ;
241- } ,
224+ ( { playing, isBuffering } ) => (
225+ < div className = "status-icon" >
226+ { isBuffering ? (
227+ < LoadingOutlined spin />
228+ ) : playing ? (
229+ < PauseOutlined />
230+ ) : (
231+ < CaretRightOutlined />
232+ ) }
233+ </ div >
234+ ) ,
242235 [ ] ,
243236 ) ;
244237
245238 const renderFullscreenButton : RenderFullscreenButton = useCallback (
246- ( { isFullscreen } ) =>
247- isFullscreen ? (
248- < CompressOutlined style = { { color : '#fff' } } />
249- ) : (
250- < ExpandOutlined style = { { color : '#fff' } } />
251- ) ,
239+ ( { isFullscreen } ) => (
240+ < div className = "status-icon" >
241+ { isFullscreen ? < CompressOutlined /> : < ExpandOutlined /> }
242+ </ div >
243+ ) ,
252244 [ ] ,
253245 ) ;
254246
@@ -334,6 +326,37 @@ export function Player(props?: {
334326 />
335327 </ div >
336328
329+ { /* Subtitle toggle */ }
330+ < div
331+ className = "player-settings-item"
332+ style = { {
333+ display : 'flex' ,
334+ alignItems : 'center' ,
335+ justifyContent : 'space-between' ,
336+ height : '32px' ,
337+ padding : '0 8px' ,
338+ borderRadius : '4px' ,
339+ } }
340+ >
341+ < div
342+ style = { {
343+ display : 'flex' ,
344+ alignItems : 'center' ,
345+ gap : '4px' ,
346+ } }
347+ >
348+ < FontSizeOutlined style = { { width : '16px' , height : '16px' } } />
349+ < span style = { { fontSize : '12px' , marginRight : '16px' } } >
350+ Subtitle
351+ </ span >
352+ </ div >
353+ < Switch
354+ size = "small"
355+ checked = { subtitleEnabled }
356+ onChange = { ( checked ) => setSubtitleEnabled ( checked ) }
357+ />
358+ </ div >
359+
337360 < div className = "player-settings-divider" />
338361
339362 { /* Playback speed */ }
@@ -368,54 +391,11 @@ export function Player(props?: {
368391 { speed } x
369392 </ div >
370393 ) ) }
371-
372- < div className = "player-settings-divider" />
373-
374- { /* Effects toggle */ }
375- < div
376- className = "player-settings-item"
377- style = { {
378- display : 'flex' ,
379- alignItems : 'center' ,
380- justifyContent : 'space-between' ,
381- height : '32px' ,
382- padding : '0 8px' ,
383- borderRadius : '4px' ,
384- } }
385- >
386- < div
387- style = { {
388- display : 'flex' ,
389- alignItems : 'center' ,
390- gap : '4px' ,
391- } }
392- >
393- < VideoCameraOutlined
394- style = { { width : '16px' , height : '16px' } }
395- />
396- < span style = { { fontSize : '12px' , marginRight : '16px' } } >
397- Effects
398- </ span >
399- </ div >
400- < Switch
401- size = "small"
402- checked = { effectsEnabled }
403- onChange = { ( checked ) => setEffectsEnabled ( checked ) }
404- />
405- </ div >
406394 </ div >
407395 ) }
408396 menu = { { items : [ ] } }
409397 >
410- < div
411- className = "status-icon"
412- onMouseEnter = { ( ) => setMouseOverSettingsIcon ( true ) }
413- onMouseLeave = { ( ) => setMouseOverSettingsIcon ( false ) }
414- style = { {
415- opacity : mouseOverSettingsIcon ? 1 : 0.7 ,
416- transition : 'opacity 0.2s' ,
417- } }
418- >
398+ < div className = "status-icon" >
419399 < PlayerSettingIcon style = { { width : '16px' , height : '16px' } } />
420400 </ div >
421401 </ Dropdown >
@@ -431,16 +411,14 @@ export function Player(props?: {
431411 setAutoZoom ,
432412 playbackSpeed ,
433413 setPlaybackSpeed ,
434- effectsEnabled ,
435- setEffectsEnabled ,
436- mouseOverSettingsIcon ,
414+ subtitleEnabled ,
415+ setSubtitleEnabled ,
437416 ] ) ;
438417
439418 // Compute chapter markers from step boundaries (each img/insight = new chapter)
440419 const chapterMarkers = useMemo ( ( ) => {
441420 if ( ! frameMap ) return [ ] ;
442- const { scriptFrames, totalDurationInFrames, openingDurationInFrames } =
443- frameMap ;
421+ const { scriptFrames, totalDurationInFrames } = frameMap ;
444422 if ( totalDurationInFrames === 0 ) return [ ] ;
445423
446424 const markers : { percent : number ; title : string ; frame : number } [ ] = [ ] ;
@@ -450,7 +428,7 @@ export function Player(props?: {
450428 sf . durationInFrames === 0
451429 )
452430 continue ;
453- const globalFrame = openingDurationInFrames + sf . startFrame ;
431+ const globalFrame = sf . startFrame ;
454432 const percent = ( globalFrame / totalDurationInFrames ) * 100 ;
455433 if ( percent > 1 && percent < 99 ) {
456434 const parts = [ sf . title , sf . subTitle ] . filter ( Boolean ) ;
@@ -498,8 +476,8 @@ export function Player(props?: {
498476 component = { Composition }
499477 inputProps = { {
500478 frameMap,
501- effects : effectsEnabled ,
502479 autoZoom,
480+ subtitleEnabled,
503481 } }
504482 durationInFrames = { Math . max ( frameMap . totalDurationInFrames , 1 ) }
505483 compositionWidth = { compositionWidth }
0 commit comments