En poques paraules
Una pàgina de comptes per a infants de nou anys en castellà, anglès, francès i alemany. Cada país escriu la divisió a la seva manera i la fitxa ho segueix; un interruptor mostra la còpia del mestre amb totes les respostes.
Què compondràs
La unitat 3 d’un quadern de càlcul de quart de primària, Les quatre operacions, en quatre edicions. Una fila de càlcul mental en tres columnes; sumes, restes i multiplicacions escrites amb una xifra per casella i una fila de caselles per al resultat; divisions i un problema en quadrícula. A la divisió les edicions se separen: la castellana i la francesa posen el divisor en una caixa a la dreta del dividend i el quocient a sota; l’anglesa el deixa fora del signe ⟌, la «caseta», amb el quocient a sobre; l’alemanya escriu 864 : 4 = en una línia amb lloc a sota per als passos, i els productes amb un punt. La coma o el punt decimal del càlcul mental també segueix la llengua. Un interruptor sobre les pàgines converteix la fitxa de l’alumne en la còpia del mestre, amb cada resposta en taronja a la seva casella.
Aquesta recepta respon a
- Com componc la divisió llarga tal com l'escriuen les escoles de cada país?
- Com faig l'edició del professor, amb les respostes al seu lloc, a partir del llibre de l'alumne?
La resposta curta
// `- 864 : 4` in the Markdown is one operation; the style sets it digit by digit in squares
// of 7.2 mm, a cell for each figure of the answer. Long division follows the country: the
// divisor in an L right of the dividend in Spain and France (potence), `864 : 4 =` on one
// line in Germany, the bracket ⟌ in English-speaking schools.
const calculo = {
id: 'calculo',
number: { shape: 'disc', background: col('accent'), fontFamily: LABEL, fontWeight: 700 },
instruction: { bold: true, color: col('ink') },
grid: { cell: mm(9), fontFamily: TEXT, fontSize: pt(15), rule: col('rule'),
color: col('ink') },
arithmetic: { columns: 4,
division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
blank: { look: 'box', width: em(3.2), color: col('rule'), weight: pt(0.8) },
area: { kind: 'grid', spacing: mm(5), color: col('rule'), weight: pt(0.4) },
answers: { color: col('accent'), fontFamily: LABEL }, // the teacher's copy, in the accent
marginTop: mm(7), marginBottom: mm(2), itemSpacing: em(0.5),
};
Ingredients
- Funcions
- Operacions en columnaEdició del professorEstils d'exerciciExercicisBuits i bancs de paraulesPreguntes obertes i zones d'escripturaObertures dissenyadesAtributs de títolPaleta de color semànticaPartició de mots i llengua del documentPàgines en un canvasExportació a PDFEstils de paràgraf
- Tipografia
- Fira Sans, Lexend (SIL OFL 1.1)
- Recursos
- Cap: totes les imatges es dibuixen en codi
Elaboració
#1 · Escriu els comptes com a línies del Markdown
// `- 864 : 4` in the Markdown is one operation; the style sets it digit by digit in squares
// of 7.2 mm, a cell for each figure of the answer. Long division follows the country: the
// divisor in an L right of the dividend in Spain and France (potence), `864 : 4 =` on one
// line in Germany, the bracket ⟌ in English-speaking schools.
const calculo = {
id: 'calculo',
number: { shape: 'disc', background: col('accent'), fontFamily: LABEL, fontWeight: 700 },
instruction: { bold: true, color: col('ink') },
grid: { cell: mm(9), fontFamily: TEXT, fontSize: pt(15), rule: col('rule'),
color: col('ink') },
arithmetic: { columns: 4,
division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
blank: { look: 'box', width: em(3.2), color: col('rule'), weight: pt(0.8) },
area: { kind: 'grid', spacing: mm(5), color: col('rule'), weight: pt(0.4) },
answers: { color: col('accent'), fontFamily: LABEL }, // the teacher's copy, in the accent
marginTop: mm(7), marginBottom: mm(2), itemSpacing: em(0.5),
};
Un :::exercise{type="arithmetic"} porta una operació per element de llista, - 864 : 4, amb els signes que escriu el seu país (:, ÷, ×, ·). El motor calcula el resultat, el quocient i la resta, i l’estil decideix com es dibuixa el compte: caselles de 7,2 mm i arithmetic.division triada per edició amb t(). La fila de càlcul mental és un exercici de buits corrent amb la llista dins d’un grup :::columns{count=3}, i cada [[70]] és una casella de la mateixa amplada que les altres.
#2 · Encapçala la fitxa
const at = (to, edge, x = 0, y = 0, size) => ({ anchor: { to, edge },
offset: { x: mm(x), y: mm(y) }, ...(size && { size }) });
const field = (id, attr, x, width) => [
{ kind: 'text', id, content: `{attr.${attr}}`, fontFamily: LABEL, fontSize: pt(9.5),
fontWeight: 600, color: col('muted'), align: 'left',
placement: at('container', 'top-left', x, 26) },
{ kind: 'rule', id: `${id}-line`, direction: 'horizontal', thickness: pt(0.75),
color: col('rule'), placement: at('container', 'top-left', x + 17, 31, { width: mm(width) }) },
];
const head = { enabled: true, minHeight: mm(36), slot: { elements: [
{ kind: 'box', id: 'band', style: { backgroundColor: col('accent'), borderRadius: mm(3) },
placement: at('container', 'top-left', 0, 0, { width: 'fill', height: mm(19) }) },
{ kind: 'text', id: 'unit', content: '{attr.unidad}', fontFamily: LABEL, fontSize: pt(9),
fontWeight: 700, color: col('accent'), align: 'center', verticalAlign: 'middle',
textTransform: 'uppercase', letterSpacing: pt(1.2), lineHeight: 1.1,
box: { backgroundColor: col('paper'), borderRadius: mm(3.5) },
placement: at('container', 'top-left', 5, 5, { width: mm(26), height: mm(9) }) },
{ kind: 'text', id: 'title', content: '{titleText}', fontFamily: LABEL, fontSize: pt(21),
fontWeight: 700, color: col('paper'), align: 'left', lineHeight: 1.1,
placement: at('container', 'top-left', 37, 5.2) },
...field('name', 'nombre', 0, 100), ...field('date', 'fecha', 124, 38),
] } };
El títol de nivell 1 de la unitat dibuixa la banda taronja, la píndola i el títol, i també els camps de nom i data a partir dels seus atributs (nombre="Nombre" fecha="Fecha"), de manera que cada edició els retola en la seva llengua.
#3 · Canvia entre la fitxa de l’alumne i la còpia del mestre
const form = document.getElementById('controls');
const labels = t({ es: ['Alumno', 'Profesor'], en: ['Pupil', 'Teacher'],
fr: ['Élève', 'Enseignant'], de: ['Schüler', 'Lehrkraft'] });
form.querySelectorAll('label span').forEach((span, k) => { span.textContent = labels[k]; });
function render() {
// The same config, edited in place: the next build sees the edition the form asks for.
config.exercises.edition = form.elements.edition.value;
const doc = buildDocument({ markdown }, config); // the faces are loaded by now
showPages(doc, { title });
document.querySelectorAll('#pt-actions a, [data-postext-pdf]').forEach((old) => old.remove());
offerPdf(() => renderToPdf(doc, { fontProvider: fontsourceProvider }),
`${RECIPE}-${LANG}-${config.exercises.edition}.pdf`);
}
form.addEventListener('change', render);
render();
exercises.edition: 'teacher' imprimeix cada resposta al seu lloc amb el color de answers.color, aquí el d’accent: les caselles del càlcul mental, les xifres de cada resultat, el quocient i la resta, la resposta model del problema. El formulari sobre les pàgines canvia la configuració al seu lloc i torna a compondre; les fonts ja estan carregades, així que n’hi ha prou amb buildDocument. La captura compon abans les dues fitxes, de manera que les pàgines publicades mostren la de l’alumne i després la del mestre.
La recepta completa
// ═══ Postext Cookbook · Nº 170 · Column arithmetic as each country writes it ═══════
// https://postext.dev/en/cookbook/column-arithmetic-by-country
// Code: MIT · Text: original (CC BY 4.0) · Pictures: none
// Fonts: Fira Sans, Lexend (SIL OFL 1.1) · Needs postext ≥ 1.59.0
import { buildDocumentWithFonts, buildDocument, renderPageToCanvas } from 'https://esm.sh/postext';
import { renderToPdf, decompressWoff2 } from 'https://esm.sh/postext-pdf';
const LANG = 'es'; // @lang: the language of the worksheet ('es' | 'en' | 'fr' | 'de')
const RECIPE = 'column-arithmetic-by-country';
// ─── 1 · Design ─────────────────────────────────────────────────────────────
// #region palette: ink, one orange accent, a pale tint, the grey of squared paper
const palette = {
ink: '#1f2328', accent: '#c4511c', tint: '#fbeee6', rule: '#b9c0c8', muted: '#5f6670',
paper: '#ffffff',
};
const col = (id) => ({ hex: palette[id], model: 'hex', paletteId: id });
const colorPalette = [
...Object.entries(palette).map(([id, hex]) => ({ id, name: id, value: { hex, model: 'hex' } })),
{ id: 'main-color', name: 'accent (defaults)', value: { hex: palette.accent, model: 'hex' } },
];
// #endregion
const [TEXT, LABEL] = ['Fira Sans', 'Lexend'];
// #region answer: operations in squares, long division as the edition's schools set it
// `- 864 : 4` in the Markdown is one operation; the style sets it digit by digit in squares
// of 7.2 mm, a cell for each figure of the answer. Long division follows the country: the
// divisor in an L right of the dividend in Spain and France (potence), `864 : 4 =` on one
// line in Germany, the bracket ⟌ in English-speaking schools.
const calculo = {
id: 'calculo',
number: { shape: 'disc', background: col('accent'), fontFamily: LABEL, fontWeight: 700 },
instruction: { bold: true, color: col('ink') },
grid: { cell: mm(9), fontFamily: TEXT, fontSize: pt(15), rule: col('rule'),
color: col('ink') },
arithmetic: { columns: 4,
division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
blank: { look: 'box', width: em(3.2), color: col('rule'), weight: pt(0.8) },
area: { kind: 'grid', spacing: mm(5), color: col('rule'), weight: pt(0.4) },
answers: { color: col('accent'), fontFamily: LABEL }, // the teacher's copy, in the accent
marginTop: mm(7), marginBottom: mm(2), itemSpacing: em(0.5),
};
// #endregion
// #region head: the unit pill, the title and the lines for a name and a date
const at = (to, edge, x = 0, y = 0, size) => ({ anchor: { to, edge },
offset: { x: mm(x), y: mm(y) }, ...(size && { size }) });
const field = (id, attr, x, width) => [
<form id="controls" aria-label="Edition">
<label><input type="radio" name="edition" value="student" checked> <span></span></label>
<label><input type="radio" name="edition" value="teacher"> <span></span></label>
</form>
<main id="pages"></main>
/* The edition switch above the desk: two pills in the sheet's orange. */
#controls {
display: flex; justify-content: center; gap: 8px; padding: 14px 16px; background: #16181d;
font: 600 14px/1.2 Lexend, system-ui, sans-serif;
}
#controls label {
display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding: 0 18px;
border-radius: 22px; color: #f4f1ea; border: 1px solid #5f6670; cursor: pointer;
}
#controls label:has(input:checked) { background: #c4511c; border-color: #c4511c; }
#controls input { accent-color: #fff; }
L'script.js compost funciona tal com és: enganxa'l com a script de mòdul en qualsevol pàgina o obre la recepta a CodePen. Carpeta de la recepta a GitHub ↗ (s'obre en una pestanya nova)
Variants
#Posa les solucions de cap per avall al peu
Un costum dels quaderns de passatemps: la clau de cada exercici, girada 180° a sota seu.
- exercises: { edition: 'student' }, // the switch above the pages sets 'teacher'
+ exercises: { edition: 'student', solutions: { placement: 'inverted', layout: 'key' } },#Divideix amb la caseta a totes les edicions
Les escoles japoneses i xineses també fan servir la caseta ⟌; una llengua que no és a la llista pren la seva pròpia.
- division: t({ es: 'potence', fr: 'potence', de: 'inline', en: 'bracket' }) },
+ division: 'bracket' },Errors freqüents
- Les operacions són de nombres enters: un compte amb decimals com
12,5 + 3,75no es llegeix i s’imprimeix tal com està escrit. Deixa els decimals als buits del càlcul mental, on la resposta és text.
Crèdits
- Recepta
- Ignacio Ferro
- Text
- Text original, CC BY 4.0
- Fonts
- Fira Sans (SIL OFL 1.1) · Lexend (SIL OFL 1.1)
- Codi
- MIT, com Postext
Editar aquest text ↗ (s'obre en una pestanya nova)Carpeta de la recepta a GitHub ↗ (s'obre en una pestanya nova)


