Shredder Theater(シュレッダー・シアター) は何をしますか?
「ファイルの削除」を美しい演出に変える:ドラッグ&ドロップ → 裁断 → 一言で締めくくる。
出力は常に1つのHTMLファイル:ダブルクリックで開け、オフラインで動作し、スマートフォンでも崩れません。
収集する入力項目
呼び出し前に次の4項目を確認し、デフォルト値で問題なければそれを使い、情報を揃えるために繰り返し質問しないこと:
| 項目 | デフォルト | 説明 |
|---|---|---|
| 締めのメッセージ | references/message-templates.md からシチュエーションに合ったものを1つ選ぶ | 唯一必須の項目 |
| 色調 | references/visual-language.md から1セット選ぶ | ユーザーからスタイルの指定があればそれに従う |
| 操作形態 | 実際のファイルドラッグ&ドロップ + 「デモ削除」ボタン | ボタンはデモ用のセーフティパス |
| 画面サイズ | レスポンシブシングルページ、スマートフォン縦画面優先 | clamp() + dvh を使用 |
- 締めのメッセージはページ全体の感情の着地点であり、具体的な一言でなければならない。「削除しました」「操作成功」といったシステムメッセージは避けること。
- ユーザーが対象者を指定した場合(「母に作る」「元彼に送る」など)、その呼称を使うこと。勝手に「主人」などに変更しない。
- ユーザーがメッセージを指定せず「適当でいい」と言った場合、シチュエーションに合った最も短いものを選び、長文は避ける。
手順
-
メッセージを先に決め、次にビジュアルを決める メッセージが感情のトーンを決定し、ビジュアルはそれに従う。逆の順序で作ると「見た目は良いが感情に響かない」ページになる。
references/message-templates.mdからメッセージを選び、references/visual-language.mdから配色を選ぶ。両方の選択理由をreferences/visual-language.mdに記録すること。なぜなら、締めの文と背景の明暗は互いに引き立て合う必要があるから。 -
5階層構造を構築する(単一HTMLファイル、CSSとJSはインライン、外部リソースは参照しない)
- 舞台層:背景。暗色系はビネット効果+ノイズ、明色系はソフトなグラデーション。ベタ塗りの領域を広くとらないこと。
- シュレッダー層:CSSで描画する(本体パネル、インジケーター、用紙投入口、ローラー)。画像素材や絵文字をメインビジュアルに使わない。
- トレイ層:処理待ちファイルリスト。実際のファイルをドラッグ&ドロップした場合、
file.nameのみを表示し、ファイル内容は読み取らない。 画像ファイルについては、URL.createObjectURL()でサムネイルを表示する——「その画像が裁断されるのを目の当たりにする」ことが感情の高まりとなる; 裁断後はrevokeObjectURL()でメモリを解放し、サムネイルはローカルのままにする。 - エフェクト層:紙くずパーティクル。紙が投入口に吸い込まれた後、投入口の下端から短冊状の紙くずが噴出し、それぞれが独立したランダムな速度・回転・落下遅延でアニメーションする。
- メッセージ層:最後に表示される締めの言葉。
-
音声はWeb Audioでリアルタイム合成し、オーディオファイルをバンドルしない
- 機械の唸り:約70Hzのノコギリ波+ローパスフィルタ、ホワイトノイズで紙を破るベースノイズ
- 裁断音:バンドパスフィルタをかけたホワイトノイズの短パルス、紙くず1つにつき1回、30~60msのランダム間隔
- 締め:sine波の「チン」という音(880→1320Hzの指数関数的減衰)
- ブラウザの自動再生ポリシーにより最初の再生がブロックされるため、最初のクリックでオーディオコンテキストを同時に再開させる必要がある;ページ上に「クリックして開始」の案内を入れること。
-
アニメーションには
transform/opacityのみを使い、レイアウトプロパティは変更しない 紙の吸い込み:scaleYで圧縮 +translateYで投入口へ + わずかにrotate、約300ms。 本体の振動:高周波・小振幅のtranslateXによる揺れ、steps()で機械的なカクつきを表現。 メッセージ表示:fade +scale(0.96 → 1)+ 文字間隔が広がってから元に戻る、約600ms ease-out。 紙くず:translateYで落下 +rotateで回転 + 透明度が減衰、着地後に積み重なる。 -
自己チェックを行ってから納品する(この手順は省略不可) 生成したファイルをブラウザで開き、以下を1つずつ確認する:
- クリックすると音が出る(ミュートではない)
- 紙が本当に吸い込まれ、紙くずが本当に落ちる
- メッセージは裁断が終わってから表示される
- 375px幅のスマートフォンビューポートで横スクロールが発生しない、メッセージがはみ出さない、日本語のタイトルが途中で改行されない
- 明色テーマで本体と背景のコントラストが十分にある(マシンが背景に「浮いている」のではなく「立っている」ように見える)
- ブラウザのコンソールにエラーがなく、未キャッチのPromise拒否(
Uncaught (in promise))がない(これがあると演出が途中で無音のまま停止する) 1つでも満たさない場合は修正してから納品し、中途半端なものをユーザーに渡さないこと。
演出フローを
async functionで構成する場合、呼び出し箇所をtry/catchで囲む:エラーが発生した場合でも、少なくとも締めのメッセージを表示し、ページが「何も起こらなかった」状態で止まらないようにする。 -
納品 HTMLファイルの絶対パスを伝え、ページの使い方(ファイルをドラッグ&ドロップするか、デモボタンをクリックするか)と締めのメッセージを一言添える。 スクリーンショットを撮っていた場合は、それも一緒に添付する。
出力契約
- 1つの
.htmlファイル、自己完結型:外部CSS/JS/フォント/画像への依存なし、オフラインで動作 - メッセージと配色はファイル上部に記述し、後から簡単に変更できるようにする
- 最低2つのパスをサポート:実際のファイルをドラッグ&ドロップするパス、ボタンをクリックするパス
- README、設定ファイル、ビルドスクリプトは生成しない
障害対応
- ユーザーが本当にファイルを削除したい場合:このスキルは演出のみを行い、実際のファイル操作は一切行わない。「このページはシミュレーションであり、ファイルはそのまま残っています」と明確に伝え、削除処理を実行してはならない。
- ブラウザが音を再生しない場合:自動再生ポリシーによるブロック。ユーザーが先にページをクリックする必要がある;ページ自体に「クリックして開始」の案内を入れておく。
- 演出が途中で止まり、何も起こらなくなる場合:ほとんどの場合、
async演出関数でエラーが発生し、未キャッチのPromise拒否になっている。 入口にtry/catchを追加し、エラーが発生した場合は締めのメッセージとエラー案内を表示し、ページが途中で止まらないようにする。 - ファイル名が長くてレイアウトが崩れる場合:ファイル名は
text-overflow: ellipsisで切り詰め、完全な名前はtitle属性に格納する。 - モバイルでオーバーフローする場合:
dvhはモバイルブラウザでvhより正確;長いメッセージはclamp()でフォントサイズを制御する。 - 暗い背景の文字が見づらい場合:本文と背景のコントラスト比は最低4.5:1に保ち、暗い背景にはクリーム色の文字、明るい背景には墨色の文字を使用する。
使用例
入力:「シュレッダーのページを作って、削除が終わったら『処理が完了しました』と表示してほしい」
出力:単一HTMLファイル。暗めの暖色スタンドライト配色、上部中央にCSSで描いたシュレッダー、中央にファイルトレイ(実際のファイルをドラッグ可能)、下部にデモボタン。クリックすると紙が投入口に吸い込まれ、本体が振動し、Web Audioで合成した裁断音が鳴り、紙くずが中段から落ちて積もり、600ms後に「処理が完了しました」がフェードイン表示され、軽やかな「チン」という音が鳴る。
入力:「もっと辛口で、元彼からのファイルを全部裁断してほしい」
出力:同上の構造だが、配色をコールドグレーの産業風に変更、メッセージは皮肉な短い文(例:「完全に消去しました。復元はできません」)、裁断音はより重く、本体の振動も大きい。
Windows(win32)プラットフォームに関する注意事項
- ファイルを開く:
start "" "<パス>\file.html"(macOS/Linux:open "<パス>/file.html") - 生成ファイルのパスはバックスラッシュを安全に記述するか、Python/Nodeで
path.joinを使用すること;SKILL.md本文に/tmp/をハードコードしない。 - macOS/Linuxでのドラッグ&ドロップは
DataTransferで対応可能、Windowsブラウザでも同様にサポート。何らかのブラウザでドラッグ&ドロップが無効になっている場合は、デモボタンのみを唯一の操作パスとし、エラーを発生させないこと。