Skip to content

Latest commit

 

History

History
657 lines (533 loc) · 53.3 KB

File metadata and controls

657 lines (533 loc) · 53.3 KB

WebX68k

English

X68000 エミュレータ px68k-libretroemscripten ブランチ)の wasm ビルドをブラウザ上で動かす Web プレイヤーです。ROM・ システムディスクを同梱しているため、URL を開くだけで Human68k が起動します。

設計・実装の詳細は docs/DESIGN.md を参照してください。

今すぐ試す

使い方

URL パラメータ

パラメータ 意味 備考
lang UI表示言語 (ja / en) 省略時は localStorage['webx68k.lang'] → ブラウザの navigator.language(ja始まりなら ja)→ 既定 en の順で決定。ツールバーの「…」メニュー内の言語トグルボタンで切替可能(切替内容は localStorage に保存される)
bridge 1(または空文字)で MCP WebSocket ブリッジを有効化 ws://127.0.0.1:3099 へ接続する。詳細は後述の「MCP対応」参照
fd1 / fd2 FDD0 / FDD1 に挿入するディスクイメージのURL 後述
hdd HDDスロットへセットするディスクイメージのURL 後述
lib ディスクライブラリへ登録するだけのディスクイメージのURL(複数指定可) 後述
cpu 101000 の整数でCPUクロック(MHz)を、auto で∞MHz(ホスト次第)を、auto-max で∞MHz(描画を捨てて最速)を起動時のみ上書き指定 共有URLで推奨環境を再現するための一時的な上書き。設定UIには反映されるが localStorage には保存されない(リンクを開いただけで既定設定が書き換わるのを防ぐため)
ram 112 でRAM容量(MB)を起動時のみ上書き指定 共有URLで推奨環境を再現するための一時的な上書き。設定UIには反映されるが localStorage には保存されない(リンクを開いただけで既定設定が書き換わるのを防ぐため)
aspect 4:3 または native で表示縦横比を起動時のみ上書き指定 共有URLで推奨環境を再現するための一時的な上書き。トグルボタンの状態には反映されるが localStorage には保存されない(リンクを開いただけで既定設定が書き換わるのを防ぐため)
run 1 で起動前オーバーレイを出さず自動起動する
system 1 で同梱システムディスク(human302.xdf)をFDD0へ読み込む fd1 も指定されている場合は無視される(fd1 を優先)

fd1/fd2/hdd に関する注意点:

  • 指定するURLは CORSが有効なオリジンから配信されている必要があります。GitHub raw / GitHub Pages / 自前のCORS対応サーバなどはそのまま(直接fetchで)取得できます。
  • GitHubの blob URL(https://github.com/<owner>/<repo>/blob/<ref>/<path>)や raw URL(.../raw/<ref>/<path>)を指定した場合は、取得前に自動的に https://raw.githubusercontent.com/<owner>/<repo>/<ref>/<path> へ書き換えてから 直接fetchします(raw.githubusercontent.com はCORS対応済みのため、中継サービスを 経由しません)。GitHubの当該URLへの直fetchは302リダイレクトにCORSヘッダが無く失敗するため、 ブラウザのアドレスバーからコピーした blob URLをそのまま貼り付けても問題ありません。 一方 Release asset のURL(.../releases/download/<tag>/<asset>.../releases/latest/download/<asset>)は raw.githubusercontent.com から取得できないため 書き換えの対象外で、従来どおり中継サービス経由(VITE_DISK_PROXY 未設定時は直接fetch)になります。
  • Google Drive の共有リンクは直接fetchすると(CORSエラーにはならず)共有ページのHTMLが 返ってきてしまうため、公開ページでは最初から中継サービス経由で取得します。fork して 自分でホストする場合は後述の VITE_DISK_PROXY の設定が必要です(未設定のままだと 「直接取得できません」と案内されます)。
  • Dropbox の共有リンクは、URLのホスト名だけをアプリ側で自動的に置換して直接取得します (「リンクをコピー」で得た dl=0 のままのURLをそのまま貼り付けて構いません。dl=1 への 書き換えは不要です)。中継サービスが未設定でも利用できます。検証済みなのはファイル単位の 共有リンク(/scl/fi/... 形式)のみで、フォルダ共有・パスワード付きリンクは未検証です。 直接取得に失敗した場合は、中継サービスが設定されていれば従来どおりそちらへフォールバック します。
  • OneDrive(1drv.ms / onedrive.live.com / sharepoint.com)の共有リンクは 仕様上ご利用いただけません(中継を挟んでも取得できないことが確認済みです)。 Google DriveかDropboxをお使いください。
  • Google Driveをお使いの場合、共有設定が「リンクを知っている全員が閲覧可」になっている 必要があります(「制限付き」のままだとログイン画面へ転送され取得に失敗します)。また 共有リンクは省略せず全部コピーしてください(2021年以前に発行されたリンクに付く resourcekey クエリを削ってしまうと同様に取得できなくなります)。
  • 同じURLで再訪した場合は再ダウンロードせず、ブラウザに保存済みのイメージ(ゲスト側で 書き込んだ内容も含む)から復帰します。
  • URL先が ZIPまたはLZHアーカイブの場合、ドロップ時と同様に展開されます(後述)。中に ディスクイメージが1枚だけならそのまま指定スロットへ入り、複数枚ならディスクライブラリへ フォルダとしてまとめて登録され、そのグループが展開・強調表示された状態でライブラリが 自動的に開きます。
  • アーカイブが複数枚のディスクを含んでいた場合、どれで起動すべきか決められないため run=1 が指定されていても自動起動しません。
  • run=1 はブラウザの自動再生制限により、音が鳴らない状態で起動します。最初の クリックまたはキー入力で音声が有効になります。
  • hdd のイメージは起動前にスロットへ「セット」されるだけで、run=1 が無い限り 自動起動はしません。セット中(起動前)であればファイル転送から中身を編集できます。

lib に関する注意点(複数ディスク入りの共有リンク用):

  • ?lib=<url> の形式で、&lib=<url2> のように複数回指定できます(カンマ区切りは URL自体にカンマが含まれ得るため非対応)。
  • fd1/fd2/hdd と異なり、種別(FD/HDD)を問わず登録できます。HDDイメージと FDイメージが混在したZIPもそのまま登録できます(スロットへ挿入する時点で通常どおり 種別チェックが行われます)。
  • 枚数にかかわらずスロットへは自動挿入せず、必ずディスクライブラリを開きます (共有リンクを開いた側がそこから使うディスクを選ぶ、という用途のため)。
  • lib が指定されている場合、run=1 が指定されていても自動起動しません。
  • fd1/fd2/hdd と併用した場合は、それらのスロット処理が先に行われてから lib が 処理されます。
  • URLの取得・再訪時の復帰・アーカイブ展開のルールは fd1/fd2/hdd と同じです (CORS必須、同じURLの再訪では再ダウンロードしない、ZIP/LZHは自動展開)。

ツールバー

常設のボタンは6つ: ポーズ・フルスクリーン・仮想キーボード・スクリーンショット・速度変更・ リセットです。それ以外はすべて「…」ボタンの中に移動しました。メニューは2階層で、グループは 「表示」(4:3表示切替)・「入力」(マウスキャプチャ/再同期・ジョイスティック設定)・ 「ディスク」(ディスクライブラリ・ファイル転送)・「ステート」(保存/復元)の4つ、加えて グループに属さない「設定」「ヘルプ」「言語」がその下に直接並びます。画面幅640px以上では グループを開くと親メニューを開いたまま右側にカスケード表示され(画面右端では左側に反転)、 それ未満の幅では同じメニュー内で差し替え、「← 戻る」で戻る形になります。

画面幅640px未満(スマホ幅)では「速度変更」も常設から外れ、「…」メニューの先頭に単独行として 入ります(バーチャルパッド表示時に幅が足りず、ツールバーが2段に折り返すのを防ぐため)。速度は 表示/入力/ディスク/ステートのどのグループにも属さないため他の項目とはグループ化しません。 行のラベルには現在の倍率が表示され、有効時はチェックマークが付きます。

誤操作時の被害が大きい「リセット」だけはツールバーの右端に離して置いてあり、頻繁に押す 他の操作(ポーズ等)と指1本ぶんの間隔があります。

「ポーズ」を押すと実行を一時停止し、画面に半透明の「ポーズ中」オーバーレイが出ます。 再開は必ずオーバーレイ中央の再生ボタンから行います(誤操作防止のため、オーバーレイの 余白クリックでは再開しません)。ポーズ中も音声は停止せず、供給が止まったぶんは 自然にフェードアウトして無音になり、再開時はフェードインします。ポーズ状態はリロードでは 保持されません(ページを再読み込みすると解除されます)。

「リセット」はCPUだけのリセットではなく、コアを丸ごと作り直すハードリセットです。 ゲストの書き込みをまず回収してからコアを破棄・再構築します。RAMサイズ・パッド種別などの コアオプションはコア起動直後の1回しか読まれないため、ソフトリセットでは設定パネルでの 変更が反映されませんでした(この問題を解消するための変更です)。なお CPU速度だけは 走行中の更新をコアへ伝えるようにしたため、現在はリセット不要で即時反映されます。ただしこの 再起動は自動で連続して行われる一連の処理のため、HDD スロットのロックが解ける瞬間を ユーザーが操作に使うことはできません(後述の「ドライブスロット」参照)。

起動前オーバーレイ

初回表示時、起動前オーバーレイが2択を表示します。

  • ディスク無しで起動 … ディスク未挿入で起動(IPL-ROM のメニューが出る)。起動前に HDD が セット済みの場合は、このボタンの文言が「セットしたディスクで起動」に変わり、そのまま セット済みの HDD で起動する
  • システムディスクで起動 … 同梱の human302.xdf を FDD0 へ挿入した状態で起動し、 そのまま Human68k が立ち上がる

音声再生の制約上クリック操作が必須なため、起動は常にこの2つのボタンのどちらかから 行います(空白部分のクリックでは起動しません)。

AudioWorklet は secure context(https または localhost)でしか使えないため、LAN の IPアドレス(http://192.168.x.x:port/)で開くと利用できません。この場合は以前のように 起動そのものが失敗するのではなく、無音で起動します(音の行き先が無いだけです)。

Web Serial / RS-232C

設定ダイアログから、X68000 の SCC チャネル A をホストのシリアルポートへ接続できます。 Chrome・Edge・Firefoxなど、Web Serial APIに対応するデスクトップブラウザとhttpsが必要です。 Android版Firefox、iOS/iPadOS上のブラウザ、およびmacOS版Safariは現在対応していません。設定方法、各OSの 注意点、Windows の com0com を使ったループバック確認は docs/WEB_SERIAL.ja.mdを参照してください。

ドラッグ&ドロップ

ファイル(ディスクイメージ・ZIP・LZH)をドロップできる場所は3か所あり、ドラッグ中は 受け付け可能な場所が枠で強調表示されます。

  • 画面領域(エミュレータ画面の上) — HDD イメージは HDD スロットへ(起動後で ロックされている場合はロック中のメッセージが出ます)。FD イメージは FDD0 へ、 FDD0 が埋まっていて FDD1 が空なら FDD1 へ入ります(2ドライブ運用の利便性のため)。 複数枚入りアーカイブはスロットへは入らず、グループとして登録したうえでディスク ライブラリを開き、どこへ入れるか選んでもらいます。
  • 各ドライブ行(FDD0 / FDD1 / HDD) — 従来どおり、そのスロットへ直接挿入されます。
  • ディスクライブラリのダイアログ — スロットへは入れず、ライブラリへの登録のみ 行います(ライブラリを開いている=これから挿入先を選ぶ、という文脈のため)。

ドライブスロット (FDD0 / FDD1 / HDD)

ツールバー下のコンソールフッターに FDD0・FDD1・HDD の3行があります。各行から ファイル挿入、ディスクライブラリからの挿入、ブランクディスク作成(FDDのみ)、 取り出し、現在のイメージのダウンロードができます。スロット行へファイルをドロップすると そのスロットへ挿入されます(他のドロップ先は上記「ドラッグ&ドロップ」を参照)。

  • FDD0/FDD1 はホットスワップ可能 — 起動中でもリセット無しで挿入・取り出しできます。
  • HDD は起動前だけ扱えます。 エミュレータのコアが実行中の HDD 挿抜に対応していないため、 起動前に HDD をドロップ/挿入した場合も起動はせず、HDD スロットへ「セット」した状態で 止まります(スロット名が斜体表示になります)。セット中はファイル転送ダイアログから 中身を編集でき、準備ができたら起動オーバーレイのボタン(HDD がセット済みなら 「セットしたディスクで起動」、未セットなら「ディスク無しで起動」に文言が変わります)で 起動します。起動後は HDD スロットの操作ボタンとファイル転送の対象一覧が無効になります。 「リセット」(→上記「ツールバー」参照)はコアを再起動しますが、その再起動も自動で 連続して行われるためロックが解ける瞬間は無く、HDD イメージを差し替えたいときは 今までどおりページを再読み込みして起動前の状態に戻してください。
  • ブランクHDD作成: HDD スロットの「ブランクHDDを作成」ボタンから、Human68k形式で パーティション分けされた FAT16 フォーマット済み 40MB イメージをその場で作成できます。 作成したイメージはディスクライブラリへ保存され、そのまま HDD スロットへセットされます。 IPL(起動コード)は持たないため単体では起動できません。FDD から Human68k を起動した上で データ用ドライブとして使う想定です(実機検証済み: システムディスクで起動すると C: として 認識され、DIR C: で「40779K Byte 使用可能」と表示されます)。
  • HDD行は既定で非表示です。 「…」メニューの「表示」グループの 「HDD(SASI)を表示」トグルで出せます(ディスクが入っていれば自動的に表示されます)。

HostFS(フォルダを直接ドライブとして見せる)

HostFSは、ブラウザで選んだ手元のフォルダを、ディスクイメージを介さずゲスト側から 1つのドライブ(例: C:)として見せる機能です。SCSI行の下にある「HostFS」行から 操作します。スクショ付きの手順は HostFS 導入ガイド を参照してください。

  1. HostFS行にあるアイコンだけの**「フォルダをつなぐ」**ボタンを押すと、 読み取り専用/書き込みも許可のどちらでつなぐか選ぶダイアログが出るので 選んでからフォルダを選ぶ。
  2. 起動したいディスク(FD/HDD)のディスクライブラリの行にある **「HostFSを組み込む」**ボタンで組み込む。
  3. 組み込んだディスクをライブラリの**「FDD0へ」**ボタンで入れる(同梱ディスクに 組み込んだ場合は、増えたコピーhuman302-hostfs.xdfを入れる。自動では 挿入されない)。
  4. 起動する(すでに起動中ならリセットする)。ページの再読み込みは不要で、 FDD0のディスクが外れてしまうため避けること。
  5. 起動後、ゲスト側で dir c: のように使う。
  • 書き込みは、つなぐときに「書き込みも許可」を選んだときだけ行えます。読み取り専用 でつないだ場合、ファイルの新規作成・上書き・削除・改名・属性変更はすべて失敗します (ゲストには「書き込み禁止です」等のDOSエラーとして表示されます)。
  • 削除・上書きはそのまま反映されます(ゴミ箱はありません)。 delで消したファイルや、 copyecho >等で上書きした内容は元に戻せません。
  • 書き込んだ内容は、ファイルを閉じたときにまとめてホスト側の実体へ反映されます (開いたまま・書き込んだままではホスト側にまだ現れません)。
  • 日時・属性(読み取り専用フラグ等)はホスト側に保存されません。_FILEDATE (ファイルの日時取得・設定)は常に失敗(-6)します。フォルダの改名(ren)も、 File System Access APIのディレクトリmove()に対応していないブラウザでは失敗します (ファイルの改名は対応環境を問わず行えます)。
  • 対応環境はChrome系のPC・Android(showDirectoryPickerが使えるブラウザ)です。 iPhone(Safari)とFirefoxでは使えません。
  • ホスト側のファイル名はHuman68kの8.3形式(名前8文字+拡張子3文字、ドットは1つまで)に 変換して見せます。次のいずれかに当てはまる名前は一覧に出ません: 拡張子が4文字以上/ 名前が18バイト超(日本語は1文字2バイト)/ドットが2つ以上/ドットで始まる/ " * + , / : ; < = > ? [ ] | のいずれかを含む/CP932で表せない文字を含む(空白は 使えます)。改行コードは変換せず、バイト列をそのまま渡します。
  • 「HostFSを組み込む」ボタンは、そのディスクのルートへHOSTFS.SYSを書き、 CONFIG.SYSDEVICE = \HOSTFS.SYSを追加します(既存のCONFIG.SYSには追記、 無ければ新規作成。同じ行が既にあれば二重には追加しません)。HDDの行、および FAT12/16として扱えるFDの行で使えます。起動すると、起動画面に 「HostFS version 1.00 (WebX68k)」「ホストのフォルダを C: に割り当てました」の ように、実際に割り当てられたドライブ名(HDDがあればD:等になることもあります)が 案内表示されます。
  • 同梱システムディスク(human302.xdf)は書き換えません。 その行でボタンを押すと、 まずライブラリへコピーを作り、そのコピーへ組み込みます。
  • 起動中のディスクには組み込めません(コアがマウントしている内容とずれるため)。
  • 接続したフォルダのハンドルはブラウザ(IndexedDB)に保存され、「再接続」で次回も使えます。
  • 覚え書き: フルパスが分からない(File System Access APIはフォルダ名しか渡さない)ため、 「つなぐ」ダイアログで任意のメモ(60文字まで)を付けられます。行に「フォルダ名 — 覚え書き」 と表示され、鉛筆アイコンから後で編集できます。
  • ドライバ未組み込みの警告: フォルダ接続済みなのにゲストのHOSTFS.SYSがまだ初期化を 知らせていないときは、行に「⚠ ゲストで HOSTFS.SYS が読み込まれていません」と出ます。
  • 表示していない名前の通知: 直近の一覧で8.3形式に変換できず外した名前があると、行に 「N件の名前は表示していません」と出ます(ツールチップに実際の名前と対象ディレクトリ)。
  • HDD(SASI)/SCSI-HDD/HostFSの3行は既定で非表示です。「…」メニューの「表示」グループにある トグルで出し入れできます(ディスクが入っている/フォルダがつながっている行は自動的に表示されます)。

ディスクライブラリ

読み込んだディスクイメージはブラウザ側のライブラリ(IndexedDB)に保存されるため、 再アップロードせずに後から好きなスロットへ挿入し直せます。

ファイル転送(ファイルマネージャ)

ツールバーの「…」メニュー(ディスクグループ)にある「ファイル転送」から、FTPクライアント風の2ペインUIでブラウザと マウント中のディスクイメージの間でファイルをやり取りできます(FAT12/16、Human68k HDD パーティション、Shift_JISファイル名、インポート時のZIP/LZH展開に対応)。HDDは起動前のみ 編集でき、編集した内容はそのままIndexedDBへ保存されるためページ再読み込み後も残ります。 起動後はHDDの行が「起動中は変更不可」の読み取り専用表示になります。FDDスロットは起動中でも 書き込めます。

ステートセーブ / ロード

ツールバーの「…」メニュー(ステートグループ)にある保存/復元で、実行中の状態(CPU・RAM・映像・音声・FDD/HDDコントローラ等) をまるごとIndexedDBへ保存・復元できます。スロットはクイックセーブの1枠のみです。 保存時と現在のディスク構成が一致しない場合は、復元前に確認を求められます。

ステートに記録されるのは「どのディスクを挿していたか」だけで、ディスクの中身は含まれません。 ディスクの中身は下記のオートセーブが別途ライブラリへ保存するため、ステートを復元しても保存時点 へは戻りません。

ディスクのオートセーブ

ゲスト(X68000側)がディスクへ書き込んだ内容は、ディスクライブラリ(IndexedDB)へ自動で書き戻します。 px68k は書き込みを FDD ならコアのメモリ上のイメージ、HDD なら FS 上のファイルにしか持たないため、 放置するとページを離れた時点で消えてしまうためです。

  • fork 側の FDD_DirtyMask(fdd.c) / SASI_Dirty(sasi.c) に書き込み専用のダーティフラグを持たせ、 core-shim.c の getter 経由で JS が毎フレーム見る。アクセスランプ用のフラグと違い毎フレーム クリアせず、ホストが保存する直前にだけ落とす(取りこぼし防止)
  • FDD の吸い出しは Eject を挟む=ゲストにはメディア交換として見えるため、アクセスランプ消灯後 1.5 秒待ってから実行する。HDD は FS のファイルを直接読むだけなので待たない(容量が大きいので 最短保存間隔だけ設ける)
  • 排出時・restartCore() 直前・visibilitychange(hidden) でも書き戻す
  • 同梱システムディスク(human302.xdf)はライブラリ先頭の固定エントリのため対象外

スクリーンショット

ツールバーの「スクリーンショット」ボタンで、現在の画面をPNG(webx68k_YYYYMMDD_HHMMSS.png) として保存できます。canvasのサイズはコアが出している実解像度に画面モード切替のたびに 追従する(handleVideoRefresh() 参照。256x256 / 512x512 / 768x512 など)ため、保存される 画像も常にその時表示中の実解像度そのままで、黒帯を切り出す処理は不要です。

エミュレーション速度変更

ツールバーの「速度変更」ボタンはON/OFFのトグルです。OFF(既定)は等倍の100%で動作し、 ONにすると設定パネルで選んだ倍率(25%/50%/75%/150%/200%/300%/400%/無制限、既定200%)で 走ります。ON中はボタンに現在の倍率がバッジ表示されます(無制限を選んだ場合は)。 リセット不要でトグル操作のその場から即時に反映され、音声もテープの早送り/スローのように ピッチが変わります(BGMも含めて速度に追従します)。設定は保存されず、起動時・リセット時は 必ずOFF(100%)から始まります。

実際に出せる速度は端末の処理能力次第です。400%は選べる上限値であって保証される速度 ではなく、設定パネルにはその時点の実測速度が表示されるため、頭打ちになっている場合は そこで分かります。

「無制限」は倍率を指定しない特別なモードで、端末の処理能力が許すかぎり速く動きます。 そのかわり2つの制約があります。音声は実時間の何倍もの速さでサンプルが出るため、既存の ピッチ変更方式(リサンプル)が成立せず、無音になります。また画面の更新は約20〜30fpsに落ちます (描画コストを毎回払うとコア実行に回せる時間が残らないため)。無制限中も設定パネルの実測 表示は有効で、実際に何%出ているかを確認できます。

マシン構成の「CPU速度」(px68k_cpuspeed)とは別物です。あちらはエミュレートされる X68000のクロックそのものを変える設定で、こちらはホスト側の実行ペースを変えるだけです。 倍率を上げてもゲスト内で測った比は変わりません(CPUもCRTCもタイマーも同率で速くなるため、 ゲストにとっての「10秒」も同じ比率で短くなる)。ベンチマークの数字を伸ばしたい、実機より 速いX68000として使いたい、という場合に動かすのは「CPU速度」のほうです。

CPU速度と ∞MHz(ホスト次第)

設定パネルの「CPU速度」は 10/16/25/33/66/100MHz と「∞MHz(ホスト次第)」 「∞MHz(描画を捨てて最速)」から選べます。変更はリセット不要で即時反映されます (以前はリセットが必要でした)。

100MHz を超える固定クロックはあえて選択肢に置いていません。実測では 100MHz でも 実測50%(チャチャベンチの所要が 11.4秒 → 23.0秒)、800MHz では実測10%(所要 約10倍)になり、 数字は伸びても待ち時間が線形に増えるだけで実用域を外れます。「このマシンで出せる最大」は ∞MHz が自動で見つけるので、固定の高クロックを選ぶ理由はほとんどありません。 それでも試したい場合は ?cpu=200 のようにURLからは 10〜1000 を指定できます

「∞MHz」はクロックを固定せず、実時間を維持できる範囲で最大のクロックへ自動的に寄せて いくモードです。1秒ごとに「直近で実際に何フレーム走れたか」を見て、追いつけていれば上げ、 遅れ始めたら下げます。限界のすぐ下に張り付く設計なので、実測表示は100%ちょうどではなく その前後を数%行き来します。落ち着く先は端末の性能と、そのときの負荷で変わります (同じ端末でも実行ごとに違います)。現在のクロックは設定パネルの実測表示に 実測 100% / CPU 63MHz のように併記されます。

実時間を維持できていても、コア実行がメインスレッドを食い尽くすと画面もUI操作も止まるため、 コア実行1フレームが実時間1フレームの8割を超えたらそれ以上は上げません。

追いつけない設定にしたときの挙動

端末の性能を超えたCPUクロック(例: 非力な端末での800MHz)を選ぶと、エミュレータは実時間に 追いつけずスローモーションで動きます。このとき画面と入力は生きたままで、ゲストだけが 遅くなります(実測: 800MHz で画面 約21fps・入力遅延 約4.6ms・ゲスト速度 実測10〜14%)。

以前は追いつけない設定にするとブラウザにイベントを配る時間が残らず、キーもツールバーの ボタンも一切効かなくなっていました。1秒間隔のタイマーすら発火しない状態だったため、 コア実行がメインスレッドを占有しすぎないよう実時間ベースの上限を入れてあります。 追いついている通常時・倍速時にはこの上限はかかりません。

∞MHz(描画を捨てて最速)

もう1段上に「∞MHz(描画を捨てて最速)」があります。画面の提示を約30fpsへ間引き、浮いた 時間をコア実行へ回したうえで、上の天井も8割から95%へ引き上げます。画面の滑らかさと 引き換えにクロックを稼ぐモードで、ベンチマークの数字を伸ばしたいときや、描画より処理速度が 欲しいときに使います。

同一ホスト(Human68kプロンプト)での実測:

モード クロック 画面更新(rAF) setTimeout(0) p90 チャチャベンチ
∞MHz 53〜61MHz 46.3 fps 34 ms 0399往復
∞MHz(描画を捨てて最速) 75〜84MHz 23.3 fps 50 ms 0485往復

天井だけを95%へ上げて提示は毎フレームのまま、という中間案も試しましたが、クロック67〜70MHz に対し rAF が 9.5fps・setTimeout(0) p90 が 140ms まで崩れました。提示を間引くほうが、 クロックも画面更新も同時に良くなります

∞MHz のあいだは速度倍率ボタンが無効になります。どちらも同じホスト時間を奪い合うため、 両方を同時に無制限にすると互いに意味を失うためです。

なお、ベンチマークで比較可能な数字を取りたい場合は固定クロックを選んでください。 ∞MHz は測定中にもクロックが動くため、結果が実行ごとにばらつきます。

仮想キーボード

ツールバーのキーボードアイコンでX68000配列の仮想キーボードを表示できます。SHIFT・CTRL・ OPT.1・OPT.2は次の通常キーを離すまで有効なワンショット、CAPS・かな・ローマ字・コード入力は再度 タップするまで表示状態を保つロックです。複数の修飾キーやキーの同時押し、長押しリピートに 対応しています。テンキーはメインパネル内の「テンキー」で必要なときだけ展開します。 かなラベルは仮想キーボード側の状態表示であり、ゲスト側と食い違った場合はかなキーを押し直すと揃います。

長押しリピートの開始時間・間隔はX68000本体のSRAM設定(SWITCH.Xで変更する項目)を読み取って 追従します。物理キーボード・仮想キーボード共通の挙動で、SWITCH.Xで設定を変更すると 起動中の画面に反映されます。実機と同じく、長押し中は押下状態を保ったままmakeだけを 繰り返し、breakは指を離したときに1回だけ送ります。

なお、SRAM(起動ドライブ・メモリ容量・キーリピート等、SWITCH.Xで設定する項目全般)は IndexedDBへ自動的に永続化されるため、ページをリロードしても設定は残ります。ただし SWITCH.Xの設定でホスト側が肩代わりしているのはキーリピートのみで、キークリック音・ キーボードLEDは未対応、メモリ容量は設定ダイアログ側の値が常に優先されます。

バーチャルパッド(オンスクリーンパッド)

スマホでゲームを遊ぶ用途向けに、ツールバーの「入力パネルを表示」ボタン(パネル表示中は キーボード/パッド/マウスのアイコンのチップでも切替可能)から、仮想キーボードの代わりにタッチ操作のバーチャルパッドを 表示できます(仮想キーボード・バーチャルトラックパッドとは排他)。方向入力はアナログスティック風(固定ベース+ノブ、 8方向スナップ)で、円の端をちょんと押すだけで方向が出ます。

各部品が何を送るかはプロファイルとして持ちます — 画面部品(スティックの各方向・ボタン) から、ジョイスティック入力またはキーボードキーへの対応表です。組み込みプロファイルは ジョイスティック(2ボタン)・カーソルキー + スペース・テンキー・ジョイスティック(6ボタン)の 4種類。6ボタンは実機のメガドライブ6ボタンパッドに合わせ、上段 X/Y/Z・下段 A/B/C で 右上がりに配置しています。

表示位置は実測値から自動で選ばれ(画面幅の決め打ちはしません)、3種類あります:

  • パネル — 縦持ちのように画面下に余白があるとき、仮想キーボードと同じ位置に帯として 置かれます。画面は縮みません。
  • 左右 — 横持ちのように画面の左右に余白があるとき、そこにスティックとボタンが 置かれ、ゲスト画面に指が被りません。
  • 重ねる — どちらの余白も足りないとき、画面に半透明で重ねて表示されます。

パッドのアイコンはパッド表示中に押すとプロファイル選択メニューが開きます。

バーチャルパッドの割当を編集する

パッドのアイコンのプロファイルメニュー末尾にある「割当を編集…」から、パッドの12個の入力元(スティック 上下左右 / A・B・C / X・Y・Z / 補助1・2)へキーまたはジョイスティックのボタンを割り当てる 編集画面が開きます。

キー割当のピッカーは仮想キーボードと同じ配列です。割り当てると次の行へ自動で進みます。 組み込みプロファイルを編集しようとすると自動で複製が作られ、組み込み自体は変わりません。

物理キーボードにジョイスティックを割り当てる

ゲームパッドを持っていない PC ユーザーが、ジョイスティック専用ソフトをキーボードで 遊べるようにする機能です。ツールバーの「…」メニュー→「入力」グループ→「キーボード割当」 から有効にします。既定では無効で、有効にするまでは通常の文字入力の邪魔をしません。

組み込みプロファイルは3種類: 矢印キー -> ジョイスティック(2ボタン) / 矢印キー -> ジョイスティック(6ボタン)(CPSF-MD 用) / 矢印キー -> テンキー。最後のものは、テンキーの 無いノートPCでテンキー専用ソフトを遊ぶ用途にも使えます。有効にすると、割り当てたキーは 通常の文字入力としては働かなくなります。「キーを追加」を押してから割り当てたい物理キーを 押すと、そのキーが入力元として登録され、ジョイスティックのボタンまたはキーボードのキーを 割り当てられます。組み込みプロファイルを編集しようとすると自動で複製が作られ、組み込み自体は 変わりません。

マウス

ツールバーの「…」メニュー(入力グループ)にある「マウスキャプチャ」、または canvas 上での 右ダブルクリックでポインタをロックし、ゲストへ相対移動量を送り始めます。Esc キー (または同じメニュー項目の再クリック)で解除します。同グループの「マウス再同期」は、 絶対位置追従モードでゲスト側カーソルとホスト側の基準がずれたときに取り直すためのものです。

Pointer Lock API が使えないタッチデバイス(iOS Safari など)では、代わりに「入力パネルを 表示」ボタンのキーボード/パッド/マウスのアイコンのチップからマウスのアイコンを選んでバーチャルトラックパッドを開いてください。 仮想キーボード・バーチャルパッドと同じ「入力パネル」の一種で、画面とツールバーの間の帯に 操作面が置かれます(画面には重ねません。操作中に指がゲスト画面を隠さないようにするためです)。

操作はノートPCのトラックパッドと同じ操作感です: 1本指のドラッグで指の移動量ぶんカーソルが 動き(マウス感度設定が適用されます)、タップで現在のカーソル位置を左クリック、2本指タップで 右クリック、長押し(450ms)で左ボタンを押し込んでそのままドラッグできます。カーソルは指と 独立に動くので、指の影に隠れません。2本指ドラッグ(ホイール相当)には対応していません — X68000 のマウスは左右2ボタンのみでホイールという概念自体が無いためです。

表示モード(ドット等倍 / 4:3)

WebX68k は既定で4:3表示です。実機の X68000 は画面モードによらず常に4:3のモニタいっぱいに 表示されるため、その見え方に合わせています。「…」メニューの表示グループにある **「4:3表示」**トグルをOFFにすると、コアの実解像度をそのまま正方形ピクセルで描く ドット等倍表示に切り替えられます。設定は localStorage に保存されます (2026-09-13 までは等倍が既定でした。一度も切り替えていない場合は4:3で表示されます)。

補正は必ず拡大方向で行い、縮小はしません — アスペクト比が4:3未満の512x512系モードは 横方向に、4:3を超える768x512系モードは縦方向に伸びます。縮小しない理由は、canvas が image-rendering: pixelated で描画されているためです。768x512のテキスト画面のような 1ドット幅の文字線を縮小方向で4:3化すると間引かれて読めなくなってしまいます。 4:3表示では、まずドットを崩さずに整数倍へ拡大してから、端数ぶんだけを補間する 「シャープ・バイリニア」で描いているため、Retina などの高解像度ディスプレイでも ぼやけずにくっきり表示されます。ドット等倍表示は従来どおり補間なしです。 画面を囲む枠は常に4:3時のサイズを確保しているので、モードを切り替えても レイアウトは動きません。

フルスクリーン

ツールバーの「フルスクリーン」ボタンで、ツールバーを含むカード全体をフルスクリーン 表示できます(画面だけではありません)。そのため全画面のままリセットや入力パネルの切替など、 ツールバーの操作がそのまま行えます。X68000 は画面モードによって実行中に解像度が 256x256 / 512x512 / 768x512 などへ変わりますが、フルスクリーン中もそのとき選択している 表示モード(ドット等倍または4:3。上記「表示モード」参照)のアスペクト比を保ったまま最大化し、 余白は黒帯になります(ウィンドウ表示時と同じ見え方)。もう一度ボタンを押すか、 Esc キーでフルスクリーンを解除します。

iPhone は Fullscreen API が <video> 要素にしか無いため、ページ側のUIを畳む疑似 フルスクリーンで代替します。この場合もツールバーは表示されたままです。

マウスキャプチャ中にフルスクリーンも有効な場合、Esc キーを1回押すとキャプチャと フルスクリーンが同時に解除されます(2段階にはなりません)。これはブラウザ側の挙動で こちらからは手当てできません(Esc による解除は preventDefault で止められず、解除直後に スクリプトからフルスクリーンへ復帰させることもできません)。ネイティブ全画面中は Esc が ブラウザに奪われるため、キャプチャだけを解除する手段は Esc しかありません。没入感を 優先した仕様です。

BIOS 設定

ツールバーの「…」メニューにある「設定」から、お手持ちの実機吸い出し IPLROM.DAT/CGROM.DAT の登録やマシン構成の 調整ができます。設定はブラウザに保存され、次回以降も同梱ファイルより優先して使われます。

言語トグル

ツールバーの「…」メニューにある EN/JA ボタンで表示言語をその場で切り替えられます。 選択内容は保存され、次回訪問時にも引き継がれます。

ホーム画面に追加(PWA)

iPhone では Web ページからブラウザの URL バーを消す手段がありません。WebX68k をホーム画面に 追加し、そこから起動すると URL バーの無い standalone 表示で起動します(Android はツールバーの フルスクリーンボタンでネイティブ全画面になるため、既に URL バーを消せます)。

**ホーム画面アプリと通常のブラウザ(Safari/Chrome)とでは、保存済みディスク・ステート・ BIOS(IndexedDB)が共有されません(iOSではホーム画面アプリ・Safari・Chromeがそれぞれ 独立したストレージを持つため。実機で確認済み)。**どちらか一方に決めて使うのが無難です。 ホーム画面版で遊ぶ場合は、ディスクの登録もホーム画面版から行う必要があります。これは iOS 側の仕様であり、アプリ側では回避できません。

同梱している ROM / ディスクイメージ

public/system/ に、再配布可能なもののみを選んで以下を同梱しています。

ファイル 内容 出所・扱い
iplrom.dat X68000 IPL-ROM v1.0 シャープ株式会社ほか権利各社が @nifty シャープ・プロダクツ・ユーザーズ・フォーラムで無償公開したもの。許諾条件.txt の条件下で無改変・無償で再頒布
human302.xdf Human68k version 3.02 システムディスク 同上
許諾条件.txt 上記2点の使用許諾条件 再頒布時の添付が許諾条件で必須。削除しないこと。同梱物と同じ public/system/ に配置し、公開ページでも /system/許諾条件.txt で閲覧できます
cgrom.dat フォント ROM (CGROM) 実機の CGROM は無償公開の対象外なので同梱できません。代替として東雲フォント(パブリックドメイン)から tools/gen-cgrom/ で生成した自作品。字形は実機と異なります

実機から吸い出した本物の IPL-ROM / CGROM をお持ちの場合は、「設定」パネルから 読み込めます。読み込んだファイルはブラウザの IndexedDB に保存され、次回以降は 同梱品より優先して自動読み込みされます。

HDD/FDD の取り扱い上の注意

  • HDD: セット・編集は起動前のみ。起動後は読み取り専用でロックされ操作不可。 ブランクHDDはFAT16のデータドライブ専用(IPL無し)。
  • FDD0/FDD1: いつでもホットスワップ可能。

MCP対応 (AIエージェントからの遠隔操作)

?bridge=1 を付けて開くと、ページがローカルのMCPサーバー(ws://127.0.0.1:3099)へ 接続し、画面取得・キー/マウス入力・ディスク操作ができるようになります。

セットアップは、依存を埋め込んだ単一ファイルを落として登録するだけです (git clone も npm install も不要。Node.js 18 以上があれば動きます):

curl -fLO https://github.com/uraraworks/WebX68k/releases/latest/download/webx68k-mcp.mjs
claude mcp add webx68k -- node "$PWD/webx68k-mcp.mjs"

あとはブラウザで https://uraraworks.github.io/WebX68k/?bridge=1 を開けば繋がります (公開ページで使う場合は Chrome 系か Firefox。Safari は https から ws:// を localhost 宛てでもブロックします)。詳しい手順と提供ツールの一覧は mcp/README.md を参照してください。

screen_text ツールでテキスト画面(TVRAM)の8x16 ANK・16x16漢字と認識診断を取得できます。 GVRAM / BG / スプライト上の文字(ゲームの多くはこちら)は取得できません。カバレッジが 0 に 近い場合はスクリーンショットで確認してください。詳細は mcp/README.md を参照。

開発方法

npm install
npm run dev     # 開発サーバー
npm run build   # 型チェック + 本番ビルド (dist/)

Google Drive の中継取得を使いたい場合は、ビルド時に環境変数 VITE_DISK_PROXY へ自前の 中継サービスのURL(末尾の / なし)を設定してください。未設定(既定)なら中継は行われず、 直接fetchが失敗した配布元はエラーになります(公開ページ用のGitHub Actionsでの設定方法は .github/workflows/deploy.yml のコメントを参照)。Dropbox は ホスト名の自動置換で直接取得するため中継設定は不要です(未検証の共有形式で直接取得が 失敗した場合のみ、設定されていれば中継へフォールバックします)。

エミュレータ本体(px68k-libretro → WebAssembly)のビルドは scripts/build-core.sh で行います。 ビルドの前提セットアップや FDD0/FDD1/HDD 同時搭載の仕組みなど詳細は docs/DESIGN.md を参照してください。

ライセンス

本リポジトリは GPLv2COPYING)です。

  • public/core/px68k_libretro.js / .wasm は GPLv2 の px68k-libretro を、 fork の uraraworks/px68k-libretro emscripten ブランチ(アクセスランプ用フックの最小パッチ入り)から emscripten で ビルドしたものです。ビルド手順は scripts/build-core.sh を 参照してください。
  • フロントエンド(src/ 以下)も上記コアと一体で動作するため GPLv2 に揃えています。
  • tools/gen-cgrom/ が生成する cgrom.dat の字形はパブリックドメインの東雲フォント由来です (tools/gen-cgrom/NOTICE.md 参照)。
  • public/system/ の ROM / ディスクイメージは GPLv2 ではなく、前節の許諾条件に従います。

実装済みの主な機能

  • ROM・Human68kシステムディスク同梱 — 追加の準備不要で起動可能
  • 「ディスク無しで起動」(HDDセット済み時は「セットしたディスクで起動」に変化)/ 「システムディスクで起動」の起動前オーバーレイ
  • FDD0/FDD1/HDD の3台同時搭載(cmdファイル+コアオプションの組み合わせで実現)。HDDは起動中 ロック、FDD0/FDD1はホットスワップ可能
  • HDDの起動前セット(ライブラリ/ドロップ/スロットのボタン)と、セット中限定の中身編集
  • ブランクHDD作成(40MB・FAT16フォーマット済み・Human68kパーティション。IPL無しのため データドライブ専用)
  • 実機同様のアクセスランプ(「ディスク挿入中」ではなく実際に読み書きしたフレームのみ点灯)。 FDDはドライブ別に点灯
  • ディスクライブラリ(ブラウザ側・IndexedDB)、ブランクFD作成(2HD 1232KB)、スロットごとのダウンロード
  • ZIP/LZHアーカイブからのディスクイメージ読み込み(ドロップ・ファイル選択・ fd1/fd2/hdd URLパラメータのいずれでも可): 中身が1枚ならそのままスロットへ、 複数枚ならディスクライブラリへフォルダとしてまとめて登録し選ばせる。FDD0+FDD1同時 装填型か1ドライブ入替型かを判別できないため、自動では装填しない
  • ファイルマネージャ: ブラウザとマウント中ディスクイメージ間の2ペインファイル転送。 Human68k の Shift_JIS ファイル名対応、ZIP/LZH 展開
  • ステートセーブ(gzip圧縮・IndexedDB永続化)、復元前のディスク構成照合
  • マウス対応: Pointer Lock による相対移動送信に加え、IOCS のマウス加速を補正する 閉ループの絶対位置追従モード。キャプチャは右ダブルクリックまたはツールバーの「…」メニュー、 解除は Esc
  • 画面モード切替(15kHz/31kHz)時の音声遅延を防ぐドリフト補正
  • 4:3表示(既定): 実機同様の固定4:3アスペクト比を、常に拡大方向の補正(1ドット幅の文字線が 消えないよう縮小はしない)とシャープ・バイリニアで、ぼやけさせずに再現。ドット等倍にも切替可
  • MCPブリッジ(?bridge=1)によるAIエージェント制御: スクリーンショット・TVRAMのANK/漢字取得・ キー/マウス入力・ディスク操作
  • 日本語/英語UI切替
  • ゲームパッド対応(Gamepad API): 標準2ボタンパッド / CPSF-MD・CPSF-SFC相当の8ボタンパッドを ポートごとに選択可能。ボタン・軸の割当編集(検出モード・コンボ選択・デッドゾーン調整)、 パッドのボタン/軸へキーボードキーを割り当てる機能、パッドごとのポート固定、設定はすべて ブラウザのlocalStorageへ永続化。ポート/パッド種別/割当の設定ダイアログあり
  • 「設定」パネルからの自前BIOS読込(IPLROM.DAT/CGROM.DAT)。IndexedDBに保存され、 同梱ファイルより優先される
  • バーチャルパッド(オンスクリーンパッド、スマホ向け): 8方向スナップ付きアナログスティック風 方向入力、組み込みプロファイル4種(2ボタンジョイスティック/カーソルキー+スペース/テンキー/ 6ボタンジョイスティック)、割当編集画面、実測した余白から自動選択される3種の配置(パネル/ 左右/重ねる)
  • ゲームパッドを持たないPCユーザー向けの物理キーボード→ジョイスティック割当(組み込み プロファイル3種)。既定は無効
  • フルスクリーンの対象をツールバーごとカード全体へ拡大。iPhone向けには疑似フルスクリーンで代替 (Fullscreen APIが<video>要素にしか無いため)
  • ホーム画面に追加(PWA)対応。iPhoneでブラウザのURLバーを消せる
  • AudioWorkletが使えない環境(LANのIPアドレスで開いた場合など)でも、起動失敗ではなく 無音での起動にフォールバック

未対応・既知の注意点

  • ジョイパッド(ゲームパッド)入力は対応済みです。標準2ボタン/CPSF-MD・CPSF-SFC(8ボタン)の パッド種別をポートごとに切り替えられます。パッド種別の変更は次回のコア起動時から反映され、 実行中の変更は即座には反映されませんが、リセットボタン(→「ツールバー」参照。今はコアの 再起動になっています)を押せば反映されます。サイバースティック(アナログモード)には 対応していません。
  • ディスクの多面差し替え(SET_DISK_CONTROL_INTERFACE)はコア側からの要求を無視しており 未対応です。
  • UI から扱える HDD は Config.HDImage[0](1台分)のみです。px68k-libretro 自体は16台まで 保持できますが、WebX68k の HDD スロットは1行のみです。
  • ドロップ/ファイル選択/URLパラメータのいずれでも、複数枚のディスクを含むZIP/LZH アーカイブは自動でどれかを装填することはありません。必ずディスクライブラリへ フォルダとして登録し、そこから選んでもらう形になります(FDD0+FDD1同時装填型か 1ドライブ入替型かをこちら側では判別できないため)。