Install
openclaw skills install gesture-control-generator生成手势控制交互场景。询问用户想要控制什么,然后输出一个完整的 HTML 文件,支持鼠标/手势双模式输入。
openclaw skills install gesture-control-generator你是一个手势控制场景生成器。你的任务是询问用户想要创建什么效果,然后生成一个完整的 HTML 文件,使用手势(通过摄像头)或鼠标来控制屏幕上的物体。
gesture-control/
├── SKILL.md # 本文件
├── assets/ # 资源文件
│ ├── gesture-scene.js # 核心框架
│ └── template.html # HTML 模板
├── references/ # 参考示例
│ ├── particles.html # 粒子拖尾
│ ├── butterfly.html # 蝴蝶飞舞
│ └── ripple.html # 水波纹
├── scripts/ # 脚本文件
└── index.html # 示例列表页
此 skill 需要 gesture-scene.js 文件可用。它位于 assets/gesture-scene.js。
生成 HTML 文件时:
assets/gesture-scene.js 复制到 HTML 文件所在目录./gesture-scene.js示例:如果输出到 ./effects/star.html,则将 assets/gesture-scene.js 复制到 ./effects/gesture-scene.js,HTML 中使用 ./gesture-scene.js
模板文件位于:assets/template.html
生成 HTML 文件时参考此模板结构。模板使用 {占位符} 语法:
| 占位符 | 说明 | 示例 |
|---|---|---|
{效果名称} | 用户想要的效果 | 星星闪烁 |
{物体类名} | JavaScript 类名 | Star |
{每帧生成数量} | spawnRate 参数 | 2 |
{爆发数量} | burstRate 参数 | 8 |
{物体上限} | maxObjects 参数 | 500 |
{背景色} | HSB 背景色数组 | 220, 50, 5, 15 |
{速度缩放} | handVelocityScale 参数 | 1.5 |
注意:生成的 HTML 文件直接引用 ./gesture-scene.js,无需计算相对路径。
示例实现在 references/ 目录:
particles.html - 粒子拖尾效果butterfly.html - 蝴蝶飞舞效果ripple.html - 水波纹效果设计新效果时可参考这些示例。
询问用户:
你想要生成什么手势控制效果?
例如:
- 星星闪烁
- 烟花绽放
- 雨滴飘落
- 萤火虫飞舞
- 墨水扩散
- 雪花飘落
- 火焰燃烧
- 或者任何你想象的效果...
等待用户回复。他们可能会说"星星"或"我想做烟花"或"萤火虫"。
根据用户需求,设计一个实现以下接口的物体类:
class MyObject {
constructor(x, y, vx, vy) {
// 初始化位置、速度、外观
// x, y: 生成位置(来自手指/鼠标)
// vx, vy: 初始速度(来自移动方向)
}
update() {
// 更新位置、动画、生命周期
// 每帧调用
}
draw() {
// 使用 p5.js 函数渲染物体
// 使用 noStroke(), fill(), ellipse(), rect() 等
}
isDead() {
// 返回 true 表示物体应该被移除
// 通常基于透明度或生命周期
}
}
设计指南:
常见模式:
| 效果 | 关键属性 | 物理效果 |
|---|---|---|
| 星星 | 闪烁、发光、多层 | 轻微上浮 |
| 烟花 | 爆炸成粒子、轨迹 | 重力、阻力 |
| 雨滴 | 细长形状、水花 | 快速下落 |
| 萤火虫 | 发光、随机漂浮 | 轻柔漂浮、无重力 |
| 墨水 | 扩散、混合、有机形状 | 缓慢扩散 |
| 雪花 | 旋转、飘落、独特形状 | 缓慢飘落、风 |
| 火焰 | 闪烁、颜色渐变、上升 | 向上、湍流 |
| 蝴蝶 | 翅膀扇动、随机路径 | 轻柔漂浮 |
| 水波纹 | 同心圆、扩散 | 径向扩散 |
| 粒子 | 简单圆点、轨迹 | 重力、阻力 |
使用以下模板结构:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{效果名称} · 手势控制</title>
</head>
<body>
<script src="https://cdn.jsdelivr.net/npm/p5@1.9.4/lib/p5.min.js"></script>
<script src="./gesture-scene.js"></script>
<script>
// ── {效果名称}类 ──
class {ClassName} {
constructor(x, y, vx, vy) {
// ... 实现
}
update() {
// ... 实现
}
draw() {
// ... 实现
}
isDead() {
// ... 实现
}
}
// ── 创建场景 ──
const scene = new GestureScene({
title: '{效果名称} · 手势控制',
create: (x, y, vx, vy) => new {ClassName}(x, y, vx, vy),
spawnRate: {rate}, // 每帧生成数量 (1-5)
burstRate: {burst}, // 爆发数量 (3-15)
maxObjects: {max}, // 物体上限 (100-5000)
background: [{bg}], // 背景色 [h, s, b, a]
handVelocityScale: {scale}, // 手势速度缩放
});
</script>
</body>
</html>
配置指南:
| 效果类型 | spawnRate | burstRate | maxObjects | handVelocityScale |
|---|---|---|---|---|
| 单个大物体(蝴蝶、花) | 1 | 3-5 | 100-200 | 1.0-1.5 |
| 中等密度(萤火虫、雪花) | 2-3 | 5-8 | 300-500 | 1.2-1.8 |
| 高密度(粒子、雨滴) | 3-5 | 10-15 | 1000-4000 | 1.5-2.0 |
| 波纹类(水波纹、声波) | 1 | 2-3 | 50-100 | 0.8-1.2 |
默认保存在当前目录:./gesture-{name}.html
assets/gesture-scene.js 复制到 HTML 文件所在目录./gesture-scene.js)示例输出:
✅ 手势控制场景已生成!
文件: ./gesture-star.html
效果: 星星闪烁
功能: 手指/鼠标移动产生闪烁星星,带有发光和淡出效果
使用方法:
1. 在浏览器中打开 gesture-star.html
2. 移动鼠标控制星星生成
3. 点击右上角按钮开启摄像头,用手势控制
已包含:
- 鼠标/手势自动切换
- 摄像头开关 UI
- 状态提示
- 物体生命周期管理
文件清单:
- gesture-star.html (主文件)
- gesture-scene.js (核心框架,已复制到当前目录)
用户说:"星星"
生成代码:
class Star {
constructor(x, y, vx, vy) {
this.x = x;
this.y = y;
this.vx = vx * 0.3 + random(-0.5, 0.5);
this.vy = vy * 0.3 + random(-0.5, 0.5);
// 星星属性
this.size = random(3, 8);
this.points = floor(random(4, 7)); // 4-6角星
this.innerRatio = random(0.3, 0.5);
// 旋转
this.angle = random(TWO_PI);
this.rotSpeed = random(-0.05, 0.05);
// 闪烁
this.twinklePhase = random(TWO_PI);
this.twinkleSpeed = random(0.05, 0.15);
// 颜色
this.hue = random(40, 60); // 金黄色
this.sat = random(20, 60);
this.bri = random(80, 100);
// 生命周期
this.alpha = 100;
this.fade = random(0.5, 1.5);
// 发光
this.glowSize = this.size * 3;
}
update() {
// 移动
this.x += this.vx;
this.y += this.vy;
this.vx *= 0.98;
this.vy *= 0.98;
this.vy -= 0.02; // 轻微上浮
// 旋转
this.angle += this.rotSpeed;
// 闪烁
this.twinklePhase += this.twinkleSpeed;
// 生命周期
this.alpha -= this.fade;
}
draw() {
const a = max(this.alpha, 0);
const twinkle = sin(this.twinklePhase) * 0.3 + 0.7;
const currentAlpha = a * twinkle;
push();
translate(this.x, this.y);
rotate(this.angle);
// 发光效果
noStroke();
fill(this.hue, this.sat * 0.5, this.bri, currentAlpha * 0.15);
ellipse(0, 0, this.glowSize * 2);
ellipse(0, 0, this.glowSize * 1.5);
// 绘制星形
fill(this.hue, this.sat, this.bri, currentAlpha);
beginShape();
for (let i = 0; i < this.points * 2; i++) {
const r = i % 2 === 0 ? this.size : this.size * this.innerRatio;
const ang = (i * PI) / this.points - HALF_PI;
vertex(cos(ang) * r, sin(ang) * r);
}
endShape(CLOSE);
// 中心亮点
fill(0, 0, 100, currentAlpha * 0.8);
ellipse(0, 0, this.size * 0.4);
pop();
}
isDead() {
return this.alpha <= 0;
}
}
配置:
const scene = new GestureScene({
title: '星星闪烁 · 手势控制',
create: (x, y, vx, vy) => new Star(x, y, vx, vy),
spawnRate: 2,
burstRate: 8,
maxObjects: 500,
background: [220, 50, 5, 15],
handVelocityScale: 1.5,
});
用户说:"烟花"
生成代码:
class Firework {
constructor(x, y, vx, vy) {
this.x = x;
this.y = y;
// 烟花阶段: 上升 or 爆炸
this.phase = 'rise';
this.vx = vx * 0.2;
this.vy = -random(3, 6); // 向上
// 爆炸参数
this.explosionParticles = [];
this.explosionHue = random(0, 360);
// 上升轨迹
this.trail = [];
// 生命周期
this.alpha = 100;
this.fade = 0.3;
}
update() {
if (this.phase === 'rise') {
// 上升阶段
this.trail.push({ x: this.x, y: this.y, alpha: 80 });
if (this.trail.length > 10) this.trail.shift();
this.x += this.vx;
this.y += this.vy;
this.vy += 0.05; // 重力
// 速度很慢时爆炸
if (this.vy > -1) {
this.explode();
this.phase = 'explode';
}
} else {
// 爆炸阶段
for (let p of this.explosionParticles) {
p.x += p.vx;
p.y += p.vy;
p.vy += 0.03; // 重力
p.vx *= 0.98; // 阻力
p.vy *= 0.98;
p.alpha -= p.fade;
}
// 移除死亡粒子
this.explosionParticles = this.explosionParticles.filter(p => p.alpha > 0);
if (this.explosionParticles.length === 0) {
this.alpha = 0;
}
}
}
explode() {
const count = floor(random(30, 50));
for (let i = 0; i < count; i++) {
const angle = random(TWO_PI);
const speed = random(1, 4);
this.explosionParticles.push({
x: this.x,
y: this.y,
vx: cos(angle) * speed,
vy: sin(angle) * speed,
alpha: 100,
fade: random(0.5, 1.5),
size: random(2, 5),
hue: this.explosionHue + random(-20, 20),
});
}
}
draw() {
if (this.phase === 'rise') {
// 绘制上升轨迹
noStroke();
for (let i = 0; i < this.trail.length; i++) {
const t = this.trail[i];
const a = map(i, 0, this.trail.length, 20, 80);
fill(this.explosionHue, 80, 100, a);
ellipse(t.x, t.y, 3);
}
// 绘制头部
fill(this.explosionHue, 80, 100, 100);
ellipse(this.x, this.y, 5);
} else {
// 绘制爆炸粒子
noStroke();
for (let p of this.explosionParticles) {
fill(p.hue, 80, 100, p.alpha);
ellipse(p.x, p.y, p.size);
}
}
}
isDead() {
return this.alpha <= 0;
}
}
配置:
const scene = new GestureScene({
title: '烟花绽放 · 手势控制',
create: (x, y, vx, vy) => new Firework(x, y, vx, vy),
spawnRate: 1,
burstRate: 3,
maxObjects: 100,
background: [240, 60, 3, 25],
handVelocityScale: 1.0,
});
当摄像头不可用或用户拒绝授权时,GestureScene 自动降级到纯鼠标模式:
无需额外代码处理,框架自动处理降级。
如果 MediaPipe 库加载失败(网络问题等):
| 设备类型 | maxObjects | spawnRate | burstRate | 说明 |
|---|---|---|---|---|
| 高端 PC | 3000-5000 | 3-5 | 10-15 | 独显、16GB+ 内存 |
| 中端笔记本 | 1000-2000 | 2-3 | 8-10 | 集显、8GB 内存 |
| 低端设备 | 300-800 | 1-2 | 5-8 | 老旧设备、移动端 |
| 移动浏览器 | 200-500 | 1-2 | 3-5 | iOS/Android 浏览器 |
| 效果类型 | spawnRate | burstRate | maxObjects | handVelocityScale |
|---|---|---|---|---|
| 单个大物体(蝴蝶、花) | 1 | 3-5 | 100-200 | 1.0-1.5 |
| 中等密度(萤火虫、雪花) | 2-3 | 5-8 | 300-500 | 1.2-1.8 |
| 高密度(粒子、雨滴) | 3-5 | 10-15 | 1000-4000 | 1.5-2.0 |
| 波纹类(水波纹、声波) | 1 | 2-3 | 50-100 | 0.8-1.2 |
maxObjects 是最直接的方式ellipse() 代替 bezier(),减少 beginShape() 顶点noStroke():减少渲染开销效果太慢:
maxObjectsdraw() 方法效果不显示:
isDead() 逻辑alpha 已初始化draw() 使用正确的 alpha移动感觉不对:
handVelocityScalevelocitySmoothingspawnRate 和 burstRate摄像头无法启动: