Skip to content

Commit efb6400

Browse files
feat(gif-player): add frame-by-frame player for GIFs and videos
Introduces a new tool to inspect media frame-by-frame, specifically designed for analyzing QA bug reports. The player supports GIF parsing via Web Workers to maintain UI responsiveness and provides video scrubbing, playback speed controls, and keyboard shortcuts for precise navigation.
1 parent 94a6014 commit efb6400

11 files changed

Lines changed: 2321 additions & 2 deletions

File tree

bun.lock

Lines changed: 977 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
"@radix-ui/react-tooltip": "^1.1.2",
2323
"class-variance-authority": "^0.7.0",
2424
"clsx": "^2.1.1",
25+
"gifuct-js": "^2.1.2",
2526
"jsqr": "^1.4.0",
2627
"jszip": "^3.10.1",
2728
"lucide-react": "^0.441.0",

src/routeTree.gen.ts

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { Route as ToolsQrReaderIndexImport } from './routes/tools/qr-reader/inde
1818
import { Route as ToolsImageSplitIndexImport } from './routes/tools/image-split/index'
1919
import { Route as ToolsImageCropIndexImport } from './routes/tools/image-crop/index'
2020
import { Route as ToolsImageConcatIndexImport } from './routes/tools/image-concat/index'
21+
import { Route as ToolsGifPlayerIndexImport } from './routes/tools/gif-player/index'
2122
import { Route as ToolsBackgroundRemoveIndexImport } from './routes/tools/background-remove/index'
2223
import { Route as SysTaskManagerIndexImport } from './routes/sys/task-manager/index'
2324

@@ -65,6 +66,13 @@ const ToolsImageConcatIndexRoute = ToolsImageConcatIndexImport.update({
6566
import('./routes/tools/image-concat/index.lazy').then((d) => d.Route),
6667
)
6768

69+
const ToolsGifPlayerIndexRoute = ToolsGifPlayerIndexImport.update({
70+
path: '/tools/gif-player/',
71+
getParentRoute: () => rootRoute,
72+
} as any).lazy(() =>
73+
import('./routes/tools/gif-player/index.lazy').then((d) => d.Route),
74+
)
75+
6876
const ToolsBackgroundRemoveIndexRoute = ToolsBackgroundRemoveIndexImport.update(
6977
{
7078
path: '/tools/background-remove/',
@@ -113,6 +121,13 @@ declare module '@tanstack/react-router' {
113121
preLoaderRoute: typeof ToolsBackgroundRemoveIndexImport
114122
parentRoute: typeof rootRoute
115123
}
124+
'/tools/gif-player/': {
125+
id: '/tools/gif-player/'
126+
path: '/tools/gif-player'
127+
fullPath: '/tools/gif-player'
128+
preLoaderRoute: typeof ToolsGifPlayerIndexImport
129+
parentRoute: typeof rootRoute
130+
}
116131
'/tools/image-concat/': {
117132
id: '/tools/image-concat/'
118133
path: '/tools/image-concat'
@@ -151,6 +166,7 @@ export interface FileRoutesByFullPath {
151166
'/testing': typeof TestingRoute
152167
'/sys/task-manager': typeof SysTaskManagerIndexRoute
153168
'/tools/background-remove': typeof ToolsBackgroundRemoveIndexRoute
169+
'/tools/gif-player': typeof ToolsGifPlayerIndexRoute
154170
'/tools/image-concat': typeof ToolsImageConcatIndexRoute
155171
'/tools/image-crop': typeof ToolsImageCropIndexRoute
156172
'/tools/image-split': typeof ToolsImageSplitIndexRoute
@@ -162,6 +178,7 @@ export interface FileRoutesByTo {
162178
'/testing': typeof TestingRoute
163179
'/sys/task-manager': typeof SysTaskManagerIndexRoute
164180
'/tools/background-remove': typeof ToolsBackgroundRemoveIndexRoute
181+
'/tools/gif-player': typeof ToolsGifPlayerIndexRoute
165182
'/tools/image-concat': typeof ToolsImageConcatIndexRoute
166183
'/tools/image-crop': typeof ToolsImageCropIndexRoute
167184
'/tools/image-split': typeof ToolsImageSplitIndexRoute
@@ -174,6 +191,7 @@ export interface FileRoutesById {
174191
'/testing': typeof TestingRoute
175192
'/sys/task-manager/': typeof SysTaskManagerIndexRoute
176193
'/tools/background-remove/': typeof ToolsBackgroundRemoveIndexRoute
194+
'/tools/gif-player/': typeof ToolsGifPlayerIndexRoute
177195
'/tools/image-concat/': typeof ToolsImageConcatIndexRoute
178196
'/tools/image-crop/': typeof ToolsImageCropIndexRoute
179197
'/tools/image-split/': typeof ToolsImageSplitIndexRoute
@@ -187,6 +205,7 @@ export interface FileRouteTypes {
187205
| '/testing'
188206
| '/sys/task-manager'
189207
| '/tools/background-remove'
208+
| '/tools/gif-player'
190209
| '/tools/image-concat'
191210
| '/tools/image-crop'
192211
| '/tools/image-split'
@@ -197,6 +216,7 @@ export interface FileRouteTypes {
197216
| '/testing'
198217
| '/sys/task-manager'
199218
| '/tools/background-remove'
219+
| '/tools/gif-player'
200220
| '/tools/image-concat'
201221
| '/tools/image-crop'
202222
| '/tools/image-split'
@@ -207,6 +227,7 @@ export interface FileRouteTypes {
207227
| '/testing'
208228
| '/sys/task-manager/'
209229
| '/tools/background-remove/'
230+
| '/tools/gif-player/'
210231
| '/tools/image-concat/'
211232
| '/tools/image-crop/'
212233
| '/tools/image-split/'
@@ -219,6 +240,7 @@ export interface RootRouteChildren {
219240
TestingRoute: typeof TestingRoute
220241
SysTaskManagerIndexRoute: typeof SysTaskManagerIndexRoute
221242
ToolsBackgroundRemoveIndexRoute: typeof ToolsBackgroundRemoveIndexRoute
243+
ToolsGifPlayerIndexRoute: typeof ToolsGifPlayerIndexRoute
222244
ToolsImageConcatIndexRoute: typeof ToolsImageConcatIndexRoute
223245
ToolsImageCropIndexRoute: typeof ToolsImageCropIndexRoute
224246
ToolsImageSplitIndexRoute: typeof ToolsImageSplitIndexRoute
@@ -230,6 +252,7 @@ const rootRouteChildren: RootRouteChildren = {
230252
TestingRoute: TestingRoute,
231253
SysTaskManagerIndexRoute: SysTaskManagerIndexRoute,
232254
ToolsBackgroundRemoveIndexRoute: ToolsBackgroundRemoveIndexRoute,
255+
ToolsGifPlayerIndexRoute: ToolsGifPlayerIndexRoute,
233256
ToolsImageConcatIndexRoute: ToolsImageConcatIndexRoute,
234257
ToolsImageCropIndexRoute: ToolsImageCropIndexRoute,
235258
ToolsImageSplitIndexRoute: ToolsImageSplitIndexRoute,
@@ -252,6 +275,7 @@ export const routeTree = rootRoute
252275
"/testing",
253276
"/sys/task-manager/",
254277
"/tools/background-remove/",
278+
"/tools/gif-player/",
255279
"/tools/image-concat/",
256280
"/tools/image-crop/",
257281
"/tools/image-split/",
@@ -270,6 +294,9 @@ export const routeTree = rootRoute
270294
"/tools/background-remove/": {
271295
"filePath": "tools/background-remove/index.tsx"
272296
},
297+
"/tools/gif-player/": {
298+
"filePath": "tools/gif-player/index.tsx"
299+
},
273300
"/tools/image-concat/": {
274301
"filePath": "tools/image-concat/index.tsx"
275302
},

src/routes/index.lazy.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,13 @@ function IndexRoute() {
3232
to="/tools/qr-reader"
3333
/>
3434

35-
{Array(5 * 6 - 5)
35+
<ToolBox
36+
name="GIF & Video Player"
37+
description="Play, scrub, and step through a GIF or video frame-by-frame — handy for QA bug reports."
38+
to="/tools/gif-player"
39+
/>
40+
41+
{Array(5 * 6 - 6)
3642
.fill(0)
3743
.map((_, i) => (
3844
<div

0 commit comments

Comments
 (0)