Files
36-character-flower/docs/settlement-gold-border-animation.md
JiaJun 5768632313 feat(game): 添加动物精灵图像变体支持并优化揭示动画
- 引入 light-animal-sprite 图像资源和 variant 属性支持
- 在动物组件中实现正常和浅色精灵图像切换功能
- 重构桌面和移动版动物组件的揭示动画逻辑
- 移除冗余的运动偏好检测和布局效果钩子
- 调整揭示动画的时间参数和平滑度曲线
- 更新资源预加载配置以包含浅色动物图像
- 修改控制组件中的投注数量调整状态管理
- 优化脚本生成精灵图像的复用性
2026-06-11 15:50:22 +08:00

7.6 KiB
Raw Blame History

结算过程金色旋转边框样式与动画

本文档保存当前 PC 端与移动端在开奖/结算过程里使用的金色边框、旋转描边和发光动画,便于后续下载、复用或对接设计标注。

源码位置

  • PC 端挂载位置:src/features/game/components/desktop/desktop-animal.tsx
  • 移动端挂载位置:src/features/game/components/mobile/mobile-animal.tsx
  • 样式定义位置:src/style/index.css

PC 端在 revealFrame 存在时渲染:

<div className="gold-reveal-glow rounded-[calc(var(--design-unit)*16)]" />
<div className="gold-reveal-static-border rounded-[calc(var(--design-unit)*16)]" />
<div className="gold-reveal-shell rounded-[calc(var(--design-unit)*16)]" />

移动端在 revealFrame 存在时渲染:

<div className="mobile-gold-reveal-glow z-10 rounded-[calc(var(--design-unit)*7)]" />
<div className="mobile-gold-reveal-static-border z-20 rounded-[calc(var(--design-unit)*7)]" />
<div className="mobile-gold-reveal-shell z-20 rounded-[calc(var(--design-unit)*7)]" />

动画机制

  • --gold-angle:注册为 CSS angle 自定义属性,用于驱动 conic-gradient 旋转。
  • rotating-gold-border:把 --gold-angle0deg 推到 360deg,形成边框旋转。
  • gold-border-pulse:让外层金色光晕做轻微透明度和缩放呼吸。
  • ::before主金色旋转边框8 秒一圈。
  • ::after高光扫光边框2.1 秒一圈,并从反向角度偏移 180deg 开始。
  • static-border:静态金色实体边框,保证边框厚度和底色稳定。
  • glow:外部径向金色光晕,增强结算聚焦感。

PC 端样式

@property --gold-angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@keyframes rotating-gold-border {
  to {
    --gold-angle: 360deg;
  }
}

@keyframes gold-border-pulse {
  0%,
  100% {
    opacity: 0.34;
    transform: scale(0.992);
  }

  50% {
    opacity: 0.54;
    transform: scale(1.008);
  }
}

.gold-reveal-shell {
  --gold-angle: 0deg;
  position: absolute;
  inset: calc(var(--design-unit) * 2.6);
  border-radius: calc(var(--design-unit) * 16);
  overflow: hidden;
  clip-path: inset(0 round calc(var(--design-unit) * 16));
  pointer-events: none;
}

.gold-reveal-shell::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: calc(var(--design-unit) * 16);
  padding: calc(var(--design-unit) * 5.6);
  background: conic-gradient(
    from var(--gold-angle),
    #534217 10%,
    #534217 20%,
    #ffe226 45%,
    #534217 60%,
    #534217 85%,
    #ffe226 95%,
    #534217 100%
  );
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: rotating-gold-border 8s linear infinite;
}

.gold-reveal-shell::after {
  content: "";
  position: absolute;
  inset: calc(var(--design-unit) * 1);
  border-radius: calc(var(--design-unit) * 15);
  padding: calc(var(--design-unit) * 4);
  background: conic-gradient(
    from calc(var(--gold-angle) + 180deg),
    rgba(255, 247, 210, 0) 0%,
    rgba(255, 247, 210, 0) 66%,
    rgba(255, 252, 232, 0.14) 71%,
    rgba(255, 254, 244, 0.98) 75%,
    rgba(255, 230, 130, 0.96) 79%,
    rgba(255, 247, 210, 0.18) 84%,
    rgba(255, 247, 210, 0) 90%,
    rgba(255, 247, 210, 0) 100%
  );
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: rotating-gold-border 2.1s linear infinite;
}

.gold-reveal-static-border {
  position: absolute;
  inset: calc(var(--design-unit) * 2.8);
  border-radius: calc(var(--design-unit) * 16);
  border: calc(var(--design-unit) * 7.4) solid rgba(181, 138, 40, 0.98);
  box-shadow:
    inset 0 0 calc(var(--design-unit) * 14) rgba(255, 241, 181, 0.38),
    0 0 calc(var(--design-unit) * 18) rgba(255, 210, 102, 0.32);
  pointer-events: none;
}

.gold-reveal-glow {
  position: absolute;
  inset: calc(var(--design-unit) * 1.4);
  border-radius: calc(var(--design-unit) * 18);
  background: radial-gradient(
    circle at center,
    rgba(255, 226, 92, 0.18) 0%,
    rgba(219, 161, 42, 0.14) 42%,
    rgba(127, 86, 13, 0.08) 62%,
    transparent 82%
  );
  filter: blur(calc(var(--design-unit) * 2.8));
  opacity: 0.36;
  pointer-events: none;
  animation: gold-border-pulse 1.9s ease-in-out infinite;
}

移动端样式

.mobile-gold-reveal-shell {
  --gold-angle: 0deg;
  position: absolute;
  inset: calc(var(--design-unit) * 2.2);
  border-radius: calc(var(--design-unit) * 7);
  overflow: hidden;
  clip-path: inset(0 round calc(var(--design-unit) * 7));
  pointer-events: none;
}

.mobile-gold-reveal-shell::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: calc(var(--design-unit) * 7);
  padding: calc(var(--design-unit) * 2.5);
  background: conic-gradient(
    from var(--gold-angle),
    #534217 10%,
    #534217 20%,
    #ffe226 45%,
    #534217 60%,
    #534217 85%,
    #ffe226 95%,
    #534217 100%
  );
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: rotating-gold-border 8s linear infinite;
}

.mobile-gold-reveal-shell::after {
  content: "";
  position: absolute;
  inset: calc(var(--design-unit) * 0.5);
  border-radius: calc(var(--design-unit) * 6.5);
  padding: calc(var(--design-unit) * 1.7);
  background: conic-gradient(
    from calc(var(--gold-angle) + 180deg),
    rgba(255, 247, 210, 0) 0%,
    rgba(255, 247, 210, 0) 66%,
    rgba(255, 247, 210, 0.14) 71%,
    rgba(255, 254, 244, 0.98) 75%,
    rgba(255, 230, 130, 0.96) 79%,
    rgba(255, 247, 210, 0.18) 84%,
    rgba(255, 247, 210, 0) 90%,
    rgba(255, 247, 210, 0) 100%
  );
  -webkit-mask:
    linear-gradient(#fff 0 0) content-box,
    linear-gradient(#fff 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  animation: rotating-gold-border 2.1s linear infinite;
}

.mobile-gold-reveal-static-border {
  position: absolute;
  inset: calc(var(--design-unit) * 2.7);
  border-radius: calc(var(--design-unit) * 7);
  border: calc(var(--design-unit) * 2.8) solid rgba(181, 138, 40, 0.98);
  box-shadow:
    inset 0 0 calc(var(--design-unit) * 7) rgba(255, 241, 181, 0.38),
    0 0 calc(var(--design-unit) * 9) rgba(255, 210, 102, 0.32);
  pointer-events: none;
}

.mobile-gold-reveal-glow {
  position: absolute;
  inset: calc(var(--design-unit) * 1.4);
  border-radius: calc(var(--design-unit) * 8);
  background: radial-gradient(
    circle at center,
    rgba(255, 226, 92, 0.2) 0%,
    rgba(219, 161, 42, 0.16) 42%,
    rgba(127, 86, 13, 0.08) 62%,
    transparent 82%
  );
  filter: blur(calc(var(--design-unit) * 1.4));
  opacity: 0.42;
  pointer-events: none;
  animation: gold-border-pulse 1.9s ease-in-out infinite;
}

减少动画模式

组件中已经接入 useReducedMotion()。当用户系统设置减少动态效果时PC 与移动端都会把旋转和呼吸动画关闭:

style={prefersReducedMotion ? { animation: 'none' } : undefined}

光晕层在减少动画模式下固定为:

style={{
  animation: 'none',
  opacity: 0.36,
  transform: 'scale(1)',
}}

复用注意事项

  • 父容器必须是 position: relative,三层边框节点必须是绝对定位。
  • 需要提供 --design-unit,当前项目用它控制 PC 与移动端等比缩放。
  • @property --gold-angle 是旋转效果的关键;如果目标浏览器不支持 @property,可改用 transform: rotate() 方案,但需要额外包一层元素。
  • 移动端额外叠加了 animalBorderImage 图片边框CSS 金色旋转边框位于图片边框下方,增强结算选中效果。