From 5100795a5dff4aaae02df2180f43da8d2534abe9 Mon Sep 17 00:00:00 2001 From: zaxwebs Date: Tue, 18 Aug 2026 04:28:01 +0530 Subject: [PATCH 1/4] feat: zoom out replay map --- src/ui/hooks/useReplayController.jsx | 3 +++ src/ui/replay/ReplayView.jsx | 5 ++++ src/ui/replay/hud/options/Options.jsx | 39 ++++++++++++++++++++++----- src/ui/replay/world/World.jsx | 12 ++++++--- 4 files changed, 48 insertions(+), 11 deletions(-) diff --git a/src/ui/hooks/useReplayController.jsx b/src/ui/hooks/useReplayController.jsx index 7af478f..bc08833 100644 --- a/src/ui/hooks/useReplayController.jsx +++ b/src/ui/hooks/useReplayController.jsx @@ -13,6 +13,7 @@ const useReplayController = (replay) => { const [playing, setPlaying] = useState(false); const [playbackSpeed, setPlaybackSpeed] = useState(1); const [selectionID, setSelectionID] = useState(null); + const [zoom, setZoom] = useState(1); const isFreeCamera = cameraID === -1; const camera = isFreeCamera ? freeCamera : replay?.players.get(cameraID)?.camera; @@ -72,6 +73,8 @@ const useReplayController = (replay) => { setPlaybackSpeed, setPlaying, setSelection, + setZoom, + zoom, }; }; diff --git a/src/ui/replay/ReplayView.jsx b/src/ui/replay/ReplayView.jsx index de9fed7..ffb3ac7 100644 --- a/src/ui/replay/ReplayView.jsx +++ b/src/ui/replay/ReplayView.jsx @@ -28,6 +28,8 @@ const ReplayView = observer(({ replay }) => { setPlaybackSpeed, setPlaying, setSelection, + setZoom, + zoom, } = useReplayController(replay); return ( @@ -44,6 +46,8 @@ const ReplayView = observer(({ replay }) => { cameraID={cameraID} players={replay.players} setCameraID={setCameraID} + setZoom={setZoom} + zoom={zoom} /> {selectedUnit && ( { setFreeCamera={setFreeCamera} setSelection={setSelection} units={replay.units} + zoom={zoom} /> ); diff --git a/src/ui/replay/hud/options/Options.jsx b/src/ui/replay/hud/options/Options.jsx index c746edb..c6b14f1 100644 --- a/src/ui/replay/hud/options/Options.jsx +++ b/src/ui/replay/hud/options/Options.jsx @@ -15,6 +15,14 @@ const StyledOptions = styled.div` text-align: center; `; +const StyledControl = styled.label` + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; + margin: 3px 0; +`; + const CameraOptionGroup = observer((props) => { const { label, players } = props; if (!players.length) { @@ -31,7 +39,9 @@ const CameraOptionGroup = observer((props) => { }); const Options = observer((props) => { - const { cameraID, players, setCameraID } = props; + const { + cameraID, players, setCameraID, setZoom, zoom, + } = props; const radiant = players.filter((p) => p.teamID === TEAM_RADIANT); const dire = players.filter((p) => p.teamID === TEAM_DIRE); @@ -41,14 +51,29 @@ const Options = observer((props) => { setCameraID(+e.target.value); }, [setCameraID]); + const onZoomChange = useCallback((e) => { + setZoom(+e.target.value); + }, [setZoom]); + return ( - - - - - - + + Camera + + + + + + + + + Zoom + + + + + + ); }); diff --git a/src/ui/replay/world/World.jsx b/src/ui/replay/world/World.jsx index 93f26bb..5e8d40d 100644 --- a/src/ui/replay/world/World.jsx +++ b/src/ui/replay/world/World.jsx @@ -30,6 +30,7 @@ const StyledWorld = styled.div` const World = observer((props) => { const { camera, isFreeCamera, patch, selectedUnit, setFreeCamera, setSelection, units, + zoom, } = props; const [dragging, setDragging] = useState(false); @@ -43,10 +44,10 @@ const World = observer((props) => { const height = mapRef.current?.height; setFreeCamera((current) => ({ ...current, - width: width ? viewport.width / width : 0, - height: height ? viewport.height / height : 0, + width: width ? viewport.width / (width * zoom) : 0, + height: height ? viewport.height / (height * zoom) : 0, })); - }, [setFreeCamera, viewport]); + }, [setFreeCamera, viewport, zoom]); const onDoubleClick = useCallback((e) => e.preventDefault(), []); @@ -85,7 +86,10 @@ const World = observer((props) => { {units.map((unit) => ( Date: Tue, 18 Aug 2026 04:34:06 +0530 Subject: [PATCH 2/4] fix: sync minimap viewport with zoom --- src/ui/hooks/useReplayController.jsx | 4 +--- src/ui/replay/ReplayView.jsx | 1 + src/ui/replay/hud/minimap/MiniMap.jsx | 9 +++++++-- src/ui/replay/world/World.jsx | 18 +----------------- 4 files changed, 10 insertions(+), 22 deletions(-) diff --git a/src/ui/hooks/useReplayController.jsx b/src/ui/hooks/useReplayController.jsx index bc08833..31b0a45 100644 --- a/src/ui/hooks/useReplayController.jsx +++ b/src/ui/hooks/useReplayController.jsx @@ -6,9 +6,7 @@ import useDebugging from './useDebugging.jsx'; import useInterval from './useInterval.jsx'; const useReplayController = (replay) => { - const [freeCamera, setFreeCamera] = useState({ - relX: 0, relY: 0, width: 0, height: 0, - }); + const [freeCamera, setFreeCamera] = useState({ relX: 0, relY: 0 }); const [cameraID, setCameraID] = useState(-1); const [playing, setPlaying] = useState(false); const [playbackSpeed, setPlaybackSpeed] = useState(1); diff --git a/src/ui/replay/ReplayView.jsx b/src/ui/replay/ReplayView.jsx index ffb3ac7..8232be1 100644 --- a/src/ui/replay/ReplayView.jsx +++ b/src/ui/replay/ReplayView.jsx @@ -41,6 +41,7 @@ const ReplayView = observer(({ replay }) => { patch={replay.patch} setFreeCamera={setFreeCamera} units={replay.units} + zoom={zoom} /> { const { camera, isFreeCamera, patch, selectedUnit, setFreeCamera, units, + zoom, } = props; const { map } = patch; + const [viewport] = useWindowDimensions(); const [dragging, setDragging] = useState(false); @@ -96,6 +99,8 @@ const MiniMap = observer((props) => { // TODO: Minimap should preferably also show buildings, creep camps etc. const heroes = units.filter((u) => u instanceof Hero); + const cameraWidth = viewport.width / (map.backdrop.size * zoom); + const cameraHeight = viewport.height / (map.backdrop.size * zoom); return ( { style={{ left: `${camera.relX * 100}%`, bottom: `${camera.relY * 100}%`, - width: `${camera.width * 100}%`, - height: `${camera.height * 100}%`, + width: `${cameraWidth * 100}%`, + height: `${cameraHeight * 100}%`, }} /> {heroes.map((unit) => ( diff --git a/src/ui/replay/world/World.jsx b/src/ui/replay/world/World.jsx index 5e8d40d..b1699cc 100644 --- a/src/ui/replay/world/World.jsx +++ b/src/ui/replay/world/World.jsx @@ -1,11 +1,7 @@ -import React, { - useCallback, useEffect, useRef, useState, -} from 'react'; +import React, { useCallback, useRef, useState } from 'react'; import styled from 'styled-components'; import { observer } from 'mobx-react-lite'; -import { useWindowDimensions } from '../../hooks/index.js'; - import Map from './Map.jsx'; import Unit from './Unit.jsx'; @@ -37,18 +33,6 @@ const World = observer((props) => { const mapRef = useRef(null); - // Ensure free camera is updated when window dimensions change - const [viewport] = useWindowDimensions(); - useEffect(() => { - const width = mapRef.current?.width; - const height = mapRef.current?.height; - setFreeCamera((current) => ({ - ...current, - width: width ? viewport.width / (width * zoom) : 0, - height: height ? viewport.height / (height * zoom) : 0, - })); - }, [setFreeCamera, viewport, zoom]); - const onDoubleClick = useCallback((e) => e.preventDefault(), []); const onMouseDown = useCallback((e) => { From 182bbf620e152c7850c0a9adce1168aa71da36e5 Mon Sep 17 00:00:00 2001 From: zaxwebs Date: Tue, 18 Aug 2026 05:35:10 +0530 Subject: [PATCH 3/4] feat: clarify replay view scale options --- src/ui/replay/hud/options/Options.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/ui/replay/hud/options/Options.jsx b/src/ui/replay/hud/options/Options.jsx index c6b14f1..a462522 100644 --- a/src/ui/replay/hud/options/Options.jsx +++ b/src/ui/replay/hud/options/Options.jsx @@ -67,11 +67,11 @@ const Options = observer((props) => { - Zoom - - - - + View + + + + From 27e1d7adf7d2b025282a2d9e03f54bb7384dd527 Mon Sep 17 00:00:00 2001 From: zaxwebs Date: Tue, 18 Aug 2026 05:37:47 +0530 Subject: [PATCH 4/4] fix: label replay zoom control --- src/ui/replay/hud/options/Options.jsx | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ui/replay/hud/options/Options.jsx b/src/ui/replay/hud/options/Options.jsx index a462522..6b9d678 100644 --- a/src/ui/replay/hud/options/Options.jsx +++ b/src/ui/replay/hud/options/Options.jsx @@ -67,8 +67,8 @@ const Options = observer((props) => { - View - + Zoom +