Code frameworks
Inicio rápido: tu primer code framework
Escribe un juego pequeño con un personaje, dos acciones y una hoja. Luego compruébalo y crea un personaje en The Forge.
Antes de empezar
- Necesitas un plan de pago para crear un Juego.
- Crea un juego privado en The Forge. Elige «CREA TU PROPIO JUEGO», luego «Editor manual», y crea el juego.
- Escribe los archivos en cualquier editor y pégalos en el editor de código fuente, o escríbelos directamente allí.
El juego
Lantern Keepers tiene un personaje, el Keeper. Un Keeper tiene un nombre, unos PV máximos y los PV actuales. Dos acciones cambian los PV: Recibir daño y Curar. Curar nunca supera el máximo.
Paso 1: el manifiesto
El manifiesto nombra el proyecto y enumera cada Framework y cada archivo de escenarios. Conserva el projectId que el editor creó para tu juego. El valor de este ejemplo es solo un marcador.
{
"formatVersion": "fabled.game-project/v1",
"projectId": "game-your-game-id",
"projectKind": "GAME",
"compilerProfile": "native-game-v1",
"name": "Lantern Keepers",
"entryFramework": "keeper",
"frameworks": ["schemas/keeper.json"],
"scenarios": ["scenarios/new-keeper.json", "scenarios/heal.json"]
}- Línea 3 Conserva el projectId que el editor creó para tu juego. Este es solo un marcador.
- Líneas 4-5 GAME es un juego completo con un personaje jugable. native-game-v1 es el único perfil.
- Línea 7 El Framework que un jugador crea primero.
- Líneas 8-9 Aquí se enumeran todos los archivos de Framework y todos los archivos de escenarios.
Paso 2: el Framework
Un archivo de Framework declara lo que introduce el jugador (entradas), lo que puede hacer el Keeper (acciones) y qué Frame lo dibuja. El constructor y cada acción apuntan a un archivo de reglas.
{
"id": "keeper",
"name": "Keeper",
"elementType": "character",
"constructor": "rules/keeper.ts",
"inputs": {
"name": { "label": "Name" },
"max_hp": { "label": "Maximum HP", "defaultValue": 10 }
},
"actions": [
{ "id": "hurt", "name": "Take damage", "source": "rules/hurt.ts" },
{ "id": "heal", "name": "Heal", "source": "rules/heal.ts" }
],
"frames": [
{ "id": "sheet", "source": "layouts/keeper.json", "default": true }
]
}- Líneas 2-5 Qué es el Framework: su id, su nombre visible, el tipo de Elemento que crea y el archivo de reglas que crea uno.
- Líneas 6-9 Entradas que rellena el jugador. Cada clave coincide con un parámetro del constructor.
- Líneas 10-13 Acciones. Cada una apunta a un archivo de reglas.
- Líneas 14-16 Los Frames que dibujan a un Keeper. Exactamente uno es el predeterminado.
Paso 3: el constructor
El constructor convierte las entradas en los valores iniciales. Su tipo de retorno enumera cada campo guardado. Un Keeper nuevo empieza con los PV al máximo.
export function construct(
name: string,
max_hp: number,
): { name: string; max_hp: number; hp: number } {
return { name: name, max_hp: max_hp, hp: max_hp };
}- Líneas 1-4 Las entradas y los campos que devuelve el constructor.
- Línea 5 Los valores iniciales. Un Keeper nuevo empieza con los PV al máximo.
Paso 4: las acciones
Una acción recibe primero el Elemento y después sus propias entradas. Cambia valores solo a través del ledger. Recibir daño suma una cantidad negativa. Cuando un jugador usa el botón de una acción con entradas, como amount, Fabled se las pide en un cuadro de diálogo.
export function hurt(self: ElementRef, amount: number): void {
ledger.add(self, "hp", 0 - amount);
}- Línea 2 ledger.add cambia hp en una cantidad. Sumar un número negativo resta.
Curar lee dos valores y luego establece los nuevos PV. No hace nada cuando el Keeper ya tiene los PV al máximo, así que ese caso no escribe nada.
export function heal(self: ElementRef, amount: number): void {
const hp: number = element.var(self, "hp") as number;
const max_hp: number = element.var(self, "max_hp") as number;
if (hp < max_hp) {
ledger.set(self, "hp", math.min(max_hp, hp + amount));
}
}- Líneas 2-3 Lee los PV actuales y los máximos. element.var da un valor que conviertes con as number.
- Línea 4 No hagas nada cuando el Keeper ya tiene los PV al máximo, así que ese caso no escribe nada.
- Línea 5 Establece hp en el menor entre el máximo y el valor curado.
Paso 5: el Frame
El Frame dibuja la hoja. El texto muestra valores con enlaces del estilo {{element.attributes.name}}. Cada botón nombra un alias de acción que declara el contrato de datos.
{
"version": "1.0",
"metadata": {
"name": "Keeper sheet",
"bindingMode": "bound",
"frameworkRef": "keeper",
"context": "BLADE",
"template": "standard-blade"
},
"dataContract": {
"requiredBindings": [
{ "binding": "element.attributes.name", "expectedType": "string" },
{ "binding": "element.attributes.hp", "expectedType": "number" },
{ "binding": "element.attributes.max_hp", "expectedType": "number" }
],
"optionalBindings": [],
"actions": [
{ "name": "hurt", "functionRef": "hurt" },
{ "name": "heal", "functionRef": "heal" }
],
"regions": []
},
"layout": {
"kind": "container",
"children": [
{ "kind": "text", "text": "{{element.attributes.name}}" },
{
"kind": "text",
"text": "HP: {{element.attributes.hp}} / {{element.attributes.max_hp}}"
},
{ "kind": "button", "label": "Take damage", "actionRef": "hurt" },
{ "kind": "button", "label": "Heal", "actionRef": "heal" }
]
}
}- Líneas 3-9 metadata da nombre al Frame e indica a qué Framework pertenece.
- Líneas 10-22 dataContract enumera los campos que lee el Frame y las acciones que pueden llamar sus botones.
- Líneas 23-34 layout es el árbol que se dibuja. El texto muestra campos con llaves dobles, y los botones nombran un alias de acción.
Paso 6: los escenarios
Un escenario crea un Keeper y comprueba sus valores iniciales.
{
"id": "new-keeper",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 }
}- Línea 4 Las entradas con las que crear al Keeper.
- Línea 5 Todos los valores que debe devolver el constructor.
Este escenario recibe daño, cura por encima del máximo y vuelve a curar con los PV al máximo. Cada paso enumera las escrituras exactas que debe hacer la acción. El último paso no enumera ninguna.
{
"id": "heal-after-damage",
"framework": "keeper",
"parameters": { "name": "Mira", "max_hp": 10 },
"expectedValues": { "name": "Mira", "max_hp": 10, "hp": 10 },
"actions": [
{
"action": "hurt",
"parameters": { "amount": 6 },
"expectedWrites": [{ "op": "ledger.add", "key": "hp", "value": -6 }]
},
{
"action": "heal",
"parameters": { "amount": 9 },
"expectedWrites": [{ "op": "ledger.set", "key": "hp", "value": 10 }]
},
{ "action": "heal", "parameters": { "amount": 3 }, "expectedWrites": [] }
]
}- Líneas 7-11 Paso uno: recibe 6 de daño. La acción debe hacer exactamente una escritura, un ledger.add de -6.
- Líneas 12-16 Paso dos: cura 9. El resultado se limita al máximo, así que hp se establece en 10.
- Línea 17 Paso tres: cura otra vez con los PV al máximo. La protección omite la escritura, así que no se espera ninguna escritura.
Llévalo a The Forge
- Abre tu juego en The Forge.
- En el paso «Jugabilidad», elige «Avanzado: código fuente y versiones» para abrir el editor de código fuente.
- Si el juego aún no tiene proyecto, elige «Escribirlo yo» para empezar con ejemplos editables. No elijas «Empezar a crear mi juego», que es la ruta con IA. Sustituye los archivos de ejemplo por los archivos de arriba: usa «Añadir archivo» para las rutas nuevas y «Eliminar archivo» para los archivos que no necesites. Conserva el projectId que el editor puso en el manifiesto.
- Elige Comprobar y previsualizar. Corrige cada problema de la lista y vuelve a comprobar.
- Elige Guardar proyecto.
- Elige Preparar mi juego. Esto crea Frameworks, Frames y contenido privados a partir de tu versión guardada.
- Elige Crear un personaje en este juego y prueba Recibir daño y Curar en la hoja.
Rómpelo a propósito
Cambia el campo que escribe Curar de hp a mana. El compilador se detiene y nombra el problema.
export function heal(self: ElementRef, amount: number): void {
const hp: number = element.var(self, "hp") as number;
const max_hp: number = element.var(self, "max_hp") as number;
if (hp < max_hp) {
ledger.set(self, "mana", math.min(max_hp, hp + amount));
}
}La comprobación informa:
Action "keeper.heal" calls ledger.set(self, "mana", ...), and "mana" is not declared on this schema. Declared scalar fields: hp, max_hp, name.Vuelve a poner el nombre hp y la comprobación pasa. Las reglas solo pueden escribir campos que devuelve el constructor.

