动画金融显示:实时 UI 模式 - Openclaw Skills

作者:互联网

2026-03-30

AI教程

什么是 动画金融显示?

动画金融显示技能为开发者提供了生产就绪的模式,用于管理实时更新的金融数据的视觉复杂性。利用 Openclaw Skills,该工具包专注于使用弹性物理引擎的高性能动画,以避免线性过渡的突兀感。它涵盖了基本的金融科技 UI 需求,包括货币格式化、大数值的紧凑表示以及本地化的百分比显示。

该技能对于构建现代交易平台或理财仪表板的开发者特别有价值,在这些场景中,数据清晰度和动态反馈至关重要。它强调技术最佳实践,如等宽数字(tabular numerals)以防止布局抖动,以及基于 CSS 的闪烁效果,以便在不影响性能的情况下提醒用户价格波动。

下载入口:https://github.com/openclaw/skills/tree/main/skills/wpank/animated-financial-display

安装与下载

1. ClawHub CLI

从源直接安装技能的最快方式。

npx clawhub@latest install animated-financial-display

2. 手动安装

将技能文件夹复制到以下位置之一

全局模式 ~/.openclaw/skills/ 工作区 /skills/

优先级:工作区 > 本地 > 内置

3. 提示词安装

将此提示词复制到 OpenClaw 即可自动安装。

请帮我使用 Clawhub 安装 animated-financial-display。如果尚未安装 Clawhub,请先安装(npm i -g clawhub)。

动画金融显示 应用场景

  • 构建具有实时价格流的高频交易仪表板
  • 开发带有实时百分比变化指示器的加密货币行情表
  • 创建可动态显示总价值变化的投资组合概览卡片
  • 设计具有紧凑金融指标可视化的管理层仪表板
  • 在金融科技应用中为跨越阈值的事件实现视觉警报
动画金融显示 工作原理
  1. Openclaw Skills 代理分析您的项目在金融数据呈现方面的 UI 需求。
  2. 它实现了一套核心格式化工具,用于货币、百分比和大数字压缩。
  3. 引入基于弹性的动画组件,使用 react-spring 或 framer-motion 处理数值过渡。
  4. 通过 CSS 关键帧和状态钩子集成视觉反馈机制,在数值变化时触发颜色闪烁。
  5. 使用 tabular-nums 优化排版,确保数值更新不会导致字符宽度的布局偏移。

动画金融显示 配置指南

要集成这些金融显示模式,首先安装所需的动画和工具依赖项:

npm install @react-spring/web clsx tailwind-merge

接下来,确保您的 Tailwind 或 CSS 配置包含必要的自定义成功和破坏性颜色,以支持闪烁动画效果。

动画金融显示 数据架构与分类体系

该技能通过清晰的 TypeScript 接口和格式化选项组织其逻辑,以维护整个 UI 的数据完整性:

组件/工具 输入数据类型 输出/效果
AnimatedNumber number 弹性动画 span 元素
FlashingValue number, formatter 变化时带颜色闪烁的值
formatCurrency number, options 本地化货币字符串
formatPercentage number, options 带正负号的百分比字符串
formatNumber number, compact boolean 格式化/缩写的数字字符串
name: animated-financial-display
model: standard
description: Patterns for animating financial numbers with spring physics, formatting, and visual feedback. Covers animated counters, price tickers, percentage changes, and value flash effects. Use when building financial dashboards or trading UIs. Triggers on animated number, price animation, financial display, number formatting, spring animation, value ticker.

Animated Financial Display

Create engaging financial number displays with smooth animations, proper formatting, and visual feedback on value changes.


When to Use

  • Building trading dashboards with live prices
  • Showing portfolio values that update in real-time
  • Displaying metrics that need attention on change
  • Any financial UI that benefits from motion

Pattern 1: Spring-Animated Number

Using framer-motion's spring physics:

import { useSpring, animated } from '@react-spring/web';
import { useEffect, useRef } from 'react';

interface AnimatedNumberProps {
  value: number;
  prefix?: string;
  suffix?: string;
  decimals?: number;
  duration?: number;
}

export function AnimatedNumber({
  value,
  prefix = '',
  suffix = '',
  decimals = 2,
  duration = 500,
}: AnimatedNumberProps) {
  const prevValue = useRef(value);

  const { number } = useSpring({
    from: { number: prevValue.current },
    to: { number: value },
    config: { duration },
  });

  useEffect(() => {
    prevValue.current = value;
  }, [value]);

  return (
    
      {number.to((n) => `${prefix}${n.toFixed(decimals)}${suffix}`)}
    
  );
}

Usage




Pattern 2: Value with Flash Effect

Flash color on value change:

import { useEffect, useState, useRef } from 'react';
import { cn } from '@/lib/utils';

interface FlashingValueProps {
  value: number;
  formatter: (value: number) => string;
}

export function FlashingValue({ value, formatter }: FlashingValueProps) {
  const [flash, setFlash] = useState<'up' | 'down' | null>(null);
  const prevValue = useRef(value);

  useEffect(() => {
    if (value !== prevValue.current) {
      setFlash(value > prevValue.current ? 'up' : 'down');
      prevValue.current = value;
      
      const timer = setTimeout(() => setFlash(null), 600);
      return () => clearTimeout(timer);
    }
  }, [value]);

  return (
    
      {formatter(value)}
    
  );
}

Pattern 3: Financial Number Formatting

// lib/formatters.ts
export function formatCurrency(
  value: number,
  options: {
    currency?: string;
    compact?: boolean;
    decimals?: number;
  } = {}
): string {
  const { currency = 'USD', compact = false, decimals = 2 } = options;

  if (compact && Math.abs(value) >= 1_000_000_000) {
    return `$${(value / 1_000_000_000).toFixed(1)}B`;
  }
  if (compact && Math.abs(value) >= 1_000_000) {
    return `$${(value / 1_000_000).toFixed(1)}M`;
  }
  if (compact && Math.abs(value) >= 1_000) {
    return `$${(value / 1_000).toFixed(1)}K`;
  }

  return new Intl.NumberFormat('en-US', {
    style: 'currency',
    currency,
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(value);
}

export function formatPercentage(
  value: number,
  options: { showSign?: boolean; decimals?: number } = {}
): string {
  const { showSign = true, decimals = 2 } = options;
  const sign = showSign && value > 0 ? '+' : '';
  return `${sign}${value.toFixed(decimals)}%`;
}

export function formatNumber(
  value: number,
  options: { compact?: boolean; decimals?: number } = {}
): string {
  const { compact = false, decimals = 0 } = options;

  if (compact) {
    return Intl.NumberFormat('en-US', {
      notation: 'compact',
      maximumFractionDigits: 1,
    }).format(value);
  }

  return new Intl.NumberFormat('en-US', {
    minimumFractionDigits: decimals,
    maximumFractionDigits: decimals,
  }).format(value);
}

Pattern 4: Price Ticker Component

interface PriceTickerProps {
  symbol: string;
  price: number;
  change24h: number;
  changePercent24h: number;
}

export function PriceTicker({
  symbol,
  price,
  change24h,
  changePercent24h,
}: PriceTickerProps) {
  const isPositive = changePercent24h >= 0;

  return (
    
{symbol}
{formatPercentage(changePercent24h)}
); }

Pattern 5: Metric Card with Animation

interface MetricCardProps {
  label: string;
  value: number;
  previousValue?: number;
  format: 'currency' | 'percent' | 'number';
}

export function MetricCard({
  label,
  value,
  previousValue,
  format,
}: MetricCardProps) {
  const formatValue = (v: number) => {
    switch (format) {
      case 'currency': return formatCurrency(v, { compact: true });
      case 'percent': return formatPercentage(v);
      case 'number': return formatNumber(v, { compact: true });
    }
  };

  const change = previousValue ? ((value - previousValue) / previousValue) * 100 : null;

  return (
    
      
{label}
{change !== null && (
= 0 ? 'text-success' : 'text-destructive' )}> {formatPercentage(change)} from previous
)}
); }

Pattern 6: CSS Value Flash Animation

@keyframes value-flash-up {
  0% { 
    color: hsl(var(--success));
    text-shadow: 0 0 8px hsl(var(--success) / 0.5);
  }
  100% { 
    color: inherit;
    text-shadow: none;
  }
}

@keyframes value-flash-down {
  0% { 
    color: hsl(var(--destructive));
    text-shadow: 0 0 8px hsl(var(--destructive) / 0.5);
  }
  100% { 
    color: inherit;
    text-shadow: none;
  }
}

.animate-flash-up {
  animation: value-flash-up 0.6s ease-out;
}

.animate-flash-down {
  animation: value-flash-down 0.6s ease-out;
}

  • Meta-skill: ai/skills/meta/design-system-creation/ — Complete design system workflow
  • financial-data-visualization — Chart theming and data visualization
  • realtime-react-hooks — Real-time data hooks for live updates

NEVER Do

  • Skip tabular-nums — Numbers will jump as they change
  • Use linear animations — Spring/ease-out feels more natural
  • Animate decimals rapidly — Too much motion is distracting
  • Forget compact formatting — Large numbers need abbreviation
  • Show raw floats — Always format with appropriate precision
  • Flash on every render — Only flash on actual value changes

Typography for Numbers

.metric {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
  font-weight: 600;
  letter-spacing: -0.02em;
}

.price-large {
  font-size: 2rem;
  font-weight: 800;
}

.percentage {
  font-size: 0.875rem;
  font-weight: 500;
}