Imágenes subidas por el jugador
Guarda las imágenes del jugador con api.media y el JSON relacionado con api.sessionStorage. Ambos pertenecen a la Sesión actual y pueden leerse desde otro dispositivo con la misma cuenta. Las imágenes del creador siguen yendo en Paneles → Recursos y se usan con referencias @asset:.
Las plantillas de la interfaz del jugador no tienen ninguna parte para subir archivos, así que esta receta necesita código de interfaz (Paneles → Código de frontend).
Elige dónde guardar cada dato
| Datos | API |
|---|---|
| Bytes de imágenes del jugador y metadatos de galería | api.media |
| ID de la imagen seleccionada, notas acotadas u otro JSON de la partida | api.sessionStorage |
| Preferencias del navegador y caché prescindible | api.storage |
| Estado del juego que necesitan las reglas o la IA | Variables declaradas del juego |
No guardes imágenes base64 en JSON, Variables del juego ni almacenamiento del navegador. Guardar en la nube requiere conexión. Las imágenes de la Sesión son independientes del paquete de exportación del Mundo; no prometas que exportar un Mundo descargará los archivos privados del jugador.
Sube y muestra una imagen
Dentro del componente, obtén const api = useYumina(). Carga la lista al abrir, después de los cambios y antes de que caduquen las URLs temporales de visualización, a los cinco minutos:
const page = await api.media.list(0);
// page.items contiene { id, entryId, metadata, version, url, thumbnailUrl, deleted, ... }.
// Carga las siguientes páginas cuando page.hasMore sea true.
if (!api.readOnly && page.uploadsEnabled) {
const result = await api.media.pick({
metadata: { title: "Retrato del personaje" }
});
if (result) {
// result es { mediaId, entryId }; null indica que el jugador canceló.
// Recarga la lista para obtener su URL temporal de visualización.
}
}Muestra url o thumbnailUrl de un elemento no eliminado. La URL puede ser nula si el archivo se eliminó permanentemente. Captura las peticiones fallidas, conserva un estado de error y muestra éxito solo cuando la promesa se resuelva correctamente. Respeta api.readOnly y uploadsEnabled al habilitar controles de subida.
Si ya tienes una entrada de archivo, usa api.media.upload(file, { entryId, uploadId, metadata }). Conserva el File seleccionado si falla la petición y reutiliza el mismo uploadId al reintentar ese archivo y petición. No recurras al almacenamiento local mientras afirmas que se guardó en la nube.
Guarda la imagen seleccionada
Guarda un ID estable en JSON y resuélvelo con media.list() para mostrarlo. No persistas url ni thumbnailUrl:
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 }
);
// Conserva saved.version para los siguientes cambios.Todos los métodos de JSON devuelven { value, version, exists }. Comprueba exists al cargar. Cada set y remove requiere { expectedVersion }; si otro dispositivo modificó el registro, SESSION_STORAGE_CONFLICT rechaza la escritura. Conserva el borrador, vuelve a cargar y reconcilia los cambios antes de enviar. No reintentes ciegamente una selección antigua.
Para quitar solo la selección, llama a api.sessionStorage.remove("selected-portrait", { expectedVersion }) con la versión más reciente. Para quitar una imagen de la Sesión actual, usa api.media.remove(item.entryId, item.version). Son acciones independientes: quitar la selección no elimina la imagen. La eliminación permanente se gestiona en Mi Biblioteca → Recursos → Imágenes de partidas y puede afectar a otras partidas, puntos de control y publicaciones compartidas.
Límites y copias guardadas
- Imágenes: JPEG/PNG/WebP estáticos, hasta 16 MiB de entrada y 40 millones de píxeles decodificados. El servidor genera una imagen WebP de hasta 2048 píxeles en su lado mayor y una miniatura. No es una copia del archivo original. Usa la capacidad existente de Recursos de la cuenta.
- JSON: 32 KiB por valor serializado en UTF-8; por Sesión, 256 KiB de valores actuales, 128 claves incluidas las marcas de eliminación y 16 MiB de historial de valores; 1.000 modificaciones por hora entre todas las Sesiones del propietario.
- Restaurar un punto de control que modifica JSON también consume estos límites. Superar una cuota devuelve HTTP 413; superar la frecuencia horaria devuelve 429. La restauración completa se revierte, incluidas imágenes e historia. No se borra el historial. Si los valores no cambian, no se duplica el historial y la restauración puede continuar aunque se hayan alcanzado estos límites de JSON.
- Los puntos de control, ramas de la misma cuenta e instantáneas compartidas capturan juntos el JSON y las referencias de imágenes. Restaurar un punto de control restaura ambos. Una publicación compartida conserva solo su estado de creación y no recibe posteriores añadidos privados.
- Las reproducciones compartidas son de solo lectura y siguen las reglas existentes de visibilidad, estado de publicación del Mundo, ocultación/moderación y nivel de contenido. Quien comparte y el creador de la Tarjeta tienen acceso privilegiado a la instantánea, incluso si está oculta, el Mundo ya no está publicado o contiene material sensible; los demás lectores deben superar los controles aplicables. Las publicaciones no listadas son accesibles por enlace. Esto no da al creador acceso a los datos actuales de la Sesión privada original, que siguen siendo exclusivos del propietario.
Galerías existentes del navegador
El adaptador reconoce los formatos actuales válidos y verificados de Oncin v2/v3/v4 y gallery_data en cualquier Mundo. La migración se ejecuta desde el navegador que conserva las imágenes originales y mantiene sus datos antiguos. No intenta adivinar datos de diarios o copias de seguridad dañados o ambiguos, recuperar datos del navegador de otro dispositivo, descargar URLs remotas ni convertir automáticamente claves arbitrarias de localStorage.
Las Tarjetas nuevas deben usar las APIs explícitas del SDK anteriores. Para otros formatos heredados, conserva los originales locales hasta confirmar tanto la subida como el guardado en la nube.
Verifica la integración
- Sube una imagen pequeña de formato admitido, espera la confirmación y recarga la Sesión.
- Abre la misma Sesión desde otro dispositivo con la misma cuenta y comprueba la imagen y la selección.
- Guarda un punto de control, cambia la selección y restaura; comprueba que las referencias de imágenes y el JSON vuelven juntos.
- Crea una rama de la misma cuenta y una instantánea compartida; comprueba el estado capturado y que la reproducción sea de solo lectura.
- Prueba la cancelación del selector, una subida fallida, errores de cuota y un cambio de JSON en conflicto desde otro dispositivo. Conserva el borrador y muestra el fallo.
Consulta las firmas en la Referencia API. La entrada de imágenes a la IA usa una función separada de adjuntos de chat; mostrar una imagen no envía sus píxeles al modelo.
