@barmark/render 0.8.0 → 0.9.1
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 +32 -1
- package/README.md +4 -2
- package/dist/html.js +58 -8
- package/dist/model.js +16 -31
- package/dist/speech.js +23 -2
- package/dist/styles.js +9 -0
- package/dist/types.d.ts +9 -2
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,35 @@ package uses [semantic versioning](https://semver.org/).
|
|
|
6
6
|
|
|
7
7
|
## [Unreleased]
|
|
8
8
|
|
|
9
|
+
## [0.9.1] - 2026-11-03
|
|
10
|
+
|
|
11
|
+
### Fixed
|
|
12
|
+
|
|
13
|
+
- **Bar numbers count the bars as written** (issue #92), each once, as a
|
|
14
|
+
band counts them and as `PlayedBar.written` gives them. Before, the
|
|
15
|
+
margin counted played bars, so a second ending or anything after a
|
|
16
|
+
repeat or a jump numbered past the printed score. A replayed section
|
|
17
|
+
now shows the numbers it was written with; the coda after a
|
|
18
|
+
`D.S. al Coda`, and bars after an open repeat, are numbered instead
|
|
19
|
+
of left blank. Screen readers hear the same numbers.
|
|
20
|
+
|
|
21
|
+
## [0.9.0] - 2026-11-03
|
|
22
|
+
|
|
23
|
+
### Added
|
|
24
|
+
|
|
25
|
+
- **Rehearsal marks** draw as a boxed label at the start of their bar
|
|
26
|
+
(`part="mark"`), spoken "rehearsal B". Bar numbers skip them.
|
|
27
|
+
- **Words on a bar** draw small, above the slot they precede, or at the
|
|
28
|
+
bar's end (`part="words"`), and are spoken in place: "bar 1: “solo” D,
|
|
29
|
+
A".
|
|
30
|
+
- **Accents and hits** draw `>` or `^` above the chord
|
|
31
|
+
(`data-articulation`), spoken "accented D" and "D short hit".
|
|
32
|
+
- **Pushes** draw `‹` (an eighth) or `«` (a sixteenth) before the slot
|
|
33
|
+
(`data-push`), spoken "D pushed" and "D pushed a sixteenth".
|
|
34
|
+
- **Omissions** are spoken "C seven no third".
|
|
35
|
+
- **Voicings** draw the chord's name; a screen reader hears the notes:
|
|
36
|
+
"C major seven voiced E3 G3 B3 C4".
|
|
37
|
+
|
|
9
38
|
## [0.8.0] - 2026-11-03
|
|
10
39
|
|
|
11
40
|
Requires `barmark` 0.11.0.
|
|
@@ -239,7 +268,9 @@ that needs no script or as the `<barmark-chart>` web component. Requires
|
|
|
239
268
|
zoom without sideways scrolling, the element renders and re-renders, and
|
|
240
269
|
a screen reader hears "bar 9: D". Run them with `bun run test:browser`.
|
|
241
270
|
|
|
242
|
-
[Unreleased]: https://github.com/kevinpeckham/barmark/compare/render-v0.
|
|
271
|
+
[Unreleased]: https://github.com/kevinpeckham/barmark/compare/render-v0.9.1...HEAD
|
|
272
|
+
[0.9.1]: https://github.com/kevinpeckham/barmark/compare/render-v0.9.0...render-v0.9.1
|
|
273
|
+
[0.9.0]: https://github.com/kevinpeckham/barmark/compare/render-v0.8.0...render-v0.9.0
|
|
243
274
|
[0.8.0]: https://github.com/kevinpeckham/barmark/compare/render-v0.7.3...render-v0.8.0
|
|
244
275
|
[0.7.3]: https://github.com/kevinpeckham/barmark/compare/render-v0.7.2...render-v0.7.3
|
|
245
276
|
[0.7.2]: https://github.com/kevinpeckham/barmark/compare/render-v0.7.1...render-v0.7.2
|
package/README.md
CHANGED
|
@@ -178,8 +178,10 @@ At the default size chords are 16px and no label is under 12px.
|
|
|
178
178
|
|
|
179
179
|
Chords appear in their canonical form whatever the author typed (`Cø`
|
|
180
180
|
shows as Cm⁷(♭5)). `%` is drawn as the bar it copies; a replayed section
|
|
181
|
-
is drawn in full
|
|
182
|
-
|
|
181
|
+
is drawn in full, and its own lyrics replace the written section's. Bar
|
|
182
|
+
numbers count the bars as written, each once, as a band counts them: a
|
|
183
|
+
repeat, an ending, a jump or a replay doesn't move them, so a replayed
|
|
184
|
+
section shows the numbers it was written with. A line with an error shows as written, underlined,
|
|
183
185
|
with its message. `layoutChart(text)` returns all of this as data, if
|
|
184
186
|
you want to draw it yourself.
|
|
185
187
|
|
package/dist/html.js
CHANGED
|
@@ -97,13 +97,20 @@ function fitWidth(block) {
|
|
|
97
97
|
return FIT_STEPS.find((step) => step >= total) ?? FIT_STEPS.at(-1) ?? 0;
|
|
98
98
|
}
|
|
99
99
|
/** Em per bar: padding, plus each slot's text and the gap after it. */
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
100
|
+
function cellWidth(cell) {
|
|
101
|
+
if (cell.kind === "direction")
|
|
102
|
+
return 1 + 0.55 * printDirection(cell.direction).length;
|
|
103
|
+
if (cell.kind === "rehearsal")
|
|
104
|
+
return 1.4 + 0.6 * cell.label.length;
|
|
105
|
+
if (cell.kind === "fermata")
|
|
106
|
+
return MIN_BAR;
|
|
107
|
+
return Math.max(MIN_BAR, 1.5 + (cell.meter ? 0.8 : 0) + cell.slots.reduce((w, s) => w + slotWidth(s), 0));
|
|
108
|
+
}
|
|
109
|
+
/** Roughly: 0.65em a baseline character, 0.4em a superscript one, 0.6em between slots, 0.45em a push mark. */
|
|
106
110
|
function slotWidth(slot) {
|
|
111
|
+
return ("push" in slot && slot.push ? 0.45 : 0) + unmarkedWidth(slot);
|
|
112
|
+
}
|
|
113
|
+
function unmarkedWidth(slot) {
|
|
107
114
|
if (slot.kind === "group")
|
|
108
115
|
return slot.members.reduce((w, m) => w + slotWidth(m), 0.2);
|
|
109
116
|
if (slot.kind !== "chord")
|
|
@@ -198,12 +205,36 @@ function cellHtml(cell, barNumber, marks, numerals) {
|
|
|
198
205
|
: "";
|
|
199
206
|
const cut = cell.cut ? `<span class="bm-cut">cut</span>` : "";
|
|
200
207
|
const change = cell.tempoChange ? ` data-tempo-change="${cell.tempoChange}"` : "";
|
|
201
|
-
|
|
208
|
+
const [slots, end] = slotsWithWords(cell, view);
|
|
209
|
+
return `<div class="bm-bar" part="bar"${cell.cut ? " data-cut" : ""}${change}${marks}>${spoken}<span class="bm-bar-body" aria-hidden="true">${meter}${slots.join("")}${cut}</span>${end}</div>`;
|
|
210
|
+
}
|
|
211
|
+
/** A bar's slots, each under any words before it, and the words after the last slot. */
|
|
212
|
+
function slotsWithWords(cell, view) {
|
|
213
|
+
const words = (at) => (cell.words ?? [])
|
|
214
|
+
.filter((w) => w.at === at)
|
|
215
|
+
.map((w) => escapeHtml(w.text))
|
|
216
|
+
.join(" ");
|
|
217
|
+
const slots = cell.slots.map((s, i) => {
|
|
218
|
+
const said = words(i);
|
|
219
|
+
const html = slotHtml(s, view);
|
|
220
|
+
return said
|
|
221
|
+
? `<span class="bm-worded"><span class="bm-words" part="words">${said}</span>${html}</span>`
|
|
222
|
+
: html;
|
|
223
|
+
});
|
|
224
|
+
const after = words(cell.slots.length);
|
|
225
|
+
return [
|
|
226
|
+
slots,
|
|
227
|
+
after
|
|
228
|
+
? `<span class="bm-words bm-words-end" part="words" aria-hidden="true">${after}</span>`
|
|
229
|
+
: "",
|
|
230
|
+
];
|
|
202
231
|
}
|
|
203
|
-
/** A fermata or a direction: a place between bars, drawn as its sign. */
|
|
232
|
+
/** A fermata, a rehearsal mark or a direction: a place between bars, drawn as its sign. */
|
|
204
233
|
function betweenBarsHtml(cell, spoken, marks) {
|
|
205
234
|
if (cell.kind === "fermata")
|
|
206
235
|
return `<div class="bm-bar bm-fermata" part="bar"${marks}>${spoken}<span aria-hidden="true">${FERMATA}</span></div>`;
|
|
236
|
+
if (cell.kind === "rehearsal")
|
|
237
|
+
return `<div class="bm-bar bm-mark" part="mark"${marks}>${spoken}<span class="bm-box" aria-hidden="true">${escapeHtml(cell.label)}</span></div>`;
|
|
207
238
|
return `<div class="bm-bar bm-direction" part="direction" data-direction="${cell.direction.kind}"${marks}>${spoken}<span aria-hidden="true">${directionGlyph(cell.direction)}</span></div>`;
|
|
208
239
|
}
|
|
209
240
|
/** Segno and coda as the score's signs; To Coda and the jumps as their words. */
|
|
@@ -218,7 +249,26 @@ function directionGlyph(d) {
|
|
|
218
249
|
const SEGNO = `<svg class="bm-sign" viewBox="0 0 20 28" width="0.9em" height="1.25em"><path d="M14.5 6.5c-1-3-6.5-3.5-7.5-.5s3 4.5 4.5 5.5 5 3.5 3 7-7.5 2-8-1" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round"/><path d="M4 24 16 3" stroke="currentColor" stroke-width="1.6"/><circle cx="4.5" cy="13" r="1.6" fill="currentColor"/><circle cx="15.5" cy="15" r="1.6" fill="currentColor"/></svg>`;
|
|
219
250
|
const CODA = `<svg class="bm-sign" viewBox="0 0 24 24" width="1em" height="1em"><circle cx="12" cy="12" r="6.5" fill="none" stroke="currentColor" stroke-width="2"/><path d="M12 1v22M1 12h22" stroke="currentColor" stroke-width="1.6"/></svg>`;
|
|
220
251
|
const FERMATA = `<svg class="bm-fermata-glyph" viewBox="0 0 24 14" width="1.4em" height="0.8em"><path d="M2 13 A10 10 0 0 1 22 13" fill="none" stroke="currentColor" stroke-width="1.8"/><circle cx="12" cy="11" r="1.8" fill="currentColor"/></svg>`;
|
|
252
|
+
/** `‹` for an eighth push, `«` for a sixteenth. */
|
|
253
|
+
const PUSH_MARK = { eighth: "‹", sixteenth: "«" };
|
|
254
|
+
const ARTICULATION_MARK = { accent: ">", hit: "^" };
|
|
255
|
+
const marksOf = (slot) => ({
|
|
256
|
+
push: "push" in slot ? (slot.push ?? null) : null,
|
|
257
|
+
articulation: slot.kind === "chord" ? (slot.articulation ?? null) : null,
|
|
258
|
+
});
|
|
259
|
+
/** A slot with its push mark before it and its accent or hit above it. */
|
|
221
260
|
function slotHtml(slot, view) {
|
|
261
|
+
const body = unmarkedSlotHtml(slot, view);
|
|
262
|
+
const { push, articulation } = marksOf(slot);
|
|
263
|
+
if (!push && !articulation)
|
|
264
|
+
return body;
|
|
265
|
+
const data = `${push ? ` data-push="${push}"` : ""}${articulation ? ` data-articulation="${articulation}"` : ""}`;
|
|
266
|
+
const above = articulation
|
|
267
|
+
? `<span class="bm-artic">${ARTICULATION_MARK[articulation]}</span>`
|
|
268
|
+
: "";
|
|
269
|
+
return `<span class="bm-marked"${data}>${push ? `<span class="bm-push" aria-hidden="true">${PUSH_MARK[push]}</span>` : ""}${above}${body}</span>`;
|
|
270
|
+
}
|
|
271
|
+
function unmarkedSlotHtml(slot, view) {
|
|
222
272
|
switch (slot.kind) {
|
|
223
273
|
case "chord":
|
|
224
274
|
return chordHtml(slot.chord, view);
|
package/dist/model.js
CHANGED
|
@@ -13,7 +13,6 @@ export function layoutChart(text, options = {}) {
|
|
|
13
13
|
parse,
|
|
14
14
|
source: text.split(/\r?\n/),
|
|
15
15
|
errors: errorsByLine(parse),
|
|
16
|
-
lastKnownBar: lastKnownBar(parse.events),
|
|
17
16
|
written: new Map(groups.flatMap((g) => (g.heading ? [[g.heading.line, g]] : []))),
|
|
18
17
|
};
|
|
19
18
|
const blocks = groups.map((g) => layoutGroup(g, ctx));
|
|
@@ -44,27 +43,6 @@ function errorsByLine(parse) {
|
|
|
44
43
|
}
|
|
45
44
|
return errors;
|
|
46
45
|
}
|
|
47
|
-
/** The count of bars up to the end of the first open repeat (all of them if there is none). */
|
|
48
|
-
function lastKnownBar(events) {
|
|
49
|
-
let count = 0;
|
|
50
|
-
const countBars = (es) => {
|
|
51
|
-
for (const e of es) {
|
|
52
|
-
if (e.kind === "bar")
|
|
53
|
-
count++;
|
|
54
|
-
else if (e.kind === "open")
|
|
55
|
-
countBars(e.events);
|
|
56
|
-
}
|
|
57
|
-
};
|
|
58
|
-
for (const e of events) {
|
|
59
|
-
if (e.kind === "open") {
|
|
60
|
-
countBars(e.events);
|
|
61
|
-
return count;
|
|
62
|
-
}
|
|
63
|
-
if (e.kind === "bar")
|
|
64
|
-
count++;
|
|
65
|
-
}
|
|
66
|
-
return Number.POSITIVE_INFINITY;
|
|
67
|
-
}
|
|
68
46
|
/** The title line, and the directives before any other content, form the header. */
|
|
69
47
|
function splitHeader(lines) {
|
|
70
48
|
const header = {};
|
|
@@ -220,17 +198,17 @@ function layoutRow(l, played, previous, ctx) {
|
|
|
220
198
|
let prev = previous;
|
|
221
199
|
for (const cell of l.cells) {
|
|
222
200
|
const model = layoutCell(cell, played[bar] ?? written[bar], prev);
|
|
223
|
-
if (cell.kind
|
|
201
|
+
if (cell.kind === "slots" || cell.kind === "simile")
|
|
224
202
|
bar++;
|
|
225
203
|
if (model.kind === "slots")
|
|
226
204
|
prev = model;
|
|
227
205
|
cells.push(model);
|
|
228
206
|
}
|
|
229
|
-
const firstIndex = played[0]?.index;
|
|
230
207
|
return {
|
|
231
208
|
kind: "row",
|
|
232
209
|
line: l.line,
|
|
233
|
-
|
|
210
|
+
// Numbered as written, as a band counts (issue #92): repeats, endings, jumps and replays don't move it.
|
|
211
|
+
barNumber: (played[0] ?? written[0])?.written ?? null,
|
|
234
212
|
opens: l.opens,
|
|
235
213
|
closes: l.closes,
|
|
236
214
|
repeat: l.repeat,
|
|
@@ -242,16 +220,23 @@ function layoutRow(l, played, previous, ctx) {
|
|
|
242
220
|
function layoutCell(cell, played, previous) {
|
|
243
221
|
if (cell.kind === "fermata")
|
|
244
222
|
return { kind: "fermata" };
|
|
245
|
-
if (cell.kind === "direction")
|
|
223
|
+
if (cell.kind === "direction" || cell.kind === "rehearsal")
|
|
246
224
|
return cell;
|
|
247
|
-
|
|
248
|
-
|
|
225
|
+
return withPlayed(layoutBar(cell, played, previous), played);
|
|
226
|
+
}
|
|
227
|
+
/** A bar or `%`, with the slots it plays. */
|
|
228
|
+
function layoutBar(cell, played, previous) {
|
|
229
|
+
const own = cell.kind === "slots" ? cell : null;
|
|
230
|
+
return {
|
|
249
231
|
kind: "slots",
|
|
250
|
-
meter:
|
|
251
|
-
slots: played?.slots ??
|
|
232
|
+
meter: (own ?? previous)?.meter ?? null,
|
|
233
|
+
slots: played?.slots ?? own?.slots ?? [],
|
|
252
234
|
cut: false,
|
|
253
|
-
|
|
235
|
+
...wordsOf(cell),
|
|
236
|
+
};
|
|
254
237
|
}
|
|
238
|
+
/** The words written on a bar, as a field to spread; nothing when it has none. */
|
|
239
|
+
const wordsOf = (cell) => cell.words ? { words: cell.words } : {};
|
|
255
240
|
/** What the parser says about the bar as played: inside a rit. or accel., and its key. */
|
|
256
241
|
function withPlayed(cell, played) {
|
|
257
242
|
const change = played?.tempoChange?.kind;
|
package/dist/speech.js
CHANGED
|
@@ -60,7 +60,10 @@ function speakPitch(label) {
|
|
|
60
60
|
return `${m[1]}${ACCIDENTAL[m[2] ?? ""] ?? ""}${octave}`;
|
|
61
61
|
}
|
|
62
62
|
/** `b9` → "flat nine"; a natural tone is added: `9` → "add nine". */
|
|
63
|
+
const LEFT_OUT = { no3: "no third", no5: "no fifth" };
|
|
63
64
|
function speakTone(tone) {
|
|
65
|
+
if (LEFT_OUT[tone])
|
|
66
|
+
return LEFT_OUT[tone];
|
|
64
67
|
const m = /^(#|b)?(\d+)$/.exec(tone);
|
|
65
68
|
if (!m)
|
|
66
69
|
return tone;
|
|
@@ -102,10 +105,23 @@ export function speakChord(record, key) {
|
|
|
102
105
|
const degree = key ? speakDegree(record.parts.root, key) : "";
|
|
103
106
|
return `${degree ? `${degree}, ` : ""}${speakParts(record.parts)}`;
|
|
104
107
|
}
|
|
108
|
+
const PUSHED = { eighth: "pushed", sixteenth: "pushed a sixteenth" };
|
|
109
|
+
/** A chord with its voicing and articulation: "accented D", "G short hit", "C major seven voiced E3 G3". */
|
|
110
|
+
function speakChordSlot(slot, key) {
|
|
111
|
+
const name = speakChord(slot.chord, key);
|
|
112
|
+
const voiced = slot.voicing ? `${name} voiced ${slot.voicing.pitches.join(" ")}` : name;
|
|
113
|
+
if (slot.articulation === "accent")
|
|
114
|
+
return `accented ${voiced}`;
|
|
115
|
+
return slot.articulation === "hit" ? `${voiced} short hit` : voiced;
|
|
116
|
+
}
|
|
105
117
|
export function speakSlot(slot, key) {
|
|
118
|
+
const said = speakUnpushed(slot, key);
|
|
119
|
+
return "push" in slot && slot.push ? `${said} ${PUSHED[slot.push]}` : said;
|
|
120
|
+
}
|
|
121
|
+
function speakUnpushed(slot, key) {
|
|
106
122
|
switch (slot.kind) {
|
|
107
123
|
case "chord":
|
|
108
|
-
return
|
|
124
|
+
return speakChordSlot(slot, key);
|
|
109
125
|
case "hold":
|
|
110
126
|
return "hold";
|
|
111
127
|
case "nc":
|
|
@@ -130,7 +146,12 @@ export function speakBar(barNumber, cell, numerals = false) {
|
|
|
130
146
|
return "fermata: hold until cued";
|
|
131
147
|
if (cell.kind === "direction")
|
|
132
148
|
return speakDirection(cell.direction);
|
|
149
|
+
if (cell.kind === "rehearsal")
|
|
150
|
+
return `rehearsal ${cell.label}`;
|
|
133
151
|
const meter = cell.meter ? `, in ${cell.meter.n}/${cell.meter.d}` : "";
|
|
134
152
|
const cut = cell.cut ? ", cut on this pass" : "";
|
|
135
|
-
|
|
153
|
+
const words = (at) => (cell.words ?? []).filter((w) => w.at === at).map((w) => `“${w.text}”`);
|
|
154
|
+
const slots = cell.slots.map((s, i) => [...words(i), speakSlot(s, numerals ? cell.key : undefined)].join(" "));
|
|
155
|
+
const spoken = [...slots, ...words(cell.slots.length)].join(", ");
|
|
156
|
+
return `bar${barNumber === null ? "" : ` ${barNumber}`}${meter}: ${spoken}${cut}`;
|
|
136
157
|
}
|
package/dist/styles.js
CHANGED
|
@@ -119,6 +119,15 @@ const css = `
|
|
|
119
119
|
.bm-row>div.bm-direction{min-width:0;padding-inline:.35em;border-right:none;align-items:flex-start;color:var(--bm-ink)}
|
|
120
120
|
.bm-sign{display:inline-block;vertical-align:middle}
|
|
121
121
|
.bm-direction-words{font:italic ${em(SIZES.repeat)}/1.2 Georgia,serif;white-space:nowrap}
|
|
122
|
+
.bm-row>div.bm-mark{min-width:0;padding-inline:.3em;border-right:none;align-items:flex-start}
|
|
123
|
+
.bm-box{display:inline-block;padding:.05em .3em;border:.08em solid var(--bm-ink);border-radius:.15em;font:700 .85em/1.1 system-ui,sans-serif;color:var(--bm-ink)}
|
|
124
|
+
.bm-worded{position:relative}
|
|
125
|
+
.bm-marked{position:relative;display:inline-flex;align-items:baseline}
|
|
126
|
+
.bm-push{font:700 .8em/1 system-ui,sans-serif;color:var(--bm-muted);margin-right:.08em}
|
|
127
|
+
.bm-artic{position:absolute;left:50%;top:-.95em;transform:translateX(-50%);font:700 .7em/1 system-ui,sans-serif;color:var(--bm-ink)}
|
|
128
|
+
.bm-marked[data-push]>.bm-artic{left:calc(50% + .25em)}
|
|
129
|
+
.bm-words{position:absolute;left:0;top:-1.05em;font:italic .62em/1 Georgia,serif;color:var(--bm-muted);white-space:nowrap}
|
|
130
|
+
.bm-bar>.bm-words-end{left:auto;right:.5em;top:.15em}
|
|
122
131
|
.bm-bar[data-ending]::after{content:attr(data-ending);position:absolute;left:.45em;top:.2em;font:italic .75em/1 Georgia,serif;color:var(--bm-muted)}
|
|
123
132
|
.bm-ending>.bm-bar{border-top:.06em solid var(--bm-muted)}
|
|
124
133
|
.bm-ending>.bm-bar[data-ending]{box-shadow:inset .06em 0 var(--bm-muted)}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ChartDiagnostic, Direction, Directives, Key, Meter, Repeat, Slot } from "barmark";
|
|
1
|
+
import type { ChartDiagnostic, Direction, Directives, Key, Meter, Repeat, Slot, Words } from "barmark";
|
|
2
2
|
export type LayoutOptions = {
|
|
3
3
|
rehearsalLetters?: boolean;
|
|
4
4
|
};
|
|
@@ -25,7 +25,7 @@ export type SectionBlock = {
|
|
|
25
25
|
export type BlockItem = {
|
|
26
26
|
kind: "row";
|
|
27
27
|
line: number;
|
|
28
|
-
/** The
|
|
28
|
+
/** The written number of the row's first bar (`PlayedBar.written`); a replay shows its section's numbers. Null for a row with no bar. */
|
|
29
29
|
barNumber: number | null;
|
|
30
30
|
opens: boolean;
|
|
31
31
|
closes: boolean;
|
|
@@ -57,6 +57,8 @@ export type CellModel = {
|
|
|
57
57
|
tempoChange?: "rit" | "accel";
|
|
58
58
|
/** The key the bar is played in, when the chart names one. */
|
|
59
59
|
key?: Key;
|
|
60
|
+
/** Words written on the bar (barmark's grammar 2.6), each before slot `at`. */
|
|
61
|
+
words?: Words[];
|
|
60
62
|
} | {
|
|
61
63
|
kind: "fermata";
|
|
62
64
|
}
|
|
@@ -64,4 +66,9 @@ export type CellModel = {
|
|
|
64
66
|
| {
|
|
65
67
|
kind: "direction";
|
|
66
68
|
direction: Direction;
|
|
69
|
+
}
|
|
70
|
+
/** A rehearsal mark on the bar after it (barmark's grammar 2.5). */
|
|
71
|
+
| {
|
|
72
|
+
kind: "rehearsal";
|
|
73
|
+
label: string;
|
|
67
74
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@barmark/render",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "Render barmark chord charts as a clean, accessible bar grid: HTML with Declarative Shadow DOM, or the <barmark-chart> web component.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"url": "https://github.com/kevinpeckham/barmark/issues"
|
|
48
48
|
},
|
|
49
49
|
"dependencies": {
|
|
50
|
-
"barmark": "^0.
|
|
50
|
+
"barmark": "^0.12.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"build": "rm -rf dist && tsc -p tsconfig.build.json",
|