Repository navigation
Packs de marcos
English · Español
Un pack de marcos le dice al diseñador cómo se ve una carta: dónde va cada pieza, qué colores usa y qué capas se dibujan sobre la ilustración. El pack integrado viaja dentro de la app; «Original» (marcos de imagen) y «Balatro» (pixel art) se descargan a demanda desde fuentes fijadas y comprobadas por hash; los usuarios pueden importar los suyos como carpeta o .zip. Esta página documenta el formato de pack (versión 2) tal como está implementado en pack.rs, los packs que se distribuyen, la maquinaria de descarga, el catálogo de letras libres y el modelo de seguridad.
La descripción del formato para el usuario es docs/packs-de-marcos.md (en español); esta página la vuelve a exponer contrastada con el código. Véase Motor del diseñador para saber cómo consume los packs el pintor y Composición del diseñador para los layouts del pack que usan las cartas de varias piezas.
flowchart LR
subgraph Sources
B["builtin: embedded in proxy-core (include_str!)"]
O["Original: Card Conjurer PNGs, pinned commit"]
D["Downloadable: proxy-builder-packs repo, pinned commit"]
U["User import: folder or .zip"]
end
B --> P["Pack::de_fabrica"]
O --> L["app_data_dir/marcos/original/"]
D --> L2["app_data_dir/marcos/id/"]
U --> L3["app_data_dir/marcos/id/"]
L --> R["recursos.rs: leer_packs / recargar_pack"]
L2 --> R
L3 --> R
P --> R
R --> V["Pack::cargar_con_imagenes: validate + huella"]
V --> E["render::pintar_cara"]
Mapa del código:
| Qué | Dónde |
|---|---|
| Formato, validación, definiciones del integrado y de Original |
src-tauri/crates/proxy-core/src/diseno/pack.rs (Pack, PackDef, EstiloDef, Capa, Condicion, Hueco, PackError, VERSION_PACK, BUILTIN, ORIGINAL, ORIGINAL_IMAGENES) |
| Ficheros del pack integrado |
src-tauri/crates/proxy-core/assets/marcos/builtin/ (pack.json más SVG por estilo y layouts/) |
| Definición de Original y lista de PNG |
src-tauri/crates/proxy-core/assets/marcos/original/ (pack.json, 4 SVG, imagenes.json) |
Carga/importación/borrado, PackInfo
|
src-tauri/src/diseno/recursos.rs |
| Descargador de Original | src-tauri/src/diseno/original.rs |
| Packs descargables |
src-tauri/src/diseno/descargables.rs, manifiesto src-tauri/assets/packs-descargables.json
|
| Letras libres |
src-tauri/src/diseno/letras_libres.rs, catálogo src-tauri/assets/letras-libres.json
|
| Comandos |
src-tauri/src/commands/diseno.rs: packs_list, pack_import, pack_remove, fonts_list, font_import, fonts_free_list, font_free_download, original_info, original_download, packs_downloadable_list, pack_downloadable_download, pack_extra_use
|
| Stores de la interfaz |
src/features/disenar/marcos-originales.ts, src/features/disenar/packs-descargables.ts, recursos-dialog.tsx
|
| Repositorio de creación de packs |
proxy-builder-packs, un repositorio aparte (véase más abajo) |
my-pack/
pack.json required
<style>/frame.svg SVG layers (use {{variables}})
m15/frame{color}.png PNG layers (one per palette)
symbols/*.png own mana symbols (optional)
labels/*.png label pill backgrounds (optional)
Solo se leen los ficheros .json, .svg y .png (recursos.rs → tipo_de); los demás se ignoran. Las letras no forman parte de un pack: el pack nombra familias de letra y deben cargarse aparte (la descarga de Balatro importa su letra como parte de la descarga del pack).
Pack::cargar_con_imagenes(ficheros, imagenes) devuelve un Pack { def, ficheros, imagenes, huella, simbolos } o un PackError:
PackError |
Causa |
|---|---|
Json |
pack.json no se puede analizar; o un base de estilo que no es uno de los cuatro estilos integrados; o una capa con ambos o ninguno de svg y png; o una capa cajaReglas que no está sola con una zona; o desde/mascara en una capa que no es PNG o que lleva tramos; o un símbolo propio que no se puede analizar |
Version |
version es 0 o mayor que VERSION_PACK (3). Una app más antigua rechaza así un pack más nuevo en lugar de pintarlo mal. El pack integrado declara la versión 1, Balatro la 2 y Original la 3 (usa desde/mascara) |
FaltaFichero |
falta el SVG de una capa, el PNG de la mascara de una capa, un PNG para alguna paleta (se comprueba para cada paleta y, para {color1}/{color2}, para cada combinación de un solo color), un PNG de fondo de etiqueta, el PNG de lealtad, un fichero de símbolo propio o el propio pack.json
|
FaltaHueco |
a un estilo le falta uno de titulo, tipo, reglas, pie (HUECOS_OBLIGATORIOS) |
FaltaEstilo |
falta el estilo pedido (Pack::estilo) |
Color |
un color mal formado (se aceptan #rgb, #rrggbb, #rrggbbaa), o falta una paleta |
Expresion |
una expresión de hueco no válida |
Las nueve paletas (W U B R G gold artifact land colorless) son obligatorias. Los colores de los huecos pueden ser una {{variable}}. De los layouts de la raíz se comprueban sus capas y colores, pero no los huecos obligatorios. En el lado de la app, recursos.rs::de_pack convierte cada error en un AppError InvalidInput con motivo: "pack_invalido" y parámetros (falta, estilo, hueco, color, version, detalle, expresion), que la interfaz traduce (véase IPC y manejo de errores).
Pack.huella es un SHA-256 de todos los ficheros de texto y luego de todos los PNG (ordenados por ruta, cada uno seguido de separadores NUL). Entra en la huella de renderizado, así que cambiar cualquier fichero del pack invalida los renderizados en caché, y es la clave de las cachés de PNG en render::imagenes_png.
- Directorio:
app_data_dir/marcos/<id>/.leer_packscargabuiltin(incrustado) más todos los directorios que haya ahí al arrancar; un directorio que no supera la validación se omite en silencio. -
Recursos::importar_pack(ruta): lee una carpeta o un.zip(leer_zip: topes por fichero de 8 MiB para json/svg y 32 MiB para png; superar uno falla conInvalidInput/motivo: "pack_grande"; las entradas con..se omiten; si todo está en una única carpeta de primer nivel, ese prefijo se quita; los topes no se aplican a las importaciones de carpeta), valida, sanea el id a[A-Za-z0-9_-], rechaza un id vacío obuiltin(motivo: "pack_id"), sustituye cualquier directorio existente con ese id, escribe los ficheros de forma atómica (escribir_atomico) y registra el pack. Importar de nuevo el mismo id lo sustituye. -
quitar_pack(id): rechazabuiltiny los ids que contengan/,\o.. -
PackInfo { id, nombre, importado, estilos, estilos_propios, origen }va a la interfaz;importadoes falso solo para builtin.estilos_propioslista los estilos propios con sus nombres por código de idioma (EstiloPropio.nombres),basey variantes (VariantePack.nombres), tal como los trae el pack; la interfaz elige el del idioma de la interfaz, si no el inglés, si no el id (nombreEnIdiomaensrc/features/disenar/estilos.ts).
Toda la geometría está en milímetros sobre una carta de 63 x 88; un estilo o layout puede declarar otro tamaño con tamano: [w, h]. El motor escala a los píxeles de salida, de modo que la vista previa, los PDF a 300/600/900 PPP y la exportación PNG salen del mismo renderizado.
Expresiones (pack::evaluar, Valor): cualquier hueco o coordenada de zona de capa es un número o una cadena que es una suma/resta de números y nombres de variable ("yTipo+1.6", "80-yTipo"). Sin paréntesis, sin multiplicación. Variables disponibles, solo cuando el estilo tiene caja de reglas dinámica (caja): yReglas (parte superior del texto de reglas), altoReglas (altura del texto de reglas), yTipo (parte superior de la barra de tipo). Si falta una variable (caja fija), la coordenada se evalúa a 0: un hueco con ancho/alto cero no se dibuja, y una capa PNG cuya zona no se puede evaluar se omite.
Variables SVG (rellenar; los nombres desconocidos quedan vacíos): se sustituyen en los SVG de las capas antes de renderizar.
| Variable | Significado |
|---|---|
{{defs}} |
definiciones de degradado: url(#marco), #brillo, #panel, #panelfr, #crema, #lateral, #vetas, #bisel, #barra (ponerlas dentro de <defs>; véase render::defs) |
{{claro}} {{medio}} {{oscuro}} {{tinte}} {{caja}} |
colores de la paleta (o la mezcla de dos paletas) |
{{fondoCaja}} {{opacidadCaja}} {{tintaCaja}} |
relleno de la caja de reglas, opacidad y la tinta del texto que se lee sobre ella |
{{refuerzoCaja}} |
0..1, cuánto más opaca se pidió la caja (para marcos de imagen con la caja ya cocida: dibujar debajo un rectángulo negro con esa opacidad) |
{{tintaCrema}} {{tintaFr}} |
tinta sobre crema y sobre la caja de F/R |
{{yReglas}} {{altoReglas}} {{yTipo}} {{yTipo04}} |
geometría de la caja dinámica. En los SVG, yReglas/altoReglas son la caja entera (parte superior y altura total); en las expresiones de hueco son el área de texto. yTipo04 es yTipo + 0.4
|
{{extensionArte}} |
Cuántos mm sigue la ilustración por debajo de su ventana (la extensión del difuminado de los ajustes finos, o la extensionDifuminado del estilo; 0 de fábrica). El negro de debajo del arte tiene que empezar ese tanto más abajo. |
{{subeCaja}} |
Cuántos mm más alta se ha pedido la caja de reglas en los ajustes finos (negativo, más baja; 0 de fábrica). |
{{= 56.25 - subeCaja}} |
Una cuenta (sumas y restas) con las variables que son números. Así un marco fijo mueve su barra de tipo y el borde de arriba de su caja. |
Los huecos pueden usar yReglas, altoReglas, yTipo y subeCaja en sumas y restas: "y": "yTipo+0.4", "h": "52.5 - subeCaja". Un pack que no use subeCaja no cambia con ese ajuste; en la caja dinámica, lo pedido simplemente se suma a su altura. El ajuste fino rulesBoxDynamic (dinámica / fija / como el marco) vale para todos los marcos: ver rules_box_dynamic en Motor-del-diseñador.
| Campo | Tipo | Significado |
|---|---|---|
id, nombre, version
|
string, string, int | identidad; version 1 o 2 |
paletas |
mapa | las nueve paletas obligatorias (abajo) |
letras |
mapa de rol a letra | roles titulo tipo reglas fr pie cinta (abajo) |
estilos |
mapa de id a estilo | ids integrados borderless extended classic fullArt más ids propios |
layouts |
mapa de nombre a estilo completo | layouts completos válidos para cualquier estilo (abajo) |
colores |
mapa de paleta a letra | lo que sustituye a {color} en las rutas PNG; por defecto W U B R G, gold a M, artifact a A, land a L, colorless a C (letras de Card Conjurer). Balatro las asigna a palabras (white, blue, …) |
origen |
string | de dónde vienen las imágenes, se muestra en la interfaz |
escalado |
suave / pixel
|
escalado por defecto de los PNG (abajo) |
simbolos |
mapa de código a fichero | símbolos de maná propios (SVG o PNG), que tapan a los de Scryfall; los códigos ausentes pasan a Scryfall |
etiquetas |
mapa de valor a etiqueta | etiqueta por valor (common uncommon rare mythic special bonus legendary plains island swamp mountain forest wastes) |
insignias |
{fondo, borde, texto, pngLealtad} |
colores de las insignias de sección y un PNG opcional para la insignia de lealtad |
coloresTexto |
{resalte, habilidad} |
color de los tramos [[highlight]] y de las palabras de habilidad en las reglas. Sin él, los marcadores se quitan y todo sale del color normal |
sustituir |
mapa de carácter a carácter | caracteres que la letra del pack no tiene y sus reemplazos, aplicados solo con este pack (se pasan a Maquetador.sustituir) |
plantillaPie |
mapa de código de idioma a plantilla | el pie por defecto del pack por idioma de diseño (recurre a en). Se usa solo cuando la plantilla de la colección es la de fábrica (pie_del_pack). Véase la sección «Textos por idioma» |
separacionCoste |
float | hueco entre los símbolos del coste como fracción del lado del símbolo (por defecto 0,05) |
Cada una de W U B R G gold artifact land colorless: claro, medio, oscuro (luz del marco, cuerpo, sombra; el degradado vertical), tinte (caja de reglas translúcida), caja, tinta (caja de reglas clara y su tinta). Elección de color: un color da su paleta; dos dan un degradado de las dos paletas; tres o más dan gold; ninguno da artifact, land o colorless. El usuario puede forzar otro (FrameColor).
familia, peso (por defecto 400), mayuscula: altura de las mayúsculas dividida por el cuerpo del em. El texto se dimensiona por la altura de las mayúsculas, que es lo que ve el ojo: tamaño de letra = hueco.mayuscula(mm) / letra.mayuscula. La familia debe estar cargada en el motor.
Una letra de un pack no tiene por qué cubrir todos los idiomas. Lo que le falte del latín («ș», «ł»…) o del cirílico sale de Spectral o Montserrat, registradas como respaldo por escritura (Letras::respaldos), en vez de pintar cuadrados. El japonés, el coreano y el chino salen de Noto Sans JP, KR, SC o TC, que la app baja la primera vez que se elige uno de esos idiomas de diseño (Letras::cargar_cjk). Véase Motor del diseñador.
nombre y variantes de los estilos, el texto de las etiquetas y la plantillaPie son mapas código de idioma → texto (BTreeMap<String, String> en pack.rs). Los códigos son los de la app (los de Scryfall): es, en, fr, de, it, pt (portugués de Brasil), ro, pl, nl, ru, uk, ja, ko, zhs (chino simplificado) y zht (chino tradicional). Un pack puede traer los que quiera:
-
nombreyvariantesse enseñan en el idioma de la interfaz; sin él, en inglés; sin inglés, el id. -
etiquetasyplantillaPiese pintan en el idioma de diseño de la carta; sin él, en inglés. - Una clave que no es de ningún idioma de la app nunca se consulta, así que en la práctica se ignora.
-
{lang}en la plantilla del pie es el código que llevan las cartas impresas en ese idioma (textos_motor::codigo_pie:FR,DE,JP,KR,CS,CT…; el español sigue comoES).
La guía de autores docs/packs-de-marcos.md (sección «Textos por idioma») recoge las mismas reglas para quien hace packs.
| Campo | Significado |
|---|---|
tamano |
lienzo [w, h] en mm, por defecto 63 x 88 |
arte |
ventana de la ilustración (un hueco; acepta variables de la caja) |
caja |
caja de reglas dinámica (CajaDinamica, abajo) |
cajaPorDefecto |
tinte (translúcida, del color de la carta, 0,80 de opacidad) o clara (clara, opaca) |
capas |
capas que se pintan sobre la ilustración, en orden |
fondo |
capas que se pintan bajo la ilustración (el papel de una carta cuya ilustración no llena la ventana) |
huecos |
huecos de texto (abajo) |
layouts |
sobrescrituras de layout a nivel de estilo (ficha, alto, o los ids de las variantes) |
radio |
radio de esquina en pantalla en mm (por defecto 3); la impresión es recta salvo que se fije el radio de los ajustes finos |
coronaLegendaria |
las cartas legendarias reciben la corona automáticamente; por defecto solo en borderless
|
ventanaArte |
máscara de la ventana de la ilustración: {x, y, w, h, radio, soloAbajo, repintar, repintarTras}
|
difuminadoArte |
mm del borde de abajo de la ilustración que se funden con negro para que no acabe en seco (el extendido de la casa: 12). Los ajustes finos lo pueden cambiar |
extensionDifuminado |
mm que sigue la ilustración por debajo de su ventana, perdiéndose; va con difuminadoArte
|
nombre |
nombre para mostrar por idioma (estilos propios) |
base |
el estilo integrado del que este estilo propio hereda el comportamiento (y al que recurre si falta el pack); por defecto classic; debe ser uno de los cuatro |
variantes |
variantes elegibles por el usuario: id a nombres por idioma |
layoutSi |
[{ "si": {...}, "layout": "id" }]: layouts elegidos según propiedades de la carta; gana la primera coincidencia |
CajaDinamica: fondo (borde inferior fijo, mm), altoMin, altoMax, barraTipo (altura de la barra de tipo sobre la caja), padArriba, padAbajo, altoComodo (altura hasta la que crece la caja antes de que la letra empiece a reducirse, hasta el 75 %), fijaDeSerie (booleano, falso de serie: la caja mide siempre altoMax salvo que el usuario active «Altura según el texto»; los tres estilos del Original lo ponen). Cuando el texto no cabe ni siquiera con altoMax, la letra baja en pasos de 0,1 pt hasta 6 pt y entonces se lanza un aviso TextoNoCabe.
ventanaArte: negro fuera de la ventana con las esquinas redondeadas a radio (o FineTuning.art_radius); soloAbajo redondea solo las esquinas inferiores; repintar es una lista de zonas [x, y, w, h] donde una capa de imagen lleva la curva ya cocida, y repintarTras el número de capas tras las cuales esas zonas se repintan con ilustración o negro cuando el usuario fija un radio. Las zonas se recortan para que nunca empiecen por encima del final de la barra de tipo (yReglas si la caja es dinámica): con una caja corta la barra baja, y repintar sus extremos los cortaría. La ventana se pinta sobre la ilustración y bajo las capas.
| Campo | Significado |
|---|---|
svg |
ruta de un SVG con {{variables}}, dibujado sobre todo el lienzo |
png |
ruta de un PNG; {color} se convierte en la letra de la paleta, {color1} / {color2} en el primer y el segundo color de la carta en orden WUBRG (la letra de incoloro si no hay; ambos iguales con un solo color), usados para los cuadrados de color cerca del título |
en |
zona {x, y, w, h} (cada una puede ser una expresión) a la que se estira el PNG; si falta, todo el lienzo |
tramos |
[arriba, abajo] mm: esas franjas (a la escala del ancho de la zona) se dibujan sin deformación y solo se estira la del medio (cajas que crecen con esquinas) |
desde |
(v3) zona {x, y, w, h} en mm (admite expresiones) medida como si el PNG cubriera la carta entera: solo se dibuja ese trozo. Sin en va en el mismo sitio de la carta; con en, estirado a esa zona. Sirve para tomar una pieza de otro marco (el despejado de Original toma el pergamino de la caja de reglas del clásico) |
mascara |
(v3) ruta de un PNG del tamaño de la carta cuyo alfa multiplica el de la capa (máscaras de Card Conjurer como m15MaskType.png: solo la barra del tipo). Con desde, se usa el mismo trozo de la máscara. Sin {color}: una máscara para todos los colores. Ninguno de los dos se combina con tramos ni con capas SVG |
cajaReglas |
true con en y sin png/svg: pinta ahí el tinte de caja de reglas pedido cuando el diseño pide una caja oscura, clara o personalizada (los marcos de imagen llevan la caja cocida). El texto de reglas toma entonces la tinta que se lee sobre ese tinte |
colores |
sobrescrituras de paleta a letra por capa |
si |
condición (abajo) |
escalado |
suave o pixel para esta capa |
mezcla |
normal, oscurecer (Darken, p. ej. líneas de barrido) o multiplicar
|
opacidad |
0..1 |
Una capa es SVG o PNG (exactamente uno) o un marcador cajaReglas. Un fichero de capa que falta en un pack recurre al fichero de la misma ruta del pack integrado al pintar.
Deben cumplirse todas las claves presentes (las ausentes se ignoran). Los hechos los calculan render::hechos_de y pintar_cara.
| Clave | Verdadera cuando |
|---|---|
corona |
la corona está activada (regla de legendaria o forzada) |
fr |
la cara tiene fuerza y resistencia |
cinta |
el nombre original va en la cinta |
emblema |
hay un emblema fijado |
tipo |
alguno de estos (en inglés, minúsculas) aparece entre las palabras de la línea de tipo en inglés: land, creature, planeswalker, artifact, enchantment, instant, sorcery, battle, token… |
basica |
tierra básica (la línea de tipo contiene basic) o no |
legendaria |
legendaria (línea de tipo o efecto de marco legendary) |
colores |
[min, max] número de colores de la cara (una tierra incolora usa su identidad) |
simbolos |
[min, max] número de símbolos del coste de maná ([3, 3] significa exactamente tres) |
variante |
el usuario eligió esa variante |
caja |
(v3) la caja de reglas elegida en el diseño es una de estas: auto, dark, light, tint (Hechos.caja, de FrameOptions.rules_box) |
Obligatorios en todo estilo: titulo, tipo, reglas, pie. Se usan cuando están: coste, fr, cinta, emblema, etiqueta (etiqueta de pastilla), simbolo (símbolo de color de fullArt), mano y vida (Vanguard).
| Campo | Significado |
|---|---|
x y w h |
rectángulo en mm (se permiten expresiones) |
rol |
rol de la letra |
mayuscula |
altura de las mayúsculas en mm (por defecto 1,78) |
color |
#rrggbb[aa] o una variable como {{tintaCaja}}
|
alinear |
inicio, centro, fin; en coste, centro centra los símbolos |
sombra |
sombra suave detrás del texto |
versalitas |
versalitas (títulos de fichas) |
mayusculas |
pone el texto en mayúsculas (los símbolos no se tocan) |
alinearV |
colocación vertical en una caja fija: inicio, centro (por defecto), fin
|
tabs, interlinea
|
solo el pie: tabuladores (mm) y paso de línea (por defecto 1,6) |
contenido |
en etiqueta: rareza (por defecto), supertipo («Legendary»), subtipoTierra (tipo de tierra básica) |
El título y la línea de tipo se estrechan horizontalmente antes de reducirse; véase Motor del diseñador. Los pies usan \n para las líneas, \t para las columnas (con tabs cada columna se estrecha hasta su tabulador; si no, las columnas se siguen unas a otras y toda la línea se estrecha hasta la mitad) y todo lo que va después de {>} queda pegado a la derecha. Si la plantilla no tiene ninguno de {credit}, {universe}, {year}, se añaden después de {>} en la última línea (p. ej. «Universe · (c) 2026 Credit»).
Dos tipos:
-
Layouts de estilo (
EstiloDef.layouts[name], unLayoutDef):arte,caja,capas,fondo,huecos. Los campos presentes sustituyen a los del estilo en bloque (una listacapassustituye la lista entera; un hueco sustituye ese hueco, los demás se quedan).-
ficha: fichas, emblemas, fichas de dos caras (título centrado en versalitas…). -
alto: caja de reglas más alta para los cuerpos con secciones (planeswalker, clase, caso, leveler, Station). Opcional. - el id de una variante de usuario, que se aplica automáticamente cuando se elige.
-
-
Layouts de pack (
PackDef.layouts[name],EstiloDefs completos válidos para cualquier estilo):saga,mazmorra,secuelaArriba(63 x 51),secuelaAbajo(33 x 63),fusionar(88 x 6),flip,batalla(88 x 63),plano(127 x 88,9),planyvanguard(88,9 x 127),pie(solo el pie). Las mitades de Split, Fuse y Room no necesitan layout propio. Dos de ellos merecen una nota, y el pack integrado, el Original y Balatro los definen así:-
mazmorra: como las mazmorras impresas, solo el título (centrado) y el plano.artemide 0 x 0, no hay huecotiponiemblema, y el huecoreglasocupa todo, de debajo del título a encima del pie; el motor pinta dentro el plano (salas, paredes, puertas), encima de lo que pinten ahí las capas del layout (véase Composición del diseñador). Quitar la línea de tipo funciona porque un layout de pack sustituye al estilo entero: no se recurre a los huecos del estilo. -
secuelaAbajo: título, una ventana de arte, línea de tipo y reglas, de arriba abajo; la pieza se pega girada a la derecha, así que su título queda a lo largo del borde derecho de la carta, como en las impresas. El motor pinta en esa ventana la ilustración de la segunda cara del diseño, como en las cartas Aftermath impresas. Un pack cuyosecuelaAbajosiga con elartea 0 x 0 deja esa mitad sin ilustración.
-
Orden de resolución (render::estilo_para): estilo propio del pack (si no, aviso EstiloNoEnElPack y el estilo integrado), si no la entrada del pack para el estilo integrado, si no la del pack integrado, si no el borderless del pack. Prioridad de la petición de layout: la petición propia de la carta (ficha, saga…), luego la variante elegida si el estilo tiene un layout con ese id, luego el primer layoutSi que coincida. Un layout de ficha que falta recurre al estilo del pack integrado en silencio; cualquier otro layout que falte recurre al layout completo del pack integrado y, si no existe, se informa PackSinLayout (no para alto).
suave (por defecto): Lanczos3, para marcos pintados o fotografiados. pixel: al ampliar, vecino más próximo, de modo que cada píxel se repite; al reducir, promedio con filtro de caja (render::reescalar_pixel, mediante fast_image_resize). Se fija a nivel de pack o por capa; los símbolos propios siguen el indicador del pack. Es lo que mantiene nítido el pixel art a 300 hasta 900 PPP.
Ubicación: src-tauri/crates/proxy-core/assets/marcos/builtin/, incrustado con include_str! mediante la macro fichero! (lista BUILTIN en pack.rs), de modo que forma parte del binario. Pack::de_fabrica() lo construye; Pack::de_fabrica_compartido() guarda en caché una copia para los recursos de reserva.
- Id
builtin, versión 1, nueve paletas, letras Spectral (títulos, tipo, reglas, F/R, cinta) y Montserrat (pie). - Cuatro estilos:
borderless(ilustración de 63 x 83 con una caja de reglas que crecefondo 83, altoMin 12, altoMax 27.4, barraTipo 6, ventana de la ilustración con radio de 6 mm redondeada abajo, corona, cinta, SVG de barra de título y de F/R; layoutsficha,alto),extendedyclassic(SVG de marcomarco.svg/marco-alto.svg; layoutsficha,alto),fullArt(tierras básicas apaisadas: franja más símbolo de color, sin layouts). - Once layouts de pack:
saga,mazmorra,secuelaArriba,secuelaAbajo,fusionar,pie,flip,batalla,plano,plan,vanguard. - Como todos los demás packs recurren a él, debe seguir funcionando como la implementación de referencia del formato.
- Tests que lo protegen:
dorados.rs(imágenes doradas),layouts.rsy los tests unitarios depack.rsyrender.rs(un_pack_de_antes_sin_el_layout_usa_el_de_la_casa,un_estilo_que_falta_sale_del_pack_de_la_casa, etc.).
Decisión: los marcos de imagen M15 del proyecto Card Conjurer no se distribuyen en el repositorio ni en los instaladores. Se descargan la primera vez que se usan y se verifican.
- Definición:
assets/marcos/original/pack.json(idoriginal, versión 3,origen= Card Conjurer), cuatro SVG (cinta.svg,cubierta-corona.svg,refuerzo-caja.svg,sombra-pie.svg) eimagenes.json:{ commit, base, imagenes: { path: sha256 } }. Actualmente 53 PNG (unos 37 MB) bajom15/regular(8 marcos, 8 de F/R, máscarasm15MaskTitle.pngym15MaskType.png),m15/new/extended(8),m15/borderless(9),m15/crowns(18), fijados a un commit de 40 hex del repositorio público, baseimg/frames/. - Tres estilos que comparten las barras de mármol y el pergamino del clásico, para que un mazo se vea coherente use cada carta el estilo que use. Decisión: los marcos extendido y despejado propios de Card Conjurer son más lisos (barra de tipo negra translúcida, placas translúcidas sin grano), así que las piezas que llevan la textura se toman del marco normal con
mascaraydesde:-
classic: marco M15 normal (m15/regular/m15Frame{color}.png),cajaPorDefecto: clara. -
extended:m15/new/extended/{color}.png(letrasw u b r g m a l; el incoloro usaa, como el clásico usaA), ilustración desde y 7,4 mm hasta debajo de la barra del tipo, a todo el ancho; encima, el marco normal con la máscaram15MaskType.pngpara una barra de tipo de mármol; la corona flotante (no hay bordes laterales bajo el título donde apoyar la normal); la caja de F/R y los colores de texto del clásico. Con la corona de legendaria (si.corona) la pieza de arriba de ese PNG (el borde del marco) asomaría alrededor de la corona, así que los 12 mm de arriba se pintan en trozos: los brillos de los lados (x0–2,3 y 60,7–63), una columna de cada brillo estirada sobre el hueco junto a la corona (desdede 0,1 mm,ende 1,1 mm, para que el brillo siga sin el borde) y el centro (3,4–59,6); la misma capa sin corona (si.corona: false) se pinta entera. Sin esto, junto a la corona de las legendarias (sobre todo en los planeswalkers) salían finas rayas verticales y una columna tenue. -
borderless: el marco «showcase» genérico de Card Conjurer (ventanaArtecon zonasrepintaryrepintarTras: 4), con el marco normal recortado porm15MaskTitle.pngym15MaskType.pngpara las barras, el interior de la caja de reglas del marco normal puesto sobre la caja del showcase solo condesde(el hueco entre los bordes de la caja está en el mismo sitio en las dos imágenes, x 4,72–58,38 mm e y 55,2–81,4 mm, así que el trozo va en su sitio sin estirar; unensacado de la zona decajaReglasquedaba 0,2 mm desplazado y dejaba un hueco en un lado), la caja de F/R del clásico, texto oscuro ycajaPorDefecto: clara. La capa del pergamino lleva"si": {"caja": ["auto", "light"]}: con una caja oscura o con tinte no se pinta, así que queda la caja translúcida del propio marco con el tinte decajaReglasencima, se sigue viendo la ilustración a través de la caja y el ajuste fino «caja de reglas más opaca» tiene sentido. El borde de la caja sale siempre del marco. - Los tres estilos definen una
cajaconfijaDeSerie, así que la caja de reglas midealtoMaxde serie y sigue la altura del texto, como el despejado de la casa, solo si el usuario activa «Altura según el texto». La caja viene cocida en el PNG con un alto fijo, por lo que el pack la rehace en tres trozos condesde+eny expresiones sobreyTipo: el de arriba (con la barra del tipo) y el de abajo se copian tal cual, y el de en medio se estira entre ellos (despejado: barra48.5–55.4, medio55.4–80puesto enyTipo+6.9con alto73.1 - yTipo, abajo80–88, más tiras de esquina para que los lados no se estiren).cajaReglasesen {4.91, "yTipo+6.55", 53.43, "74.34 - yTipo"}yrefuerzo-caja.svgusa{{yReglas}}/{{altoReglas}};ventanaArte.repintarTrasvale 9 en el despejado. Las tierras básicas usan el estilofullArtpropio del pack: la barra de mármol del título del despejado (el trozo del título del showcasey 3,0–10,3más el marco normal conm15MaskTitle.png, movida ay 72,7) —la del título y no la del tipo, porque el trozo de la barra del tipo queda abierto por abajo, donde se une la caja de reglas— sobre una ventana de ilustración a sangre hasta 81 mm con las esquinas de abajo redondeadas a 3 mm (ventanaArte, sinrepintarni tiras de esquina, que son de la caja de reglas), con el nombre centrado en la barra y el símbolo de maná dentro de ella, a la izquierda; sinfullArtpropio, un pack recurre al de la casa (franja oscura). El pack define todos sus propioslayoutsde pack (saga, clase, mazmorra, flip, secuelaArriba/secuelaAbajo, fusionar, pie, batalla, plano, plan, vanguard), hechos con trozos de sus PNG (barras en tres trozos a partir de la barra del título, cajas de reglas en nueve trozos del marco normal, con el mismo mármol y los bordes de color), y una variantealtoen cada estilo (caja de reglas hasta 34,6 mm) para que quepan planeswalkers, casos y leveler (ninguno de los layouts especiales recurre al aspecto de la casa); las clases usan un layoutclase(arte a la izquierda, niveles a la derecha) y, en packs sin él,alto. Balatro hace lo mismo con las piezas de su Joker (balatro/source/layouts.py, que llamabuild.py). El layoutpreparede Scryfall (criatura preparada con su hechizo, p. ej. Emérita del conflicto) esMaquetacion::Preparar: el cuerpo de la aventura con la columna del hechizo a la derecha (Contenido::Aventura.libro_derecha).
-
- Descarga (
original.rs): URL =https://raw.githubusercontent.com/Investigamer/cardconjurer/<commit>/<base><path>.descargarreescribe siempre los ficheros de definición con la versión incrustada en la app, lista las imágenes cuyo SHA-256 en disco no coincide (pendientes/bueno), las baja una a una, rechaza cualquier fichero cuyo SHA-256 difiera (ErrorCode::Networkconfichero), escribe de forma atómica enapp_data_dir/marcos/original/, informa del progreso y llama arecargar_pack("original"). Evento de progreso:original://progresscon{ done, total }.info()devuelveOriginalInfo { listo, faltan, total }. -
leer_packsllama aoriginal::definicion_al_diaen cada arranque para que la definición del pack en disco coincida siempre con la versión de la app aunque las imágenes se bajaran hace mucho. - Una app más nueva puede pedir imágenes que una anterior no bajó (las del extendido).
leer_packsyrecargar_packcargan este pack conoriginal::cargar: si el pack entero falla, se queda solo con los estilos que cargan por sí solos, así que los que faltan caen al pack integrado en vez de desaparecer todo el pack Original. Al arrancar,lib.rslanzaoriginal::completar, que baja lo pendiente cuando la carpeta ya tiene unpack.json(nunca en una instalación nueva: eso sigue siendo a petición). Sin red solo registra un aviso y lo vuelve a intentar en el siguiente arranque o cuando el usuario elige el pack. - Tests (
original.rs): la lista está bien formada (commit de 40 caracteres, base con barra final, más de 40 imágenes, rutas.pngsin.., hashes de 64 caracteres); se rechaza un fichero con otro hash; se reescribe una definición antigua; si no se ha descargado nada, todo está pendiente; sin las imágenes nuevas el pack carga sin el estilo extendido (sin_las_imagenes_nuevas_carga_sin_ese_estilo).en_vivo(ignorado) descarga de verdad. Enproxy-core,el_pack_original_es_valido_con_sus_imagenescomprueba que la lista de imágenes es justo la que piden las capas, máscaras incluidas.
descargables.rs + assets/packs-descargables.json entregan packs alojados en el repositorio aparte de packs. A diferencia de Original, todo (incluido pack.json) viene de ese repositorio.
Forma del manifiesto (Manifiesto { repo, packs: Vec<Descargable> }):
| Campo | Significado |
|---|---|
repo |
https://raw.githubusercontent.com/PoolFlamingo/proxy-builder-packs |
packs[].id, nombre
|
id del pack (también el directorio de instalación) y nombre para mostrar |
commit |
commit de 40 hex del repositorio de packs; cada URL es <repo>/<commit>/<carpeta><path>
|
carpeta |
carpeta del pack dentro del repositorio (balatro/) |
ficheros |
mapa de ruta relativa a SHA-256: pack.json, layers/, symbols/, labels/ (128 ficheros para Balatro) |
letras |
letras: ruta, sha256, licencia, licencia_sha256
|
extras |
imágenes extra: ruta (con prefijo extras/), sha256, tipo (reverso, ficha, tierra, carta), nombre (137 para Balatro: 82 cartas listas, 50 tierras, 3 fichas, 2 reversos) |
Comportamiento:
-
lista(state)devuelveDescargableInfo { id, nombre, listo, faltan, total, bytes, extras }para cada pack que estédisponible: su commit debe ser un hash real de 40 hex (publicado) o, solo en compilaciones de depuración (cfg!(debug_assertions)), debe estar definidaPB_PACKS_LOCAL.listosignifica que todo lo que hay en disco coincide con su hash y el pack está cargado; losextrassolo se listan cuando está listo. -
descargar(state, id, progreso): calcula las tareas pendientes (ficheros más extras cuyo hash en disco difiere) y las letras que faltan (el id de la letra es el hash del fichero, comparado con las letras importadas), baja cada una mediantestate.externo.bajar(url, MAX_IMAGEN)(tope de 15 MiB), verifica el hash (comprobar; un desajuste esErrorCode::Networkconfichero), escribe de forma atómica, importa las letras conimportar_letra_datosy guarda cada licencia enfuentes/licencias/<stem>-LICENCIA.txt, luegoquitar_lo_que_sobraborra todo lo que haya en las carpetas del pack y de los extras que el nuevo manifiesto ya no liste (rutas antiguas, restos de.part) y, por último,recargar_pack. Una segunda ejecución sin cambios no baja nada (total == 0), así que actualizar a una versión nueva del pack baja solo los ficheros que han cambiado. - Ubicaciones: el pack en
app_data_dir/marcos/<id>/, los extras enapp_data_dir/packs-extras/<id>/(separados para que no se carguen con el pack). - Extras:
extra_por_indice(bytes que mostrar, hash vuelto a comprobar),usar_extra/ruta_extra(al almacén de blobs, para que el extra pueda ser un reverso de carta o una carta propia; el comandopack_extra_use). - Sobrescritura para desarrollo: con
PB_PACKS_LOCAL=<carpeta del repositorio de packs>(solo compilaciones de depuración), los ficheros se leen de esa carpeta en lugar de la red; los hashes se siguen comprobando. - Eventos:
packs://progresscon{ id, done, total }. Interfaz:src/features/disenar/packs-descargables.ts(usePacksDescargables). - Tests:
el_manifiesto_se_entiende(forma de la URL del repositorio,pack.jsonpresente, hashes de 64 caracteres, y cada URL de fichero supera la lista de permitidosurl_permitida),una_huella_que_no_cuadra_no_vale,lo_de_una_version_anterior_se_quita; el ignoradobalatro_en_vivodescarga y comprueba 7 estilos propios.
El único pack descargable hasta ahora (id: balatro, versión 2, escalado: pixel). Marcos de pixel art con la temática del juego, construidos a partir de siete plantillas PSD, cada una expuesta como estilo propio: joker, planeswalker, espectral, tarot, planeta, vale, tierra (los ids siguen en español porque los diseños guardados se refieren a ellos; los nombres para mostrar salen de los mapas nombre por idioma del pack). Seis heredan de classic, tierra de fullArt. Usa:
-
layouts: todos los estilos tienen un layoutficha;tierratiene ademásbasica, elegido porlayoutSicuando la carta es una tierra básica. - 31 símbolos propios (
W U B R G C T,0a20,X Y Z) dibujados como fichas de póker, conseparacionCoste0,122. - 13 etiquetas de pastilla (rarezas,
legendary, tipos de tierra básica) con el texto escrito por el motor en el idioma del diseño. -
coloresTexto(colores de resaltado y de palabra de habilidad),insignias(incluidapngLealtad),sustituir(8 caracteres tipográficos asignados a ASCII para la letra pixel),plantillaPie(pie de una sola línea) y una caja de reglas dinámica conaltoComodoen seis de los siete estilos (planeswalkerusa una caja fija). - La letra
m6x11plus.ttf(de uso libre con atribución; el fichero de licencia se distribuye y se guarda en la máquina del usuario). - El formato admite variantes, pero el
pack.jsonactual no declara ninguna. - Extras: dos reversos de carta, fichas, tierras básicas y cartas ya hechas del mazo de ejemplo.
Cuando el manifiesto pasa a un commit nuevo del repositorio de packs, un pack instalado muestra los ficheros cambiados como pendientes (faltan) hasta que el usuario lo vuelve a descargar desde «Letras, marcos y símbolos»; un cambio que solo toca los layouts es un único fichero, pack.json. Deducido: mientras tanto la copia instalada sigue cargando con sus layouts anteriores, porque los packs se leen del disco diga lo que diga el manifiesto.
Los créditos están en el CREDITS.md del pack (plantillas de una artista de la comunidad redistribuidas con permiso; Balatro pertenece a su editor; las cartas son proxies para jugar, no para vender).
El contenido de los packs se construye y se versiona en un repositorio aparte, clonado junto a este (proxy-builder-packs, publicado como PoolFlamingo/proxy-builder-packs). Tiene sus propias sesiones de trabajo e historial, y la app solo lo ve a través del manifiesto. Estructura del repositorio:
proxy-builder-packs/
README.md
balatro/
pack.json the pack definition
layers/<template>/ PNG layers cropped to the card area (common, joker, land, planeswalker, planet, spectral, tarot, voucher)
symbols/ mana chips
labels/ rarity, legendary and land-type pills
fonts/ m6x11plus.ttf and its licence
extras/{cards,tokens,backs,lands}/ ready-made images
extras.json inventory of extras (type and display name)
CREDITS.md
source/ convert.py, build.py, manifest.py, inventory.json/.md, references.json, views/
Las carpetas y los nombres de fichero están en inglés; los ids de estilo y las claves de JSON siguen en español porque los leen la app y los mazos guardados.
Flujo de trabajo (del README del repositorio, ejecutado dentro de balatro/source/ en un virtualenv con psd-tools, pillow y numpy; siempre python -I):
-
convert.py <carpeta con los PSD> ..: exporta todas las capas de imagen (excepto la ilustración de muestra, el texto y las muestras de color) recortadas al área de carta de un lienzo de 1365 x 1855, con la zona de cada capa en mm, y escribeinventory.json/inventory.md. Las capas de texto se registran con caja, tamaño, color y alineación. Las capas visibles se recomponen y se comparan con el compuesto del propio PSD como comprobación. -
build.py .. <carpeta con los extras originales> <m6x11plus.ttf>: genera símbolos, etiquetas, las cajas de color delayers/common, copia las letras y los extras (recortados sin los 3 mm de sangrado) y escribepack.json. Borra las capas que no usa, así que hay que volver a ejecutarconvert.pyantes de repetir este paso. -
manifest.py .. <commit>: imprime la entrada del manifiesto de la app para el pack (el SHA-256 de cada fichero, la lista de letras con licencias, los extras con prefijoextras/y hashes). Omitesource/,extras/,fonts/,golden/,extras.json,README.md,CREDITS.mddeficheros.
Publicar una versión nueva del pack:
- Hacer commit y push de los cambios del pack al repositorio de packs (el commit debe existir en el remoto porque la app descarga por commit).
- Ejecutar
manifest.pycon ese hash completo de commit y sustituir la entrada del pack ensrc-tauri/assets/packs-descargables.json. - Ejecutar los tests de la app (
el_manifiesto_se_entiende) y, opcionalmente, el ignoradobalatro_en_vivo. - Sacar una release de la app; los jugadores reciben los ficheros nuevos la próxima vez que abran la descarga del pack (solo se bajan los ficheros que han cambiado).
Durante el desarrollo, usa PB_PACKS_LOCAL con un commit de relleno (que no sea de 40 hex) en el manifiesto para probar antes de hacer push. Los tests del lado del motor que necesitan el contenido del pack (balatro_con_sus_imagenes, balatro_matriz, balatro_contra_el_autor) reciben la carpeta del pack mediante PB_BALATRO (véase Motor del diseñador).
src-tauri/assets/letras-libres.json lista 22 familias con licencia OFL del repositorio de Google Fonts, fijadas a un commit, con el SHA-256 y el tamaño de cada fichero y de cada licencia. Se descargan con un botón del diálogo de recursos, no están en el repositorio ni en los instaladores y se importan como cualquier letra del usuario.
Entrada (Familia): id, familia (el nombre usado en colecciones y packs), uso (UsoLetra: titulo, reglas, ambos), cursiva (tiene cursiva, usada para el texto recordatorio y de ambientación), ficheros: [{ ruta, sha256, bytes }], licencia: { ruta, sha256 }. Raíz: commit y base (ofl/).
Criterio de selección: legibles a tamaño de carta, sin trazos finos. Familias: Cinzel, Almendra, Uncial Antiqua, Grenze Gotisch, Eczar, Amarante, Metamorphous, Inknut Antiqua, Bitter, Domine (títulos); Grenze, Caudex, Cardo, Vollkorn, Libre Baskerville, Literata, Merriweather, Lora, Pixelify Sans (ambos; Pixelify Sans es la alternativa libre a la letra de Balatro); Crimson Pro, Source Serif 4, PT Serif (reglas). Las imágenes de muestra están en src/assets/letras/<id>.png.
Flujo (letras_libres.rs):
-
lista(state):LetraLibre { id, familia, uso, cursiva, descargada, bytes };descargadacuando el SHA-256 de todos los ficheros ya está entre las letras importadas (el id de la letra es el hash del fichero). -
descargar(state, id): para cada fichero que aún no está, bajahttps://raw.githubusercontent.com/google/fonts/<commit>/ofl/<ruta>, exige el SHA-256 fijado, lo importa conimportar_letra_datos(datos, "ttf")(guardado comofuentes/<sha256>.ttf), luego baja y verifica la licencia y la escribe enfuentes/licencias/<id>-OFL.txt. Cualquier desajuste aborta conErrorCode::Network. - Tests:
el_catalogo_esta_bien_escrito(commit de 40 caracteres, al menos 10 familias, ids únicos, cada ruta empieza por su id y termina en.ttfsin.., hashes de 64 caracteres, la licencia termina enOFL.txt),sin_descargar_ninguna_esta; los ignoradoslos_ficheros_son_los_del_catalogo(necesitaPB_GF, una copia local del repositorio de Google Fonts; comprueba los hashes y que cada fichero registra la familia declarada) yen_vivo. - Añadir una familia: copiar sus ficheros y su licencia del repositorio de Google Fonts en el commit (el fijado o uno nuevo), calcular el SHA-256 y el tamaño, añadir una entrada, añadir un PNG de muestra, ejecutar el test de hashes ignorado con
PB_GF. Si el commit cambia, todas las entradas deben seguir coincidiendo con ese commit.
-
Contenido fijado. Todo el contenido remoto de los packs se direcciona por un hash de commit completo y se verifica con un SHA-256 guardado en el binario de la app (
imagenes.json,packs-descargables.json,letras-libres.json). Se rechaza una rama sobrescrita a la fuerza, un fichero cambiado o una respuesta manipulada (ErrorCode::Network), así que un host comprometido no puede inyectar imágenes ni letras. -
Escrituras atómicas. Los ficheros se escriben con
escribir_atomico(temporal y luego renombrado), de modo que un fallo no deja ningún fichero a medias que pueda pasar por completo; la siguiente ejecución vuelve a comprobar los hashes. -
Lista de permitidos para el repositorio de packs.
descargables.rspasa porstate.externo(fuentes::Externo), que solo acepta la lista cerradaPERMITIDOSdesrc-tauri/src/fuentes/mod.rs(la entrada del repositorio de packs esraw.githubusercontent.comcon el prefijo de ruta/PoolFlamingo/proxy-builder-packs/), vuelve a comprobar cada redirección y limita cada descarga aMAX_IMAGEN(15 MiB). Un test unitario comprueba que todas las URL del manifiesto superan la lista. -
Original y letras.
original.rs,letras_libres.rsyletras_cjk.rs(las letras CJK, catálogosrc-tauri/assets/letras-cjk.json, véase Capa de aplicación del diseñador) usan su propio clientereqwestcon URL de repositorio fijadas en tiempo de compilación (Card Conjurer, Google Fonts) y los hashes fijados, no la lista de permitidos deExterno. Sus prefijos de URL no los puede controlar el usuario. -
Vista web. El contenido del pack lo baja Rust; la vista web nunca sale a la red (su CSP en
tauri.conf.jsonsolo permiteconnect-srca los endpoints de IPC), solo muestra imágenes renderizadas mediantepbimg://. Véanse Arquitectura y Fuentes externas. -
Packs de usuario. Solo se leen
.json,.svg,.png; los topes de tamaño se aplican a los zip; el id se sanea ybuiltinestá reservado; las rutas que contienen..se omiten. Un pack de usuario es de confianza en la medida en queresvgrasteriza sus SVG; Deducido: un SVG hostil, como mucho, puede producir píxeles incorrectos o malgastar CPU, ya que no interviene ningún motor de scripts. -
Licencias. Las letras descargadas conservan el texto de su licencia junto a ellas en
fuentes/licencias/.
docs/packs-de-marcos.md es la guía de creación mantenida, en español. Afirmaciones contrastadas con el código en esta página: reglas de versión del pack (1 o 2), paletas y huecos obligatorios, claves de si, nombres y tamaños de los layouts, PB_PACKS_LOCAL. Pequeña divergencia detectada: la guía dice que el pack Original distribuye «tres SVG propios» mientras que ORIGINAL en pack.rs lista cuatro; el comentario de módulo de descargables.rs menciona fuente/manifiesto.py mientras que el script del repositorio de packs es source/manifest.py.
| Objetivo | Empezar por |
|---|---|
Un campo nuevo en pack.json
|
pack.rs (añadirlo con #[serde(default, skip_serializing_if…)], subir VERSION_PACK solo si una app antigua lo pintaría mal), consumirlo en render.rs, documentarlo en docs/packs-de-marcos.md y aquí |
Una condición si nueva |
Condicion, Hechos y Condicion::cumple en pack.rs, rellenar Hechos en render::hechos_de
|
| Un pack descargable nuevo | construirlo en el repositorio de packs, añadir su entrada de manifiesto, asegurarse de que su prefijo de URL está permitido en PERMITIDOS
|
| Un layout de pack nuevo | añadirlo al pack.json integrado y su SVG, añadir un caso en tests/layouts.rs (Composición del diseñador) |
Use and build · Uso y desarrollo
- User-Guide · Guía de usuario
- Development-Setup · Preparación del entorno de desarrollo
- Testing-and-CI · Tests y CI
- Releases-and-Auto-Updates · Versiones y actualizaciones automáticas
- Conventions · Convenciones
Architecture · Arquitectura
- Architecture · Arquitectura
- IPC-and-Error-Handling · IPC y manejo de errores
- Rust-App-Layer · Capa de aplicación Rust
Data · Datos
- Deck-Model · Modelo del mazo
- Storage-and-Blobs · Almacenamiento y blobs
- Deck-Package-Format · Formato del paquete de mazo
- Deck-Library · Biblioteca de mazos
Getting cards · Conseguir cartas
- Decklist-Parsing · Parseo de la lista del mazo
- Scryfall-Integration · Integración con Scryfall
- External-Sources · Fuentes externas
- Card-Identification-and-OCR · Identificación de cartas y OCR
Layout, images, PDF · Maquetación, imagen y PDF
- Layout-Engine · Motor de maquetación
- Imaging-and-PDF · Imagen y PDF
- Export · Exportación
- Live-Preview · Vista previa en vivo
- Statistics · Estadísticas
Card designer · Diseñador de cartas
- Designer-Overview · Visión general del diseñador
- Designer-Engine · Motor del diseñador
- Designer-Composition · Composición del diseñador
- Frame-Packs · Packs de marcos
- Designer-App-Layer · Capa de aplicación del diseñador
- Designer-UI · Interfaz del diseñador
- Card-Editor-Dialog · Diálogo Editar carta
Game table · Mesa de juego
Frontend · Frontend
- Frontend-Architecture · Arquitectura del frontend
- State-Stores · Stores de estado
- Internationalization · Internacionalización
- Themes-and-Skins · Temas y skins
- Settings-and-Shell · Ajustes y shell
- Tutorials · Tutoriales
- Decklist-Panel · Panel de la lista del mazo
- Add-Card-and-Variants · Añadir carta y variantes
- Set-Browser · Explorador de sets
Reference · Referencia