Skip to content

时间线预览暂停/scrub 时合成帧不居中铺满(缩到一角/露黑底)——预览容器非 16:9 时 aspect-ratio 与 height:100% 冲突 #125

Description

@appergb

现象

在 Timeline 标签处于暂停 / scrub状态时,合成帧预览没有居中铺满预览区:画面被压扁、缩小并偏到一侧(常见左/下),四周露出 --bg-preview-canvas 深色底,观感就是“黑屏 + 画面缩在左下角”。无论 seek 到哪一帧,只要暂停就复现。“黑屏”和“缩在左下角”是同一个 CSS 布局缺陷的两种表现。

复现

  1. 时间线放入任意素材,切到 Timeline 预览标签。
  2. 暂停(或拖动 scrub bar 后松手),触发 composite_frame 贴 GPU 合成帧。
  3. 把预览面板调成比项目画幅更高/更窄(例如把右侧时间线拉高、或窗口偏竖),即见合成帧变小、偏位、四周黑边。预览面板恰好 ≈16:9 时反而正常——这是判断依据。

根因

纯前端 CSS 布局问题,位于 web/src/components/preview/Preview.tsxtimelineFrameUrl 分支外层包裹 div(约 L168-186)。该 box 同时设置了三条互相冲突的样式:

  • aspectRatio: \${timeline.width} / ${timeline.height}`` (L170)
  • height: "100%" (L171)
  • maxWidth/maxHeight: "100%" (L172-173)

CSS 中显式 height 优先级高于 aspect-ratioheight:100% 撑满容器高度后,aspect-ratio 只反推 width;当该 width 超过容器宽度时 maxWidth:100% 把它截断,而 height 不会回缩 → box 的实际宽高比退化成容器的宽高比,aspect-ratio 失效。内层 <img width:100% height:100% objectFit:contain> (L184) 在这个“形状已错”的 box 里再做一次 contain,于是合成帧被二次 letterbox、缩小、偏置。

实测复现(Vite dev server 注入同款结构测量):容器 640×480 + 项目 1920×1080 → box 实测 624×464、boxAspect=1.34(应为 1.78);容器 300×400 → boxAspect=0.74。

已排除后端/合成/坐标系src-tauri/src/render.rspreview_render_size 按项目比例等比缩放(最长边封顶 1280),DTO rename_all=camelCase 与前端字段一致;crates/opentake-render/src/plan/affine.rs 单测 identity_transform_full_canvas_centered 证明默认 transform 满画幅居中;gpu/shader.wgsl (L259-272) NDC y-up 与 wgpu 一致、仅在 UV v=1-v 翻转一次,无 Y 轴翻转把画面画到左下象限的问题。

位置

  • web/src/components/preview/Preview.tsx:168-186(合成帧分支,主因)
  • web/src/components/preview/Preview.tsx:189-205(空状态占位 box 同样写法,次要,可一并评估)

建议修复

<img> 自身承担全部 aspect-fit,去掉与 aspect-ratio 冲突的 height:100%。最稳方案(已在 dev server 跨纵向/横向/宽扁/窄高所有容器验证:内容恒为正确比例、恒居中 centerOff=x0,y0、可放大可缩小、各朝向都只填满一个维度):

) : timelineFrameUrl ? (
  <img
    src={timelineFrameUrl}
    alt=""
    draggable={false}
    style={{ width: "100%", height: "100%", objectFit: "contain", display: "block" }}
  />
) : (

由父级 flex(已 alignItems/justifyContent: center)居中,objectFit:contain 负责按比例缩放 + letterbox。

备注:若想保留画幅边框/底色,外层 box 只能用 aspectRatio + maxWidth + maxHeight绝不要再写 height:100%width:100%)。但任何“单一显式维度”的写法在相反朝向容器下都会再破比例(实测 width:100%+height:auto 在宽扁容器下 boxAspect 冲到 5.35)。因此首选上面 img 满 stage 方案。

验收

  • 预览面板拉成竖高、宽扁、正方、≈16:9 四种比例,暂停态合成帧均居中铺满最大可用区域,不偏角、不留多余黑带。
  • scrub 后松手贴帧,画面比例与项目画幅一致(横屏 16:9、竖屏 9:16 均对)。
  • 与播放态 <TimelinePlayback>、单素材预览切换时布局一致、无跳变。

Metadata

Metadata

Assignees

No one assigned

    Labels

    P1重要 Bug,影响核心功能area:frontendReact 前端bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions