@ugfoundation/swaralipi-js 0.8.0 → 0.8.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.
- package/dist/{batch-NJMT3M5Z.js → batch-6FPBT5DP.js} +4 -4
- package/dist/{batch-NJMT3M5Z.js.map → batch-6FPBT5DP.js.map} +1 -1
- package/dist/{chunk-4HMHTXDE.js → chunk-FULC22MN.js} +3 -3
- package/dist/{chunk-4HMHTXDE.js.map → chunk-FULC22MN.js.map} +1 -1
- package/dist/{chunk-YFVAVICF.js → chunk-UMBKIGVQ.js} +3 -3
- package/dist/{chunk-YFVAVICF.js.map → chunk-UMBKIGVQ.js.map} +1 -1
- package/dist/cli.cjs +1 -1
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/convert/index.cjs +1 -1
- package/dist/convert/index.cjs.map +1 -1
- package/dist/convert/index.js +2 -2
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/spec/index.cjs +1 -1
- package/dist/spec/index.cjs.map +1 -1
- package/dist/spec/index.d.cts +1 -1
- package/dist/spec/index.d.ts +1 -1
- package/dist/spec/index.js +1 -1
- package/dist/viewer/index.cjs +156 -87
- package/dist/viewer/index.cjs.map +1 -1
- package/dist/viewer/index.d.cts +11 -5
- package/dist/viewer/index.d.ts +11 -5
- package/dist/viewer/index.js +155 -86
- package/dist/viewer/index.js.map +1 -1
- package/package.json +1 -1
package/dist/viewer/index.d.cts
CHANGED
|
@@ -116,6 +116,9 @@ interface Arc {
|
|
|
116
116
|
/** 0-based index of the arc's first / last **cell** within the row. */
|
|
117
117
|
start: number;
|
|
118
118
|
end: number;
|
|
119
|
+
/** Index, within that cell's notes, of the note the arc hangs from / into. */
|
|
120
|
+
startNote: number;
|
|
121
|
+
endNote: number;
|
|
119
122
|
/** True when the matching end lies on a previous / following system. */
|
|
120
123
|
openLeft: boolean;
|
|
121
124
|
openRight: boolean;
|
|
@@ -123,11 +126,14 @@ interface Arc {
|
|
|
123
126
|
line?: boolean;
|
|
124
127
|
}
|
|
125
128
|
/**
|
|
126
|
-
* Resolve under-arcs for one row
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* -
|
|
129
|
+
* Resolve under-arcs for one row down to the **note** each end hangs from, so a
|
|
130
|
+
* slur inside one half-matra cell (মজ্ঞা) still runs centre to centre. Sources,
|
|
131
|
+
* scanned left→right:
|
|
132
|
+
* - spec `meend: 'start' | 'end'` — exact notes;
|
|
133
|
+
* - below-annotation raws, which belong to the whole cell (NLTR types them
|
|
134
|
+
* centred under the column): `w` opens on the cell's first sounded note,
|
|
135
|
+
* `x` closes on its last, `$` (Swarabitan's short in-cell arc) runs first to
|
|
136
|
+
* last, and `xw` — close, then re-open — meets in the middle instead.
|
|
131
137
|
* Unmatched `x` → arc from cell 0 with a squared-off (open) left end;
|
|
132
138
|
* unclosed `w` → arc to the last cell with an open right end — both match
|
|
133
139
|
* the print's behavior when an arc continues across a system wrap.
|
package/dist/viewer/index.d.ts
CHANGED
|
@@ -116,6 +116,9 @@ interface Arc {
|
|
|
116
116
|
/** 0-based index of the arc's first / last **cell** within the row. */
|
|
117
117
|
start: number;
|
|
118
118
|
end: number;
|
|
119
|
+
/** Index, within that cell's notes, of the note the arc hangs from / into. */
|
|
120
|
+
startNote: number;
|
|
121
|
+
endNote: number;
|
|
119
122
|
/** True when the matching end lies on a previous / following system. */
|
|
120
123
|
openLeft: boolean;
|
|
121
124
|
openRight: boolean;
|
|
@@ -123,11 +126,14 @@ interface Arc {
|
|
|
123
126
|
line?: boolean;
|
|
124
127
|
}
|
|
125
128
|
/**
|
|
126
|
-
* Resolve under-arcs for one row
|
|
127
|
-
*
|
|
128
|
-
*
|
|
129
|
-
*
|
|
130
|
-
* -
|
|
129
|
+
* Resolve under-arcs for one row down to the **note** each end hangs from, so a
|
|
130
|
+
* slur inside one half-matra cell (মজ্ঞা) still runs centre to centre. Sources,
|
|
131
|
+
* scanned left→right:
|
|
132
|
+
* - spec `meend: 'start' | 'end'` — exact notes;
|
|
133
|
+
* - below-annotation raws, which belong to the whole cell (NLTR types them
|
|
134
|
+
* centred under the column): `w` opens on the cell's first sounded note,
|
|
135
|
+
* `x` closes on its last, `$` (Swarabitan's short in-cell arc) runs first to
|
|
136
|
+
* last, and `xw` — close, then re-open — meets in the middle instead.
|
|
131
137
|
* Unmatched `x` → arc from cell 0 with a squared-off (open) left end;
|
|
132
138
|
* unclosed `w` → arc to the last cell with an open right end — both match
|
|
133
139
|
* the print's behavior when an arc continues across a system wrap.
|
package/dist/viewer/index.js
CHANGED
|
@@ -194,42 +194,64 @@ function alignRows(rows) {
|
|
|
194
194
|
}
|
|
195
195
|
function resolveArcs(cells) {
|
|
196
196
|
const arcs = [];
|
|
197
|
-
let
|
|
197
|
+
let open;
|
|
198
198
|
let sawEnds = false;
|
|
199
199
|
const fillCells = [];
|
|
200
|
-
const openAt = (
|
|
200
|
+
const openAt = (cell, note) => {
|
|
201
201
|
sawEnds = true;
|
|
202
|
-
|
|
202
|
+
open ??= { cell, note };
|
|
203
203
|
};
|
|
204
|
-
const closeAt = (
|
|
204
|
+
const closeAt = (cell, note) => {
|
|
205
205
|
sawEnds = true;
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
206
|
+
const from = open ?? { cell: 0, note: 0 };
|
|
207
|
+
arcs.push({
|
|
208
|
+
start: from.cell,
|
|
209
|
+
startNote: from.note,
|
|
210
|
+
end: cell,
|
|
211
|
+
endNote: note,
|
|
212
|
+
openLeft: open === void 0,
|
|
213
|
+
openRight: false
|
|
214
|
+
});
|
|
215
|
+
open = void 0;
|
|
212
216
|
};
|
|
213
217
|
cells.forEach((cell, i) => {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
218
|
+
const pitched = cell.notes.flatMap((n, j) => isPitched(n) ? [j] : []);
|
|
219
|
+
const first = pitched[0] ?? 0;
|
|
220
|
+
const last = pitched[pitched.length - 1] ?? cell.notes.length - 1;
|
|
221
|
+
let marks = "";
|
|
222
|
+
cell.notes.forEach((note, j) => {
|
|
223
|
+
if (note.meend === "start") openAt(i, j);
|
|
224
|
+
else if (note.meend === "end") closeAt(i, j);
|
|
225
|
+
for (const b of note.below ?? []) if (isArcRaw(b.raw)) marks += b.raw;
|
|
226
|
+
});
|
|
227
|
+
const reopens = /[xX].*[wW]/.test(marks);
|
|
228
|
+
for (const ch of marks) {
|
|
229
|
+
if (ch === "w" || ch === "W") openAt(i, reopens ? last : first);
|
|
230
|
+
else if (ch === "x" || ch === "X") closeAt(i, reopens ? first : last);
|
|
231
|
+
else if (ch === "$") {
|
|
232
|
+
openAt(i, first);
|
|
233
|
+
closeAt(i, last);
|
|
234
|
+
} else fillCells.push(i);
|
|
225
235
|
}
|
|
226
236
|
});
|
|
227
|
-
|
|
228
|
-
|
|
237
|
+
const lastCell = Math.max(cells.length - 1, 0);
|
|
238
|
+
const lastNote = (c) => Math.max((cells[c]?.notes.length ?? 1) - 1, 0);
|
|
239
|
+
if (open !== void 0) {
|
|
240
|
+
arcs.push({
|
|
241
|
+
start: open.cell,
|
|
242
|
+
startNote: open.note,
|
|
243
|
+
end: lastCell,
|
|
244
|
+
endNote: lastNote(lastCell),
|
|
245
|
+
openLeft: false,
|
|
246
|
+
openRight: true
|
|
247
|
+
});
|
|
229
248
|
} else if (!sawEnds && fillCells.length > 0) {
|
|
249
|
+
const end = Math.max(...fillCells);
|
|
230
250
|
arcs.push({
|
|
231
251
|
start: Math.min(...fillCells),
|
|
232
|
-
|
|
252
|
+
startNote: 0,
|
|
253
|
+
end,
|
|
254
|
+
endNote: lastNote(end),
|
|
233
255
|
openLeft: true,
|
|
234
256
|
openRight: true,
|
|
235
257
|
line: true
|
|
@@ -237,6 +259,35 @@ function resolveArcs(cells) {
|
|
|
237
259
|
}
|
|
238
260
|
return arcs;
|
|
239
261
|
}
|
|
262
|
+
function arcInk(cells, arcs) {
|
|
263
|
+
const ink = { cells: cells.map(() => ""), notes: cells.map((c) => c.notes.map(() => "")) };
|
|
264
|
+
const mark = (c, j, cls, clip = false) => {
|
|
265
|
+
ink.notes[c][j] += ` ${cls}`;
|
|
266
|
+
if (clip && !ink.cells[c].includes(" sw-mk")) ink.cells[c] += " sw-mk";
|
|
267
|
+
};
|
|
268
|
+
for (const arc of arcs) {
|
|
269
|
+
const { start: s, end: e, startNote: j, endNote: k } = arc;
|
|
270
|
+
const hookL = arc.line !== true && !arc.openLeft;
|
|
271
|
+
const hookR = arc.line !== true && !arc.openRight;
|
|
272
|
+
if (s === e && hookL && hookR) {
|
|
273
|
+
if (j === k) {
|
|
274
|
+
mark(s, j, "sw-mos");
|
|
275
|
+
mark(s, j, "sw-mcs");
|
|
276
|
+
} else {
|
|
277
|
+
mark(s, j, "sw-mob");
|
|
278
|
+
for (let n = j + 1; n < k; n++) mark(s, n, "sw-mf");
|
|
279
|
+
mark(s, k, "sw-mcb");
|
|
280
|
+
}
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
for (let c = s; c <= e; c++) {
|
|
284
|
+
if (c === s && hookL) mark(c, j, "sw-mo", true);
|
|
285
|
+
else if (c === e && hookR) mark(c, k, "sw-mc", true);
|
|
286
|
+
else mark(c, 0, "sw-mm", true);
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
return ink;
|
|
290
|
+
}
|
|
240
291
|
var SVARA_CHAR = /[srgmpqndtkuv]/;
|
|
241
292
|
function rawMarks(raw, count) {
|
|
242
293
|
if (raw === void 0) return void 0;
|
|
@@ -412,21 +463,9 @@ function renderNote(note, kind, opts, ctx) {
|
|
|
412
463
|
const raw = rawDisplay(note);
|
|
413
464
|
return bracketGlyphs(note, "open") + (raw !== void 0 ? `<span class="sw-raw" title="${escapeHtml(raw)}">${escapeHtml(raw)}</span>` : "") + bracketGlyphs(note, "close");
|
|
414
465
|
}
|
|
415
|
-
function renderArc(arc, offset) {
|
|
416
|
-
const open = arc.line === true;
|
|
417
|
-
const cls = [
|
|
418
|
-
"sw-arc",
|
|
419
|
-
arc.openLeft || open ? "sw-arc--openl" : "",
|
|
420
|
-
arc.openRight || open ? "sw-arc--openr" : ""
|
|
421
|
-
].filter(Boolean).join(" ");
|
|
422
|
-
const left = open || arc.openLeft ? "" : '<i class="sw-arc-l">w</i>';
|
|
423
|
-
const right = open || arc.openRight ? "" : '<i class="sw-arc-r">x</i>';
|
|
424
|
-
const from = offset + arc.start + COL_BASE;
|
|
425
|
-
const to = offset + arc.end + COL_BASE + 1;
|
|
426
|
-
return `<span class="${cls}" style="grid-column:${from} / ${to}">${left}<i class="sw-arc-m"></i>${right}</span>`;
|
|
427
|
-
}
|
|
428
466
|
function renderRow(row, partIdx, rowIdx, offset, ctx) {
|
|
429
467
|
const cells = groupRowIntoCells(row.notes);
|
|
468
|
+
const ink = arcInk(cells, resolveArcs(cells));
|
|
430
469
|
const out = [];
|
|
431
470
|
if (row.label !== void 0)
|
|
432
471
|
out.push(`<span class="sw-label">${escapeHtml(ctx.tr(row.label))}</span>`);
|
|
@@ -436,11 +475,10 @@ function renderRow(row, partIdx, rowIdx, offset, ctx) {
|
|
|
436
475
|
const barCls = cell.kind === "bar" ? " sw-bar-cell" : "";
|
|
437
476
|
const notes = cell.notes.map((note, j) => {
|
|
438
477
|
const path = `${partIdx}.${rowIdx}.${cell.start + j}`;
|
|
439
|
-
const cls = isPitched(note) ? " sw-p" : "";
|
|
440
478
|
const bar = note.bar !== void 0 ? ` sw-bar sw-bar--${note.bar}` : "";
|
|
441
|
-
return `<span class="sw-n${
|
|
479
|
+
return `<span class="sw-n${bar}${ink.notes[ci][j]}" data-note="${path}">${renderNote(note, cell.kind, opts[j], ctx)}</span>`;
|
|
442
480
|
}).join("");
|
|
443
|
-
out.push(`<span class="sw-cell${barCls}" style="grid-column:${col}">${notes}</span>`);
|
|
481
|
+
out.push(`<span class="sw-cell${barCls}${ink.cells[ci]}" style="grid-column:${col}">${notes}</span>`);
|
|
444
482
|
const slices = cellLyricSlices(cell);
|
|
445
483
|
if (slices !== void 0) {
|
|
446
484
|
const html = slices.map((t) => `<span>${escapeHtml(lyricText(t, ctx))}</span>`).join("");
|
|
@@ -453,7 +491,6 @@ function renderRow(row, partIdx, rowIdx, offset, ctx) {
|
|
|
453
491
|
if (below.length > 0)
|
|
454
492
|
out.push(`<span class="sw-below" style="grid-column:${col}">${renderAnnotation(below, ctx)}</span>`);
|
|
455
493
|
});
|
|
456
|
-
for (const arc of resolveArcs(cells)) out.push(renderArc(arc, offset));
|
|
457
494
|
return `<div class="sw-row">${out.join("")}</div>`;
|
|
458
495
|
}
|
|
459
496
|
function renderHeader(meta, ctx) {
|
|
@@ -511,7 +548,7 @@ function fitSwaralipi(root, minScale = 0, zoom = 1, minSpacing = 0.35, minSize =
|
|
|
511
548
|
sheet.style.removeProperty("--sw-size");
|
|
512
549
|
sheet.style.removeProperty("--sw-tight");
|
|
513
550
|
const available = scroll.clientWidth;
|
|
514
|
-
let natural = block.
|
|
551
|
+
let natural = block.offsetWidth;
|
|
515
552
|
if (available === 0 || natural === 0) continue;
|
|
516
553
|
if (natural > available && minSpacing < 1) {
|
|
517
554
|
let loose = minSpacing;
|
|
@@ -519,11 +556,11 @@ function fitSwaralipi(root, minScale = 0, zoom = 1, minSpacing = 0.35, minSize =
|
|
|
519
556
|
for (let i = 0; i < 6; i++) {
|
|
520
557
|
const mid = (loose + tight) / 2;
|
|
521
558
|
sheet.style.setProperty("--sw-tight", String(mid));
|
|
522
|
-
if (block.
|
|
559
|
+
if (block.offsetWidth <= available) loose = mid;
|
|
523
560
|
else tight = mid;
|
|
524
561
|
}
|
|
525
562
|
sheet.style.setProperty("--sw-tight", String(loose));
|
|
526
|
-
natural = block.
|
|
563
|
+
natural = block.offsetWidth;
|
|
527
564
|
}
|
|
528
565
|
const base = parseFloat(getComputedStyle(sheet).fontSize);
|
|
529
566
|
if (!(base > 0)) continue;
|
|
@@ -621,31 +658,45 @@ ${FONT_FACES}
|
|
|
621
658
|
column-gap: calc(var(--sw-cell-gap, 0.4em) * var(--sw-tight, 1));
|
|
622
659
|
align-items: end;
|
|
623
660
|
width: max-content;
|
|
661
|
+
/* The last column's cell spacers overhang half a gap past the grid; clip
|
|
662
|
+
that sideways so it neither counts as width to fit nor raises a scrollbar. */
|
|
663
|
+
overflow-x: clip;
|
|
624
664
|
}
|
|
625
665
|
.sw-part { display: contents; }
|
|
666
|
+
/* Four FIXED bands per row \u2014 above / notation / arc / lyric \u2014 so a beat label,
|
|
667
|
+
* a \u0995\u09A3 or a \u09AE\u09C0\u09A1\u09BC never changes how far a line sits from its words: the
|
|
668
|
+
* notation hugs its lyric and the next system starts a little further off,
|
|
669
|
+
* as the printed \u09B8\u09CD\u09AC\u09B0\u09AC\u09BF\u09A4\u09BE\u09A8 sets it. Content taller than its band overflows
|
|
670
|
+
* rather than pushing the rhythm apart. */
|
|
626
671
|
.sw-row {
|
|
627
672
|
grid-column: 1 / -1;
|
|
628
673
|
display: grid;
|
|
629
674
|
grid-template-columns: subgrid;
|
|
630
|
-
grid-template-rows:
|
|
675
|
+
grid-template-rows: 0.95em 1.35em 0.4em 1.35em;
|
|
631
676
|
align-items: end;
|
|
632
|
-
padding: 0.
|
|
677
|
+
padding-bottom: 0.35em;
|
|
678
|
+
line-height: 1.35;
|
|
633
679
|
}
|
|
634
680
|
.sw-label { grid-column: 1; grid-row: 2; padding-right: 0.5em; font-weight: 600; }
|
|
635
681
|
|
|
636
|
-
/* One column per cell
|
|
637
|
-
* flex
|
|
638
|
-
*
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
.sw-cell
|
|
642
|
-
.sw-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
.sw-
|
|
648
|
-
.sw-
|
|
682
|
+
/* One column per cell, its notes set tight as one word (\u09B0\u09B8\u09BE) and centred by
|
|
683
|
+
* two flex spacers. Each spacer overhangs half the column gap (a min-width
|
|
684
|
+
* paid back by a negative margin, so the column is sized by the notes alone),
|
|
685
|
+
* which lets neighbouring cells' spacers meet mid-gap: a \u09AE\u09C0\u09A1\u09BC crossing cells is
|
|
686
|
+
* inked by these boxes with no hole between them. */
|
|
687
|
+
.sw-cell, .sw-lyr { display: flex; justify-content: center; white-space: nowrap; }
|
|
688
|
+
.sw-cell {
|
|
689
|
+
--sw-half-gap: calc(var(--sw-cell-gap, 0.4em) * var(--sw-tight, 1) / 2);
|
|
690
|
+
grid-row: 2;
|
|
691
|
+
align-self: stretch;
|
|
692
|
+
}
|
|
693
|
+
.sw-cell::before, .sw-cell::after { content: ''; flex: 1 0 0; min-width: var(--sw-half-gap); }
|
|
694
|
+
.sw-cell::before { margin-left: calc(var(--sw-half-gap) * -1); }
|
|
695
|
+
.sw-cell::after { margin-right: calc(var(--sw-half-gap) * -1); }
|
|
696
|
+
.sw-cell > .sw-n { position: relative; }
|
|
697
|
+
.sw-above { grid-row: 1; font-size: 0.62em; line-height: 1; justify-self: center; white-space: nowrap; }
|
|
698
|
+
.sw-below { grid-row: 3; font-size: 0.62em; line-height: 1; justify-self: center; white-space: nowrap; }
|
|
699
|
+
.sw-lyr { grid-row: 4; }
|
|
649
700
|
|
|
650
701
|
/* ---- notation clusters & marks ---- */
|
|
651
702
|
.sw-cl { position: relative; display: inline-block; }
|
|
@@ -666,12 +717,16 @@ ${FONT_FACES}
|
|
|
666
717
|
.sw-ati-taar::before { top: -0.3em; }
|
|
667
718
|
.sw-ati-mandra::before { bottom: -0.35em; }
|
|
668
719
|
|
|
669
|
-
/* grace notes: small raised clusters \u2014 \u0995\u09A3 before the note, \u09B0\u09C7\u09B6 after it
|
|
720
|
+
/* grace notes: small raised clusters \u2014 \u0995\u09A3 before the note, \u09B0\u09C7\u09B6 after it.
|
|
721
|
+
* line-height 0 (here and on .sw-micro): a raised inline box taller than the
|
|
722
|
+
* strut grows its line box and drops that one note's baseline below its
|
|
723
|
+
* neighbours' (css2 \xA710.8). */
|
|
670
724
|
.sw-kan,
|
|
671
725
|
.sw-resh {
|
|
672
726
|
position: relative;
|
|
673
727
|
display: inline-block;
|
|
674
728
|
font-size: 0.58em;
|
|
729
|
+
line-height: 0;
|
|
675
730
|
vertical-align: 0.75em;
|
|
676
731
|
}
|
|
677
732
|
.sw-kan { margin-right: 0.08em; }
|
|
@@ -703,7 +758,7 @@ ${FONT_FACES}
|
|
|
703
758
|
.sw-cut::before { top: 0.2em; }
|
|
704
759
|
.sw-cut::after { top: 0.55em; }
|
|
705
760
|
.sw-br { opacity: 0.8; padding: 0 0.06em; }
|
|
706
|
-
.sw-micro { font-size: 0.6em; vertical-align: super; opacity: 0.8; }
|
|
761
|
+
.sw-micro { font-size: 0.6em; line-height: 0; vertical-align: super; opacity: 0.8; }
|
|
707
762
|
|
|
708
763
|
/* raw fallback: never dropped, visibly non-notation. Swarabitan first \u2014
|
|
709
764
|
* raw IS that font's encoding, so undecoded cells show NLTR's own glyphs
|
|
@@ -723,32 +778,46 @@ ${FONT_FACES}
|
|
|
723
778
|
/* a bar owns a whole column but needs no matra of width */
|
|
724
779
|
.sw-bar-cell { min-width: 0; }
|
|
725
780
|
|
|
726
|
-
/* ---- \u09AE\u09C0\u09A1\u09BC under-arcs (from w/x segments and spec meend) ----
|
|
727
|
-
* Swarabitan
|
|
728
|
-
* flat
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
732
|
-
.sw-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
781
|
+
/* ---- \u09AE\u09C0\u09A1\u09BC under-arcs (from w/x/$ segments and spec meend) ----
|
|
782
|
+
* Swarabitan's own arc, all langs: w is the opening hook, curling down from
|
|
783
|
+
* its tip into a flat, x its mirror, y that flat alone \u2014 and they join
|
|
784
|
+
* hole-free, so one run of text is a whole end (tools/align-check/glyph.html).
|
|
785
|
+
* Each end sets its hook tip on its note's centre and runs the flat toward the
|
|
786
|
+
* other end (render.ts arcInk): across cells it is cut at the mid-gap, where
|
|
787
|
+
* the next cell's run carries on (.sw-mk clips a cell half a gap past each
|
|
788
|
+
* side, as far as its spacers reach); inside one cell, at its note's edge. So
|
|
789
|
+
* a long arc extends the flat and a short one trims it off. line-height 0 sets
|
|
790
|
+
* every run's baseline the same distance below its note. The clip reaches
|
|
791
|
+
* 0.5px further so two cells' anti-aliased edges overlap instead of leaving a
|
|
792
|
+
* hairline seam between their identical flats. */
|
|
793
|
+
.sw-mk { clip-path: inset(-3em calc(var(--sw-half-gap) * -1 - 0.5px)); }
|
|
794
|
+
.sw-mo::after, .sw-mob::after, .sw-mos::after,
|
|
795
|
+
.sw-mc::before, .sw-mcb::before, .sw-mcs::before,
|
|
796
|
+
.sw-mf::before, .sw-mm::before {
|
|
797
|
+
content: 'yyyyyyyyyyyy';
|
|
798
|
+
position: absolute;
|
|
799
|
+
top: calc(100% + 0.05em);
|
|
800
|
+
font-family: Swarabitan;
|
|
737
801
|
font-size: 0.9em;
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
.sw-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
802
|
+
line-height: 0;
|
|
803
|
+
white-space: pre;
|
|
804
|
+
overflow-x: clip;
|
|
805
|
+
}
|
|
806
|
+
.sw-mo::after, .sw-mob::after, .sw-mos::after { content: 'wyyyyyyyyyyyy'; }
|
|
807
|
+
/* rtl: a closing run cut short keeps its hook on its right edge */
|
|
808
|
+
.sw-mc::before, .sw-mcb::before, .sw-mcs::before { content: 'yyyyyyyyyyyyx'; direction: rtl; }
|
|
809
|
+
.sw-mo::after, .sw-mob::after { left: 50%; }
|
|
810
|
+
.sw-mc::before, .sw-mcb::before { right: 50%; }
|
|
811
|
+
.sw-mos::after { left: 0; }
|
|
812
|
+
.sw-mcs::before { right: 0; }
|
|
813
|
+
.sw-mf::before { left: 0; right: 0; }
|
|
814
|
+
.sw-mm::before { left: -12em; }
|
|
815
|
+
/* Inside one cell a hook gets half a note to curl in, about a third of its
|
|
816
|
+
* curl: squeezed to half width (same stroke) it lands flat at the cut, so the
|
|
817
|
+
* two flats meet level whatever the notes' widths \u2014 a small arc, not a V. */
|
|
818
|
+
.sw-mob::after, .sw-mos::after, .sw-mcb::before, .sw-mcs::before { width: 100%; transform: scaleX(0.5); }
|
|
819
|
+
.sw-mob::after, .sw-mos::after { transform-origin: left; }
|
|
820
|
+
.sw-mcb::before, .sw-mcs::before { transform-origin: right; }
|
|
752
821
|
|
|
753
822
|
/* ---- annotation content ---- */
|
|
754
823
|
.sw-beat { position: relative; display: inline-block; padding: 0 0.1em; }
|