Figma 交互式无线设备扫描与蓝牙/Wi-Fi 配对连接系统(Wireless Device Discovery, Wi-Fi & Bluetooth Pairing Console Architecture)组件架构实战:从动态雷达扫描脉冲波纹(Radar Pulse Ripples)、信号强度阶梯指示导轨(Signal RSSI Bars: 弱/中/强/满格)、外设分类原子插槽(Peripheral Slots)到 Variables 配对状态机与 Dev Mode 前端 Web Bluetooth API 生产级代码交付

2026 年 11 月 15 日

在当今物联网(IoT)、智能穿戴、智能家居、车载中控系统以及桌面外设管理器(如蓝牙耳机、无线机械键盘、手柄与绘图板)的产品设计中,无线设备扫描与配对连接控制台(Wireless Device Discovery & Pairing Console) 是用户建立数字连接的第一道门户。

然而,传统的静态原型往往只能展示“已连接”的理想状态,面对真实世界中扫描雷达脉冲扩散、信号强弱动态跳变、PIN 码验证弹窗、连接超时熔断与外设能力插槽分化等复杂分支时,产品原型容易与真实工程割裂。本教程将基于 Auto Layout 弹性自适应布局、Figma Variables 变量系统、组件属性与变体插槽,深度还原一套高扩展、多状态闭环且支持 Dev Mode 前端代码交付 的无线设备连接架构体系。


业务场景与架构痛点:传统无线连接面板的设计瓶颈 #

在无线连接场景中,由于无线电磁环境衰减与硬件握手协议的异步性,设备连接具有高度的动态不确定性。

对比静态拼装方案与系统级组件化架构在研发协同中的表现差异:

评估维度 传统静态线框拼装 工业级无线配对组件架构
扫描反馈 仅有静态加载菊花图标,无法表达扫描范围与感知半径 雷达同心圆扩散脉冲微交互,视觉化传达近场探测状态
信号强度 散落的 4 根固定矩形,缺乏动态绑定机制 4 阶递增阶梯导轨,通过数值变量直接映射真实 RSSI 阈值
设备分类 每种设备单独画一套卡片,改动时维护成本高昂 原子级插槽解耦(Audio/Input/Display/Smart Home),支持热插拔
异常流转 漏画鉴权失败、PIN 码不匹配、连接超时重试状态 变体状态机原生覆盖从 Idle 到 Timeout 的 7 态生命周期
前端代码映射 开发需自行揣摩动画曲线与 CSS 关键帧 Dev Mode 直接导出规范的 Web Bluetooth API 握手逻辑与 Tailwind 布局

通过组件化架构重构,UI/UX 设计师能在数秒内组装出覆盖全异常分支的硬件连接向导,并使前端研发获得精确的几何与逻辑约束。


核心原子层:雷达脉冲波纹与 RSSI 信号阶梯导轨 #

建立控制台组件系统,首先需拆解并封装两个最具无线特征的底层原子元器件:近场雷达波纹(Radar Pulse) 与 RSSI 信号条(Signal Strength Indicator)。

1. 雷达脉冲扩散波纹的 Auto Layout 几何拓扑 #

为了使雷达波纹具备物理扩散感,避免使用低效的位图序列帧,应采用纯矢量矢量圆环与绝对定位(Absolute Position)技术:

  • 发射核心基座(Emitter Core):中心放置一个 32px × 32px 的高亮度圆形,填充品牌色主色(如 #2563EB),叠加轻微外发光(Spread: 2px, Blur: 8px)。
  • 同心扩散环(Pulse Ripples):创建三个尺寸分别为 72px、120px、168px 的正圆形矢量线框,描边(Stroke)设置为 1.5px,圆环不透明度(Opacity)自内向外依序衰减为 60%、30%、10%。
  • Smart Animate 循环动效:将外圈圆环做成 3 帧渐变交互,在组件集(Component Set)中配置 After delay: 1ms -> Smart Animate (Ease-out 1600ms),使波纹产生连续扩散退隐的微光效果。

2. 四阶 RSSI 信号强度指示条(Signal Strength Meter) #

真实无线通信以接收信号强度指示(RSSI,单位 dBm)评估连线质量。我们将其标准化为 4 阶递增直方图导轨:

  1. 几何参数规范:
    • 4 根垂直矩形圆角条(Pill Bars),宽度统一为 3px,圆角设置为 1.5px。
    • 纵向高度采用等比梯级递增:第 1 阶为 4px、第 2 阶为 7px、第 3 阶为 10px、第 4 阶为 13px。
    • 间距(Item Spacing)通过 设计令牌规范全景速查字典 统一锁定为 2px。
  2. 状态与变量映射:
    • 0 格 / 无信号 (RSSI < -90dBm):全部填充为底灰色 --neutral-300(深色模式下为 --neutral-700)。
    • 1 格 / 信号弱 (-90dBm ~ -80dBm):仅第 1 条点亮橙黄色 --warning-500。
    • 2 格 / 信号中 (-80dBm ~ -70dBm):前 2 条点亮品牌色或绿色 --success-400。
    • 3 格 / 信号良好 (-70dBm ~ -60dBm):前 3 条点亮 --success-500。
    • 4 格 / 满格 (-60dBm 以上):全亮满格,象征极佳传输吞吐。

复合组件构建:外设卡片原子插槽与 7 态流转矩阵 #

在底层原子准备就绪后,接下来构建设备列表中的外设卡片(Peripheral Device Row/Card)。

1. 三栏式自适应 Auto Layout 架构 #

外设卡片采用横向(Horizontal)流式容器,内部分解为三个独立功能区:

  1. 左侧图标插槽(Leading Icon Slot):
    • 固定尺寸容器 40px × 40px,内嵌自适应图标变体(DeviceType: Headphones / Keyboard / Mouse / SmartDisplay / GenericBLE)。
    • 容器背景使用柔和的 --surface-subtle(rgba(37, 99, 235, 0.08)),圆角为 10px。
  2. 中间信息展示区(Device Metadata Rail):
    • 纵向 Auto Layout,宽度设为 Fill container。
    • 上层为设备名称(Title Text,如 "Keychron K2 Pro"),设为 14px Semi-Bold;
    • 下层为设备广播 MAC 地址与连接协议信息(Subtitle Text,如 "Connected • BLE 5.3 • Battery 85%"),设为 12px Regular,颜色为次级文本色。
  3. 右侧操作与状态坞(Trailing Action Dock):
    • 水平 Auto Layout,集成 RSSI 信号微标、加载指示器(Spinner)与操作按钮(Connect / Disconnect / Pair / Settings)。

2. 7 态生命周期状态机矩阵 #

外设卡片在整个配对流程中需经历如下 7 个标准化状态,严密覆盖各种交互边界:

状态类型 视觉特征 操作坞呈现 交互与转移动作
1. Discovered (已发现) 静态高亮,展示信号强度 紧凑型按钮 "Connect" 点击后触发配对握手请求
2. Pairing (配对中) 图标缓慢呼吸,信号条置灰 旋转环形 Spinner + "Pairing..." 屏蔽重复点击,等待底层握手回执
3. Passkey (PIN码验证) 展开下浮层,展示 6 位配对码 文本输入框或确认/取消双按钮 需用户核对设备端 PIN 码
4. Connected (已连接) 标题前增加绿点,电量百分比显现 勾选徽章或三点更多操作菜单 成为默认音频/输入设备
5. Disconnecting (断开中) 标题降权,进度条闪烁 置灰禁用态标签 发送解除配对广播
6. Failed (配对失败) 边框或底色微染红提示色 警告微标 + 红色重试按钮 "Retry" 气泡提示:"密钥协商失败或超时"
7. Timeout (无响应) 卡片透明度降至 50% 离线灰色徽章 "Offline" 提示用户唤醒设备或移至近处

交互实操:利用 Figma Variables 驱动动态配对控制台 #

为了在给客户或研发走查演示时提供高度沉浸的原型体验,我们可以通过 Figma Variables 变量系统 建立全局交互状态机。

1. 变量集合(Variables Collection)定义 #

在本地变量面板中新建名为 Device_Discovery 的变量集合,录入以下关键变量:

{
  "isScanning": true,           // 布尔值:控制雷达波纹与全局扫描指示器显隐
  "selectedDevice": "",         // 字符串:当前用户选中配对的目标设备名称
  "pairingStage": "idle",       // 字符串枚举:idle | pairing | passkey | success | error
  "passkeyPIN": 782409,         // 数值:动态随机 PIN 码
  "deviceCount": 4,             // 数值:已扫描到的活跃外设数量
  "connectionQuality": 3        // 数值:1~4 阶 RSSI 信号强度
}

2. 原型动作绑定(Interaction Actions) #

  • 触发扫描:在顶部 "Scan Devices" 按钮上绑定 On Click 事件,设置条件判断:
    Set variable: isScanning = true
    Set variable: deviceCount = deviceCount + 1
    
  • 点击卡片配对:在外设卡片上绑定 On Click:
    Set variable: selectedDevice = "Sony WH-1000XM5"
    Set variable: pairingStage = "pairing"
    After delay 1200ms -> Set variable: pairingStage = "passkey"
    
  • PIN 码验证确认:在弹窗确认按钮上绑定:
    Set variable: pairingStage = "success"
    Set variable: isScanning = false
    

通过变量与组件变体的动态绑定,整个面板无需复制几十个画板,即可完成真实而严谨的多设备多态配对推演。


研发协同与前端交付:Dev Mode 与 Web Bluetooth API 生产级代码对齐 #

在 Dev Mode 交付流程 中,工程师不仅需要获取 CSS 外观参数,更需要理解组件所映射的现代浏览器底层通信规范。

1. 现代 CSS 关键帧:雷达波纹与 RSSI 信号条实现 #

前端使用现代 Tailwind CSS 或标准 CSS 动画复现雷达波纹:

/* 雷达波纹连续脉冲扩散动画 */
@keyframes radar-pulse {
  0% {
    transform: scale(0.6);
    opacity: 0.8;
  }
  50% {
    opacity: 0.4;
  }
  100% {
    transform: scale(1.8);
    opacity: 0;
  }
}

.radar-ripple-ring {
  position: absolute;
  border-radius: 9999px;
  border: 1.5px solid var(--color-brand-primary, #2563eb);
  animation: radar-pulse 2.4s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
}

/* 错开三个波纹圆环的延迟相位 */
.radar-ripple-ring:nth-child(1) { animation-delay: 0s; }
.radar-ripple-ring:nth-child(2) { animation-delay: 0.8s; }
.radar-ripple-ring:nth-child(3) { animation-delay: 1.6s; }

2. React + TypeScript + Web Bluetooth API 数据流模型 #

将 Figma 中的变体状态无缝映射至前端真实的蓝牙设备发现逻辑:

import React, { useState } from 'react';

export type PairingState = 'idle' | 'pairing' | 'passkey' | 'connected' | 'failed' | 'timeout';

export interface DiscoveredPeripheral {
  id: string;
  name: string;
  rssi: number; // -100 ~ -30 dBm
  deviceType: 'headphones' | 'keyboard' | 'mouse' | 'ble_generic';
  batteryLevel?: number;
  pairingState: PairingState;
}

export const BluetoothDeviceRow: React.FC<{
  device: DiscoveredPeripheral;
  onConnect: (device: DiscoveredPeripheral) => void;
}> = ({ device, onConnect }) => {
  // 转换 RSSI 为 1~4 阶 UI 标尺
  const getSignalLevel = (rssi: number): number => {
    if (rssi >= -60) return 4;
    if (rssi >= -70) return 3;
    if (rssi >= -80) return 2;
    return 1;
  };

  const level = getSignalLevel(device.rssi);

  return (
    <div className="flex items-center justify-between p-3.5 bg-white dark:bg-slate-900 border border-slate-200 dark:border-slate-800 rounded-xl hover:border-blue-500 transition-colors">
      <div className="flex items-center space-x-3.5">
        <div className="w-10 h-10 rounded-lg bg-blue-50 dark:bg-blue-950/40 text-blue-600 flex items-center justify-center">
          {/* 设备类型图标原子插槽 */}
          <span className="text-sm font-bold uppercase">{device.deviceType.slice(0, 2)}</span>
        </div>
        <div>
          <h4 className="text-sm font-semibold text-slate-900 dark:text-slate-100">{device.name || 'Unknown Device'}</h4>
          <p className="text-xs text-slate-500">
            {device.pairingState === 'connected' ? `Connected • Battery ${device.batteryLevel ?? 100}%` : `Signal ${device.rssi} dBm`}
          </p>
        </div>
      </div>

      <div className="flex items-center space-x-3">
        {/* 4 阶 RSSI 信号条 */}
        <div className="flex items-end space-x-0.5 h-3.5" title={`Signal: ${device.rssi} dBm`}>
          {[4, 7, 10, 13].map((height, idx) => (
            <div
              key={idx}
              style={{ height: `${height}px` }}
              className={`w-[3px] rounded-full transition-colors ${
                idx < level ? 'bg-blue-600 dark:bg-blue-400' : 'bg-slate-200 dark:bg-slate-700'
              }`}
            />
          ))}
        </div>

        {/* 状态操作按钮 */}
        {device.pairingState === 'idle' && (
          <button
            onClick={() => onConnect(device)}
            className="px-3 py-1.5 text-xs font-medium text-white bg-blue-600 hover:bg-blue-700 rounded-lg shadow-sm"
          >
            Connect
          </button>
        )}
        {device.pairingState === 'pairing' && (
          <span className="text-xs text-blue-600 animate-pulse font-medium">Pairing...</span>
        )}
        {device.pairingState === 'connected' && (
          <span className="text-xs text-emerald-600 font-semibold bg-emerald-50 dark:bg-emerald-950/40 px-2.5 py-1 rounded-md">
            Connected
          </span>
        )}
      </div>
    </div>
  );
};

避坑指南与最佳实践校验清单 #

在落地无线设备管理系统时,请务必核对以下设计与工程规范:

  1. 防止扫描列表高频重绘抖动:当雷达扫描发现新设备时,外设列表应按照 RSSI 信号强弱排序,但需加入 1.5 秒防抖(Debounce)阈值,禁止列表项在用户准备点击的一瞬间发生剧烈跳位。
  2. 严守 48px 无障碍操作热区:外设卡片右侧的连线按钮与断开图标,即使视觉呈现尺寸仅为 28px,也必须通过外层 Auto Layout 增加透明内边距,确保触控热区不少于 48px × 48px。
  3. 未命名设备的优雅降级:真实广播中大量设备仅广播 MAC 地址或十六进制序列号,设计系统必须提供优雅降级文案(如 "Unnamed BLE Peripheral [E4:2C]"),并以浅灰色弱化显示。
  4. 键盘快捷微调效率:在对齐雷达同心圆与四阶直方图微小元素时,熟练运用 快捷键操作 进行多层穿透选择与等间距分布,可极大消除手工对齐公差。

通过本套架构,无论是构建专业级硬件配套客户端还是移动端 IoT 场景,设计与开发团队都能以最严密、规范的方式快速落地高质量无线设备交互体验。

❓ 常见问题与答疑 (FAQ)

高频疑难解析与避坑指南
A

完全不需要。绝大多数核心功能在免费 Starter 计划中均可完整体验与实操练习,无需额外付费购买付费团队版。