Créer un document YAML pas à pas
Ce guide part d'un fichier vide pour construire un template strict
filemaker: "1.0". Un champ inconnu, une unité absente ou une combinaison
invalide échoue au lieu d'être devinée. Le YAML décrit le document ; les données
typées restent dans un JSON séparé, les polices et assets sont explicites et le
format de sortie est choisi lors de l'export.
1. Commencez par le plus petit document
Enregistrez report.yml :
filemaker: "1.0"
model: document
id: my-first-report
page:
preset: A4
elements:
- id: title
type: text
text: "Hello, FileMaker"
x: 20mm
y: 20mm
width: 170mm
height: 12mm
style:
font: NotoSans
font_size: 22pt
color: "#17324d"
filemakersélectionne le contrat ; V1 exige exactement"1.0".modelvautdocument,canvasoudataset.idest l'identifiant logique stable.pagedéfinit la surface physique.elementscontient les objets visuels dans un ordre stable.- Tout texte exige une police enregistrée ; les polices hôte ne sont jamais découvertes automatiquement.
appcore-filemaker check report.yml --json
appcore-filemaker validate report.yml \
--font NotoSans=./NotoSans-Regular.ttf \
--json
appcore-filemaker render report.yml \
--font NotoSans=./NotoSans-Regular.ttf \
--format pdf \
--output report.pdf
check valide le schéma. validate lie aussi les données et résout le layout.
render écrit l'artefact. Utilisez un preflight strict pour la sortie finale.
2. Choisissez la géométrie de page
page:
preset: A4
orientation: portrait
margin: { top: 12mm, right: 12mm, bottom: 15mm, left: 12mm }
safe: { top: 8mm, right: 8mm, bottom: 8mm, left: 8mm }
bleed: { top: 3mm, right: 3mm, bottom: 3mm, left: 3mm }
crop_marks: false
presetsélectionne une taille versionnée. V1 fournit les séries papier A/B/C, les formats nord-américains, écran, photo, enveloppe, étiquette, thermique et réseaux sociaux.orientationvautportraitoulandscape.marginréserve l'espace de layout.safedéfinit la zone sûre.bleeddéfinit la fond perdu hors du trim.crop_marksdemande les marques de coupe aux exporters compatibles.- Pour une taille personnalisée, utilisez
widthetheightà la place depreset, jamais avec lui.
page:
width: 1920px
height: 1080px
3. Utilisez des unités explicites
| Forme | Signification |
|---|---|
12pt | points PostScript |
20px | pixels logiques à 96 DPI |
15mm, 2.5cm, 1in | dimensions physiques |
50% | moitié de la dimension du conteneur |
0.5norm | forme normalisée de 50 % |
12lu | unités logiques du contexte |
auto | mesure automatique lorsqu'elle est permise |
Écrivez x: 20mm, jamais x: 20 sans unité.
4. Réutilisez thèmes, tokens et styles
themes:
base:
tokens:
ink: "#17324d"
accent: "#2e75b6"
pale: "#eef4f8"
style: { color: "$ink" }
board:
extends: base
theme: board
styles:
title: { font: NotoSans, font_size: 24pt, color: "$ink" }
card: { fill: "$pale", stroke: "$accent", stroke_width: 1pt }
themesdéclare des thèmes.extendshérite d'un autre thème sans cycle.tokensexpose des valeurs$nom.themeactive un thème.- Le
styleracine s'applique au template entier. stylesdéclare des fragments nommés.styles: [title, card]sur un élément les applique dans l'ordre.- Le
stylede l'élément est sa dernière couche statique.
Tous les champs de style :
| Champ | Rôle |
|---|---|
fill | couleur de remplissage |
stroke | couleur du contour |
stroke_width | épaisseur du contour |
opacity | opacité 0..1000000 |
font | nom logique de police enregistré |
font_size | taille de police |
color | couleur du texte |
Les couleurs acceptent noms stables, hex, rgb(...), rgba(...), gray(...),
cmyk(...) en millionièmes et couleurs typées. opacity: 240000 signifie 24 %.
5. Contrôlez la mesure du texte
- id: summary
type: text
text: "A bounded operational summary"
x: 20mm
y: 40mm
width: 100mm
height: 18mm
styles: [title]
text_options:
overflow: shrink
max_lines: 2
min_font_size: 10pt
line_height: 1200000
writing_mode: horizontal
overflow vaut wrap, shrink, ellipsis, clip, expand ou error.
shrink s'arrête à min_font_size; max_lines est borné; line_height est
un multiplicateur en millionièmes. writing_mode vaut horizontal (par
défaut) ou vertical. Le texte vertical est coupé selon la hauteur, chaque
colonne est façonnée de haut en bas et les colonnes avancent de droite à gauche.
PDF, SVG, PNG/JPEG et HTML utilisent les mêmes colonnes et runs résolus sans
reflow ; PDF et raster utilisent directement les avances des glyphes.
wrapcrée des retours à la ligne ;shrinkréduit le texte jusqu'àmin_font_size;ellipsistermine le texte en overflow par une ellipse ;clipcoupe l'overflow et enregistre un diagnostic ;expandagrandit la boîte mesurée ;erroréchoue si le texte ne tient pas.
Ajouts beta 5 (publiés le 2026-10-01)
Les ajouts ci-dessous sont disponibles dans
appcore-filemaker 0.1.0-beta.5. Ce sont des fonctions génériques de mise en
page; chaque application fournit ses données typées et ses libellés métier.
Les éléments texte et les colonnes de tableau acceptent
align_x: start|center|end; text_options.padding_inline applique un retrait
symétrique à chaque ligne façonnée. L'alignement utilise la largeur finale
après césure et réduction. Les champs YAML inconnus restent rejetés.
Les blocs texte autonomes acceptent
text_options.padding: { top, right, bottom, left }; des insets absolus,
logiques ou en pourcentage inférieur à 50 % réduisent le rectangle mesuré et
sont appliqués par tous les exports visuels. Les côtés horizontaux utilisent
la largeur de l'élément; haut et bas utilisent sa hauteur. La pagination du
texte développé réserve le padding vertical sur chaque fragment.
Chaque colonne accepte aussi padding: { top, right, bottom, left } en
longueurs absolues ou logiques non négatives. Le rectangle intérieur résolu sert
à la mesure, la pagination et au dessin dans chaque export; les colonnes auto
incluent les retraits horizontaux dans leur largeur mesurée.
Les règles conditionnelles du tableau acceptent text_offset_y pour déplacer
verticalement le texte peint sans modifier le contenu mesuré, la hauteur des
lignes ni la pagination. Utilisez une longueur absolue ou logique non nulle,
inférieure à la taille de police effective et à la hauteur intérieure de la
cellule. Le texte reste découpé aux limites d'origine; PDF, SVG, raster et HTML
appliquent le même décalage.
text_offset_y_first_page et text_offset_y_continuation le remplacent selon
le rôle physique de la page.
Les compositions d'une ligne avec un style partagé peuvent utiliser
text_segments à la place de text ou du binding de l'élément :
data_schema:
amount: { type: string }
elements:
- id: total
type: text
x: 10mm
y: 20mm
width: 180mm
height: 8mm
text_segments:
- { text: 'TOTAL:', gap_after: 7pt }
- { binding: data.amount }
text_options: { overflow: error, max_lines: 1, align_x: end }
Chaque segment exige exactement un text littéral ou un binding résolu en
chaîne. Les segments partagent le style de l'élément, restent horizontaux sur
une ligne et ne se replient pas séparément ; les espaces acceptent des longueurs
absolues ou logiques non négatives. Styles mixtes, composition BiDi et contenu
multiligne utilisent des éléments de flux séparés.
Le texte horizontal overflow: expand dans un flux vertical se divise
uniquement entre lignes façonnées complètes. Une ligne plus haute que la zone
utile échoue explicitement. Pour garder des éléments frères liés, définissez
keep_with_next: true jusqu'à l'avant-dernier élément du flux vertical. Les
lignes de tableau peuvent utiliser keep_together_by: layout_group: les clés
contiguës identiques restent ensemble si elles tiennent; les groupes plus grands
se divisent entre lignes complètes. Chaque ligne doit tenir sur une page.
Représentez un bloc logique plus haut qu'une page par plusieurs lignes
composantes avec la même clé; placez les valeurs totalisées sur une seule ligne
pour éviter leur double agrégation.
Les styles conditionnels acceptent aussi line_height, un ratio en millionièmes
de 500000 à 4000000. Le template peut régler l'interligne par style de ligne;
par exemple style: { line_height: 1250000 } signifie 1,25. Ce contrôle
typographique reste générique et n'introduit aucune règle de mise en page métier.
6. Dessinez des vecteurs sémantiques
- { id: surface, type: rect, x: 20mm, y: 70mm, width: 70mm, height: 35mm, style: { fill: "#eef4f8" } }
- { id: status, type: circle, x: 25mm, y: 76mm, width: 20mm, height: 20mm, style: { fill: "#2a9d8f" } }
- { id: divider, type: line, x: 20mm, y: 112mm, width: 170mm, height: 0pt, style: { stroke: "#2e75b6", stroke_width: 1pt } }
type implémenté | Usage |
|---|---|
text | texte façonné avec police explicite |
image | image résolue explicitement |
line | ligne droite ou commandes path |
rect | rectangle |
circle | largeur et hauteur résolues identiques |
ellipse | ellipse |
polygon | polygone fermé sans courbes |
path | lignes et courbes de Bézier cubiques |
group | conteneur d'enfants |
table | table typée et paginée |
chart reste réservé. La source non publiée supporte EAN-8/EAN-13 via
type: barcode et QR Code UTF-8 via type: qr, validés et abaissés en paths
vectoriels au layout. Voir le guide pour les budgets de payload et paths. Composez
les graphiques avec rect, line, path et text.
- id: trend
type: path
x: 105mm
y: 70mm
width: 80mm
height: 35mm
style: { stroke: "#f4a261", stroke_width: 2pt }
path:
- { command: move, x: 0%, y: 80% }
- { command: line, x: 30%, y: 55% }
- { command: curve, x1: 45%, y1: 70%, x2: 70%, y2: 10%, x: 100%, y: 20% }
Commandes : move, line, curve, close. Une courbe prend x1, y1,
x2, y2, x, y.
7. Séparez les données
data_schema:
report_title: { type: string }
requests: { type: integer }
target_met: { type: boolean }
rows: { type: array }
above_target:
type: boolean
computed: 'data.target_met == true'
Types : string, integer, decimal, boolean, date, date_time,
duration, currency, array, object, null. Ajoutez nullable: true si
null est valide. computed est déterministe et n'effectue aucun IO.
- id: bound-title
type: text
binding: data.report_title
x: 20mm
y: 20mm
width: 170mm
height: 12mm
styles: [title]
- id: success-badge
type: rect
when: data.target_met
x: 160mm
y: 20mm
width: 30mm
height: 10mm
bindingfournit la valeur principale.whencontrôle la visibilité.repeatdéveloppe un élément pour chaque valeur d'un tableau borné.style_rulesapplique des styles conditionnels ordonnés.
- id: repeated-row
type: group
repeat: data.rows
children: []
style_rules:
- when: 'data.target_met == true'
style: { fill: "#e4f4ec", color: "#1f7a4d" }
8. Utilisez groupes et flows
- id: kpis
type: group
x: 20mm
y: 55mm
width: 170mm
height: 35mm
layout: flow_horizontal
distribute: space_between
gap: 5mm
children:
- { id: kpi-a, type: rect, width: 50mm, height: 30mm }
- { id: kpi-b, type: rect, width: 50mm, height: 30mm }
- { id: kpi-c, type: rect, width: 50mm, height: 30mm }
layout vaut absolute, flow_vertical ou flow_horizontal. distribute
vaut start, center, end, space_between, space_around ou
space_evenly. Une distribution autre que start exige des tailles enfants
explicites ou préférées. gap définit l'espacement normal.
9. Construisez une table paginée
- id: results
type: table
binding: data.rows
x: 15mm
y: 120mm
width: 180mm
height: 150mm
style: { font: NotoSans, font_size: 8pt, color: "#17324d" }
table:
columns:
- { field: name, header: Name, width: { mode: flex, value: 2 } }
- { field: amount, header: Amount, width: { mode: fixed, value: 30mm } }
- { field: status, header: Status, width: { mode: auto } }
repeat_header: true
group_by: region
total_fields: [amount]
conditional_styles:
- { when: 'data.status == "Watch"', style: { fill: "#fff2e8", color: "#8f4b17" } }
auto_sample_rows: 8
max_rows: 100
max_row_fields: 12
max_cell_bytes: 256
header_height: 8mm
row_height: 7mm
columnsfixe l'ordre visuel.fixedest exact,flexpartage le reste etautomesure un échantillon borné.repeat_headerrépète l'en-tête après pagination.group_bymaintient la continuité du groupe.total_fieldsémet les totaux exacts sur la dernière page seulement.conditional_stylesévalue chaque ligne commedata.auto_sample_rowsborne la mesure.max_rows,max_row_fields,max_cell_bytespeuvent seulement réduire les limites globales.row_height: automesure les lignes ; une valeur explicite est plus prévisible.
Les règles conditionnelles acceptent aussi padding_first_page et
padding_continuation pour remplacer le retrait d'une ligne selon la page de
destination; à défaut, le padding ordinaire de la règle s'applique. Il s'agit
de contrôles de mise en page génériques et déclaratifs.
Les ajouts YAML beta5 comprennent aussi row_anchor_field pour des
ancres de ligne qui suivent leur page physique, page_bodies.first et
page_bodies.continuation pour des zones de tableau distinctes, et min_height
conditionnel avec des variantes première page/continuation. Ces fonctions
n'ajoutent aucun calcul ni agencement spécifique à une application dans le
Runtime.
Limites connues de cette révision source : chaque ligne/cellule de tableau doit tenir sur une page ; les blocs logiques plus grands ne peuvent se poursuivre qu'en lignes complètes ou éléments d'un flux vertical. Les runs rich text ne sont pas pris en charge; des éléments séparés dans un flux sont l'alternative. La source non publiée supporte EAN-8/EAN-13 et QR Code au layout ; les autres symbologies ne sont pas inférées. Les polices doivent être fournies et sélectionnées explicitement ; le Runtime ne choisit pas implicitement les polices de l'hôte. Chaque application garde ses données métier et son dessin YAML ; ces primitives génériques n'encodent pas les règles commerciales d'une application particulière.
10. Ajoutez rôles de page, numérotation et filigrane
page:
preset: A4
master:
header:
- { id: top-rail, type: rect, x: 0mm, y: 0mm, width: 100%, height: 7mm, style: { fill: "#17324d" }, locked: true }
footer:
- { id: page-number, type: text, text: "Page {page} of {pages}", x: 160mm, y: 285mm, width: 35mm, height: 5mm, style: { font: NotoSans, font_size: 8pt }, locked: true }
first:
footer:
- id: confidential
type: text
text: "CONFIDENTIAL"
x: 5mm
y: 113mm
width: 200mm
height: 42mm
style: { font: NotoSans, font_size: 78pt, color: "#8da3b5", opacity: 240000 }
transform: { rotate: -32, origin_x: 50%, origin_y: 50% }
locked: true
masterapparaît sur chaque page ;firstapparaît sur la première page ;continuationapparaît uniquement sur les pages intermédiaires ;lastapparaît sur la dernière page si le document en a plusieurs ;{page}et{pages}sont résolus après pagination ;- les layers de page ne collisionnent pas avec le corps ;
locked: truerefuse les patches runtime sur cet élément.
11. Résolvez les images explicitement
- id: hero
type: image
asset: images/hero.png
x: 20mm
y: 40mm
width: 170mm
height: 70mm
image:
fit: cover
focal_x: 500000
focal_y: 350000
crop: { left: 0, top: 0, right: 0, bottom: 0 }
respect_exif: true
fit vaut contain, cover, fill, none, scale_down. Foyer et crop sont
en parties par million de 0 à 1000000. Fournissez le même resolver borné à
racine canonique au layout et à l'export ; traversal et liens sortants échouent.
12. Guides, regions, anchors et constraints
guides:
content-left: 15mm
regions:
body: { x: 15mm, y: 25mm, width: 180mm, height: 245mm }
elements:
- id: card
type: rect
region: body
anchors: { left: "guide:content-left" }
constraints:
min_width: 40mm
preferred_width: 60mm
max_width: 90mm
preferred_height: 30mm
aspect_ratio: 2000000
align_y: center
guidessont des positions nommées ;regionssont des rectangles nommés avec overridecollisionfacultatif ;regionchoisit le conteneur de l'élément ;anchorsvise un guide ou un bord antérieur, avec offset facultatif ;constraintsacceptemin_width,preferred_width,max_width,min_height,preferred_height,max_height,aspect_ratioen millionièmes ;align_xetalign_yvalentstart,center,end; ne combinez pas alignement et coordonnée explicite sur le même axe.
13. Appliquez un transform
transform:
translate_x: 2mm
translate_y: 0mm
rotate: -15
scale_x: 1000000
scale_y: 1000000
flip_x: false
flip_y: false
mirror: none
origin_x: 50%
origin_y: 50%
L'échelle utilise les millionièmes. mirror vaut none, horizontal,
vertical ou both. Tous les exporters graphiques reçoivent le même transform.
14. Collision et exclusions
Utilisez la forme courte pour sortir du système :
collision: false
Ou utilisez la déclaration complète :
collision:
enabled: true
group: content
collides_with: [content, exclusion]
ignore: [decorative-line]
priority: 10
movable: true
bounds: layout
policy: push
Les policies sont push, error, overlay, next_page, shrink. L'héritage
est document → page → region → group → élément.
exclusions:
header-clearance:
x: 0mm
y: 0mm
width: 100%
height: 18mm
group: exclusion
collides_with: [content]
Une exclusion réserve une géométrie répétée sans la peindre.
15. Components et includes
components:
metric-card:
props: { label: Metric }
slots: { detail: [] }
elements:
- { id: surface, type: rect, x: 0mm, y: 0mm, width: 50mm, height: 25mm }
elements:
- id: requests-card
type: group
component: metric-card
props: { label: Requests }
Un component déclare props, slots remplaçables et elements. Une instance
utilise component, props, slots.
includes:
- path: fragments/header.yml
namespace: report
Les includes exigent un resolver sandboxed. namespace évite les collisions
d'ID. Un fragment inclus ne peut posséder les layers physiques de page.
16. Intention facultative pour le bridge IA
ai:
purpose: "Maintain a bounded monthly report."
rules:
- "Preserve page numbering."
- "Never remove the confidential watermark."
editable: [report-title, results]
locked: [confidential, page-number]
Le core déterministe conserve seulement cette policy. Le bridge optionnel peut
interpréter purpose, rules, les ID editable et les ID locked.
Référence complète des champs racine
| Champ | Requis | Rôle |
|---|---|---|
filemaker | oui | version exacte "1.0" |
model | oui | document, canvas, dataset |
id | oui | ID logique stable |
page | non | géométrie, bords, collision, layers |
collision | non | policy de collision héritée |
includes | non | fragments explicites |
components | non | composants réutilisables |
themes | non | héritage, tokens et style |
theme | non | thème actif |
style | non | style global |
styles | non | styles nommés |
guides | non | positions nommées |
regions | non | conteneurs rectangulaires |
exclusions | non | géométrie réservée non peinte |
data_schema | non | contrat de données typées |
elements | non | éléments racine ordonnés |
ai | non | intention pour bridge externe |
page accepte preset, width, height, orientation, margin, bleed,
safe, crop_marks, collision, master, first, continuation, last.
Chaque objet de bord accepte top, right, bottom, left. Chaque rôle de
page accepte les listes background, header, footer.
Référence complète des champs d'un élément
| Champ | Rôle |
|---|---|
id | ID ASCII sûr unique de 1–128 octets |
type | type de l'élément |
component | component à instancier |
props | propriétés de l'instance |
slots | contenu des slots nommés |
x, y, width, height | géométrie avec unités |
constraints | tailles min/préférée/max et ratio |
align_x, align_y | alignement dans le conteneur |
text | texte littéral |
text_options | overflow, lignes, minimum, écriture |
table | options obligatoires d'une table |
asset | référence image explicite |
image | fit, focus, crop et EXIF |
path | commandes vectorielles |
styles | liste de styles nommés |
style | style inline |
style_rules | styles conditionnels ordonnés |
transform | translation, rotation, échelle, miroir, origine |
layout | layout absolute ou flow |
distribute | distribution des enfants du flow |
gap | distance entre les enfants |
binding | expression data principale |
when | expression de visibilité |
repeat | expansion d'un tableau |
anchors | anchors de placement nommés |
region | region contenant l'élément |
children | éléments imbriqués |
locked | refuse les patches runtime |
hidden | masqué initialement |
layer | nom de la layer visuelle |
z_index | ordre dans la layer |
collision | override de collision |
Les champs sont liés au type : text_options s'applique à text; une table
n'accepte que min_font_size, line_height et writing_mode, car son planner
contrôle l'overflow et les limites de lignes des cellules. table et un
binding de tableau sont obligatoires pour table; path seulement sur
line, path, polygon; une table n'accepte ni children ni slots.
Ordre de travail recommandé
- Version, model, ID, page et un texte.
- Exécutez
check. - Enregistrez la police et exécutez
validate. - Ajoutez
data_schemaet le JSON typé séparé. - Créez tokens et styles nommés avant de répéter le style inline.
- Ajoutez groupes et tables par petits incréments validés.
- Utilisez
inspect,explain,debugpour comprendre le layout. - Exécutez
preflight --strictpour le format final. - Rendez seulement lorsque le preflight est propre.
appcore-filemaker schema --json et
appcore-filemaker capabilities --json donnent la vérité exécutable du
binaire installé. Comparez le
YAML de base
et le
YAML intermédiaire.