Skip to content

Commit 53fb434

Browse files
committed
refactor(player): remove effects system and add subtitle toggle
- Remove all cyberpunk visual effects (opening/ending scenes, glitch, ripple, cursor trail, scanlines, HUD corners, 3D transforms) - Delete OpeningScene, EndingScene, ProgressBar, CyberOverlays components - Simplify frame-calculator, StepScene, export-branded-video - Replace effectsEnabled store state with subtitleEnabled toggle - Add subtitle visibility toggle to player settings panel - Unify control bar button styles (play/pause, fullscreen, settings) - Improve sidebar icon-button hover effect to match theme toggle
1 parent d3e905c commit 53fb434

File tree

13 files changed

+227
-2978
lines changed

13 files changed

+227
-2978
lines changed

apps/report/src/components/sidebar/index.less

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,13 @@
3737
cursor: pointer;
3838
display: flex;
3939
align-items: center;
40+
justify-content: center;
41+
padding: 6px;
42+
border-radius: 8px;
43+
transition: all 0.2s;
4044

4145
&:hover {
42-
background: #f5f5f5;
46+
background: #e6e8eb;
4347
}
4448
}
4549
}
@@ -448,7 +452,7 @@
448452
.page-nav-left {
449453
.page-nav-toolbar .icon-button {
450454
&:hover {
451-
background: rgba(255, 255, 255, 0.08);
455+
background: #2c2e31;
452456
}
453457

454458
svg {

packages/visualizer/src/component/player/index.less

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
max-width: 100%;
1616
max-height: 100%;
1717
padding: 12px;
18-
background: #f2f4f7;
1918
box-sizing: border-box;
2019
border: 1px solid #f2f4f7;
2120
border-radius: @radius;
@@ -46,8 +45,7 @@
4645
overflow: hidden;
4746
position: relative;
4847
background-color: #000;
49-
border-top-right-radius: 4px;
50-
border-top-left-radius: 4px;
48+
border-radius: 4px;
5149

5250
// Player wrapper positions chapter markers relative to the player.
5351
// Uses aspect-ratio (set via style) + width/height constraints
@@ -71,10 +69,12 @@
7169
}
7270
}
7371

74-
// Remove border/outline from Remotion control bar buttons
72+
// Reset Remotion control bar buttons so inner .status-icon handles hover
7573
button {
7674
border: none;
7775
outline: none;
76+
background: none;
77+
padding: 0;
7878
}
7979

8080
// Chapter markers overlaid on Remotion's seek bar
@@ -117,6 +117,32 @@
117117
// Remotion seek bar styles are overridden via JS in useEffect (see index.tsx)
118118
}
119119

120+
// Shared icon style for all Remotion control bar buttons
121+
// (play/pause, fullscreen, download, settings)
122+
.status-icon {
123+
transition: 0.2s;
124+
width: 24px;
125+
height: 24px;
126+
border-radius: 4px;
127+
display: flex;
128+
align-items: center;
129+
justify-content: center;
130+
flex-shrink: 0;
131+
color: #fff;
132+
cursor: pointer;
133+
opacity: 0.7;
134+
135+
svg {
136+
color: #fff;
137+
font-size: 14px;
138+
}
139+
140+
&:hover {
141+
opacity: 1;
142+
background: rgba(255, 255, 255, 0.15);
143+
}
144+
}
145+
120146
// Custom controls rendered inside Remotion Player's control bar
121147
.player-custom-controls {
122148
display: flex;
@@ -128,28 +154,6 @@
128154
.ant-spin {
129155
color: #fff;
130156
}
131-
132-
.status-icon {
133-
transition: 0.2s;
134-
width: 24px;
135-
height: 24px;
136-
border-radius: 4px;
137-
display: flex;
138-
align-items: center;
139-
justify-content: center;
140-
flex-shrink: 0;
141-
color: #fff;
142-
cursor: pointer;
143-
144-
svg {
145-
color: #fff;
146-
font-size: 14px;
147-
}
148-
149-
&:hover {
150-
background: rgba(255, 255, 255, 0.15);
151-
}
152-
}
153157
}
154158
}
155159

@@ -172,7 +176,6 @@
172176
// Dark mode styles
173177
[data-theme='dark'] {
174178
.player-container {
175-
background: #141414;
176179
border-color: #292929;
177180

178181
&[data-fit-mode='height'] {
@@ -187,7 +190,6 @@
187190
.canvas-container {
188191
background-color: #000;
189192
}
190-
191193
}
192194
}
193195

packages/visualizer/src/component/player/index.tsx

Lines changed: 61 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -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';
1515
import { Player as RemotionPlayer } from '@remotion/player';
1616
import 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

Comments
 (0)