@imontene/mdrender 2.6.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Cambios
2
2
 
3
+ ## 2.7.0 — 2026-10-23
4
+
5
+ - `--watermark-field` pone ahora dos campos de luz en cada página: arriba a la izquierda (antes
6
+ arriba a la derecha) y uno nuevo abajo a la derecha. El campo junto al título de la primera
7
+ página no cambia.
8
+
9
+ ## 2.6.1 — 2026-10-22
10
+
11
+ - **PDF mucho más livianos con los campos de luz.** Chrome convertía los degradados CSS del
12
+ campo en varias imágenes por página. Ahora el campo es un SVG que queda en el PDF como
13
+ sombreado vectorial, con el mismo aspecto:
14
+ - con `--watermark-field`, el README pasa de 3,0 MB a 0,41 MB (antes unos 290 KB más por
15
+ página, ahora unos 7 KB en total);
16
+ - con el tema Anti-Gravity, el campo junto al título ya no añade ~140 KB a cada documento
17
+ con título (el ejemplo pasa de 332 KB a 195 KB).
18
+
3
19
  ## 2.6.0 — 2026-10-22
4
20
 
5
21
  - **Marcas de agua** con el degradado Anti-Gravity, solo en el PDF y desactivadas por defecto:
package/README.md CHANGED
@@ -157,7 +157,7 @@ equipo); `--port` fija el puerto y `--no-open` no abre el navegador.
157
157
  | `--font <manrope\|inter>` | Tipografía del texto (ver abajo) | `manrope` |
158
158
  | `--no-justify` | Párrafos alineados a la izquierda en el PDF (ver abajo) | justificado |
159
159
  | `--watermark <texto>` | Marca de agua en diagonal en cada página del PDF, con el degradado Anti-Gravity | — |
160
- | `--watermark-field` | Campo de luz con el degradado en la esquina de cada página del PDF | — |
160
+ | `--watermark-field` | Campos de luz con el degradado arriba a la izquierda y abajo a la derecha de cada página del PDF | — |
161
161
  | `--density <densidad>` | `normal` o `compact` (menos espacio entre líneas y bloques) | `normal` |
162
162
  | `--font-size <tamaño>` | Tamaño del texto en `pt` o `px`, de 6 a 24 pt; p. ej. `10pt` | `10.5pt` |
163
163
  | `--theme <tema\|css>` | `antigravity`, `antigravity-dark`, `light`, `dark` o un `.css` que reemplaza el tema (ver abajo) | `antigravity` |
@@ -202,7 +202,7 @@ Anti-Gravity, cada una por separado y solo en el PDF:
202
202
 
203
203
  ```bash
204
204
  mdrender informe.md --watermark "Borrador" # texto en diagonal en cada página
205
- mdrender informe.md --watermark-field # campo de luz en la esquina de cada página
205
+ mdrender informe.md --watermark-field # campos de luz arriba a la izquierda y abajo a la derecha
206
206
  ```
207
207
 
208
208
  También como `watermark: Borrador` y `watermarkField: true` en el front matter o en
@@ -11,7 +11,6 @@
11
11
  --ag-hairline-strong: #3a4352;
12
12
  --ag-accent: #7ea4ff;
13
13
  --ag-accent-soft: #16213b;
14
- --ag-opacity-field: 0.22;
15
14
  --ag-shadow-card: 0 1px 2px rgba(0, 0, 0, 0.4), 0 12px 32px rgba(0, 0, 0, 0.35);
16
15
 
17
16
  --alert-warning: #e3b341;
@@ -16,10 +16,6 @@
16
16
  --ag-hairline-strong: #c9d0db;
17
17
  --ag-accent: #2456d3;
18
18
  --ag-accent-soft: #ecf1fd;
19
- --ag-field-blue: #4f7cff;
20
- --ag-field-cyan: #22c3e6;
21
- --ag-field-violet: #8c6cf0;
22
- --ag-opacity-field: 0.16;
23
19
  --ag-shadow-card: 0 1px 2px rgba(15, 20, 25, 0.04), 0 12px 32px rgba(15, 20, 25, 0.06);
24
20
 
25
21
  /* The variables theme.css is written with */
@@ -152,12 +148,10 @@ h6 {
152
148
  right: 0;
153
149
  bottom: 0;
154
150
  width: 36%;
155
- opacity: var(--ag-opacity-field);
156
151
  pointer-events: none;
157
- background:
158
- radial-gradient(28% 38% at 58% 45%, var(--ag-field-blue), transparent),
159
- radial-gradient(16% 26% at 78% 58%, var(--ag-field-cyan), transparent),
160
- radial-gradient(25% 30% at 40% 32%, var(--ag-field-violet), transparent);
152
+ /* An SVG image (render/field.ts) set by mdrender, with the theme's opacity: CSS gradients
153
+ fading to transparent print as heavy bitmaps. */
154
+ background: var(--ag-field-image) center / 100% 100% no-repeat;
161
155
  }
162
156
 
163
157
  /* Text */
package/dist/cli.js CHANGED
@@ -66,7 +66,7 @@ function addDocumentOptions(command) {
66
66
  .option("--font <font>", "text typeface: manrope or inter (default: manrope)")
67
67
  .option("--no-justify", "align paragraphs left in the PDF instead of justifying them")
68
68
  .option("--watermark <text>", "text across every PDF page, in the Anti-Gravity gradient")
69
- .option("--watermark-field", "a soft field of light in the corner of every PDF page")
69
+ .option("--watermark-field", "soft fields of light in the top-left and bottom-right corners of every PDF page")
70
70
  .option("--density <density>", "normal or compact (tighter spacing) (default: normal)")
71
71
  .option("--font-size <size>", "text size, e.g. 10pt or 11pt (default: 10.5pt)")
72
72
  .option("--theme <theme>", "antigravity, antigravity-dark, light, dark, or a .css file replacing the theme " +
package/dist/convert.js CHANGED
@@ -12,7 +12,8 @@ import { BrowserSession } from "./render/browser.js";
12
12
  import { DEFAULT_FOOTER, headerFooterTemplate } from "./render/header-footer.js";
13
13
  import { fillMermaid, renderMermaid } from "./render/mermaid.js";
14
14
  import { SMALL_SCALE } from "./render/mermaid-fit.js";
15
- import { headerFooterStyle, mermaidThemeVariables } from "./render/antigravity.js";
15
+ import { headerFooterStyle, isAntigravityTheme, mermaidThemeVariables, } from "./render/antigravity.js";
16
+ import { fieldImage } from "./render/field.js";
16
17
  import { FONT_FAMILIES, fontStack } from "./render/fonts.js";
17
18
  import { WATERMARK_CSS, watermarkHtml } from "./render/watermark.js";
18
19
  import { contentHeightPx, contentWidthPx, lengthToPx, textWidthPx } from "./render/page.js";
@@ -110,6 +111,9 @@ function layoutCss(options, margin) {
110
111
  rules.push("h1, h2, h3, h4, h5, h6 { line-height: 1.4; }");
111
112
  if (options.justify)
112
113
  rules.push(JUSTIFY_CSS);
114
+ if (isAntigravityTheme(options.theme)) {
115
+ rules.push(`:root { --ag-field-image: ${fieldImage(isDarkTheme(options.theme))}; }`);
116
+ }
113
117
  if (options.fontSize)
114
118
  rules.push(`html { font-size: ${options.fontSize}; }`);
115
119
  return rules.join("\n");
package/dist/options.d.ts CHANGED
@@ -51,7 +51,7 @@ export interface DocumentOptions {
51
51
  mermaidFlip: MermaidFlip;
52
52
  /** Text set diagonally across every page of the PDF, in the Anti-Gravity gradient. */
53
53
  watermark?: string;
54
- /** A soft field of light (the Anti-Gravity gradient) in the corner of every PDF page. */
54
+ /** Soft fields of light (the Anti-Gravity gradient) in two corners of every PDF page. */
55
55
  watermarkField: boolean;
56
56
  /** Justify paragraphs in the PDF (body, quotes, alerts), breaking long words with hyphens. */
57
57
  justify: boolean;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The Anti-Gravity gradient field: three soft lights (field-blue, field-cyan, field-violet),
3
+ * each an ellipse fading to transparent inside its box.
4
+ *
5
+ * Drawn as an SVG image rather than CSS radial-gradient()s: Chrome rasterizes CSS gradients that
6
+ * fade to transparent into several bitmaps per page (about 70 KB each, repeated on every page),
7
+ * while SVG gradients with stop-opacity go into the PDF as small vector shadings.
8
+ */
9
+ export declare const FIELD_COLORS: {
10
+ blue: string;
11
+ cyan: string;
12
+ violet: string;
13
+ };
14
+ /** Field opacity on light pages and on dark ones (the design system's opacity-field tokens). */
15
+ export declare const FIELD_OPACITY: {
16
+ light: number;
17
+ dark: number;
18
+ };
19
+ /** The field as an SVG stretched over its box (viewBox in %, no aspect ratio kept). */
20
+ export declare function fieldSvg(opacity: number): string;
21
+ /**
22
+ * CSS `url(…)` of the field image. The SVG has only double quotes, which the encoding escapes, so
23
+ * the value is safe inside single quotes, also in a style="…" attribute.
24
+ */
25
+ export declare function fieldImage(dark: boolean): string;
@@ -0,0 +1,36 @@
1
+ /**
2
+ * The Anti-Gravity gradient field: three soft lights (field-blue, field-cyan, field-violet),
3
+ * each an ellipse fading to transparent inside its box.
4
+ *
5
+ * Drawn as an SVG image rather than CSS radial-gradient()s: Chrome rasterizes CSS gradients that
6
+ * fade to transparent into several bitmaps per page (about 70 KB each, repeated on every page),
7
+ * while SVG gradients with stop-opacity go into the PDF as small vector shadings.
8
+ */
9
+ export const FIELD_COLORS = { blue: "#4f7cff", cyan: "#22c3e6", violet: "#8c6cf0" };
10
+ /** Field opacity on light pages and on dark ones (the design system's opacity-field tokens). */
11
+ export const FIELD_OPACITY = { light: 0.16, dark: 0.22 };
12
+ /** Each light: centre and radii in % of the box (as `radial-gradient(rx ry at cx cy)`). */
13
+ const LIGHTS = [
14
+ { color: FIELD_COLORS.blue, cx: 58, cy: 45, rx: 28, ry: 38 },
15
+ { color: FIELD_COLORS.cyan, cx: 78, cy: 58, rx: 16, ry: 26 },
16
+ { color: FIELD_COLORS.violet, cx: 40, cy: 32, rx: 25, ry: 30 },
17
+ ];
18
+ /** The field as an SVG stretched over its box (viewBox in %, no aspect ratio kept). */
19
+ export function fieldSvg(opacity) {
20
+ const gradients = LIGHTS.map(({ color, cx, cy, rx, ry }, i) => `<radialGradient id="f${i}" gradientUnits="userSpaceOnUse" cx="0" cy="0" r="1" ` +
21
+ `gradientTransform="translate(${cx} ${cy}) scale(${rx} ${ry})">` +
22
+ `<stop offset="0" stop-color="${color}" stop-opacity="${opacity}"/>` +
23
+ `<stop offset="1" stop-color="${color}" stop-opacity="0"/></radialGradient>`).join("");
24
+ const fills = LIGHTS.map((_, i) => `<rect width="100" height="100" fill="url(#f${i})"/>`).join("");
25
+ return (`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" preserveAspectRatio="none">` +
26
+ `<defs>${gradients}</defs>${fills}</svg>`);
27
+ }
28
+ /**
29
+ * CSS `url(…)` of the field image. The SVG has only double quotes, which the encoding escapes, so
30
+ * the value is safe inside single quotes, also in a style="…" attribute.
31
+ */
32
+ export function fieldImage(dark) {
33
+ const svg = fieldSvg(dark ? FIELD_OPACITY.dark : FIELD_OPACITY.light);
34
+ return `url('data:image/svg+xml,${encodeURIComponent(svg)}')`;
35
+ }
36
+ //# sourceMappingURL=field.js.map
@@ -1,7 +1,7 @@
1
1
  export interface WatermarkOptions {
2
2
  /** Text set across every page; undefined or blank for none. */
3
3
  text?: string;
4
- /** A field of light in the corner of every page. */
4
+ /** Fields of light in the top-left and bottom-right corners of every page. */
5
5
  field: boolean;
6
6
  /** Size of the text area in CSS px (the text runs along its diagonal). */
7
7
  widthPx: number;
@@ -1,11 +1,12 @@
1
1
  import { escapeHtml } from "../html.js";
2
+ import { FIELD_COLORS, fieldImage } from "./field.js";
2
3
  /**
3
4
  * Watermarks in the Anti-Gravity gradient (field-blue → field-cyan → field-violet), PDF only:
4
- * a text set diagonally across every page, and a soft field of light in the top-right corner of
5
- * every page. Both sit behind the content. Chrome repeats a `position: fixed` element on every
5
+ * a text set diagonally across every page, and soft fields of light in the top-left and
6
+ * bottom-right corners of every page. Both sit behind the content. Chrome repeats a `position: fixed` element on every
6
7
  * printed page, at the same place in the text area, so pagination is left alone.
7
8
  */
8
- const FIELD = { blue: "#4f7cff", cyan: "#22c3e6", violet: "#8c6cf0" };
9
+ const FIELD = FIELD_COLORS;
9
10
  /** Angle (degrees, counter-clockwise) and font size (px) that fit `text` on the diagonal. */
10
11
  export function diagonalText(text, widthPx, heightPx) {
11
12
  const angle = (Math.atan2(heightPx, widthPx) * 180) / Math.PI;
@@ -22,9 +23,13 @@ function textMark(text, widthPx, heightPx, dark) {
22
23
  return `<div class="mdr-watermark-text" style="opacity: ${dark ? 0.14 : 0.1}"><span style="font-size: ${fontSize}px; transform: rotate(${(-angle).toFixed(2)}deg)">${escapeHtml(text.toUpperCase())}</span></div>`;
23
24
  }
24
25
  function fieldMark(dark) {
25
- // The same three lights as the title block's field (theme-antigravity.css), each fading out
26
- // inside the box so no edge shows.
27
- return `<div class="mdr-watermark-field" style="opacity: ${dark ? 0.22 : 0.16}"></div>`;
26
+ // The same field as the title block's (render/field.ts), as a vector SVG image, in the
27
+ // top-left and bottom-right corners of every page.
28
+ const style = `style="background-image: ${fieldImage(dark)}"`;
29
+ return [
30
+ `<div class="mdr-watermark-field mdr-field-top-left" ${style}></div>`,
31
+ `<div class="mdr-watermark-field mdr-field-bottom-right" ${style}></div>`,
32
+ ].join("\n");
28
33
  }
29
34
  /** HTML of the requested marks, to go before the document body; "" when none is requested. */
30
35
  export function watermarkHtml(options) {
@@ -72,15 +77,15 @@ export const WATERMARK_CSS = `.mdr-watermark { display: none; }
72
77
  }
73
78
  .mdr-watermark-field {
74
79
  position: absolute;
75
- top: 0;
76
- right: 0;
77
80
  width: 40%;
78
81
  height: 230px;
79
- background:
80
- radial-gradient(28% 38% at 58% 45%, ${FIELD.blue}, transparent),
81
- radial-gradient(16% 26% at 78% 58%, ${FIELD.cyan}, transparent),
82
- radial-gradient(25% 30% at 40% 32%, ${FIELD.violet}, transparent);
82
+ background-position: center;
83
+ background-size: 100% 100%;
84
+ background-repeat: no-repeat;
83
85
  }
86
+ /* The lights gather towards the right of the field's box: mirror it so they sit in its corner. */
87
+ .mdr-field-top-left { top: 0; left: 0; transform: scaleX(-1); }
88
+ .mdr-field-bottom-right { bottom: 0; right: 0; transform: scaleY(-1); }
84
89
  .mdr-watermark:has(.mdr-watermark-field) ~ .markdown-body .doc-header::before { display: none; }
85
90
  }`;
86
91
  //# sourceMappingURL=watermark.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@imontene/mdrender",
3
- "version": "2.6.0",
3
+ "version": "2.7.0",
4
4
  "description": "Command-line app for Windows and Linux that renders Markdown — with LaTeX equations and Mermaid diagrams — to PDF and HTML set in Manrope or Inter",
5
5
  "keywords": [
6
6
  "markdown",