Install any skill in seconds. Free to start, no credit card required.
Get Started Free →微信小游戏开发技术限制与最佳实践指南,帮助 Claude Code 在开发微信小游戏时遵循正确的 API 和技术规范。
.claude/skills/itamarzand88-weixin-game/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-11 | ✗→✓ | ▲ Improved | 338% | 0% |
| case-20 | ✗→✓ | ▲ Improved | 178% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 466% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 587% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 196% | 0% |
<!-- source: weixin-minigame-dev — https://raw.githubusercontent.com/wukaikailive/weixin-game-skill/main/skill.md -->
指导 Claude Code 在开发微信小游戏时遵循技术限制和实现规范。
TRIGGER when:
wx. API(如 wx.createCanvas、wx.onTouchStart 等)game.json 或 project.config.json(微信小游戏配置文件)DO NOT trigger when:
微信小游戏运行在 JavaScriptCore/V8 引擎中,不是浏览器环境:
| 特性 | 浏览器 | 微信小游戏 | |------|--------|-----------| | 全局对象 | window | globalThis | | DOM | document.* | 不支持 | | Canvas 创建 | document.createElement('canvas') | wx.createCanvas() | | 图片加载 | new Image() | wx.createImage() | | 存储 | localStorage | wx.setStorageSync() | | 音频 | new Audio() | wx.createInnerAudioContext() | | 网络 | fetch() / XMLHttpRequest | wx.request() |
主包限制: 4MB
分包总限制: 20MB
单分包限制: 2MB(建议不超过 1.5MB)应对策略:
subpackages 配置)javascript// ❌ 不支持的 API ctx.roundRect() // 需手动实现圆角矩形 ctx.toDataURL() // 部分限制 ctx.getImageData() // 性能敏感 // ✅ 手动实现圆角矩形 function drawRoundRect(ctx, x, y, w, h, r) { ctx.beginPath() ctx.moveTo(x + r, y) ctx.lineTo(x + w - r, y) ctx.quadraticCurveTo(x + w, y, x + w, y + r) ctx.lineTo(x + w, y + h - r) ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h) ctx.lineTo(x + r, y + h) ctx.quadraticCurveTo(x, y + h, x, y + h - r) ctx.lineTo(x, y + r) ctx.quadraticCurveTo(x, y, x + r, y) ctx.closePath() }
javascript// ❌ 部分格式不支持或不稳定 ctx.fillStyle = '#00d4ff40' // 带透明度的简写 hex ctx.fillStyle = 'hsl(200, 100%, 50%)' // HSL 格式 // ✅ 推荐使用 rgba ctx.fillStyle = 'rgba(0, 212, 255, 0.25)' ctx.fillStyle = '#00d4ff' // 标准 hex
javascript// 必须配置合法域名(小程序后台配置) // 仅支持 HTTPS // 请求超时默认 60 秒 // ❌ 不支持 fetch('https://api.example.com/data') // ✅ 使用 wx.request wx.request({ url: 'https://api.example.com/data', method: 'GET', success(res) { console.log(res.data) }, fail(err) { console.error(err) } }) // WebSocket 限制 wx.connectSocket({ url: 'wss://socket.example.com' // 必须是 wss })
javascript// ❌ 浏览器写法 window.gameState = {} window.myGlobal = value // ✅ 微信小游戏写法 // 方案1: 使用 globalThis globalThis.gameState = {} // 方案2: 文件顶层定义 let gameState = {} // 模块级变量 // 方案3: 创建全局管理器 // GameGlobal.js export const GameGlobal = { state: {}, config: {} }
javascript// 主 Canvas(屏幕 Canvas) const mainCanvas = wx.createCanvas() const ctx = mainCanvas.getContext('2d') // 离屏 Canvas(用于缓存、预渲染) const offCanvas = wx.createOffscreenCanvas({ type: '2d', width: 512, height: 512 }) // 获取实际显示尺寸 const { windowWidth, windowHeight } = wx.getSystemInfoSync() mainCanvas.width = windowWidth mainCanvas.height = windowHeight
javascript// ✅ 微信小游戏图片加载 function loadImage(src) { return new Promise((resolve, reject) => { const img = wx.createImage() img.onload = () => resolve(img) img.onerror = (err) => reject(err) img.src = src // 相对路径或配置的 CDN 域名 }) } // 加载多张图片 async function loadAssets() { const assets = { player: await loadImage('images/player.png'), enemy: await loadImage('images/enemy.png'), bg: await loadImage('images/background.png') } return assets }
javascript// 微信使用全局触摸事件,不是 Canvas 上的事件 class TouchManager { constructor() { this.touches = new Map() this.callbacks = { start: [], move: [], end: [] } this.init() } init() { wx.onTouchStart(e => this.handleTouch('start', e)) wx.onTouchMove(e => this.handleTouch('move', e)) wx.onTouchEnd(e => this.handleTouch('end', e)) wx.onTouchCancel(e => this.handleTouch('end', e)) } handleTouch(type, e) { e.touches.forEach(touch => { this.callbacks[type].forEach(cb => cb(touch)) }) } on(type, callback) { this.callbacks[type].push(callback) } } // 使用 const touchManager = new TouchManager() touchManager.on('start', (touch) => { console.log('Touch at:', touch.clientX, touch.clientY) })
javascript// 音频管理器 class AudioManager { constructor() { this.sounds = new Map() this.music = null this.muted = false } // 加载音效 loadSound(name, src) { const audio = wx.createInnerAudioContext() audio.src = src this.sounds.set(name, audio) return audio } // 播放音效 playSound(name, volume = 1.0) { if (this.muted) return const audio = this.sounds.get(name) if (audio) { audio.volume = volume audio.stop() audio.play() } } // 播放背景音乐 playMusic(src, loop = true) { if (this.music) { this.music.stop() this.music.destroy() } this.music = wx.createInnerAudioContext() this.music.src = src this.music.loop = loop this.music.play() } // 销毁所有音频 destroy() { this.sounds.forEach(audio => audio.destroy()) this.sounds.clear() if (this.music) { this.music.destroy() this.music = null } } }
javascript// ✅ 微信存储 API // 同步存储 wx.setStorageSync('playerData', { level: 5, score: 1000 }) const data = wx.getStorageSync('playerData') || {} // 异步存储(推荐用于大数据) wx.setStorage({ key: 'largeData', data: largeObject, success() { console.log('Saved') }, fail(err) { console.error(err) } }) // 删除 wx.removeStorageSync('key') wx.clearStorageSync() // 清空所有
微信小游戏右上角有固定的操作菜单按钮("..."按钮),点击后显示菜单选项。必须避开此区域放置关键UI元素。
┌─────────────────────────────────┐
│ [≡] [•••] │ ← 右上角菜单按钮区域(约44px高度)
│ │
│ 安全区 (safeArea) │ ← 主要内容区域
│ │
│ │
│ │
│ _______________________________│ ← 底部安全区域(iPhone X系列手势条)
└─────────────────────────────────┘避开区域尺寸:
systemInfo.statusBarHeightjavascript// 获取安全区域信息 const systemInfo = wx.getSystemInfoSync() const { safeArea, statusBarHeight } = systemInfo // 安全区域边界 console.log('安全区域:', { top: safeArea.top, // 安全区域顶部 y 坐标 bottom: safeArea.bottom, // 安全区域底部 y 坐标 left: safeArea.left, // 安全区域左侧 x 坐标 right: safeArea.right, // 安全区域右侧 x 坐标 width: safeArea.width, // 安全区域宽度 height: safeArea.height // 安全区域高度 }) // 右上角按钮区域(保守估计) const menuButtonArea = { top: statusBarHeight, height: 44, right: systemInfo.windowWidth, width: 87 // iOS 较宽,Android 较窄 }
javascriptclass SafeAreaManager { constructor() { const systemInfo = wx.getSystemInfoSync() this.safeArea = systemInfo.safeArea this.screenWidth = systemInfo.windowWidth this.screenHeight = systemInfo.windowHeight this.statusBarHeight = systemInfo.statusBarHeight // 计算危险区域(需要避开) this.dangerAreas = { // 顶部:状态栏 + 菜单按钮 top: { y: 0, height: Math.max(this.safeArea.top, this.statusBarHeight + 44) }, // 右上角:菜单按钮 topRight: { x: this.screenWidth - 100, y: 0, width: 100, height: this.statusBarHeight + 44 }, // 底部:手势条区域(iPhone X系列) bottom: { y: this.safeArea.bottom, height: this.screenHeight - this.safeArea.bottom } } } // 检查坐标是否在安全区域 isInSafeArea(x, y, width = 0, height = 0) { const danger = this.dangerAreas // 检查是否与顶部危险区域重叠 if (y < danger.top.height) return false // 检查是否与右上角危险区域重叠 if (x + width > danger.topRight.x && y < danger.topRight.height) return false // 检查是否与底部危险区域重叠 if (y + height > danger.bottom.y) return false return true } // 获取建议的安全布局边界 getSafeBounds() { return { top: this.dangerAreas.top.height, bottom: this.safeArea.bottom, left: this.safeArea.left, right: this.safeArea.right } } // 调整元素位置到安全区域 adjustToSafeArea(x, y, width, height) { const bounds = this.getSafeBounds() // 调整 x 坐标 if (x < bounds.left) x = bounds.left if (x + width > bounds.right) x = bounds.right - width // 调整 y 坐标 if (y < bounds.top) y = bounds.top if (y + height > bounds.bottom) y = bounds.bottom - height return { x, y } } } // 使用示例 const safeArea = new SafeAreaManager() // 放置按钮时检查 const button = { x: 10, y: 10, width: 100, height: 44 } if (!safeArea.isInSafeArea(button.x, button.y, button.width, button.height)) { // 调整到安全区域 const adjusted = safeArea.adjustToSafeArea(button.x, button.y, button.width, button.height) button.x = adjusted.x button.y = adjusted.y }
javascript// ❌ 错误:按钮放在右上角菜单按钮下方 const button = { x: screenWidth - 120, y: 20 } // ✅ 正确:按钮放在安全区域内 const safeY = safeArea.top + 10 const button = { x: screenWidth - 120, y: safeY } // ❌ 错误:忽略底部手势条 const bottomButton = { y: screenHeight - 50 } // ✅ 正确:考虑底部安全区域 const safeBottomY = safeArea.bottom - 50 - 10 const bottomButton = { y: safeBottomY }
javascript// 获取设备信息 const deviceInfo = wx.getDeviceInfo() const isIPhoneX = deviceInfo.model.includes('iPhone X') || deviceInfo.model.includes('iPhone 1') // iPhone 11, 12, 13, 14, 15 系列 // iPhone X 系列特殊处理 if (isIPhoneX) { // 底部额外留白 this.bottomPadding = 34 }
javascriptclass ScreenAdapter { constructor(designWidth = 375, designHeight = 667) { this.designWidth = designWidth this.designHeight = designHeight const info = wx.getSystemInfoSync() this.screenWidth = info.windowWidth this.screenHeight = info.windowHeight this.pixelRatio = info.pixelRatio this.safeArea = info.safeArea // 计算缩放(保持宽高比) this.scale = Math.min( this.screenWidth / designWidth, this.screenHeight / designHeight ) // 计算偏移(居中) this.offsetX = (this.screenWidth - designWidth * this.scale) / 2 this.offsetY = (this.screenHeight - designHeight * this.scale) / 2 } // 屏幕坐标 -> 游戏坐标 screenToGame(x, y) { return { x: (x - this.offsetX) / this.scale, y: (y - this.offsetY) / this.scale } } // 游戏坐标 -> 屏幕坐标 gameToScreen(x, y) { return { x: x * this.scale + this.offsetX, y: y * this.scale + this.offsetY } } // 获取安全区域(避开刘海屏、底部手势条) getSafeArea() { return { top: this.safeArea.top, bottom: this.safeArea.bottom, left: this.safeArea.left, right: this.safeArea.right } } }
javascript// ❌ 每帧都清除整个画布 ctx.clearRect(0, 0, canvas.width, canvas.height) // ✅ 只清除变化区域(对于静态背景) ctx.clearRect(obj.x - 1, obj.y - 1, obj.width + 2, obj.height + 2) // ✅ 使用离屏 Canvas 缓存静态元素 const cacheCanvas = wx.createOffscreenCanvas({ width: 200, height: 200 }) const cacheCtx = cacheCanvas.getContext('2d') // 绘制一次 cacheCtx.drawImage(backgroundImg, 0, 0) // 主循环中直接绘制缓存 ctx.drawImage(cacheCanvas, 0, 0)
javascriptclass ObjectPool { constructor(createFn, initialSize = 10) { this.createFn = createFn this.pool = [] this.active = [] // 预创建对象 for (let i = 0; i < initialSize; i++) { this.pool.push(createFn()) } } get() { const obj = this.pool.pop() || this.createFn() this.active.push(obj) return obj } release(obj) { const index = this.active.indexOf(obj) if (index > -1) { this.active.splice(index, 1) this.pool.push(obj) } } releaseAll() { while (this.active.length) { this.pool.push(this.active.pop()) } } } // 使用示例:子弹池 const bulletPool = new ObjectPool(() => ({ x: 0, y: 0, active: false }), 20)
javascript// 资源预加载 class AssetLoader { constructor() { this.images = new Map() this.audios = new Map() } async loadImages(list) { const promises = list.map(item => loadImage(item.src).then(img => { this.images.set(item.name, img) return { name: item.name, img } }) ) return Promise.all(promises) } getImage(name) { return this.images.get(name) } } // 使用 const loader = new AssetLoader() await loader.loadImages([ { name: 'player', src: 'images/player.png' }, { name: 'enemy', src: 'images/enemy.png' } ])
微信小游戏的好友排行榜必须在开放数据域中实现,主域无法直接访问好友数据。
项目结构:
├── game.js # 主域入口
├── open-data-context/ # 开放数据域
│ └── index.js # 排行榜逻辑
└── game.json # 配置game.json 配置:
json{ "openDataContext": "open-data-context" }
主域与开放数据域通信:
javascript// 主域 game.js const openDataContext = wx.getOpenDataContext() // 发送消息到开放数据域 openDataContext.postMessage({ type: 'updateScore', score: 1000, level: 5 }) // 创建共享 Canvas(用于显示排行榜) const sharedCanvas = openDataContext.canvas sharedCanvas.width = 300 sharedCanvas.height = 400 // 在主 Canvas 上绘制共享 Canvas const mainCtx = mainCanvas.getContext('2d') mainCtx.drawImage(sharedCanvas, 50, 100)
开放数据域 index.js:
javascript// 接收主域消息 wx.onMessage(data => { if (data.type === 'updateScore') { // 更新用户数据到云端 wx.setUserCloudStorage({ KVDataList: [{ key: 'score', value: JSON.stringify({ score: data.score, level: data.level }) }], success() { console.log('分数上传成功') // 刷新排行榜 getFriendRanking() } }) } if (data.type === 'getRanking') { getFriendRanking() } }) // 获取好友排行榜 function getFriendRanking() { wx.getFriendCloudStorage({ keyList: ['score'], success(res) { // res.data 是好友数据数组 const sorted = res.data.sort((a, b) => { const scoreA = JSON.parse(a.KVDataList[0].value).score const scoreB = JSON.parse(b.KVDataList[0].value).score return scoreB - scoreA }) // 绘制排行榜到 Canvas drawRanking(sorted) } }) } // 绘制排行榜 function drawRanking(data) { const canvas = wx.createCanvas() const ctx = canvas.getContext('2d') ctx.fillStyle = '#fff' ctx.fillRect(0, 0, canvas.width, canvas.height) ctx.fillStyle = '#333' ctx.font = '14px Arial' data.forEach((player, index) => { const score = JSON.parse(player.KVDataList[0].value).score ctx.fillText(`${index + 1}. ${player.nickname}: ${score}`, 10, 30 + index * 25) }) }
重要限制:
wx.getFriendCloudStorage() 只能在开放数据域调用wx. API(如网络请求受限)sharedCanvas 与主域共享用于将耗时计算放到后台线程,避免阻塞主线程。
javascript// 主线程 const worker = wx.createWorker('workers/physics.js') // 发送数据 worker.postMessage({ type: 'calculate', bodies: physicsData }) // 接收结果 worker.onMessage(res => { if (res.type === 'result') { // 更新物理状态 updatePhysics(res.data) } }) // workers/physics.js worker.onMessage(data => { if (data.type === 'calculate') { // 执行耗时计算 const result = heavyPhysicsCalculation(data.bodies) // 返回结果 worker.postMessage({ type: 'result', data: result }) } })
微信小游戏对内存敏感,需要主动管理:
javascript// 监听内存警告 wx.onMemoryWarning((res) => { console.log('内存警告,级别:', res.level) // level: 0-5,越大越严重 // 清理缓存 textureCache.clear() audioCache.clear() // 释放未使用的资源 gc() }) // 主动触发垃圾回收(调试用) wx.triggerGC() // 获取内存使用情况 const performance = wx.getPerformance() const memory = performance.getEntriesByType('memory') console.log('内存使用:', memory)
内存优化建议:
javascript// 1. 及时销毁音频 const audio = wx.createInnerAudioContext() audio.src = 'sound.mp3' audio.play() audio.onEnded(() => { audio.destroy() // 播放完毕后销毁 }) // 2. 图片对象池 class ImagePool { constructor(maxSize = 20) { this.pool = new Map() this.maxSize = maxSize } get(src) { if (this.pool.has(src)) { return this.pool.get(src) } const img = wx.createImage() img.src = src if (this.pool.size >= this.maxSize) { // 移除最旧的 const firstKey = this.pool.keys().next().value this.pool.delete(firstKey) } this.pool.set(src, img) return img } } // 3. 避免内存泄漏 class GameManager { constructor() { this.listeners = [] } addListener(callback) { this.listeners.push(callback) } destroy() { // 清除所有监听器 this.listeners = [] } }
javascript// 被动分享(用户点击右上角菜单) wx.onShareAppMessage(() => { return { title: '来挑战我的高分!', imageUrl: 'images/share.png', query: 'level=5&score=1000' // 参数会传递给被分享者 } }) // 主动分享 wx.shareAppMessage({ title: '我通关了第5关!', imageUrl: 'images/share-level5.png', query: 'from=share&level=5', success() { console.log('分享成功') }, fail(err) { console.error('分享失败', err) } }) // 分享到群 wx.shareAppMessage({ title: '一起来玩!', imageUrl: 'images/share.png', toGroup: true })
javascript// 发起支付(需在小程序后台开通) wx.requestMidasPayment({ mode: 'game', env: 0, // 0: 正式环境, 1: 沙箱环境 offerId: '123456', // 商品ID currencyType: 'CNY', buyQuantity: 10, success(res) { console.log('支付成功', res) // 发放道具 }, fail(err) { console.error('支付失败', err) } })
javascript// 检查 API 是否可用 if (wx.canIUse('getDeviceInfo')) { const deviceInfo = wx.getDeviceInfo() } // 比较基础库版本 function compareVersion(v1, v2) { v1 = v1.split('.') v2 = v2.split('.') const len = Math.max(v1.length, v2.length) while (v1.length < len) v1.push('0') while (v2.length < len) v2.push('0') for (let i = 0; i < len; i++) { const num1 = parseInt(v1[i]) const num2 = parseInt(v2[i]) if (num1 > num2) return 1 if (num1 < num2) return -1 } return 0 } const systemInfo = wx.getSystemInfoSync() const baseVersion = systemInfo.SDKVersion if (compareVersion(baseVersion, '2.10.0') >= 0) { // 使用新 API } else { // 降级处理 }
window is not definedjavascript// ❌ 使用 window window.myVar = value // ✅ 使用 globalThis 或模块变量 globalThis.myVar = value
document is not definedjavascript// ❌ 使用 document const el = document.getElementById('xxx') document.createElement('canvas') // ✅ 使用微信 API const canvas = wx.createCanvas()
javascript// 检查路径是否正确 // 检查是否配置了 download 域名(网络图片) // 检查图片格式(支持 png, jpg, gif) wx.createImage() img.onerror = (e) => { console.error('Image load failed:', e) }
javascript// 用户交互后才能播放音频 // 首次播放需要在 touchstart/touchend 回调中触发 let audioInitialized = false wx.onTouchStart(() => { if (!audioInitialized) { // 初始化音频 audioInitialized = true } })
my-minigame/
├── game.json # 游戏配置
├── game.js # 入口文件
├── project.config.json # 项目配置
├── js/
│ ├── Game.js # 游戏主类
│ ├── scenes/ # 场景
│ │ ├── MenuScene.js
│ │ └── GameScene.js
│ ├── entities/ # 实体类
│ │ ├── Player.js
│ │ └── Enemy.js
│ ├── managers/ # 管理器
│ │ ├── AudioManager.js
│ │ ├── InputManager.js
│ │ └── SceneManager.js
│ └── utils/ # 工具类
│ ├── ObjectPool.js
│ └── ScreenAdapter.js
├── images/ # 图片资源
├── audio/ # 音频资源
└── subpackages/ # 分包
├── level2/
└── level3/json{ "deviceOrientation": "portrait", "showStatusBar": false, "networkTimeout": { "request": 10000, "connectSocket": 10000, "uploadFile": 10000, "downloadFile": 10000 }, "subpackages": [ { "name": "level2", "root": "subpackages/level2" }, { "name": "level3", "root": "subpackages/level3" } ], "plugins": {} }
开发微信小游戏时,Claude Code 应确保:
window、document、DOM APIwx.createCanvas() 创建 Canvaswx.createImage() 加载图片wx.createInnerAudioContext() 播放音频wx.onTouchStart/Move/End 处理触摸wx.setStorageSync/getStorageSync 存储wx.request() 进行网络请求roundRect() 等不支持的 APIrgba() 或标准 #RRGGBB 格式wx.getSystemInfoSync().safeArea 获取安全区域wx.onMemoryWarning 处理内存警告wx.canIUse() 检查 API 兼容性| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 8,125 | 10,554 | +30% | 1 | 1 | 0% | 1,849 | 10,474 | +466% | 0 | 0 | — |
case-02 | pass→pass | 5,807 | 4,787 | -18% | 1 | 1 | 0% | 1,318 | 9,055 | +587% | 0 | 0 | — |
case-03 | pass→pass | 13,941 | 8,683 | -38% | 1 | 1 | 0% | 3,420 | 10,123 | +196% | 0 | 0 | — |
case-04 | pass→pass | 7,252 | 6,609 | -9% | 1 | 1 | 0% | 1,619 | 9,366 | +479% | 0 | 0 | — |
case-05 | pass→pass | 5,495 | 5,960 | +8% | 1 | 1 | 0% | 1,279 | 9,254 | +624% | 0 | 0 | — |
case-06 | pass→pass | 9,120 | 7,913 | -13% | 1 | 1 | 0% | 1,917 | 9,772 | +410% | 0 | 0 | — |
case-07 | pass→pass | 10,341 | 6,129 | -41% | 1 | 1 | 0% | 2,205 | 9,213 | +318% | 0 | 0 | — |
case-08 | pass→pass | 6,089 | 5,208 | -14% | 1 | 1 | 0% | 1,377 | 9,091 | +560% | 0 | 0 | — |
case-09 | pass→pass | 6,717 | 7,015 | +4% | 1 | 1 | 0% | 1,387 | 9,457 | +582% | 0 | 0 | — |
case-10 | pass→pass | 8,758 | 8,517 | -3% | 1 | 1 | 0% | 2,029 | 9,680 | +377% | 0 | 0 | — |
case-11 | fail→pass | 9,898 | 8,759 | -12% | 1 | 1 | 0% | 2,232 | 9,786 | +338% | 0 | 0 | — |
case-12 | pass→pass | 9,890 | 9,545 | -3% | 1 | 1 | 0% | 2,221 | 10,016 | +351% | 0 | 0 | — |
case-13 | pass→pass | 12,308 | 8,204 | -33% | 1 | 1 | 0% | 2,555 | 9,619 | +276% | 0 | 0 | — |
case-14 | pass→pass | 9,577 | 7,043 | -26% | 1 | 1 | 0% | 2,130 | 9,477 | +345% | 0 | 0 | — |
case-15 | pass→pass | 14,764 | 11,318 | -23% | 1 | 1 | 0% | 3,145 | 10,627 | +238% | 0 | 0 | — |
case-16 | pass→pass | 7,012 | 5,253 | -25% | 1 | 1 | 0% | 1,504 | 8,966 | +496% | 0 | 0 | — |
case-17 | pass→pass | 8,813 | 6,066 | -31% | 1 | 1 | 0% | 1,931 | 9,225 | +378% | 0 | 0 | — |
case-18 | pass→pass | 8,579 | 5,706 | -33% | 1 | 1 | 0% | 1,796 | 9,045 | +404% | 0 | 0 | — |
case-19 | pass→pass | 7,750 | 8,503 | +10% | 1 | 1 | 0% | 1,665 | 10,020 | +502% | 0 | 0 | — |
case-20 | fail→pass | 15,572 | 10,196 | -35% | 1 | 1 | 0% | 3,804 | 10,574 | +178% | 0 | 0 | — |
case-21 | pass→pass | 14,418 | 14,548 | +1% | 1 | 1 | 0% | 3,090 | 11,147 | +261% | 0 | 0 | — |
case-22 | pass→pass | 12,930 | 13,160 | +2% | 1 | 1 | 0% | 2,933 | 10,826 | +269% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.