Skip to content
Merged
Show file tree
Hide file tree
Changes from 22 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
405ca4c
feat(player): add opening and step scenes for video player
quanru Feb 9, 2026
850657b
feat(visualizer): implement cyberpunk visual effects in video export
quanru Feb 9, 2026
7fdeaa3
feat(visualizer): enhance browser shell with 3D effects and chrome el…
quanru Feb 9, 2026
b2492f6
feat(visualizer): introduce ScriptFrame data structure and refactor c…
quanru Feb 9, 2026
f7066e6
fix(player): improve player frame retrieval and enhance subtitle hand…
quanru Feb 10, 2026
7a94f3d
refactor(blackboard): remove unused PIXI imports and enhance overlay …
quanru Feb 10, 2026
3a6249e
feat(visualizer): enhance device support in visualizer
quanru Feb 10, 2026
fd1ed87
refactor(visualizer): implement frame state derivation for Remotion p…
quanru Feb 10, 2026
ec375c3
feat(player): disable volume controls in Player component
quanru Feb 10, 2026
c3ffe8d
feat(player): embed toolbar controls into Remotion Player control bar
quanru Feb 10, 2026
76f737c
feat(player): add fullscreen button with shared icon style in Remotio…
quanru Feb 23, 2026
223408c
refactor(export-branded-video): improve variable declaration formatti…
quanru Feb 24, 2026
445647f
feat(player): enhance device shell rendering and improve progress cal…
quanru Feb 25, 2026
214fe63
feat(player): update custom controls with play/pause button and impro…
quanru Feb 25, 2026
2b2f1b6
feat(player): add chapter markers overlay and improve player wrapper …
quanru Feb 28, 2026
6be444a
feat(player): update styles for chapter markers and seek bar, enhance…
quanru Mar 2, 2026
52e8d32
feat(player): enhance player wrapper for aspect ratio handling and po…
quanru Mar 2, 2026
6bd2465
feat(player): improve device shell rendering for portrait mode and en…
quanru Mar 3, 2026
d357bbb
refactor(player): remove effects system and add subtitle toggle
quanru Mar 3, 2026
d0062c0
fix(report): prevent layout overlap when browser width shrinks
quanru Mar 4, 2026
434e006
feat(player): enhance layout for sidebar resizing and remove device t…
quanru Mar 4, 2026
f162f7e
refactor(player): simplify layout calculations for portrait mode in S…
quanru Mar 4, 2026
060059d
refactor(report): replace pixi.js with Canvas 2D in Timeline and clea…
quanru Mar 4, 2026
bc09655
feat(player): implement frame player hook and enhance player controls…
quanru Mar 4, 2026
f5c5728
fix(player): improve resource cleanup for report downloads and video …
quanru Mar 4, 2026
8977df1
feat(player): add subtitle rendering and styling to enhance user expe…
quanru Mar 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 27 additions & 2 deletions apps/report/src/App.less
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,31 @@ footer.mt-8 {
padding: 0 8px;
}

.main-layout {
display: flex;
flex-direction: row;
flex-grow: 1;
height: 100%;
overflow: hidden;
}

.page-side {
height: calc(100% - 8px);
background: #f2f4f7;
padding-right: 8px;
margin-bottom: 8px;
overflow-x: auto;
flex-shrink: 0;
overflow-x: hidden;
overflow-y: auto;
}

.resize-handle {
width: 8px;
flex-shrink: 0;
cursor: col-resize;

&:hover {
background: rgba(0, 0, 0, 0.06);
}
}

[data-theme='dark'] .page-side {
Expand Down Expand Up @@ -181,6 +200,8 @@ footer.mt-8 {
border-radius: 16px;
background: #fff;
margin-bottom: 8px;
min-width: 0;
overflow: hidden;

.main-right-header {
height: 50px;
Expand Down Expand Up @@ -295,6 +316,10 @@ footer.mt-8 {
color: rgba(255, 255, 255, 0.45) !important;
}

.resize-handle:hover {
background: rgba(255, 255, 255, 0.06);
}

.main-right {
background: #1f1f1f;

Expand Down
110 changes: 59 additions & 51 deletions apps/report/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import type {
} from './types';

let globalRenderCount = 1;
const SIDEBAR_WIDTH_KEY = 'midscene-sidebar-width';
const DEFAULT_SIDEBAR_WIDTH = 280;

function Visualizer(props: VisualizerProps): JSX.Element {
const { dumps } = props;
Expand All @@ -53,7 +55,10 @@ function Visualizer(props: VisualizerProps): JSX.Element {
const modelBriefs = useExecutionDump((store) => store.modelBriefs);
const reset = useExecutionDump((store) => store.reset);
const [mainLayoutChangeFlag, setMainLayoutChangeFlag] = useState(0);
const mainLayoutChangedRef = useRef(false);
const [sidebarWidth, setSidebarWidth] = useState(() => {
const saved = localStorage.getItem(SIDEBAR_WIDTH_KEY);
return saved ? Number(saved) : DEFAULT_SIDEBAR_WIDTH;
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sidebarWidth is initialized from localStorage using Number(saved) without validation. If the stored value is missing/invalid, this can become NaN and result in an invalid style.width. Consider validating/clamping the parsed value (and falling back to DEFAULT_SIDEBAR_WIDTH when Number.isFinite is false).

Suggested change
return saved ? Number(saved) : DEFAULT_SIDEBAR_WIDTH;
const parsed = saved !== null ? Number(saved) : NaN;
// Fallback to default if the stored value is missing, invalid, or non-positive.
return Number.isFinite(parsed) && parsed > 0
? parsed
: DEFAULT_SIDEBAR_WIDTH;

Copilot uses AI. Check for mistakes.
});
const dump = useExecutionDump((store) => store.dump);
const [timelineCollapsed, setTimelineCollapsed] = useState(false);
const {
Expand Down Expand Up @@ -153,62 +158,65 @@ function Visualizer(props: VisualizerProps): JSX.Element {
);

mainContent = (
<PanelGroup
autoSaveId="main-page-layout"
direction="horizontal"
onLayout={() => {
if (!mainLayoutChangedRef.current) {
setMainLayoutChangeFlag((prev) => prev + 1);
}
}}
>
<Panel maxSize={95} defaultSize={25} minSize={15}>
<div className="page-side">
<Sidebar
dumps={dumps}
proModeEnabled={proModeEnabled}
onProModeChange={setProModeEnabled}
replayAllScripts={replayAllScripts}
setReplayAllMode={setReplayAllMode}
/>
</div>
</Panel>
<PanelResizeHandle
<div className="main-layout">
<div className="page-side" style={{ width: sidebarWidth }}>
<Sidebar
dumps={dumps}
proModeEnabled={proModeEnabled}
onProModeChange={setProModeEnabled}
replayAllScripts={replayAllScripts}
setReplayAllMode={setReplayAllMode}
/>
</div>
<div
className="resize-handle"
onDragging={(isChanging) => {
if (mainLayoutChangedRef.current && !isChanging) {
onMouseDown={(e) => {
e.preventDefault();
const startX = e.clientX;
const startWidth = sidebarWidth;
let latestWidth = startWidth;
const onMouseMove = (ev: MouseEvent) => {
latestWidth = Math.max(
200,
Math.min(500, startWidth + ev.clientX - startX),
);
setSidebarWidth(latestWidth);
};
const onMouseUp = () => {
document.removeEventListener('mousemove', onMouseMove);
document.removeEventListener('mouseup', onMouseUp);
localStorage.setItem(SIDEBAR_WIDTH_KEY, String(latestWidth));
setMainLayoutChangeFlag((prev) => prev + 1);
}
mainLayoutChangedRef.current = isChanging;
};
document.addEventListener('mousemove', onMouseMove);
document.addEventListener('mouseup', onMouseUp);
}}
/>
<Panel defaultSize={75} maxSize={95}>
<div className="main-right">
<div
className="main-right-header"
onClick={() => setTimelineCollapsed(!timelineCollapsed)}
style={{ cursor: 'pointer', userSelect: 'none' }}
<div className="main-right">
<div
className="main-right-header"
onClick={() => setTimelineCollapsed(!timelineCollapsed)}
style={{ cursor: 'pointer', userSelect: 'none' }}
>
<span
className="timeline-collapse-icon"
style={{
display: 'inline-block',
marginRight: 8,
transition: 'transform 0.2s',
transform: timelineCollapsed
? 'rotate(-90deg)'
: 'rotate(0deg)',
}}
>
<span
className="timeline-collapse-icon"
style={{
display: 'inline-block',
marginRight: 8,
transition: 'transform 0.2s',
transform: timelineCollapsed
? 'rotate(-90deg)'
: 'rotate(0deg)',
}}
>
</span>
Record
</div>
{!timelineCollapsed && <Timeline key={mainLayoutChangeFlag} />}
<div className="main-content">{content}</div>
</span>
Record
</div>
</Panel>
</PanelGroup>
{!timelineCollapsed && <Timeline key={mainLayoutChangeFlag} />}
<div className="main-content">{content}</div>
</div>
</div>
);
}

Expand Down
8 changes: 6 additions & 2 deletions apps/report/src/components/sidebar/index.less
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,13 @@
cursor: pointer;
display: flex;
align-items: center;
justify-content: center;
padding: 6px;
border-radius: 8px;
transition: all 0.2s;

&:hover {
background: #f5f5f5;
background: #e6e8eb;
}
}
}
Expand Down Expand Up @@ -456,7 +460,7 @@
.page-nav-left {
.page-nav-toolbar .icon-button {
&:hover {
background: rgba(255, 255, 255, 0.08);
background: #2c2e31;
}

svg {
Expand Down
4 changes: 4 additions & 0 deletions apps/report/src/components/store/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ export interface DumpStoreType {
modelBriefs: string[];
insightWidth: number | null;
insightHeight: number | null;
deviceType: string | undefined;
activeExecution: ExecutionDump | null;
activeExecutionAnimation: AnimationScript[] | null;
activeTask: ExecutionTask | null;
Expand Down Expand Up @@ -94,6 +95,7 @@ export const useExecutionDump = create<DumpStoreType>((set, get) => {
modelBriefs: [],
insightWidth: null,
insightHeight: null,
deviceType: undefined,
activeTask: null,
activeExecution: null,
activeExecutionAnimation: null,
Expand Down Expand Up @@ -159,6 +161,7 @@ export const useExecutionDump = create<DumpStoreType>((set, get) => {
height,
modelBriefs,
sdkVersion,
deviceType,
} = allScriptsInfo;

set({
Expand All @@ -167,6 +170,7 @@ export const useExecutionDump = create<DumpStoreType>((set, get) => {
insightHeight: height,
modelBriefs,
sdkVersion,
deviceType,
});

const replayAvailable = allScripts.length > 0;
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/agent/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,7 @@ export class Agent<
groupDescription: this.opts.groupDescription,
executions: [],
modelBriefs: [],
deviceType: this.interface.interfaceType,
});
this.executionDumpIndexByRunner = new WeakMap<TaskRunner, number>();

Expand Down
4 changes: 4 additions & 0 deletions packages/core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -705,6 +705,7 @@ export interface IGroupedActionDump {
groupDescription?: string;
modelBriefs: string[];
executions: IExecutionDump[];
deviceType?: string;
}

/**
Expand All @@ -716,6 +717,7 @@ export class GroupedActionDump implements IGroupedActionDump {
groupDescription?: string;
modelBriefs: string[];
executions: ExecutionDump[];
deviceType?: string;

constructor(data: IGroupedActionDump) {
this.sdkVersion = data.sdkVersion;
Expand All @@ -725,6 +727,7 @@ export class GroupedActionDump implements IGroupedActionDump {
this.executions = data.executions.map((exec) =>
exec instanceof ExecutionDump ? exec : ExecutionDump.fromJSON(exec),
);
this.deviceType = data.deviceType;
}

/**
Expand Down Expand Up @@ -771,6 +774,7 @@ export class GroupedActionDump implements IGroupedActionDump {
groupDescription: this.groupDescription,
modelBriefs: this.modelBriefs,
executions: this.executions.map((exec) => exec.toJSON()),
deviceType: this.deviceType,
};
}

Expand Down
7 changes: 3 additions & 4 deletions packages/visualizer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
"react-dom": ">=19.1.0"
},
"devDependencies": {
"@pixi/unsafe-eval": "7.4.2",
"@rsbuild/plugin-less": "^1.5.0",
"@rsbuild/plugin-node-polyfill": "1.4.2",
"@rsbuild/plugin-react": "^1.4.1",
Expand All @@ -37,8 +36,6 @@
"@types/react-dom": "^18.3.1",
"execa": "9.3.0",
"http-server": "14.1.1",
"pixi-filters": "6.0.5",
"pixi.js": "8.1.1",
"query-string": "9.1.1",
"react": "18.3.1",
"react-dom": "18.3.1",
Expand All @@ -58,9 +55,11 @@
"@midscene/playground": "workspace:*",
"@midscene/shared": "workspace:*",
"@midscene/web": "workspace:*",
"@remotion/player": "4.0.419",
"antd": "^5.21.6",
"buffer": "6.0.3",
"dayjs": "^1.11.11"
"dayjs": "^1.11.11",
"remotion": "4.0.419"
},
"license": "MIT"
}
Loading