diff --git a/apps/admin-web/src/api/adminApiTypes.ts b/apps/admin-web/src/api/adminApiTypes.ts
index 88933171a..f590021f3 100644
--- a/apps/admin-web/src/api/adminApiTypes.ts
+++ b/apps/admin-web/src/api/adminApiTypes.ts
@@ -332,6 +332,14 @@ export interface AdminEditorAssetListQuery {
limit?: number | null;
}
+export interface AdminEditorImageSequenceFramePayload {
+ imageSrc: string;
+ objectKey?: string | null;
+ assetObjectId?: string | null;
+ width: number;
+ height: number;
+}
+
export interface AdminEditorAssetPayload {
assetId: string;
ownerUserId: string;
@@ -362,6 +370,8 @@ export interface AdminEditorAssetPayload {
taskGenerator: string;
taskCostMudPoints: number;
children: AdminEditorAssetPayload[];
+ imageSequenceFrames?: AdminEditorImageSequenceFramePayload[] | null;
+ imageSequenceDurationMs?: number | null;
}
export interface AdminEditorAssetListResponse {
@@ -413,6 +423,8 @@ export interface AdminEditorShowcaseAssetPayload {
rejectedAt?: string | null;
updatedAt: string;
showcaseCategory?: string | null;
+ imageSequenceFrames?: AdminEditorImageSequenceFramePayload[] | null;
+ imageSequenceDurationMs?: number | null;
}
export interface AdminEditorShowcaseListResponse {
diff --git a/apps/admin-web/src/components/AdminEditorAssetMedia.tsx b/apps/admin-web/src/components/AdminEditorAssetMedia.tsx
index 9e93be572..3b3b41e99 100644
--- a/apps/admin-web/src/components/AdminEditorAssetMedia.tsx
+++ b/apps/admin-web/src/components/AdminEditorAssetMedia.tsx
@@ -1,8 +1,9 @@
-import { X } from 'lucide-react';
+import { Pause, Play, X } from 'lucide-react';
import { useCallback, useEffect, useState } from 'react';
import type { AdminAssetReadUrlResponse } from '../api/adminApiClient';
import { getAdminAssetReadUrl, isAdminApiError } from '../api/adminApiClient';
+import type { AdminEditorImageSequenceFramePayload } from '../api/adminApiTypes';
const ADMIN_ASSET_READ_EXPIRE_SECONDS = 300;
const ADMIN_ASSET_READ_DISPATCH_SPACING_MS = 40;
@@ -18,6 +19,8 @@ export interface AdminPreviewableEditorAsset {
objectKey?: string | null;
assetKind?: string | null;
thumbnailSrc?: string | null;
+ imageSequenceFrames?: AdminEditorImageSequenceFramePayload[] | null;
+ imageSequenceDurationMs?: number | null;
}
export function AdminEditorAssetThumbnail({
@@ -98,6 +101,45 @@ function AdminEditorAssetPreviewMedia({
token: string;
}) {
const mediaKind = resolveAdminAssetMediaKind(entry);
+ const label = entry.label || entry.assetId;
+
+ if (mediaKind === 'image-sequence') {
+ const sequence = normalizeAdminImageSequence(entry);
+ return sequence ? (
+