@heroiclands/package-build 24.0.1 → 24.0.2

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.
Files changed (50) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/assets/preview/gitea.ini +1 -1
  3. package/assets/styles/content-base.css +33 -0
  4. package/bin/content-commands.mjs +9 -7
  5. package/docs/api.md +6 -5
  6. package/docs/authoring/links-and-markup.md +164 -16
  7. package/docs/commands.md +16 -14
  8. package/docs/configuration.md +16 -0
  9. package/docs/content-format.md +4 -2
  10. package/docs/guides/writing-in-invented-scripts.md +68 -6
  11. package/docs/reference/format-details.md +143 -49
  12. package/docs/reference/note-types.md +47 -28
  13. package/docs/source-preview.md +2 -2
  14. package/engine/content-blocks.mjs +6 -2
  15. package/engine/content-format.yaml +2 -0
  16. package/engine/content-index.mjs +5 -1
  17. package/engine/content-render.mjs +2 -1
  18. package/engine/content-scripts.mjs +268 -21
  19. package/engine/content-scroll.mjs +389 -0
  20. package/engine/font-outlines.mjs +394 -0
  21. package/engine/language-data.mjs +154 -63
  22. package/engine/language-rows.mjs +32 -6
  23. package/engine/language-terms.mjs +32 -8
  24. package/engine/map-lexicon.mjs +31 -6
  25. package/engine/note-vocabulary.mjs +58 -6
  26. package/engine/pdf-fonts.mjs +1 -1
  27. package/engine/pdf-render.mjs +52 -11
  28. package/engine/run-rows.mjs +45 -3
  29. package/engine/script-direction.mjs +67 -0
  30. package/engine/script-emphasis-terms.mjs +11 -3
  31. package/engine/script-font-delivery.mjs +42 -9
  32. package/engine/script-fonts.mjs +7 -0
  33. package/engine/verse-metre.mjs +1 -0
  34. package/engine/written-in.mjs +208 -0
  35. package/package.json +1 -1
  36. package/site-theme/static/css/style.css +7 -0
  37. package/types/engine/content-scripts.d.mts +31 -6
  38. package/types/engine/content-scroll.d.mts +179 -0
  39. package/types/engine/font-outlines.d.mts +67 -0
  40. package/types/engine/language-data.d.mts +13 -0
  41. package/types/engine/language-rows.d.mts +4 -3
  42. package/types/engine/language-terms.d.mts +7 -0
  43. package/types/engine/map-lexicon.d.mts +4 -3
  44. package/types/engine/pdf-fonts.d.mts +10 -0
  45. package/types/engine/run-rows.d.mts +28 -6
  46. package/types/engine/script-direction.d.mts +10 -0
  47. package/types/engine/script-emphasis-terms.d.mts +10 -3
  48. package/types/engine/script-font-delivery.d.mts +5 -3
  49. package/types/engine/script-fonts.d.mts +9 -0
  50. package/types/engine/written-in.d.mts +76 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # @heroiclands/package-build
2
2
 
3
+ ## 24.0.2
4
+
5
+ ### Patch Changes
6
+
7
+ **Languages**
8
+
9
+ - A language whose stress always falls on the first syllable says so with `stress: { two: first, longer: first }`, and its verse is scanned that way.
10
+ - A reference note can state a setting's spelling guide as data: its letters and marks, with an `ipa` sound for each letter and final, and the languages that write each letter.
11
+
12
+ **Scripts**
13
+
14
+ - A `scroll` fence sets text in a script written in columns as a handscroll: columns read right to left, scrolling sideways on screen and continuing on panels in the book.
15
+ - A language note names the script it is written in with `data.writtenIn: { map, font }`, so text marked with the language alone is set in that script; a run's own `map=` or `font=` still chooses another.
16
+
3
17
  ## 24.0.1
4
18
 
5
19
  ### Patch Changes
@@ -9,7 +9,7 @@ RENDER_CONTENT_MODE = sanitized
9
9
  [markup.sanitizer.markdown.previewDiv]
10
10
  ELEMENT = div
11
11
  ALLOW_ATTR = class
12
- REGEXP = ^(hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|border)( (hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|border))*$
12
+ REGEXP = ^(hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|scroll|border)( (hl-preview(?:-[a-z-]+)?|content-figure(?:-[a-z-]+)?|verse(?:-[a-z-]+)?|scroll|border))*$
13
13
 
14
14
  [markup.sanitizer.markdown.previewSpan]
15
15
  ELEMENT = span
@@ -285,6 +285,39 @@
285
285
  text-align: start;
286
286
  }
287
287
 
288
+ /*
289
+ * A scroll: a script written in columns, top to bottom, read from the right,
290
+ * as a handscroll unrolls. Each paragraph starts a fresh column, flush at the
291
+ * top. The line height sets the column pitch: one em for the character and
292
+ * half an em between columns. `--scroll-rows` sets a column's length in
293
+ * characters; without it a column runs as long as its paragraph.
294
+ * `--scroll-cols` sets the panel's width in columns; without it the panel is
295
+ * as wide as its text. A panel wider than its container scrolls sideways,
296
+ * starting at the right.
297
+ */
298
+ :is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll {
299
+ writing-mode: vertical-rl;
300
+ line-height: 1.5;
301
+ inline-size: max-content;
302
+ max-block-size: 100%;
303
+ overflow-x: auto;
304
+ overflow-y: hidden;
305
+ margin: 1rem 0;
306
+ }
307
+
308
+ :is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll[data-rows] {
309
+ inline-size: calc(var(--scroll-rows) * 1em);
310
+ }
311
+
312
+ :is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll[data-cols] {
313
+ block-size: calc(var(--scroll-cols) * 1.5em);
314
+ }
315
+
316
+ :is(.journal-entry-page, .journal-entry-content, .editor-content, .prosemirror) .scroll p {
317
+ margin: 0;
318
+ text-indent: 0;
319
+ }
320
+
288
321
  /*
289
322
  * Emphasis in a script follows the script's convention, never a weight or a
290
323
  * slant the face does not have: the element keeps the face's Regular, and its
@@ -31,7 +31,7 @@
31
31
  * npx package-build map [--tree] [--from <shortcode>] [--chart <shortcode>] [--travel] [--out <dir>]
32
32
  * npx package-build reachability <dir> [file] [--index <shortcode>]
33
33
  * npx package-build transliterate <map> [--lang <language>] [--font <slug>] [--hex] [text..]
34
- * npx package-build lexicon <language> --map <map> [--font <slug>] [--derived] [--json]
34
+ * npx package-build lexicon <language> [--map <map>] [--font <slug>] [--derived] [--json]
35
35
  * npx package-build addresses diff --from <zip|dir> [--strict]
36
36
  * npx package-build npc new (--spec <json> | --specfile <path>) [--seed <text>] [--out <path>]
37
37
  *
@@ -2472,7 +2472,8 @@ function transliterateCommand() {
2472
2472
  })
2473
2473
  .option("font", {
2474
2474
  type: "string",
2475
- describe: "The face; required when the map lists more than one",
2475
+ describe:
2476
+ "The face; the language's `data.writtenIn` face where the map is drawn in it, and required when neither it nor the map gives one",
2476
2477
  })
2477
2478
  .option("hex", {
2478
2479
  type: "boolean",
@@ -2518,7 +2519,7 @@ function transliterateCommand() {
2518
2519
  }
2519
2520
 
2520
2521
  /**
2521
- * `package-build lexicon <language> --map <map>` — every word of a language's
2522
+ * `package-build lexicon <language> [--map <map>]` — every word of a language's
2522
2523
  * lexicon with its native form under a map, as the build writes it; with
2523
2524
  * `--derived`, the forms its rules derive follow, each naming its word in a
2524
2525
  * sixth column. Under a logographic map the third column says where a
@@ -2540,12 +2541,13 @@ function lexiconCommand() {
2540
2541
  })
2541
2542
  .option("map", {
2542
2543
  type: "string",
2543
- demandOption: true,
2544
- describe: "The `data.map.name` of a mapping note",
2544
+ describe:
2545
+ "The `data.map.name` of a mapping note; the language's `data.writtenIn` map where left out",
2545
2546
  })
2546
2547
  .option("font", {
2547
2548
  type: "string",
2548
- describe: "The face; required when the map lists more than one",
2549
+ describe:
2550
+ "The face; the language's `data.writtenIn` face where the map is drawn in it, and required when neither it nor the map gives one",
2549
2551
  })
2550
2552
  .option("derived", {
2551
2553
  type: "boolean",
@@ -2567,7 +2569,7 @@ function lexiconCommand() {
2567
2569
  }
2568
2570
  const listed = lexiconEntries(read.ctx, {
2569
2571
  lang: String(argv.language),
2570
- map: String(argv.map),
2572
+ map: argv.map === undefined ? undefined : String(argv.map),
2571
2573
  font: argv.font,
2572
2574
  derived: Boolean(argv.derived),
2573
2575
  });
package/docs/api.md CHANGED
@@ -1735,11 +1735,12 @@ A note's markdown, and a document plan, rendered as Typst source. **This module
1735
1735
 
1736
1736
  Which glyph an icon name resolves to, read from the font that carries it. {@link module:engine/content-icons} states an icon's family and its name and **deliberately holds no codepoints**: writing them out by hand would be a second copy of a table the font already owns, wrong the first time the icon set renumbers anything, and wrong silently. So the renderer resolves a name against the file it is going to embed, which is this module.
1737
1737
 
1738
- | Export | Signature | Returns | Use it when |
1739
- | ------------------- | ------------------------------------------------ | ------------------------------------------------------------------- | -------------------------------------------------------------------- |
1740
- | `glyphTable` | `function glyphTable(file)` | {Map<string, number>} Name → codepoint. | Every glyph name a font carries, with the codepoint that reaches it. |
1741
- | `familyName` | `function familyName(file)` | {string} The family name, or "" when the table cannot be read. | The family name a font file announces, for Typst's `text(font: …)`. |
1742
- | `resolveIconGlyphs` | `function resolveIconGlyphs(registry, iconFonts` | {Map<string, {font: string, codepoint: number}>} Icon name → glyph. | Resolve every icon in a registry against the fonts a consumer named. |
1738
+ | Export | Signature | Returns | Use it when |
1739
+ | ------------------- | ------------------------------------------------ | -------------------------------------------------------------------- | -------------------------------------------------------------------- |
1740
+ | `glyphTable` | `function glyphTable(file)` | {Map<string, number>} Name → codepoint. | Every glyph name a font carries, with the codepoint that reaches it. |
1741
+ | `familyName` | `function familyName(file)` | {string} The family name, or "" when the table cannot be read. | The family name a font file announces, for Typst's `text(font: …)`. |
1742
+ | `resolveIconGlyphs` | `function resolveIconGlyphs(registry, iconFonts` | {Map<string, {font: string, codepoint: number}>} Icon name → glyph. | Resolve every icon in a registry against the fonts a consumer named. |
1743
+ | `tableDirectory` | `function tableDirectory(buf)` | {Map<string, {offset: number, length: number}>} Its table directory. | The tables an sfnt file holds, by tag. |
1743
1744
 
1744
1745
  ### `engine.pdfBuild`
1745
1746
 
@@ -546,13 +546,105 @@ as a grid with a row per verse line.
546
546
  Each finding is an error at the text that is wrong; see
547
547
  [a verse in columns](../diagnostics.md#a-worked-case-a-verse-in-columns).
548
548
 
549
+ ### Scrolls
550
+
551
+ Some scripts are written in vertical columns, top to bottom, with the columns
552
+ read from the right, as on a handscroll. A `scroll` fence sets a passage in one
553
+ of these scripts:
554
+
555
+ ````markdown
556
+ ```scroll {rows=25 cols=12 lang=tsu map=tengchou}
557
+ chen teng chou hing
558
+ tan tsou dou rou
559
+
560
+ gen chei chou tsuen
561
+ ```
562
+ ````
563
+
564
+ A scroll fence is a real code fence, so Markdown never reformats its body.
565
+
566
+ - **Paragraphs.** The lines of a paragraph are joined into one text. Where
567
+ the source breaks a line makes no difference to where a column breaks. A
568
+ blank line starts a new paragraph, flush at the top of a fresh column, with
569
+ no indent and no mark between paragraphs. This follows classical practice.
570
+ - **`rows=`** is the number of characters in a column, and **`cols=`** the
571
+ number of columns in a panel. Each is a whole number above zero, and either
572
+ may be left out.
573
+ - **`lang=`, `font=` and `map=`** work as they do on a verse fence. See
574
+ [marking language, font and mapping](#marking-language-font-and-mapping).
575
+ The text is mapped before it is laid out, so under a
576
+ [logographic map](#logographic-maps) each word is written by its
577
+ characters, one to a morpheme. The map's rows decide what is written
578
+ between words, and a map for a script that runs its characters together
579
+ writes a space as nothing. If the fence names no `font=`, it takes the face
580
+ of its map, provided the map is drawn in exactly one face. A fence marked
581
+ only with a language whose note names its script, such as
582
+ ` ```scroll {rows=25 cols=12 lang=tsu} `, takes that script's map and face;
583
+ see [a language's script](#a-languages-script).
584
+ - **The direction comes from the script.** The face's script note states
585
+ `direction: vertical-rl` in its `data.script`; see
586
+ [script notes and emphasis](../reference/format-details.md#script-notes-and-emphasis).
587
+ A script that states no direction is written in lines, and a scroll fence
588
+ set in it is an error. Markup never states a direction itself.
589
+ - **Spans stay horizontal.** A `[…]{lang=… font=… map=…}` span in the same
590
+ script sets its characters left to right, inline, so a short phrase can sit
591
+ in a line of prose.
592
+
593
+ **On the site, in the preview and in Foundry**, a scroll is a `<div
594
+ class="scroll">` with one `<p>` for each paragraph. The stylesheet sets it
595
+ with `writing-mode: vertical-rl`. A column is one em wide, with half an em
596
+ between columns, so the column pitch is 1.5em.
597
+
598
+ | Attribute | Stated | Left out |
599
+ | --------- | --------------------------------------------------------------------------- | ----------------------------------------------------------- |
600
+ | `rows=N` | Each column is N ems tall: `inline-size: calc(var(--scroll-rows) * 1em)` | Each paragraph is a single column, as long as the paragraph |
601
+ | `cols=M` | The panel is M columns wide: `block-size: calc(var(--scroll-cols) * 1.5em)` | The panel is as wide as its text |
602
+
603
+ The sizes are carried as `data-rows` and `data-cols`, and as the custom
604
+ properties `--scroll-rows` and `--scroll-cols` in the element's `style`. A
605
+ panel wider than its page, or than `cols` columns, scrolls sideways. It opens
606
+ at the right, where the text begins, and unrolls to the left like a
607
+ handscroll.
608
+
609
+ **In the book**, Typst has no vertical writing, so the build draws each panel
610
+ as an image from the face's own TrueType outlines. Each panel is an SVG of at
611
+ most `rows` × `cols` characters, with its columns read from the right. Its alt
612
+ text is the roman text it was written from. Panels follow one another from
613
+ right to left and wrap down the page. Emphasis follows the script's convention:
614
+ rubric characters are drawn in the book's red, and an overline is a rule to the
615
+ right of the column.
616
+
617
+ | Attribute | Stated | Left out |
618
+ | --------- | -------------------------------- | -------------------------------------------------------------------------------------------- |
619
+ | `rows=N` | Each column holds N characters | Each column holds as many characters as the longest paragraph, up to 40 |
620
+ | `cols=M` | Each panel holds up to M columns | Each column is a panel of its own, so as many columns sit side by side as the measure allows |
621
+
622
+ In the book, a space that a map leaves in the text takes up a whole cell.
623
+
624
+ **Errors.** Each of these is an error at its line and column, reported by
625
+ `lint`, the site build, the Foundry compile and the book:
626
+
627
+ | Message | Fix |
628
+ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------- |
629
+ | `` `rows=0` is not a number of characters: `rows=` is a whole number above zero `` | Write a whole number above zero, or leave the key out. |
630
+ | `` `cols=two` is not a number of columns: `cols=` is a whole number above zero `` | Write a whole number above zero, or leave the key out. |
631
+ | `` `width=` is not a scroll attribute; a scroll takes `rows=`, `cols=`, `lang=`, `font=` and `map=` `` | Remove the key. |
632
+ | ``a `scroll` fence names the face it is set in, with `font=`, a map drawn in one face, with `map=`, or a language whose note names its script in `data.writtenIn`, with `lang=` `` | Name the face, the map, or a language with a script. |
633
+ | ``the map `x` is drawn in more than one face; a `scroll` fence names its face with `font=` `` | Add `font=`. |
634
+ | ``a `scroll` fence sets a script written in columns, and the script of `semaron-kuriale` is written in lines; set it in a face whose script note states `direction: vertical-rl`, or use a div`` | Set the text in a script written in columns, or use a div. |
635
+ | `scroll fence is empty`, `scroll fence needs a closing code fence`, `` a scroll fence takes no `#id` `` | Write the text, close the fence, or remove the id. |
636
+
637
+ A fence with an error in its opening line is shown as code. A fence whose text
638
+ has an error is set exactly as written.
639
+
549
640
  ## Marking language, font and mapping
550
641
 
551
- Three keys go in the attribute block a span, a fenced div or a verse fence
552
- already takes. Each is optional, and each does one thing:
642
+ Three keys go in the attribute block a span, a fenced div, a verse fence or a
643
+ [scroll fence](#scrolls) already takes. Each is optional, and each does one thing:
553
644
 
554
645
  - **`lang=`** names the language of the text. It becomes the element's
555
- language tag and changes nothing else.
646
+ language tag, and where the language's note names
647
+ [its script](#a-languages-script), the run takes that script's map and face.
556
648
  - **`font=`** names the font the text is set in: one of the faces of
557
649
  `@heroiclands/fonts`, or `mono`, `serif` or `sans`.
558
650
  - **`map=`** names a [mapping note](#mapping-notes), which rewrites the text
@@ -606,6 +698,60 @@ Zaron tholmeza, [an oath, a vow]{lang=en font=serif}.
606
698
  :::
607
699
  ```
608
700
 
701
+ ### A language's script
702
+
703
+ A language note can name the script its language is written in, as one map and
704
+ one face, in `data.writtenIn`:
705
+
706
+ ```yaml
707
+ data:
708
+ writtenIn: { map: semaron, font: semaron-kuriale }
709
+ ```
710
+
711
+ A run marked with that language alone is then mapped and set as though it named
712
+ both. With Vylari's note stating the default above, these two spans are set
713
+ identically:
714
+
715
+ ```markdown
716
+ The lintel is cut with [Zaron tholmeza]{lang=vyl}.
717
+ The lintel is cut with [Zaron tholmeza]{lang=vyl font=semaron-kuriale map=semaron}.
718
+ ```
719
+
720
+ The same holds for a div, a verse fence and a [scroll fence](#scrolls). A run
721
+ fills in what it leaves unstated, and an explicit key overrides its half of the
722
+ default:
723
+
724
+ | The run states | It takes from the language |
725
+ | -------------------------- | -------------------------------------------------------------- |
726
+ | neither `map=` nor `font=` | the map and the face |
727
+ | `font=` alone | the map, where the map is drawn in that face; otherwise no map |
728
+ | `map=` alone | the face, where that map is drawn in it; otherwise no face |
729
+ | both | nothing |
730
+
731
+ So a language written in more than one script names its usual one in
732
+ `data.writtenIn` and marks a run in another with that script's keys:
733
+ `[Gar-Anlagh]{lang=khel font=qalezu-hand map=qalezu}`. `[Zaron]{lang=vyl
734
+ font=serif}` sets Vylari in the page's serif, unmapped, since Semaron's map is
735
+ not drawn in it.
736
+
737
+ The default is the run's own language's, read after a div or fence around the
738
+ run gives it its keys. Inside `::: {lang=vyl}`, a gloss marked
739
+ `[an oath]{lang=en}` takes no face from Vylari. A language whose note states no
740
+ `data.writtenIn` marks its runs with its tag alone.
741
+
742
+ `lint` checks the key on the language note: `map` must be the `data.map.name`
743
+ of a mapping note in the package, and `font` one of the faces that map lists.
744
+ Each is an error at its value, and the default then fills no run:
745
+
746
+ > `` `data.writtenIn.map` is `semoran`, which no mapping note's `data.map.name` declares; did you mean `semaron`? ``
747
+ >
748
+ > `` `data.writtenIn.font` is `teng-chou`, which the map `semaron` is not drawn in; it is drawn in `semaron-kuriale` ``
749
+ >
750
+ > `` `data.writtenIn` names the script a language is written in, and this note's `subType` is not `language` ``
751
+
752
+ The face a language's script names is delivered with the package's fonts, as a
753
+ face named by `font=` is.
754
+
609
755
  ### What `lang=` takes
610
756
 
611
757
  `lang=` is read in this order:
@@ -622,7 +768,8 @@ still a well-formed tag, such as `vly` for `vyl`, is read as the tag of a real
622
768
  language. When such a value is within one edit of a declared name (a letter
623
769
  added, dropped or changed, two neighbours swapped, or a different case), `lint`
624
770
  warns and names the declared language. Text marked with `lang=` alone is not
625
- checked against any lexicon; a run with `lang=` and `map=` is, as
771
+ checked against any lexicon unless its language names
772
+ [its script](#a-languages-script); a run with `lang=` and a map is, as
626
773
  [a mapped run's words](#a-mapped-runs-words) describes.
627
774
 
628
775
  ### What `font=` takes
@@ -993,13 +1140,14 @@ finding the lint reports in `data.map`.
993
1140
  Every target rewrites marked text first, so a page, a Foundry journal and a
994
1141
  book all show the same thing.
995
1142
 
996
- | Marking | The text | The element |
997
- | -------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------ |
998
- | `lang=` alone | As written | Tagged with the language's tag, `lang="art-x-vyl"` |
999
- | `map=` | Rewritten by the map, line by line | As below |
1000
- | `font=` a face | As written, or as the map wrote it | The tag, `script` and the face's class; not indexed by the site's search |
1001
- | `font=mono`, `serif`, `sans` | As written, or as the map wrote it | The tag and `font-mono`, `font-serif` or `font-sans` |
1002
- | A div or fence in a right-to-left face | As above | Also `dir="rtl"`; a div also carries `script-block` |
1143
+ | Marking | The text | The element |
1144
+ | -------------------------------------- | ---------------------------------- | ------------------------------------------------------------------------- |
1145
+ | `lang=` alone | As written | Tagged with the language's tag, `lang="art-x-vyl"` |
1146
+ | `map=` | Rewritten by the map, line by line | As below |
1147
+ | `font=` a face | As written, or as the map wrote it | The tag, `script` and the face's class; not indexed by the site's search |
1148
+ | `font=mono`, `serif`, `sans` | As written, or as the map wrote it | The tag and `font-mono`, `font-serif` or `font-sans` |
1149
+ | A div or fence in a right-to-left face | As above | Also `dir="rtl"`; a div also carries `script-block` |
1150
+ | A scroll fence | Each paragraph on one line | `scroll`, the tag, `script` and the face's class; see [scrolls](#scrolls) |
1003
1151
 
1004
1152
  No target writes `<bdo>`, `<bdi>` or a Unicode direction control character: a
1005
1153
  right-to-left face's code points carry their own direction. Text with an error
@@ -1135,7 +1283,7 @@ SELECT owner, kind, tag, font, line FROM runs WHERE lang = 'vyl' ORDER BY owner,
1135
1283
  ```
1136
1284
  ````
1137
1285
 
1138
- Its columns are `owner`, `kind` (`span`, `block` or `verse`), `lang` as written,
1286
+ Its columns are `owner`, `kind` (`span`, `block`, `verse` or `scroll`), `lang` as written,
1139
1287
  the `tag` it resolves to (`NULL` when it resolves to none), `font`, `map`, `line`
1140
1288
  and `column`. A run inside a div or a fence records the keys it inherits. See
1141
1289
  [the `runs` relation](../reference/format-details.md#content-tables).
@@ -1297,7 +1445,7 @@ A column's heading is its SQL alias, so `AS "Name"` is what a reader sees. A cel
1297
1445
  | `entries` | Every note, stubs included. |
1298
1446
  | `events` | One row per event a `lore`, `place` or `affiliation` note writes in `data.events`, with `whenSort` to order them by date. |
1299
1447
  | `names` | Each authored `.name` span, with its containing NOTE Address, visible text, optional type/subtype and source line/column. |
1300
- | `runs` | Each span, div and verse fence marked with `lang=`, `font=` or `map=`, with its containing NOTE Address, its `kind`, `lang` as written, the `tag` it resolves to, `font`, `map`, and source line/column. See [marking language, font and mapping](#marking-language-font-and-mapping). |
1448
+ | `runs` | Each span, div and verse fence marked with `lang=`, `font=` or `map=`, with its containing NOTE Address, its `kind`, `lang` as written, the `tag` it resolves to, the `font` and `map` it is set with (its own, inherited, or its language's [script](#a-languages-script)), and source line/column. See [marking language, font and mapping](#marking-language-font-and-mapping). |
1301
1449
  | `maps` | One row per row of a mapping note's `data.map`, with its containing NOTE Address, the map's `name`, the `font` whose own row it is (`NULL` for a shared row), the row's 1-based place as `"row"`, and its `"from"`, `"to"`, `before` and `"at"`. See [mapping notes](#mapping-notes). |
1302
1450
  | `natives` | One row per native form a language note's word states in `native`, with that note as its `language`, the word's place as `word`, its `form`, the entry's place as `native`, and its `map`, `font` and `"text"`. See [what `map=` takes](#what-map-takes). |
1303
1451
  | `words` | One row per word a language note writes in `data.words`, with that note as its `language`, its `position` and what it is built from. |
@@ -1311,16 +1459,16 @@ A column's heading is its SQL alias, so `AS "Name"` is what a reader sees. A cel
1311
1459
  | `tongues` | One row per tag a language note writes in `data.tongues`: `tag`, `meaning` and `tongue_language`. |
1312
1460
  | `retired` | One row per form a language note writes in `data.retired`: `form`, `instead` as a list, and `why`. |
1313
1461
  | `scope` | One row per value of a language note's `data.scope`: the `kind` it is under and the `value`. |
1314
- | `letters` | One row per entry of a language note's `data.sounds.letters`: `letters` as a list, `kind`, `like`, `place` and `tongue`. |
1462
+ | `letters` | One row per entry of a language note's or a spelling guide's `data.sounds.letters`: `letters` as a list, `kind`, `like`, `place`, `ipa` and `tongue`. |
1315
1463
  | `edges` | One row per entry of a language note's `data.sounds.edges`: the `edge` and its `sounds` as a list. |
1316
1464
  | `clusters` | One row per language note stating `data.sounds.clusters`, with its `max`. |
1317
1465
  | `cluster_groups` | One row per group of a language note's `data.sounds.clusters.groups`: `what`, `clusters` as a list, and `use`. |
1318
1466
  | `stress` | One row per language note stating `data.sounds.stress`, with its `two`, `longer` and `mark` (`NULL` where unstated). |
1319
- | `finals` | One row per entry of a language note's `data.sounds.finals`: `final` and `like`. |
1467
+ | `finals` | One row per entry of a language note's `data.sounds.finals`: `final`, `like` and `ipa`. |
1320
1468
  | `syllables` | One row per language note stating `data.sounds.syllables`: each rule a column, the harmony as `harmony_back`, `harmony_front`, `harmony_neutral`, `harmony_neutralAs` and `harmony_partners`, a list of `{ vowel, partner }`. |
1321
1469
  | `joining` | One row per entry of a language note's `data.sounds.joining`: `first`, `second`, `written` and `example`. |
1322
1470
  | `joins` | One row per entry of a language note's `data.sounds.joins`: `meeting`, `rule`, `letters` and `"where"`. |
1323
- | `marks` | One row per entry of a language note's `data.sounds.marks`: `mark`, `letters`, `kind` and `"limit"`. |
1471
+ | `marks` | One row per entry of a language note's or a spelling guide's `data.sounds.marks`: `mark`, `letters`, `kind` and `"limit"`. |
1324
1472
  | `skeleton` | One row per entry of a language note's `data.sounds.skeleton`: `second` and `between`. |
1325
1473
  | `frames` | One row per frame of a language note's `data.sounds.frames`: `frame`, `shape`, `class`, `makes` and `examples` as `{ root, form }`. |
1326
1474
  | `read_past` | One row per entry of a language note's `data.sounds.readPast`: `written`, `readAs` and `what`. |
package/docs/commands.md CHANGED
@@ -3101,11 +3101,11 @@ from standard input, less one trailing newline. Writes nothing.
3101
3101
  | `map` | string | — | The `data.map.name` of a mapping note. |
3102
3102
  | `text` | string, variadic | stdin | The passage; `-` reads it from stdin. |
3103
3103
 
3104
- | Option | Type | Default | Description |
3105
- | -------- | ------- | -------------------------- | ------------------------------------------------------------------------------- |
3106
- | `--lang` | string | — | A language declared in `languages`, whose lexicon is read first. |
3107
- | `--font` | string | the map's one face, if one | The face, whose own rows come first; required when the map lists more than one. |
3108
- | `--hex` | boolean | `false` | Print the code points, as `U+XXXX` separated by spaces. |
3104
+ | Option | Type | Default | Description |
3105
+ | -------- | ------- | --------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
3106
+ | `--lang` | string | — | A language declared in `languages`, whose lexicon is read first. |
3107
+ | `--font` | string | the language's face where the map is drawn in it, else the map's one face, if one | The face, whose own rows come first; required when neither gives one and the map lists more than one. |
3108
+ | `--hex` | boolean | `false` | Print the code points, as `U+XXXX` separated by spaces. |
3109
3109
 
3110
3110
  **EXIT STATUS**
3111
3111
 
@@ -3158,14 +3158,15 @@ List a language's words with their native forms under a map.
3158
3158
  **SYNOPSIS**
3159
3159
 
3160
3160
  ```
3161
- package-build lexicon <language> --map <map> [--font <slug>] [--derived] [--json]
3161
+ package-build lexicon <language> [--map <map>] [--font <slug>] [--derived] [--json]
3162
3162
  ```
3163
3163
 
3164
3164
  **DESCRIPTION**
3165
3165
 
3166
3166
  Reads the content index and lists every word of the language note
3167
3167
  [`languages.<language>.note`](configuration.md#languages) names, in `data.words`
3168
- order, each with its native form under `<map>`: the stated exception where the
3168
+ order, each with its native form under `<map>`, or under the script the
3169
+ language note names in `data.writtenIn` when `--map` is left out: the stated exception where the
3169
3170
  word has one, else the rows' spelling, each exactly as
3170
3171
  `package-build transliterate` and the build give it. Each line holds, separated
3171
3172
  by tabs, the word's `form`, its native form, `exception` or `rows`, its `class`
@@ -3196,17 +3197,18 @@ the lexicon's own words. A derived line carries its word's `class` and `gloss`.
3196
3197
  | ---------- | ------ | ------- | --------------------------------------------------- |
3197
3198
  | `language` | string | — | A declared language whose `note` names its lexicon. |
3198
3199
 
3199
- | Option | Type | Default | Description |
3200
- | ----------- | ------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
3201
- | `--map` | string | — | Required: the `data.map.name` of a mapping note. |
3202
- | `--font` | string | the map's one face, if one | The face; required when the map lists more than one. |
3203
- | `--derived` | boolean | `false` | Also list the forms the language's rules derive, each with the word it comes from. |
3204
- | `--json` | boolean | `false` | Print a JSON array of `{ form, native, exception, class, gloss }` instead; a derived form adds `from`. Under a logographic map `source` (`own`, `parts` or `none`) takes the place of `exception`, and an ambiguous word adds `ambiguous: true`. |
3200
+ | Option | Type | Default | Description |
3201
+ | ----------- | ------- | --------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
3202
+ | `--map` | string | the language's `data.writtenIn` map | The `data.map.name` of a mapping note; required when the language note states no `data.writtenIn`. |
3203
+ | `--font` | string | the language's face where the map is drawn in it, else the map's one face, if one | The face; required when neither gives one and the map lists more than one. |
3204
+ | `--derived` | boolean | `false` | Also list the forms the language's rules derive, each with the word it comes from. |
3205
+ | `--json` | boolean | `false` | Print a JSON array of `{ form, native, exception, class, gloss }` instead; a derived form adds `from`. Under a logographic map `source` (`own`, `parts` or `none`) takes the place of `exception`, and an ambiguous word adds `ambiguous: true`. |
3205
3206
 
3206
3207
  **EXIT STATUS**
3207
3208
 
3208
3209
  1 if the content index could not be built for any note, or the language, the
3209
- map or the face names nothing, the language states no `note`, or a capitalised
3210
+ map or the face names nothing, no map is named and the language note states no
3211
+ `data.writtenIn`, the language states no `note`, or a capitalised
3210
3212
  word has a native form the rows cannot capitalise, each reported as a finding.
3211
3213
  Otherwise 0.
3212
3214
 
@@ -767,11 +767,27 @@ spells every other word by the map's rows; see
767
767
  Every word of such a run is a word of the lexicon, of a name the language note's
768
768
  own register lists, or a regular form of a lexicon word, and any other word is an error; see
769
769
  [a mapped run's words](authoring/links-and-markup.md#a-mapped-runs-words).
770
+ The language note may also name the script the language is written in, as
771
+ `data.writtenIn: { map, font }`, and a run marked with the language alone is
772
+ then mapped and set in it; see
773
+ [a language's script](authoring/links-and-markup.md#a-languages-script). The
774
+ script belongs to the language note, and the configuration never states it.
770
775
  A language with no `note` tags its text and has no lexicon. Whether the note
771
776
  resolves is checked by `package-build lint`, at the key:
772
777
 
773
778
  > ``package-build.config.yaml:5:5: error: `languages.vyl.note` is `skill-vylarilg`, which names no language note in thalorna; it names a skill note whose subType is language``
774
779
 
780
+ **The direction text is written in** belongs to the script, not to the
781
+ language, and the configuration never states it. Where the script note listing
782
+ a face states `direction: vertical-rl` in its `data.script`, text in that face
783
+ is written in columns, top to bottom, with the columns read from the right. A
784
+ passage of it goes in a
785
+ [`scroll` fence](authoring/links-and-markup.md#scrolls). On the site, in the
786
+ preview and in Foundry, the fence is set with `writing-mode: vertical-rl` in a
787
+ panel that scrolls sideways from the right. In the book, its panels are images
788
+ drawn from the face's TrueType file, which the installed fonts package lists
789
+ under `files.ttf`. A span in the same face stays horizontal.
790
+
775
791
  The shape is checked when the configuration loads, and each fault is a
776
792
  configuration error at its key:
777
793
 
@@ -31,7 +31,9 @@ Leading `:` captions describe the next supported block; `:@` captions also numbe
31
31
 
32
32
  A code fence with language `verse` keeps verse lines, stanza breaks and relative indentation. Its numbered caption uses the **Poem** label. Generic `:::` divs and `[inline spans]{.class}` accept attributes. See [verse](authoring/links-and-markup.md#verse), [fenced divs](authoring/links-and-markup.md#fenced-divs) and [inline spans](authoring/links-and-markup.md#inline-spans). `numstep=N` numbers every Nth line. `col1=` and `col2=` set the poem in at most two columns, each a `:`-joined stack of `language[/mapping[/font]]` entries, the first in the normal tone and the rest in grey; with columns, each blank-line group of `[text]{lang=…}` spans is one verse line, every entry sets the span in its language, and a `***` line breaks the stanza. See [verse in columns](authoring/links-and-markup.md#verse-in-columns).
33
33
 
34
- A span, a generic div or a verse fence marks its text's language with `lang=`, the font it is set in with `font=` and a mapping with `map=`, each optional, and the runs inside a div or a fence inherit its keys. `lang=` is a name the package declares in `languages` or a BCP 47 tag, and gives the language tag alone. `font=` is a face of the installed `@heroiclands/fonts`, named by its class without `hl-`, or `mono`, `serif` or `sans`. `map=` names a mapping note: a `doc` note whose `data.map` lists the fonts it is drawn in and rows that rewrite the text before it is set, a font's own rows first. With `lang=` naming a language whose configured `note` names its language note, a word whose entry states a `native` form for the map is written by it, and the rows spell every other word. A map stating `logographic: true` spells no word by its rows: each word is written by its own `native` entry or its parts' writings, and a word with neither, or whose form stands for entries written differently, is a located error. Every word of such a run is a lexicon form, a word of a name the language note's own register lists under a tongue other than `translation`, or a form a plural row, the verb pattern or an affix stating `replaces` derives from a lexicon form, and any other word is an error at the word. A character a face does not draw, after the map, is an error at the character it came from. A verse fence that states `scan=` (the `name` of a `data.metres` entry of a `doc` note) with a `lang=` whose language note states `data.sounds.stress` is counted line by line by the beat convention, and a line that cannot have the metre's beats is a warning at the line; see [metres](reference/format-details.md#metres). Text with a font, a map or a declared language is plain, except that text set in a face takes `*…*` and `**…**`: they render by the convention its language note's `data.emphasis` states, else the one the script note listing its face states in `data.script` (`rubric` or `overline`), else plainly, and a language whose `data.emphasis` is `words` makes them an error. Every marked construct is a row of the `runs` relation, every mapping row of the `maps` relation, and every native form of the `natives` relation. See [marking language, font and mapping](authoring/links-and-markup.md#marking-language-font-and-mapping).
34
+ A code fence with language `scroll` sets text in a script whose script note states `direction: vertical-rl` as columns, top to bottom, read from the right. The lines of a paragraph are joined, and each paragraph starts a fresh column. `rows=N` is the characters in a column and `cols=M` the columns in a panel, each a whole number above zero; `lang=`, `font=` and `map=` mark the text as on a verse fence, and a fence naming no `font=` takes the face of a map drawn in one. The site, the preview and Foundry set it with `writing-mode: vertical-rl` in a panel that scrolls sideways from the right; the book draws its panels as images from the face's outlines, each with its roman text as alt text. A scroll fence in a script written in lines is an error. See [scrolls](authoring/links-and-markup.md#scrolls).
35
+
36
+ A span, a generic div, a verse fence or a scroll fence marks its text's language with `lang=`, the font it is set in with `font=` and a mapping with `map=`, each optional, and the runs inside a div or a fence inherit its keys. `lang=` is a name the package declares in `languages` or a BCP 47 tag, and gives the language tag; where the language note states `data.writtenIn`, the script the language is written in as a `map` and a `font` the map lists, a run marked with the language alone takes that map and face, and a run's own `map=` or `font=` overrides its half of the default. `font=` is a face of the installed `@heroiclands/fonts`, named by its class without `hl-`, or `mono`, `serif` or `sans`. `map=` names a mapping note: a `doc` note whose `data.map` lists the fonts it is drawn in and rows that rewrite the text before it is set, a font's own rows first. With `lang=` naming a language whose configured `note` names its language note, a word whose entry states a `native` form for the map is written by it, and the rows spell every other word. A map stating `logographic: true` spells no word by its rows: each word is written by its own `native` entry or its parts' writings, and a word with neither, or whose form stands for entries written differently, is a located error. Every word of such a run is a lexicon form, a word of a name the language note's own register lists under a tongue other than `translation`, or a form a plural row, the verb pattern or an affix stating `replaces` derives from a lexicon form, and any other word is an error at the word. A character a face does not draw, after the map, is an error at the character it came from. A verse fence that states `scan=` (the `name` of a `data.metres` entry of a `doc` note) with a `lang=` whose language note states `data.sounds.stress` is counted line by line by the beat convention, and a line that cannot have the metre's beats is a warning at the line; see [metres](reference/format-details.md#metres). Text with a font, a map or a declared language is plain, except that text set in a face takes `*…*` and `**…**`: they render by the convention its language note's `data.emphasis` states, else the one the script note listing its face states in `data.script` (`rubric` or `overline`), else plainly, and a language whose `data.emphasis` is `words` makes them an error. Every marked construct is a row of the `runs` relation, every mapping row of the `maps` relation, and every native form of the `natives` relation. See [marking language, font and mapping](authoring/links-and-markup.md#marking-language-font-and-mapping).
35
37
 
36
38
  Mark a name without a note as `[Name]{.name data-type="being"}`; the optional
37
39
  classification uses the declared note vocabulary. The [name-marking
@@ -175,6 +177,6 @@ Places, affiliations, lore and beings may name their culture in `data.culture`,
175
177
 
176
178
  An affiliation may name the trade, temple or order tongue it keeps in its own `data.language`. An affiliation that reaches no culture is a warning, in a tree holding a culture note. A language needs no culture and no affiliation. See [type: affiliation](reference/format-details.md#type-affiliation).
177
179
 
178
- A language note (`type: skill`, `subType: language`) states its words in frontmatter: `data.words` states each word as a map of its form, class, field and gloss — one sense or a list of them, which a dictionary numbers — with its source, its variant forms, the pieces it is built from and a note, beside `data.classModifiers`, `data.fields` and `data.affixes`, each affix with the `kind` it makes, for a given name's ending who the name is `given` to, and the stem closes it is barred after; a zero affix states `zero: true` and no form. The notes a word is cited from are derived, not written: a note cites a word by marking it in italics in its prose, matched by form or a variant with diacritics and case set aside. The language of a word is the note it sits on, and none of it reaches the compiled Item. A daughter language names its parent in `data.family` and reads the parent's words as its own; the `language_lineage` relation joins a language to its ancestors. Classes come from the [master word classes](reference/format-details.md#word-classes). A culture or an affiliation states its own glossary entries in `data.glossary`: common words in its core vocabulary, dictionary words with a context meaning, or phrases, compounds and terms of art outside the dictionary with their own gloss. An entry naming a word of its resolved language takes the word's senses and class and links to its language entry; a `definition` supplies the entry's meaning instead. Common marks belong to the glossary's owner. A language note with nonempty `data.words` receives its full Dictionary section automatically: one alphabetical list with field tags and one key. A culture or affiliation with nonempty `data.glossary` receives only its explicitly declared entries in its Glossary section; ranks and offices stand in the affiliation's own sections. A note without the relevant frontmatter receives no such section. All surfaces show these sections after the authored text, or under an existing `{#dictionary}`, `{#lexicon}` or `{#glossary}` heading after its introduction. There are no setting-wide dictionary or glossary pages. Every entry resolves to a language — its own `language`, else the affiliation's, its parents' or its culture's, else the culture's — or is an error at the entry. The `words`, `affixes`, `fields`, `glossary` and `language_lineage` relations hold them for `sql` fences, the `dictionary` relation lists each word under every language that has it, inherited words included, and the `terms` relation each glossary entry, rank and office with its culture associations; a fence sets custom views with `layout=dictionary` or `layout=glossary`. A language note names the tag a dictionary prints for it in `data.abbreviation`. A `doc` note states a setting's core concepts in `data.concepts`, a language note says it must cover them with `data.core: true`, and a word names the concepts it serves in `concept`; `package-build core` lists what each covering language has no word for (see [the core vocabulary](reference/format-details.md#the-core-vocabulary)). Every fact a check reads about a language's names, sounds and history is frontmatter too: `data.tongues` and `data.register` (every name the setting gives in the language's reach, the notes carrying each derived from the index, and a name tagged `other:<tongue>` or `exonym:<tongue>` one that the tongue's own language note registers under that tongue), `data.retired`, `data.scope`, `data.sounds` (letters with their place, word edges from a closed list, the cluster limit and the groups of clusters inside a word, the stress rule (`two`, `longer` and `mark`), syllable finals, syllable rules and vowel harmony with each vowel's front partner, the joining of parts, written marks, a root's skeleton vowel and frames, the spellings read past, and named mutations such as wearing and voicing), `data.soundChanges` (named sets of ordered steps), `data.elements` (each standing `opening`, `closing`, `either` or `link`, for one kind of name, with the word it is the stem of and its joining form), `data.roots`, `data.cognates` (with a reconstructed `proto` form), `data.callingNames`, `data.older` (the forms older than the rules), `data.negation` (the negative particle and the mutation it brings) and `data.naming` (how long each class of name runs, the edges names keep that words do not, the element kinds each kind of name draws on, what a place name takes from what it is held from, and the near name), each a relation — `sounds` as `letters`, `edges`, `clusters`, `cluster_groups`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past` and `mutations`, `soundChanges` as `sound_changes`, `callingNames` as `calling_names` — that a fence sets back on the page. A word's citations also come from a note whose name, alias or rank or office title spells it whole. See [a language's words](reference/format-details.md#a-languages-words), [a language's register, sounds and history](reference/format-details.md#a-languages-register-sounds-and-history), [glossary terms](reference/format-details.md#glossary-terms) and [dictionaries and glossaries](reference/format-details.md#dictionaries-and-glossaries).
180
+ A language note (`type: skill`, `subType: language`) states its words in frontmatter: `data.words` states each word as a map of its form, class, field and gloss — one sense or a list of them, which a dictionary numbers — with its source, its variant forms, the pieces it is built from and a note, beside `data.classModifiers`, `data.fields` and `data.affixes`, each affix with the `kind` it makes, for a given name's ending who the name is `given` to, and the stem closes it is barred after; a zero affix states `zero: true` and no form. The notes a word is cited from are derived, not written: a note cites a word by marking it in italics in its prose, matched by form or a variant with diacritics and case set aside. The language of a word is the note it sits on, and none of it reaches the compiled Item. A daughter language names its parent in `data.family` and reads the parent's words as its own; the `language_lineage` relation joins a language to its ancestors. Classes come from the [master word classes](reference/format-details.md#word-classes). A culture or an affiliation states its own glossary entries in `data.glossary`: common words in its core vocabulary, dictionary words with a context meaning, or phrases, compounds and terms of art outside the dictionary with their own gloss. An entry naming a word of its resolved language takes the word's senses and class and links to its language entry; a `definition` supplies the entry's meaning instead. Common marks belong to the glossary's owner. A language note with nonempty `data.words` receives its full Dictionary section automatically: one alphabetical list with field tags and one key. A culture or affiliation with nonempty `data.glossary` receives only its explicitly declared entries in its Glossary section; ranks and offices stand in the affiliation's own sections. A note without the relevant frontmatter receives no such section. All surfaces show these sections after the authored text, or under an existing `{#dictionary}`, `{#lexicon}` or `{#glossary}` heading after its introduction. There are no setting-wide dictionary or glossary pages. Every entry resolves to a language — its own `language`, else the affiliation's, its parents' or its culture's, else the culture's — or is an error at the entry. The `words`, `affixes`, `fields`, `glossary` and `language_lineage` relations hold them for `sql` fences, the `dictionary` relation lists each word under every language that has it, inherited words included, and the `terms` relation each glossary entry, rank and office with its culture associations; a fence sets custom views with `layout=dictionary` or `layout=glossary`. A language note names the tag a dictionary prints for it in `data.abbreviation`. A `doc` note states a setting's core concepts in `data.concepts`, a language note says it must cover them with `data.core: true`, and a word names the concepts it serves in `concept`; `package-build core` lists what each covering language has no word for (see [the core vocabulary](reference/format-details.md#the-core-vocabulary)). Every fact a check reads about a language's names, sounds and history is frontmatter too: `data.tongues` and `data.register` (every name the setting gives in the language's reach, the notes carrying each derived from the index, and a name tagged `other:<tongue>` or `exonym:<tongue>` one that the tongue's own language note registers under that tongue), `data.retired`, `data.scope`, `data.sounds` (letters with their place, their IPA and the tongues that write them, each a declared tag or a language note's Address, word edges from a closed list, the cluster limit and the groups of clusters inside a word, the stress rule (`two`, `longer`, which may be `first`, and `mark`), syllable finals with their IPA, syllable rules and vowel harmony with each vowel's front partner, the joining of parts, written marks, a root's skeleton vowel and frames, the spellings read past, and named mutations such as wearing and voicing), `data.soundChanges` (named sets of ordered steps), `data.elements` (each standing `opening`, `closing`, `either` or `link`, for one kind of name, with the word it is the stem of and its joining form), `data.roots`, `data.cognates` (with a reconstructed `proto` form), `data.callingNames`, `data.older` (the forms older than the rules), `data.negation` (the negative particle and the mutation it brings) and `data.naming` (how long each class of name runs, the edges names keep that words do not, the element kinds each kind of name draws on, what a place name takes from what it is held from, and the near name), each a relation — `sounds` as `letters`, `edges`, `clusters`, `cluster_groups`, `stress`, `finals`, `syllables`, `joining`, `joins`, `marks`, `skeleton`, `frames`, `read_past` and `mutations`, `soundChanges` as `sound_changes`, `callingNames` as `calling_names` — that a fence sets back on the page. A `doc` note may state a spelling guide's `data.sounds.letters` and `data.sounds.marks` alone, its letter rows naming tongues by language note Addresses, and they join the `letters` and `marks` relations under the guide's Address. A word's citations also come from a note whose name, alias or rank or office title spells it whole. See [a language's words](reference/format-details.md#a-languages-words), [a language's register, sounds and history](reference/format-details.md#a-languages-register-sounds-and-history), [glossary terms](reference/format-details.md#glossary-terms) and [dictionaries and glossaries](reference/format-details.md#dictionaries-and-glossaries).
179
181
 
180
182
  Blockquote alerts use `[!NOTE]`, `[!TIP]`, `[!IMPORTANT]`, `[!WARNING]`, or `[!]`, with optional attributes after the marker. They replace the former info and warn div fences; secret blocks remain supported. See [alerts](authoring/links-and-markup.md#alerts).