Skip to content

Commit b133a65

Browse files
authored
feat(visualizer): device-aware shell rendering with Remotion Player (#2023)
* feat(player): add opening and step scenes for video player * feat(visualizer): implement cyberpunk visual effects in video export * feat(visualizer): enhance browser shell with 3D effects and chrome elements * feat(visualizer): introduce ScriptFrame data structure and refactor calculateFrameMap function * fix(player): improve player frame retrieval and enhance subtitle handling in video export * refactor(blackboard): remove unused PIXI imports and enhance overlay functionality chore(deps): remove unnecessary pixi dependencies from package.json and pnpm-lock.yaml * feat(visualizer): enhance device support in visualizer * refactor(visualizer): implement frame state derivation for Remotion player * feat(player): disable volume controls in Player component * feat(player): embed toolbar controls into Remotion Player control bar Use renderCustomControls API to place download, export, and settings buttons directly in the player's built-in control bar instead of a separate toolbar section below the video. * feat(player): add fullscreen button with shared icon style in Remotion Player * refactor(export-branded-video): improve variable declaration formatting in drawChromeTitleBar function * feat(player): enhance device shell rendering and improve progress calculation * feat(player): update custom controls with play/pause button and improve button styles * feat(player): add chapter markers overlay and improve player wrapper structure * feat(player): update styles for chapter markers and seek bar, enhance tooltip design * feat(player): enhance player wrapper for aspect ratio handling and portrait mode support * feat(player): improve device shell rendering for portrait mode and enhance layout calculations * 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 * fix(report): prevent layout overlap when browser width shrinks Add min-width constraints and proper overflow handling to prevent page-side and main-right panels from overlapping at narrow widths. * feat(player): enhance layout for sidebar resizing and remove device type dependencies * refactor(player): simplify layout calculations for portrait mode in StepsTimeline * refactor(report): replace pixi.js with Canvas 2D in Timeline and clean up player - Rewrite Timeline component from pixi.js to Canvas 2D API - Remove pixi.js and pixi-filters dependencies - Delete pixi-loader utility module - Hide resize handle visual indicator completely - Simplify StepScene layout calculations for portrait mode - Add Remotion license acknowledgment to suppress console warning * feat(player): implement frame player hook and enhance player controls; remove unused components and dependencies * fix(player): improve resource cleanup for report downloads and video exports * feat(player): add subtitle rendering and styling to enhance user experience
1 parent 83b04f6 commit b133a65

File tree

25 files changed

+2448
-2374
lines changed

25 files changed

+2448
-2374
lines changed

apps/report/package.json

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,6 @@
2323
"@rsbuild/plugin-type-check": "^1.3.2",
2424
"@types/chrome": "0.0.279",
2525
"antd": "^5.21.6",
26-
"pixi-filters": "6.0.5",
27-
"pixi.js": "8.1.1",
2826
"react": "18.3.1",
2927
"react-dom": "18.3.1",
3028
"react-resizable-panels": "2.0.22",

apps/report/src/App.less

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,27 @@ footer.mt-8 {
8181
padding: 0 8px;
8282
}
8383

84+
.main-layout {
85+
display: flex;
86+
flex-direction: row;
87+
flex-grow: 1;
88+
height: 100%;
89+
overflow: hidden;
90+
}
91+
8492
.page-side {
8593
height: calc(100% - 8px);
8694
background: #f2f4f7;
87-
padding-right: 8px;
8895
margin-bottom: 8px;
89-
overflow-x: auto;
96+
flex-shrink: 0;
97+
overflow-x: hidden;
98+
overflow-y: auto;
99+
}
100+
101+
.resize-handle {
102+
width: 8px;
103+
flex-shrink: 0;
104+
cursor: col-resize;
90105
}
91106

92107
[data-theme='dark'] .page-side {
@@ -181,6 +196,8 @@ footer.mt-8 {
181196
border-radius: 16px;
182197
background: #fff;
183198
margin-bottom: 8px;
199+
min-width: 0;
200+
overflow: hidden;
184201

185202
.main-right-header {
186203
height: 50px;

apps/report/src/App.tsx

Lines changed: 59 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ import type {
3131
} from './types';
3232

3333
let globalRenderCount = 1;
34+
const SIDEBAR_WIDTH_KEY = 'midscene-sidebar-width';
35+
const DEFAULT_SIDEBAR_WIDTH = 280;
3436

3537
function Visualizer(props: VisualizerProps): JSX.Element {
3638
const { dumps } = props;
@@ -53,7 +55,10 @@ function Visualizer(props: VisualizerProps): JSX.Element {
5355
const modelBriefs = useExecutionDump((store) => store.modelBriefs);
5456
const reset = useExecutionDump((store) => store.reset);
5557
const [mainLayoutChangeFlag, setMainLayoutChangeFlag] = useState(0);
56-
const mainLayoutChangedRef = useRef(false);
58+
const [sidebarWidth, setSidebarWidth] = useState(() => {
59+
const saved = localStorage.getItem(SIDEBAR_WIDTH_KEY);
60+
return saved ? Number(saved) : DEFAULT_SIDEBAR_WIDTH;
61+
});
5762
const dump = useExecutionDump((store) => store.dump);
5863
const [timelineCollapsed, setTimelineCollapsed] = useState(false);
5964
const {
@@ -153,62 +158,65 @@ function Visualizer(props: VisualizerProps): JSX.Element {
153158
);
154159

155160
mainContent = (
156-
<PanelGroup
157-
autoSaveId="main-page-layout"
158-
direction="horizontal"
159-
onLayout={() => {
160-
if (!mainLayoutChangedRef.current) {
161-
setMainLayoutChangeFlag((prev) => prev + 1);
162-
}
163-
}}
164-
>
165-
<Panel maxSize={95} defaultSize={25} minSize={15}>
166-
<div className="page-side">
167-
<Sidebar
168-
dumps={dumps}
169-
proModeEnabled={proModeEnabled}
170-
onProModeChange={setProModeEnabled}
171-
replayAllScripts={replayAllScripts}
172-
setReplayAllMode={setReplayAllMode}
173-
/>
174-
</div>
175-
</Panel>
176-
<PanelResizeHandle
161+
<div className="main-layout">
162+
<div className="page-side" style={{ width: sidebarWidth }}>
163+
<Sidebar
164+
dumps={dumps}
165+
proModeEnabled={proModeEnabled}
166+
onProModeChange={setProModeEnabled}
167+
replayAllScripts={replayAllScripts}
168+
setReplayAllMode={setReplayAllMode}
169+
/>
170+
</div>
171+
<div
177172
className="resize-handle"
178-
onDragging={(isChanging) => {
179-
if (mainLayoutChangedRef.current && !isChanging) {
173+
onMouseDown={(e) => {
174+
e.preventDefault();
175+
const startX = e.clientX;
176+
const startWidth = sidebarWidth;
177+
let latestWidth = startWidth;
178+
const onMouseMove = (ev: MouseEvent) => {
179+
latestWidth = Math.max(
180+
200,
181+
Math.min(500, startWidth + ev.clientX - startX),
182+
);
183+
setSidebarWidth(latestWidth);
184+
};
185+
const onMouseUp = () => {
186+
document.removeEventListener('mousemove', onMouseMove);
187+
document.removeEventListener('mouseup', onMouseUp);
188+
localStorage.setItem(SIDEBAR_WIDTH_KEY, String(latestWidth));
180189
setMainLayoutChangeFlag((prev) => prev + 1);
181-
}
182-
mainLayoutChangedRef.current = isChanging;
190+
};
191+
document.addEventListener('mousemove', onMouseMove);
192+
document.addEventListener('mouseup', onMouseUp);
183193
}}
184194
/>
185-
<Panel defaultSize={75} maxSize={95}>
186-
<div className="main-right">
187-
<div
188-
className="main-right-header"
189-
onClick={() => setTimelineCollapsed(!timelineCollapsed)}
190-
style={{ cursor: 'pointer', userSelect: 'none' }}
195+
<div className="main-right">
196+
<div
197+
className="main-right-header"
198+
onClick={() => setTimelineCollapsed(!timelineCollapsed)}
199+
style={{ cursor: 'pointer', userSelect: 'none' }}
200+
>
201+
<span
202+
className="timeline-collapse-icon"
203+
style={{
204+
display: 'inline-block',
205+
marginRight: 8,
206+
transition: 'transform 0.2s',
207+
transform: timelineCollapsed
208+
? 'rotate(-90deg)'
209+
: 'rotate(0deg)',
210+
}}
191211
>
192-
<span
193-
className="timeline-collapse-icon"
194-
style={{
195-
display: 'inline-block',
196-
marginRight: 8,
197-
transition: 'transform 0.2s',
198-
transform: timelineCollapsed
199-
? 'rotate(-90deg)'
200-
: 'rotate(0deg)',
201-
}}
202-
>
203-
204-
</span>
205-
Record
206-
</div>
207-
{!timelineCollapsed && <Timeline key={mainLayoutChangeFlag} />}
208-
<div className="main-content">{content}</div>
212+
213+
</span>
214+
Record
209215
</div>
210-
</Panel>
211-
</PanelGroup>
216+
{!timelineCollapsed && <Timeline key={mainLayoutChangeFlag} />}
217+
<div className="main-content">{content}</div>
218+
</div>
219+
</div>
212220
);
213221
}
214222

apps/report/src/components/pixi-loader/index.tsx

Lines changed: 0 additions & 24 deletions
This file was deleted.

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
}
@@ -456,7 +460,7 @@
456460
.page-nav-left {
457461
.page-nav-toolbar .icon-button {
458462
&:hover {
459-
background: rgba(255, 255, 255, 0.08);
463+
background: #2c2e31;
460464
}
461465

462466
svg {

apps/report/src/components/store/index.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ export interface DumpStoreType {
5959
modelBriefs: string[];
6060
insightWidth: number | null;
6161
insightHeight: number | null;
62+
deviceType: string | undefined;
6263
activeExecution: ExecutionDump | null;
6364
activeExecutionAnimation: AnimationScript[] | null;
6465
activeTask: ExecutionTask | null;
@@ -94,6 +95,7 @@ export const useExecutionDump = create<DumpStoreType>((set, get) => {
9495
modelBriefs: [],
9596
insightWidth: null,
9697
insightHeight: null,
98+
deviceType: undefined,
9799
activeTask: null,
98100
activeExecution: null,
99101
activeExecutionAnimation: null,
@@ -159,6 +161,7 @@ export const useExecutionDump = create<DumpStoreType>((set, get) => {
159161
height,
160162
modelBriefs,
161163
sdkVersion,
164+
deviceType,
162165
} = allScriptsInfo;
163166

164167
set({
@@ -167,6 +170,7 @@ export const useExecutionDump = create<DumpStoreType>((set, get) => {
167170
insightHeight: height,
168171
modelBriefs,
169172
sdkVersion,
173+
deviceType,
170174
});
171175

172176
const replayAvailable = allScripts.length > 0;

0 commit comments

Comments
 (0)