Skills Plugins MCP Prompt Model 博客 我的中心

ui-demo

Playwrightを使用して美しいUIデモ動画を録画する。ユーザーがWebアプリのデモ、ウォークスルー、スクリーン録画、またはチュートリアル動画の作成を求める場合に使用する。可視カーソル、自然なリズム、プロフェッショナルな仕上がりのWebM動画を生成する。

DeepseekModel キュレーション済みスキル 品質 優秀 · 90 v1.0.0

取得

https://deepseekmodel.com/api/download.php?id=affaan-m-ecc-docs-ja-jp-skills-ui-demo-skill-md&format=skill
ダウンロード .skill 標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能
.skill ファイルの system_prompt フィールドの実際の内容。
name ui-demo description Playwrightを使用して美しいUIデモ動画を録画する。ユーザーがWebアプリのデモ、ウォークスルー、スクリーン録画、またはチュートリアル動画の作成を求める場合に使用する。可視カーソル、自然なリズム、プロフェッショナルな仕上がりのWebM動画を生成する。 origin ECC UI デモ動画レコーダー Playwrightの動画録画機能を使用して、注入されたカーソルオーバーレイ、自然なリズム、ナラティブフローを備えた美しいWebアプリのデモ動画を録画する。 使用場面 ユーザーが「デモ動画」「スクリーン録画」「操作デモ」または「チュートリアル」を求める場合 ユーザーが機能またはワークフローを視覚的に見せたい場合 ユーザーがドキュメント、オンボーディング、ステークホルダーへのデモのために動画が必要な場合 3フェーズのプロセス すべてのデモは 探索 -> リハーサル -> 録画 の3つのフェーズを経る。録画フェーズに直接ジャンプしない。 フェーズ 1:探索 スクリプトを書く前に、ターゲットページを探索して実際の内容を把握する。 なぜか 見たことのない内容のスクリプトは書けない。フィールドが <textarea> ではなく <input> の場合、ドロップダウンが <select> ではなくカスタムコンポーネントの場合、コメントボックスが @mentions や #tags をサポートしている場合があある。仮定は録画を静かに壊す。 方法 フローの各ページに移動し、インタラクティブな要素をダンプする: // Run this for each page in the flow BEFORE writing the demo script const fields = await page. evaluate ( () => { const els = []; document . querySelectorAll ( 'input, select, textarea, button, [contenteditable]' ). forEach ( el => { if (el. offsetParent !== null ) { els. push ({ tag : el. tagName , type : el. type || '' , name : el. name || '' , placeholder : el. placeholder || '' , text : el. textContent ?. trim (). substring ( 0 , 40 ) || '' , contentEditable : el. contentEditable === 'true' , role : el. getAttribute ( 'role' ) || '' , }); } }); return els; }); console . log ( JSON . stringify (fields, null , 2 )); 確認すべき内容 フォームフィールド : <select> 、 <input> 、カスタムドロップダウン、コンボボックスのどれか? 選択オプション :オプションの値とテキストをダンプする。プレースホルダーには value="0" または value="" が含まれることがあり、非空に見える。 Array.from(el.options).map(o => ({ value: o.value, text: o.text })) を使用する。テキストに「選択」が含まれるオプションや値が "0" のオプションをスキップする。 リッチテキスト :コメントボックスは @mentions 、 #tags 、Markdown、絵文字をサポートしているか?プレースホルダーテキストを確認する。 必須フィールド :どのフィールドがフォームの送信をブロックするか?ラベルの required 、 * を確認し、空のフォームを送信してバリデーションエラーを確認する。 動的コンテンツ :他のフィールドを入力した後にフィールドが表示されるか? ボタンラベル :正確なテキスト( "Submit" 、 "Submit Request" 、 "Send" など)。 テーブル列ヘッダー :テーブル駆動のモーダルには、各 input[type="number"] をその列ヘッダーにマッピングする。すべての数値入力が同じ意味を持つと仮定しない。 出力 スクリプトに正しいセレクターを書くために使用する、ページごとのフィールドマッピング。例: /purchase-requests/new: - 予算コード: <select>(ページの最初のドロップダウン、4オプション) - 希望納期: <input type="date"> - 背景説明: <textarea>(inputではない) - BOMテーブル: インライン編集可能なセル、span.cursor-pointer -> inputパターン - 送信: <button> テキスト="送信" /purchase-requests/N(詳細): - コメント: <input placeholder="メッセージを入力...">、@ユーザーと#PRタグに対応 - 送信: <button> テキスト="送信"(入力前は無効) フェーズ 2:リハーサル 録画せずにすべてのステップを実行する。各セレクターが解決されることを確認する。 なぜか セレクターの失敗は、デモ録画が壊れる最大の原因。リハーサルは録画を無駄にする前に問題を発見する。 方法 ensureVisible を使用する——ログを記録して大きくエラーを報告するラッパー: async function ensureVisible ( page, locator, label ) { const el = typeof locator === 'string' ? page. locator (locator). first () : locator; const visible = await el. isVisible (). catch ( () => false ); if (!visible) { const msg = `REHEARSAL FAIL: " ${label} " not found - selector: ${ typeof locator === 'string' ? locator : '(locator object)' } ` ; console . error (msg); const found = await page. evaluate ( () => { return Array . from ( document . querySelectorAll ( 'button, input, select, textarea, a' )) . filter ( el => el. offsetParent !== null ) . map ( el => ` ${el.tagName} [ ${el.type || '' } ] " ${el.textContent?.trim().substring( 0 , 30 )} "` ) . join ( '\n ' ); }); console . error ( ' Visible elements:\n ' + found); return false ; } console . log ( `REHEARSAL OK: " ${label} "` ); return true ; } リハーサルスクリプトの構造 const steps = [ { label : 'Login email field' , selector : '#email' }, { label : 'Login submit' , selector : 'button[type="submit"]' }, { label : 'New Request button' , selector : 'button:has-text("New Request")' }, { label : 'Budget Code select' , selector : 'select' }, { label : 'Delivery date' , selector : 'input[type="date"]:visible' }, { label : 'Description field' , selector : 'textarea:visible' }, { label : 'Add Item button' , selector : 'button:has-text("Add Item")' }, { label : 'Submit button' , selector : 'button:has-text("Submit")' }, ]; let allOk = true ; for ( const step of steps) { if (! await ensureVisible (page, step. selector , step. label )) { allOk = false ; } } if (!allOk) { console . error ( 'REHEARSAL FAILED - fix selectors before recording' ); process. exit ( 1 ); } console . log ( 'REHEARSAL PASSED - all selectors verified' ); リハーサルが失敗した場合 可視要素のダンプを読む。 正しいセレクターを見つける。 スクリプトを更新する。 リハーサルを再実行する。 すべてのセレクターが通過した後のみ続行する。 フェーズ 3:録画 探索とリハーサルが通過した後にのみ、録画を作成する。 録画の原則 1. ナラティブフロー 動画をストーリーとして計画する。ユーザーが指定した順序に従うか、このデフォルト順序を使用する: エントリー :ログインまたは開始点へのナビゲーション コンテキスト :周囲を確認して、視聴者がどこにいるか理解できるようにする アクション :主要なワークフローステップを実行する バリアント :設定、テーマ、ローカライゼーションなどの補助機能を表示する 結果 :結果、確認、または新しい状態を表示する 2. リズム ログイン後: 4秒 ナビゲーション後: 3秒 ボタンクリック後: 2秒 主要なステップ間: 1.5〜2秒 最終アクション後: 3秒 入力の遅延:文字ごとに 25〜40ms 3. カーソルオーバーレイ マウスの動きを追うSVGの矢印カーソルを注入する: async function injectCursor ( page ) { await page. evaluate ( () => { if ( document . getElementById ( 'demo-cursor' )) return ; const cursor = document . createElement ( 'div' ); cursor. id = 'demo-cursor' ; cursor. innerHTML = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M5 3L19 12L12 13L9 20L5 3Z" fill="white" stroke="black" stroke-width="1.5" stroke-linejoin="round"/> </svg>` ; cursor. style . cssText = ` position: fixed; z-index: 999999; pointer-events: none; width: 24px; height: 24px; transition: left 0.1s, top 0.1s; filter: drop-shadow(1px 1px 2px rgba(0,0,0,0.3)); ` ; cursor. style . left = '0px' ; cursor. style . top = '0px' ; document . body . appendChild (cursor); document . addEventListener ( 'mousemove' , ( e ) => { cursor. style . left = e. clientX + 'px' ; cursor. style . top = e. clientY + 'px' ; }); }); } オーバーレイはナビゲーション時に破棄されるため、ページナビゲーションのたびに injectCursor(page) を呼び出す。 4. マウスの動き カーソルを瞬間移動させない。クリック前にターゲットに移動する: async function moveAndClick ( page, locator, label, opts = {} ) { const { postClickDelay = 800 , ...clickOpts } = opts; const el = typeof locator === 'string' ? page. locator (locator). first () : locator; const visible = await el. isVisible (). catch ( () => false ); if (!visible) { console . error ( `WARNING: moveAndClick skipped - " ${label} " not visible` ); return false ; } try { await el. scrollIntoViewIfNeeded (); await page. waitForTimeout ( 300 ); const box = await el. boundingBox (); if (box) { await page. mouse . move (box. x + box. width / 2 , box. y + box. height / 2 , { steps : 10 }); await page. waitForTimeout ( 400 ); } await el. click (clickOpts); } catch (e) { console . error ( `WARNING: moveAndClick failed on " ${label} ": ${e.message} ` ); return false ; } await page. waitForTimeout (postClickDelay); return true ; } デバッグのために各呼び出しに説明的な label を含める。 5. 入力 瞬時に入力するのではなく、目に見えるように入力する: async function typeSlowly ( page, locator, text, label, charDelay = 35 ) { const el = typeof locator === 'string' ? page. locator (locator). first () : locator; const visible = await el. isVisible (). catch ( () => false ); if (!visible) { console . error ( `WARNING: typeSlowly skipped - " ${label} " not visible` ); return false ; } await moveAndClick (page, el, label); await el. fill ( '' ); await el. pressSequentially (text, { delay : charDelay }); await page. waitForTimeout ( 500 ); return true ; } 6. スクロール ジャンプではなくスムーズスクロールを使用する: await page. evaluate ( () => window . scrollTo ({ top : 400 , behavior : 'smooth' })); await page. waitForTimeout ( 1500 ); 7. ダッシュボードパン ダッシュボードや概要ページを表示する場合、主要な要素の上にカーソルを移動させる: async function panElements ( page, selector, maxCount = 6 ) { const elements = await page. locator (selector). all (); for ( let i = 0 ; i < Math . min (elements. length , maxCount); i++) { try { const box = await elements[i]. boundingBox (); if (box && box. y < 700 ) { await page. mouse . move (box. x + box. width / 2 , box. y + box. height / 2 , { steps : 8 }); await page. waitForTimeout ( 600 ); } } catch (e) { console . warn ( `WARNING: panElements skipped element ${i} (selector: " ${selector} "): ${e.message} ` ); } } } 8. 字幕 ビューポートの下部に字幕バーを注入する: async function injectSubtitleBar ( page ) { await page. evaluate ( () => { if ( document . getElementById ( 'demo-subtitle' )) return ; const bar = document . createElement ( 'div' ); bar. id = 'demo-subtitle' ; bar. style . cssText = ` position: fixed; bottom: 0; left: 0; right: 0; z-index: 999998; text-align: center; padding: 12px 24px; background: rgba(0, 0, 0, 0.75); color: white; font-family: -apple-system, "Segoe UI", sans-serif; font-size: 16px; font-weight: 500; letter-spacing: 0.3px; transition: opacity 0.3s; pointer-events: none; ` ; bar. textContent = '' ; bar. style . opacity = '0' ; document . body . appendChild (bar); }); } async function showSubtitle ( page, text ) { await page. evaluate ( ( t ) => { const bar = document . getElementById ( 'demo-subtitle' ); if (!bar) return ; if (t) { bar. textContent = t; bar. style . opacity = '1' ; } else { bar. style . opacity = '0' ; } }, text); if (text) await page. waitForTimeout ( 800 ); } ナビゲーションのたびに injectSubtitleBar(page) を injectCursor(page) と一緒に呼び出す。 使用パターン: await showSubtitle (page, 'Step 1 - Logging in' ); await showSubtitle (page, 'Step 2 - Dashboard overview' ); await showSubtitle (page, '' ); ガイドライン: 字幕テキストは短く、60文字以内が望ましい。 一貫性のために Step N - Action 形式を使用する。 長い一時停止でインターフェースが自己説明的な場合は字幕をクリアする。 スクリプトテンプレート 'use strict' ; const { chromium } = require ( 'playwright' ); const path = require ( 'path' ); const fs = require ( 'fs' ); const BASE_URL = process. env . QA_BASE_URL || 'http://localhost:3000' ; const VIDEO_DIR = path. join (__dirname, 'screenshots' ); const OUTPUT_NAME = 'demo-FEATURE.webm' ; const REHEARSAL = process. argv . includes ( '--rehearse' ); // Paste injectCursor, injectSubtitleBar, showSubtitle, moveAndClick, // typeSlowly, ensureVisible, and panElements here. ( async () => {
このスキルを起動するキーワード。クリックでコピーできます。

このスキルにはトリガーワードがありません。

ダウンロードした .skill に含まれるフィールド。
フィールド 説明
formatフォーマット識別子(skill/v1)
skill_idスキル固有 ID
nameスキル名
versionバージョン
description説明
categoryカテゴリ(配列)
trigger_wordsトリガーワード
tagsタグ
sourceソース
source_urlソース URL(本ページ)
exported_atエクスポート日時(ダウンロード毎)
system_promptシステムプロンプト本文
model_configモデル設定:provider / model / temperature / max_tokens / top_p
examplesサンプル
install_guide各プラットフォームの導入説明(Coze / Dify / Claude / カスタム)
同じスキルを各プラットフォーム形式で出力できます。
.skill 標準形式。system_prompt と model_config を収録し、任意の Agent で利用可能 ダウンロード
.skillpro 拡張形式。scripts / tools / dependencies / hooks を含む ダウンロード
.json 純粋な JSON 出力。system_prompt とモデル設定のみ ダウンロード
Coze frontmatter 付き Markdown。Coze へのインポート用 ダウンロード
Dify Dify DSL。アプリ作成後にそのままインポート ダウンロード

每日精选 Skill 推荐,免费送到你邮箱

输入邮箱,每天接收一个精选 AI Agent 技能推荐。完全免费,持续更新。

提交后我们会发送一封确认邮件,点击邮件里的链接才会开始收信。

完全免费,取消任意时间。我们不会发送垃圾邮件。