Communitygithub.com

undefine-org/使用体験からUXへ

アプリ使用中に得たバグ報告や摩擦点(「なぜこれがここにある?」)を、製品が確立すべき体験に変換し、構造上の原因を見つけて修正し、Beam Lispのブラウザ名前空間で実際のブラウザ上で自分で試し、モデルのやり取りも収めた動画シナリオとして保存します。Othmanがアプリ使用報告を送ってきたとき、手動テストや「自分で使ってみて」と依頼されたとき、機能を動画でドキュメント化したいときに使用します。

使用体験からUXへ とは?

このスキルは、アプリケーションの使用中に発生した問題(バグ、摩擦、UX上の疑問)を報告として受け取り、それを「製品が実現すべき体験」に変換するためのワークフローを提供します。報告された症状(例:「クライアントが会話の途中で消える」)から出発し、その背後にある体験を一文で書き起こし、構造的な原因を特定し、コードレベルで修正します。修正後は、Beam Lispのブラウザ名前空間を使って実際のブラウザ上で手動テストを行い、その操作をそのまま撮影可能なシナリオに変換します。さらに、モデル(AIエージェント)の行動をテープに記録し、再現可能な形で保存することで、コストゼロで数秒の動画として何度でも再生できます。このスキルは、Claude CodeやBeam Lispのような開発ツール環境で動作し、特にOthmanのようなプロダクトオーナーからのフィードバックを迅速に検証・記録・改善するサイクルを実現します。

対応~Claude Code~Codex CLI✓Cursor
npx skills add https://github.com/undefine-org/enchanted-skills/tree/main/ux-from-use

お気に入りのAIに質問する

このエージェントスキルを事前に読み込んだ状態で新しいチャットを開きます。

ドキュメント

使用体験から体験へ

報告は症状を名付けます。作業はその背後にある体験です。「クライアントが会話が主題に移ると消える」はバグです。「会話はその主題を集める:クライアントは主題が追加されると留まる」は構築し、確認し、撮影すべきものです。まずその一文を書きなさい。症状を許容した構造を修正し、その一文を製品を使って証明しなさい。

ループ

  1. 使用を収集する。 報告書、次に実際の使用の痕跡(その人の会話、日誌、ログ、存在、触れたファイル)を読む。それらは誰も書かなかった期待を保持している(「彼らはどこにいるの?」は要約ではなくポイントそのものを期待している)。
  2. 体験を書く。 報告ごとに一文、現在形、その人の視点から、実装の言葉を使わずに。リストを保持する。それが動画のナレーションとクレームのメッセージになる。
  3. 構造的な理由を見つける。 なぜ製品がそもそもこれをできたのかを問う。通常、一つの原因が複数の報告を説明する(表示名から取得されたID;単語を共有する2つのカウント;挿入時にクラスを落とすレンダラー)。原因を修正し、それを表示した画面を修正しない。
  4. 自分で使ってみる。 ブラウザ名前空間(下記)を通じて、関連する各人物として実アプリをデスクトップ幅と電話幅で操作する。スクリーンショットを見る。コードの意図ではなく、ページが何を言っているかを数える。
  5. 保存する。 手動のステップをシナリオに変換する:アクションはイベントに、チェックはクレームに、体験文はシーンのナレーションになる。モデルのターンをテープに記録し、動画が数秒でコストゼロで再生できるようにする。
  6. 修正ではなく体験を報告する。 要約では、その人がこれから見つけるであろうことから始め、次に原因、そして動画とその再生方法を記載する。

ハウステイスト(Othmanが繰り返し要求してきたこと)

  • コピーを減らす。 状態は描画される:トーン、ウェイト、配置、リング、マーク。画面を説明する文は、その画面が間違っていることを意味する。
  • アイデアごとに一語。 用語集を保持し、それを守る:「critère」(手順に対して判断される)は決して「point」(人が決定するもの)ではない。2つのカウントが単語を共有する場合、誰かがそれらを足し合わせるだろう。
  • ものは蓄積される。 タグは積み重なる(種類、次にクライアント、次に主題)。現在のものは埋められ、他のものはアウトラインのまま残る。人がすでに見たコンテキストを決して置き換えない。
  • テキストの前に数字を描く。 履歴はチャートで開き、各系列が一つずつ、値がラベル付けされる。テキストはその下に、イベントごとに一行で配置され、要求に応じて開く。
  • すべての参照はその場所につながる。 段落番号はその段落にスクロールし、それをハイライトする。引用はその箇所を見つける。スクロールバーは、ものがどこにあるかを、その色で示す。
  • デフォルトでライブ。 フルリロードなし。一人の人が行った変更は、開いているすべてのページに即座に表示される。遅いページでの繰り返しタップは効果を繰り返してはならない:ジェスチャーはべき等である。
  • コントロールは、そのものがある場所に、 それを使用できる人にのみ表示される。読み取り専用の人は、コントロールなしで状態を見る。
  • 誰がいるかを知る。 IDとロールはすべての画面とすべてのエージェントに届く。「パートナーが確認しなければならない」とパートナーに伝えてはならない。
  • 正直なエッジ。 製品がまだ何をしていないかを率直に言う。それができない画面を指してはならない。
  • 電話幅は第一級のリーダー: 16pxのガター、水平スクロールなし(minmax(0,1fr)、1frではない)、アカウントは常にアクセス可能。
  • モックアップとナレーションは製品の言語で(Knowledgerの場合はフランス語)。

ブラウザ名前空間を使った手動テスト

Beam Lispのネイティブブラウザ(beam-lispツリー内のoptional/browser-port)は、ヘッド付きのChromiumをプライベートなヘッドレスSwayで実行し、信頼された入力と連続スクリーンキャストを提供します。これはシナリオが操作するのと同じオブジェクトであるため、手動セッションが書き直すことなくテストに成長します。簡単な確認にはagent-browserを使用してください。保存する価値のあるものにはブラウザ名前空間を使用してください。

マシンごとに一度

cd ~/projects/beam-lisp/optional/browser-port
nix develop --command cargo build --release --locked --features native-browser
nix build .#runtime-wayland --out-link ~/.local/share/bl-browser/runtime-wayland   # chromium, sway, wayvnc
command -v ffmpeg || nix profile add nixpkgs#ffmpeg

これを使用するものは bl run -p ~/projects/beam-lisp/optional/browser-port/bl … で実行します(または bl test -p …)。

プローブ:一つのファイル、一人の人物、実際の入力

templates/probe.bl が出発点です。その核心:

(ns probe (:require [browser.page :as page]))
(def rt (str (System/get_env "HOME") "/.local/share/bl-browser/runtime-wayland/bin/"))
(def p (page/open! {:executable (str (System/get_env "HOME") "/projects/beam-lisp/optional/browser-port/target/release/bl-browser-port")
                    :width 1440 :height 860
                    :launch {"profile" "/tmp/probe/profile" "runtime" "/tmp/probe/runtime"
                             "chromium" (str rt "chromium") "compositor" (str rt "sway") "vnc" (str rt "wayvnc")
                             "width" 1440 "height" 960}}))
(try
  ;; 誰が見ているか:プロキシが追加するID(ここではTailscaleヘッダー);ライブソケットにも届く
  (page/cdp! p "Network.enable" {})
  (page/cdp! p "Network.setExtraHTTPHeaders" {"headers" {"tailscale-user-login" "[email protected]" "tailscale-user-name" "timinou"}})
  (page/record! p "/tmp/probe/take.mp4" {:fps 24})          ; オプション:セッション全体を動画として
  (page/navigate! p "http://127.0.0.1:24025/a/sahel-…")
  (page/wait! p "document.documentElement.dataset.live==='1'") ; JS述語、デフォルト30秒タイムアウト
  (page/click! p ".rv-rail a.para[data-goto]")               ; 信頼されたポインター:移動、押下、解放
  (println (page/evaluate! p "scrollY"))                     ; 人が見るであろうものをページに問い合わせる
  (page/screenshot! p "/tmp/probe/after.png")                ; そしてそれを見る
  (page/stop-recording! p)
  (finally (page/close! p)))

動詞は navigate! wait! click! hover! fill! key! drag! evaluate! screenshot! record! stop-recording! show-cursor! cdp! です。cdp! はChromiumが提供する他のすべてのもの(ビューポート、ネットワーク、クッキー、エミュレーション(電話用の Emulation.setDeviceMetricsOverride))にアクセスします。

プローブを保存する価値あるものにする習慣

  • コードではなくページに問い合わせる。 すべてのチェックは、人がそのものを見たときに true を返すJS式です:行の数、タグのテキスト、scrollY、ポインター下の要素のクラス。これらの式は変更されずにクレームになります。
  • 意味で選択する。 テストが必要な場所に安定したデータ属性をアプリに与えます(button.cell[data-person='Karim Saadi'][data-team='Associés'])、決して「5番目のボタン」ではありません。
  • 各人物になる。 各人物に対して、そのIDでページを開きます。2つのページを並べて、ライブが証明されます:一方が行動し、もう一方がリロードなしで変化します。
  • 最初のペイントと修正されたページの両方を確認する。 ライブアプリはHTMLを一度レンダリングし、その後データからパッチを適用します。バグはその差分に隠れます(挿入時にドロップされたクラス、タグ名として読まれるテキストで始まるリスト)。すべての画面にURLで一度到達し、さらにナビゲートして一度到達します。
  • 接続されただけでなく、ページがライブになるのを待つ。 ライブクライアントは、サーバーレンダリングされたページをソケットの最初のレンダリングで置き換える可能性があります。その間に入力されたテキストは失われます。テストにとっても、読み込み後すぐに入力する人にとっても同じです。アプリはそのマウント全体で入力された内容を保持し、その後ライブであることを示す必要があります(data-mounted)。テストはこのフラグを待ちます。
  • 電話幅で見る。 390pxで document.documentElement.scrollWidth === innerWidth を確認し、その後スクリーンショットを見ます。
  • 実際のデータには決して触れず、それを証明する。 アプリをデータのreflinkコピー(cp -a --reflink=auto)と予備のポートに向けます。その後、信頼する前に分離を証明します:コピー内の1つの名前を変更し(カナリア:チーム「AssociésX」)、それに対して行動し、コピーが変更され、実際のファイルのタイムスタンプが変更されていないことを確認します。書き込むプロセスの種類ごとに一度これを行います(ページハンドラー、ライブソケット、バックグラウンドジョブ)。Beam Lispでは、テストからの System/put_env はページハンドラーに到達しますが、ライブソケットには到達しません:設定されたデータフォルダーを読まないソケットはデフォルト(実際のデータ)にフォールバックします。アプリは、そのサーバーが起動するときに構成をVM全体に固定(persistent_term)し、そこから読み取る必要があります。実際のデータに触れなければならない場合は、ファイルのスナップショットを取り、行動し、差分を確認して変更のみであることを確認し、復元します。

プローブから動画へ

scenario.demo/defdemo は通常のテスト(bl test)です。ステップは一対一で対応します:

プローブシナリオ
(page/navigate! p url)(s/does :othman [:navigate url])
(page/wait! p js)(s/does :othman [:wait js])
(page/click! p sel) / hover! / fill! / key![:click sel] [:hover sel] [:fill sel text] [:key "Enter"]
目で見るための一時停止[:pause ms]
(page/evaluate! p js) が真でなければならない(s/sees :othman (fn [p _] (= true (page/evaluate! p js))) "the experience")
人物browser.film/owned-worlds 内のアクターで、開くときにIDを設定するようラップされる
ナレーションの段落(demo/scene :id {:title … :say … :capture :video} events…)

templates/feature-demo.bl は完全なファイルです:アプリデータの分離コピー、テストVM内の予備ポートで起動されたアプリ、IDを持つ記録されたワールド、音声キーがない場合のサイレントトラック、3つのシーンを持つ1つのデモ。動作例:knowledger-interface-review/apps/practice/test/features-demo.bl(5つの動画:レビュー、履歴、ピース、2人の人物間でライブ変更されたチーム、テープ上の会話)。

シーンは修正ではなく体験として書きなさい:「すべてのポイントがその場所につながる」、決して「§-リンクハンドラーを修正」ではありません。ナレーションがドキュメントです。

モデルのターンをテープに

エージェントが行うことはすべて、アプリ自身のツールドアを通るべきであり、モデルの選択だけがモデルのものとなります。テープは、モデルの実行ごとに、それが行ったドア呼び出しを順序付けて、最終的な回答を保持します。キーはモデル、システムプロンプト、プロンプトのハッシュ(クロック、エポック風の数字、16進IDはマスクされます)です。

  • record:テープにあるものを再生し、ないものはモデルを実行し、それを保持します。
  • replay(デフォルト):テープにない実行はエラーターンです。リプレイは決して静かにモデルにフォールバックしません。
  • リプレイは同じドアを通じて同じ呼び出しをペース配分して行い、製品が再び作業を行い、画面に表示されるようにします。数秒で無料で。

プロンプトに到達するすべてのもの(会社名、日付があれば)をテストデータに固定するか、キーがずれます。テープをコミットします。リファレンス実装:apps/practice/src/practice/cassette.bl と conversation.bl 内の2つのフック(ターンとドア)。

実行とレンダリング

bl test -p ~/projects/beam-lisp/optional/browser-port/bl app/test/features-demo.bl             # リプレイ、証明、キャプチャ
DEMO_RECORD=1 bl test -p …                       # 不足しているモデルターンをテープに記録(モデル資格情報が必要)
BL_DEMO_EXPORT=1 bl test -p …                    # 動画ごとにMP4 + 字幕 + チャプターもレンダリング

各動画は、そのフィクスチャ内で最後のテイクをクリアします。なぜなら、録画は決して上書きしないからです。各ナレーションは2つの字幕行(約130文字)以内に収めてください。さもないとレンダラーは拒否します。負荷がかかったマシンはスクリーンキャストエンコーダーを飢えさせる可能性があります:frames/recordings.json を確認し、encodedFrames が秒数×fps程度であることを確認し、テイクが短い場合は再実行します。

レンダリング(scenario.film/export!)にはPython 3とlibass付きのFFmpegが必要です。DEEPGRAM_API_KEY が設定されている場合、ナレーションは音声で読み上げられます。そうでない場合、各シーンは字幕が読まれるのにかかる時間と同じ長さのサイレントトラックを取得します。音声キーが存在することを決して前提にしないでください。動画は (scenario.demo/serve! dir {:port 4163}) でループバック上でブラウズするか、work serve で公開します。

完了と言う前に

  • 報告された各項目には、その体験文、原因、および実際のブラウザで関連する各人物としてそれを証明するクレームがあります。
  • デスクトップと電話幅の両方が、アサートだけでなくスクリーンショットで確認されています。
  • 触れたすべての画面について、最初のペイントとパッチ適用後のページの両方がチェックされています。
  • ライブ動作は、必要に応じて2人の人物で証明されています。
  • テストによって実際のデータは変更されていません。触れたものは復元され、差分が表示されています。
  • 動画はネットワークなしでテープから再生されます。テープとシナリオはコミットされ、レンダリングはコミットされません。
  • 要約は、その人が今見つけるであろうことから始まります。

Individual skills in this repo

This repo contains 1 individual skill — each has its own dedicated page.

関連スキル