v
Skip to content

プレイヤーがアップロードする画像 ​

プレイヤー画像は api.media、関連する小さなJSONは api.sessionStorage に保存します。どちらも現在のプレイセッションに属し、同じアカウントで別のデバイスから読み込めます。作者が用意する画像は、これまでどおり パネル → アセット に置き、@asset: 参照で使います。

プレイヤー画面のテンプレートにはアップロード用の部品がないため、このレシピには画面のコード(パネル → フロントエンドコード)が必要です。

保存先を選ぶ ​

データAPI
プレイヤー画像のバイト列とギャラリーメタデータapi.media
選択中の画像ID、長さを制限したメモ、セーブ固有のJSONapi.sessionStorage
ブラウザ内だけの設定や削除可能なキャッシュapi.storage
ルールやAIが使うゲーム状態宣言済みゲーム変数

画像のbase64をJSON、ゲーム変数、ブラウザストレージに保存しないでください。クラウド保存にはネットワーク接続が必要です。セッション画像はワールドのエクスポートバンドルとは別であり、ワールドをエクスポートすればプレイヤーの非公開ファイルもダウンロードされるとは限りません。

アップロードと表示 ​

コンポーネント内で const api = useYumina() を取得します。ギャラリーを開くとき、変更後、表示URLの5分の有効期限前に一覧を取得し直します。

tsx
const page = await api.media.list(0);
// page.items contains { id, entryId, metadata, version, url, thumbnailUrl, deleted, ... }.
// Load subsequent pages when page.hasMore is true.

if (!api.readOnly && page.uploadsEnabled) {
  const result = await api.media.pick({
    metadata: { title: "Character portrait" }
  });
  if (result) {
    // result is { mediaId, entryId }; null means the player canceled.
    // Reload the list to obtain its temporary display URL.
  }
}

削除されていない項目の url または thumbnailUrl を表示します。ファイルが完全に削除されている場合、URLはnullになることがあります。リクエストの失敗を捕捉してエラーを表示し、Promiseが成功するまで保存済みと表示しないでください。アップロード操作は api.readOnly と uploadsEnabled に従います。

既存のファイル入力には api.media.upload(file, { entryId, uploadId, metadata }) を使います。失敗時は選択した File を保持し、同じファイルとリクエストを再試行するときは同じ uploadId を再利用します。ローカル保存に切り替えた状態でクラウド保存済みと表示しないでください。

選択中の画像を保存する ​

JSONには安定したエントリIDを保存し、表示時に media.list() の結果と照合します。url と thumbnailUrl は永続保存しません。

tsx
const previous = await api.sessionStorage.get("selected-portrait");
const saved = await api.sessionStorage.set(
  "selected-portrait",
  { entryId: selectedItem.entryId, mediaId: selectedItem.id },
  { expectedVersion: previous.version }
);
// Keep saved.version for later changes.

すべてのJSONメソッドは { value, version, exists } を返します。読み込み時は exists を確認します。set と remove には毎回 { expectedVersion } が必要です。他のデバイスが変更した場合は SESSION_STORAGE_CONFLICT で書き込みが拒否されます。下書きを保持して読み直し、変更を調整してから送信してください。古い選択を自動再試行しないでください。

選択だけを解除する場合は、最新バージョンで api.sessionStorage.remove("selected-portrait", { expectedVersion }) を呼びます。現在セッションから画像を外す場合は api.media.remove(item.entryId, item.version) を呼びます。選択解除は画像の削除とは別の操作です。ファイルの完全削除は マイライブラリ → アセット → セーブ画像 で行い、他のセーブ、チェックポイント、共有にも影響することがあります。

上限とスナップショット ​

  • 画像は静止画JPEG/PNG/WebP、入力最大16 MiB、デコード後4,000万画素まで。サーバーは長辺最大2048ピクセルのWebP画像とサムネイルを生成します。元ファイルのバックアップではなく、既存のアカウントのアセット容量を使います。
  • JSONはUTF-8で直列化した値ごとに32 KiB。セッション内の現在値合計256 KiB、削除記録を含む128キー、値の履歴16 MiB。所有者の全セッションで1時間あたり1,000回の変更までです。
  • JSONを変更するチェックポイント復元も容量・頻度制限の対象です。容量超過はHTTP 413、頻度超過は429となり、画像とストーリーを含む復元全体がロールバックされます。履歴は削除しません。値が変わらない復元は履歴を複製しないため、これらのJSON制限に達していても実行できます。
  • チェックポイント、同一アカウントのブランチ、共有スナップショットにはJSONと画像参照を一緒に保存します。復元時も一緒に戻ります。共有には作成時点の状態だけを含み、その後の非公開の追加内容は反映されません。
  • 共有リプレイは読み取り専用で、既存の公開範囲、ワールドの公開状態、非表示・モデレーション状態、コンテンツレベルのルールに従います。共有者とカード作者には特別な閲覧権があり、非表示、ワールドが未公開、またはセンシティブなスナップショットも閲覧できます。その他の閲覧者には該当するチェックが適用されます。限定公開の共有はリンクからアクセスできます。これによって作者が元の非公開セッションの現在データにアクセスできるわけではなく、そのデータは所有者だけがアクセスできます。

既存のブラウザギャラリー ​

互換アダプターは、すべてのワールドで検証済みのOncin v2/v3/v4および gallery_data の現在の有効な形式を認識します。移行は元画像があるブラウザで実行され、古いローカルデータを保持します。破損または判定できないjournal/backupを推測で復元せず、他のデバイスのブラウザからも回収しません。リモートURLの取得や任意のlocalStorageキーの自動変換も行いません。

新しいカードは上記のSDK APIを使ってください。他の旧形式を移行する場合も、アップロードとクラウド保存の両方が成功するまで元のローカルデータを残します。

接続を確認する ​

  1. 対応形式の小さな画像をアップロードし、成功を待ってセッションを再読み込みする。
  2. 同じアカウントの別デバイスで同じセッションを開き、画像と選択内容を確認する。
  3. チェックポイントを保存してから選択を変え、復元で画像参照とJSONが一緒に戻ることを確認する。
  4. 同一アカウントのブランチと共有スナップショットを作成し、保存時の状態とリプレイの読み取り専用動作を確認する。
  5. 選択のキャンセル、アップロード失敗、容量エラー、他デバイスとのJSON競合を確認する。下書きを残し、失敗を表示する。

シグネチャは APIリファレンス を参照してください。AIへの画像入力は別のチャット添付機能です。画面に画像を表示するだけでは、モデルに画像のピクセルは送信されません。