AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Apple Design

skill-zhouyinlong-lab-dog-skills-apple-design · by ZhouYinLong-lab

>

No reviews yet
0 installs
31 views
0.0% view→install

Install

$ agentstack add skill-zhouyinlong-lab-dog-skills-apple-design

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-zhouyinlong-lab-dog-skills-apple-design)

Reliability & compatibility

Security review passed
0 installs to date
no reviews yet
1mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Apple Design? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Apple Design — 苹果设计哲学(Web 实现版)

> 把 Apple 的流体界面哲学翻译成 Web 开发者能直接用的 CSS 和 JavaScript。 > 核心信条:"界面之所以感觉'活着',是因为运动始终从当前值开始,继承用户的速度,投射动量向前,并在任何瞬间都能被抓住和逆转。" > 上游来源:emilkowalski/skills (MIT, 4500+ ⭐)


设计哲学总览

Apple 流体界面的 16 条原则:

  感知层 (用户感觉到什么)
  ├─ 1. 即时响应 — 消灭延迟
  ├─ 2. 直接操作 — 1:1 跟随
  ├─ 3. 中断性   — 任何瞬间可逆转
  └─ 4. 行为而非动画 — 用弹簧不用关键帧

  物理层 (如何做到)
  ├─ 5. 速度传递   — 手势结束→动画开始,无缝衔接
  ├─ 6. 动量投影   — 预测自然停止位置
  ├─ 7. 橡皮筋边界 — 渐进阻力,非硬停
  ├─ 8. 空间一致性 — 进场退场沿同一路径
  └─ 9. 帧级流畅   — 只用 transform+opacity

  视觉层 (看起来怎样)
  ├─ 10. 材质与景深 — backdrop-filter + 动态模糊
  ├─ 11. 排版      — 光学字号 + 动态字重
  ├─ 12. 色彩      — 语义色彩 + 深色模式
  └─ 13. 触觉反馈 — 按下→缩放→释放

  包容层 (对所有人)
  ├─ 14. 减少动效   — prefers-reduced-motion
  ├─ 15. 减少透明度 — prefers-reduced-transparency
  └─ 16. 增强对比度 — prefers-contrast

原则 1:即时响应 — 消灭延迟

> "在 pointerdown 时响应,不是在 click 时。"

/* ✅ 100ms 内的即时反馈 */
.button:active {
  transform: scale(0.97);
  transition: transform 100ms ease-out;
}

/* ❌ 等到 click 事件才反应 = 有可感知的延迟 */

交互事件优先级

| 事件 | 响应时间目标 | 用途 | |------|------------|------| | pointerdown | 即时(0-50ms) | 按钮按下、卡片选中 | | pointermove | 每帧(~16ms) | 拖拽、滑动 | | click | 不用于视觉反馈 | 仅用于逻辑提交 | | 300ms tap delay | 必须消除 | 用 touch-action: manipulation |

/* 消除移动端 300ms 点击延迟 */
button, a, [role="button"] {
  touch-action: manipulation;
}

原则 2:直接操作 — 1:1 跟随

> "界面必须像真实物体一样'粘'在手指上。"

// ✅ 使用 setPointerCapture,手指移出元素边界后仍能跟踪
element.addEventListener('pointerdown', (e) => {
  element.setPointerCapture(e.pointerId);
  // 记录起始位置和速度历史
});

// 跟踪最近 5 帧的速度(非仅当前位置)
const velocityHistory = [];
element.addEventListener('pointermove', (e) => {
  velocityHistory.push({
    x: e.movementX,
    y: e.movementY,
    time: performance.now()
  });
  if (velocityHistory.length > 5) velocityHistory.shift();
  
  // 立即更新元素位置(1:1 跟随,无延迟)
  element.style.transform = `translate(${currentX}px, ${currentY}px)`;
});

铁律:拖拽过程中不使用任何动画/过渡——元素必须 1:1 跟随手指。


原则 3:中断性 — 最重要的原则

> "每一个动画都必须在飞行途中被重定向。"

❌ CSS @keyframes — 无法中断
   一旦开始,必须播放完毕。用户新输入被忽略。

⚠️ CSS transitions — 部分可中断
   改变目标值时从中断点平滑过渡,但缺乏物理感。

✅ Springs — 天生可中断
   弹簧始终从"当前值"开始,天然支持任意时刻重定向。

什么该用什么

| 场景 | 推荐方案 | 原因 | |------|---------|------| | 手势驱动 UI(Drawer/Sheet/卡片滑动) | Spring | 需要继承速度、可中断、物理真实 | | 弹出层(Popover/Dropdown/Tooltip) | CSS transition | 简单够用,可中断 | | 纯装饰动画(背景渐变/呼吸灯) | @keyframes | 不需要交互,无所谓 | | 页面切换 | Spring 或 transition | 取决于是否需要手势驱动 |

Spring 动画配置

import { animate } from 'motion'; // 或 framer-motion

// 默认阻尼弹簧(无弹性,最常用)
animate(el, { y: 0 }, {
  type: 'spring',
  bounce: 0,      // 阻尼比 = 1.0,临界的
  duration: 0.4   // 响应时间(非固定时长)
});

// 仅拖拽松手时有轻微弹性
animate(el, { y: target }, {
  type: 'spring',
  bounce: 0.2,
  duration: 0.4
});

Apple 的两参数弹簧模型

| 参数 | 含义 | 推荐范围 | |------|------|---------| | Damping Ratio (阻尼比) | 控制过冲:1.0=无弹性, "如果一个动效看起来像动画但表现得像物理,它就是弹簧。"

区分"动画思维"和"物理思维":

| 动画思维 ❌ | 物理思维 ✅ | |-----------|-----------| | "这个元素在 300ms 内从 A 移动到 B" | "这个元素受到一个力,推向目标位置" | | 固定时长,不可中断 | 基于物理,天生可中断 | | transition: transform 300ms | spring({ bounce: 0, duration: 0.4 }) | | 松手后突然跳变 | 松手后继承速度平滑过渡 |


原则 5:速度传递

> "手势结束 → 弹簧开始,必须无缝继承手指的速度。"

// 在 pointerup 时计算手指速度
element.addEventListener('pointerup', (e) => {
  const lastEvent = velocityHistory[velocityHistory.length - 1];
  const firstEvent = velocityHistory[0];
  const dt = lastEvent.time - firstEvent.time;
  
  const velocityX = (lastEvent.x - firstEvent.x) / dt * 1000; // px/s
  const velocityY = (lastEvent.y - firstEvent.y) / dt * 1000;
  
  // 将速度传递给弹簧
  animate(el, {
    x: targetX,
    y: targetY
  }, {
    type: 'spring',
    bounce: 0.2,
    duration: 0.4,
    velocity: velocityX  // Motion 库直接接收 px/s
  });
});

铁律:松手位置 + 松手速度 → 弹簧目标 → 无缝。任何可见的"跳变"都是 bug。


原则 6:动量投影

> "不要从松手位置吸附到最近边界。用速度预测元素会自然停在哪里,再吸附到最近的 snap point。"

// Apple 的指数衰减动量投影公式
function project(initialVelocity, decelerationRate = 0.998) {
  return (initialVelocity / 1000) * decelerationRate / (1 - decelerationRate);
}

// 使用
const projectedStop = currentPosition + project(releaseVelocity);
const target = nearestSnapPoint(projectedStop, snapPoints);

| 场景 | Deceleration Rate | |------|-------------------| | 快速轻扫(flick) | 0.998(Apple 默认) | | 慢速拖动 | 0.995 | | 分页滑动 | 0.999(几乎无摩擦) |


原则 7:橡皮筋边界(Soft Boundaries)

> "边界不是硬墙,是越来越强的橡皮筋。"

// Apple 的橡皮筋阻力函数
function rubberband(overshoot, dimension, constant = 0.55) {
  return (overshoot * dimension * constant) / (dimension + constant * Math.abs(overshoot));
}

// 应用示例
const maxScroll = contentHeight - containerHeight;
if (scrollY > maxScroll) {
  const overshoot = scrollY - maxScroll;
  visualOffset = maxScroll + rubberband(overshoot, containerHeight);
}

视觉表现:

正常滚动: ████████████░░  范围内线性
过冲区域: ██████████████▓  阻力越来越大的橡皮筋
松手回弹: ██████████████░░ ← spring 弹回边界内

原则 8:空间一致性

> "元素从哪来,就回哪去。"

/* ✅ 下拉菜单从触发它的按钮展开,也收回那个位置 */
.dropdown {
  transform-origin: var(--trigger-x) var(--trigger-y);
  /* 不是 transform-origin: center; ← 错误! */
}

/* ✅ 进场和退场沿同一路径 */
.sheet-enter  { transform: translateY(100%); }
.sheet-exit   { transform: translateY(100%); }
/* 出场是进场的继续,而非镜像反转 */

原则 9:帧级流畅

> "让每一帧都在 16ms 内完成。"

/* ✅ 可动的属性 */
.animated {
  will-change: transform, opacity;
  /* 提前告知浏览器,让它在合成器线程上准备 */
}

/* ✅ 动画结束后清理 */
.animated.animation-done {
  will-change: auto;
}

每帧位置变化控制在感知阈值以下:

  • 平移: "浮起来的元素要有空间感——模糊 + 半透明 + 阴影。"
/* iOS 风格的工具栏 */
.toolbar {
  background: rgba(255, 255, 255, 0.72);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-top: 0.5px solid rgba(255, 255, 255, 0.4);
}

/* 深色模式 */
@media (prefers-color-scheme: dark) {
  .toolbar {
    background: rgba(30, 30, 30, 0.72);
    backdrop-filter: blur(20px) saturate(180%);
    border-top: 0.5px solid rgba(255, 255, 255, 0.1);
  }
}

材质层级系统

| 层级 | 背景透明度 | backdrop-filter blur | 阴影 | 场景 | |------|-----------|---------------------|------|------| | L0 背景 | 不透明 | 无 | 无 | 主内容区 | | L1 浮层 | 0.72 | 20px | 0 2px 8px rgba(0,0,0,0.08) | 卡片 | | L2 弹出 | 0.85 | 30px | 0 4px 16px rgba(0,0,0,0.12) | 弹窗/Sheet | | L3 模态 | 0.92 | 40px | 0 8px 32px rgba(0,0,0,0.16) | Modal | | L4 系统 | 0.95 | 50px | 0 16px 48px rgba(0,0,0,0.20) | 系统级覆盖 |

/* 动态材质:弹出时 blur 和 scale 同步动画 */
.modal {
  backdrop-filter: blur(0px);
  transform: scale(0.95);
  transition: backdrop-filter 400ms ease-out,
              transform 400ms ease-out;
}
.modal.open {
  backdrop-filter: blur(40px);
  transform: scale(1);
}

滚动边缘渐变

/* 用渐变遮罩替代硬分界线 */
.scroll-container {
  --fade-size: 20px;
  mask-image: linear-gradient(
    to bottom,
    transparent 0%,
    black var(--fade-size),
    black calc(100% - var(--fade-size)),
    transparent 100%
  );
  -webkit-mask-image: linear-gradient(
    to bottom,
    transparent 0%,
    black var(--fade-size),
    black calc(100% - var(--fade-size)),
    transparent 100%
  );
}

原则 11:排版

> "字号越大,字间距越紧;字号越小,字间距越松。"

:root {
  /* Apple 的设计标记 */
  --font-ui: 'system-ui', -apple-system, BlinkMacSystemFont, 'SF Pro Text',
             'Segoe UI', Roboto, sans-serif;
  --font-display: 'SF Pro Display', 'system-ui', -apple-system, sans-serif;
  --font-mono: 'SF Mono', 'SFMono-Regular', 'Consolas', 'Liberation Mono',
              'Menlo', monospace;
}

/* 基础排版规则 */
body {
  font-family: var(--font-ui);
  font-optical-sizing: auto;        /* 让浏览器根据字号自动微调字形 */
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
}

/* 字间距:大字紧、小字松 */
.large-title  { letter-spacing: -0.02em; }  /* 34pt → -2% */
.title-1      { letter-spacing: -0.01em; }  /* 28pt → -1% */
.title-2      { letter-spacing: -0.005em; } /* 22pt → -0.5% */
.headline     { letter-spacing: 0; }        /* 17pt → 0 */
.body         { letter-spacing: 0.005em; }  /* 15pt → +0.5% */
.caption      { letter-spacing: 0.01em; }   /* 12pt → +1% */

/* 行高:大字紧、小字松 */
.large-title  { line-height: 1.1; }
.title-1      { line-height: 1.15; }
.headline     { line-height: 1.3; }
.body         { line-height: 1.5; }
.caption      { line-height: 1.6; }

/* 动态字重 */
@supports (font-variation-settings: 'wght' 400) {
  .sf-pro {
    font-family: 'SF Pro Display', 'system-ui', sans-serif;
    font-variation-settings: 'wght' 400;
  }
}

布局单位

❌ 不要用 px 固定布局
✅ 用 rem / em / vw / vh / % 构建可伸缩的排版系统

html { font-size: 62.5%; }  /* 1rem = 10px,便于计算 */
/* Apple 实际用 17pt = 17px 作为根字号基准 */

原则 12:色彩 — 语义与动态

:root {
  /* Apple 的语义色彩系统 */
  --color-label: rgba(0, 0, 0, 0.85);
  --color-secondary-label: rgba(0, 0, 0, 0.55);
  --color-tertiary-label: rgba(0, 0, 0, 0.25);
  --color-placeholder-text: rgba(0, 0, 0, 0.25);

  --color-system-fill: rgba(120, 120, 128, 0.2);
  --color-secondary-system-fill: rgba(120, 120, 128, 0.16);

  --color-separator: rgba(60, 60, 67, 0.12);
  --color-opaque-separator: rgba(60, 60, 67, 0.36);

  /* 强调色 */
  --color-tint: #007AFF;       /* iOS Blue */
  --color-tint-hover: #0056CC;
}

@media (prefers-color-scheme: dark) {
  :root {
    --color-label: rgba(255, 255, 255, 0.85);
    --color-secondary-label: rgba(255, 255, 255, 0.55);
    --color-tertiary-label: rgba(255, 255, 255, 0.25);
    --color-separator: rgba(84, 84, 88, 0.6);
    --color-tint: #0A84FF;
  }
}

关键:不要用 #000#FFF 纯色。Apple 的全系统颜色都带透明度,让底层内容透出。


原则 13:触觉反馈 — 按下→缩放→释放

/* Apple 风格的三段式按钮反馈 */
.btn {
  transform: scale(1);
  transition: transform 100ms ease-out;
}

/* 按下:缩小 */
.btn:active {
  transform: scale(0.97);
  transition: transform 50ms ease-out;
}

/* 释放:弹回(如果使用 spring) */
/* CSS transition 会在 pointerup 时自动回弹 */
// 释放时的弹簧回弹(更有质感)
btn.addEventListener('pointerup', () => {
  animate(btn, { scale: 1 }, {
    type: 'spring',
    bounce: 0.5,      // 给释放加一点弹性
    duration: 0.3
  });
});

原则 14-16:无障碍 — 三种动效偏好

/* 14. 减少动效 */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
  
  .sheet, .modal, .drawer {
    transition: opacity 200ms ease;
    transform: none !important;
  }
}

/* 15. 减少透明度(对有视觉障碍的用户) */
@media (prefers-reduced-transparency: reduce) {
  .toolbar {
    background: var(--color-background-solid, white);
    backdrop-filter: none;
  }
  .modal {
    background: var(--color-background-solid, white);
    backdrop-filter: none;
  }
}

/* 16. 增强对比度 */
@media (prefers-contrast: more) {
  .card {
    border: 2px solid var(--color-label);
  }
  .separator {
    background: var(--color-label);
  }
}

铁律:响应这三个媒体查询不是"加分项",是基础要求。


CSS 技艺速查

现代 CSS 入场动画

/* 使用 @starting-style(Chrome 117+)做声明式入场 */
.popover {
  transform: scale(1);
  opacity: 1;
  transition: transform 200ms ease-out,
              opacity 200ms ease-out;

  @starting-style {
    transform: scale(0.95);
    opacity: 0;
  }
}
/* 无需 JS,元素插入 DOM 时自动播放入场动画 */

Clip-path 揭示动画

/* 替代 height 动画的展开效果 */
.collapsible {
  clip-path: inset(0 0 0 0);
  transition: clip-path 300ms ease-out;
}
.collapsible.collapsed {
  clip-path: inset(0 0 100% 0);
}

/* Tab 内容切换 */
.tab-panel {
  clip-path: inset(0 0 0 0);
  transition: clip-path 250ms ease-in-out;
}
.tab-panel.exit-left {
  clip-path: inset(0 100% 0 0);
}

模糊桥接(Blur Bridge)

// 当两个状态差异太大无法自然过渡时,
// 在过渡中段加一层 blur 来掩盖视觉跳跃
const el = document.querySelector('.transitioning');
el.style.filter = 'blur(4px)';
el.style.opacity = '0.5';

await animate(el, { /* 状态切换 */ }, { duration: 0.2 });

el.style.filter = 'blur(0px)';
el.style.opacity = '1';

安装方式

Claude Code

cp -r apple-design/ ~/.claude/skills/apple-design/

上游安装(获取 Emil 完整设计工程技能集)

npx skills add emilkowalski/skills

本 skill 专注于 Apple 设计哲学的 Web 实现,与 animation-craft(动画工艺元技能)互补使用。


与 Dog-Skills 生态的协作

apple-design          →  设计哲学层("Apple 怎么做?")
animation-craft       →  工艺执行层("怎么写才对?")
dog-frontier          →  全链路工程("怎么把一切串起来?")
ui-ux-pro-max         →  风格数据库("还有什么风格可选?")

典型协作流程

  1. 用户:"帮我做一个 iOS 风格的底部抽屉"
  2. apple-design → 提供原则:弹簧物理、速度传递、材质层级
  3. animation-craft Phase 2 → 生成具体代码(参数:damping 0.8, response 0.3)
  4. animation-craft Phase 3 → 审查代码是否通过 10 条标准

触发示例

  • "帮我做一个像 iOS 那样的底部弹出抽屉"
  • "这个弹窗动画不够 Apple,帮我优化"
  • "给这个列表加上 iOS 风格的橡皮筋回弹"
  • "做一个 Apple 风格的毛玻璃导航栏"
  • "按 Apple 设计规范审查一下这个页面的动效"
  • "create an iOS-style fluid gesture for this card"
  • "把这段拖拽代码改成 Apple 的流体交互风格"
  • "这个 Modal 的进出动画太生硬了,按 Apple 标准重写"
  • "帮我用 SF Pro 的排版规范重新设置这个页面的字体"

上游致谢

本 skill 基于 Emil Kowalski 的 apple-design skill (MIT License),核心灵感来自:

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.