@pepperhorn/chordl-core 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/LICENSE +21 -0
  2. package/dist/audio/midi-export.d.ts +23 -0
  3. package/dist/audio/midi-export.js +155 -0
  4. package/dist/audio/midi-export.js.map +1 -0
  5. package/dist/chord-sheet/codec.d.ts +14 -0
  6. package/dist/chord-sheet/codec.js +119 -0
  7. package/dist/chord-sheet/codec.js.map +1 -0
  8. package/dist/chord-sheet/defaults.d.ts +13 -0
  9. package/dist/chord-sheet/defaults.js +48 -0
  10. package/dist/chord-sheet/defaults.js.map +1 -0
  11. package/dist/chord-sheet/index.d.ts +3 -0
  12. package/dist/chord-sheet/index.js +4 -0
  13. package/dist/chord-sheet/index.js.map +1 -0
  14. package/dist/chord-sheet/schema.d.ts +6 -0
  15. package/dist/chord-sheet/schema.js +17 -0
  16. package/dist/chord-sheet/schema.js.map +1 -0
  17. package/dist/config.d.ts +2 -0
  18. package/dist/config.js +15 -0
  19. package/dist/config.js.map +1 -0
  20. package/dist/engine/auto-fingering.d.ts +36 -0
  21. package/dist/engine/auto-fingering.js +344 -0
  22. package/dist/engine/auto-fingering.js.map +1 -0
  23. package/dist/engine/highlight-mapper.d.ts +3 -0
  24. package/dist/engine/highlight-mapper.js +46 -0
  25. package/dist/engine/highlight-mapper.js.map +1 -0
  26. package/dist/engine/keyboard-layout.d.ts +6 -0
  27. package/dist/engine/keyboard-layout.js +65 -0
  28. package/dist/engine/keyboard-layout.js.map +1 -0
  29. package/dist/engine/note-spelling.d.ts +54 -0
  30. package/dist/engine/note-spelling.js +103 -0
  31. package/dist/engine/note-spelling.js.map +1 -0
  32. package/dist/engine/scale-fingering.d.ts +21 -0
  33. package/dist/engine/scale-fingering.js +130 -0
  34. package/dist/engine/scale-fingering.js.map +1 -0
  35. package/dist/engine/staff-constants.d.ts +16 -0
  36. package/dist/engine/staff-constants.js +20 -0
  37. package/dist/engine/staff-constants.js.map +1 -0
  38. package/dist/engine/staff-glyphs.d.ts +17 -0
  39. package/dist/engine/staff-glyphs.js +59 -0
  40. package/dist/engine/staff-glyphs.js.map +1 -0
  41. package/dist/engine/staff-layout.d.ts +28 -0
  42. package/dist/engine/staff-layout.js +238 -0
  43. package/dist/engine/staff-layout.js.map +1 -0
  44. package/dist/engine/svg-constants.d.ts +19 -0
  45. package/dist/engine/svg-constants.js +40 -0
  46. package/dist/engine/svg-constants.js.map +1 -0
  47. package/dist/index.d.ts +42 -0
  48. package/dist/index.js +37 -0
  49. package/dist/index.js.map +1 -0
  50. package/dist/logging.d.ts +70 -0
  51. package/dist/logging.js +24 -0
  52. package/dist/logging.js.map +1 -0
  53. package/dist/parser/natural-language.d.ts +9 -0
  54. package/dist/parser/natural-language.js +406 -0
  55. package/dist/parser/natural-language.js.map +1 -0
  56. package/dist/parser/progression-parser.d.ts +16 -0
  57. package/dist/parser/progression-parser.js +97 -0
  58. package/dist/parser/progression-parser.js.map +1 -0
  59. package/dist/pipeline.d.ts +33 -0
  60. package/dist/pipeline.js +203 -0
  61. package/dist/pipeline.js.map +1 -0
  62. package/dist/progression/form-templates.d.ts +11 -0
  63. package/dist/progression/form-templates.js +105 -0
  64. package/dist/progression/form-templates.js.map +1 -0
  65. package/dist/progression/index.d.ts +5 -0
  66. package/dist/progression/index.js +4 -0
  67. package/dist/progression/index.js.map +1 -0
  68. package/dist/progression/progression-resolver.d.ts +29 -0
  69. package/dist/progression/progression-resolver.js +135 -0
  70. package/dist/progression/progression-resolver.js.map +1 -0
  71. package/dist/progression/roman-numeral.d.ts +14 -0
  72. package/dist/progression/roman-numeral.js +78 -0
  73. package/dist/progression/roman-numeral.js.map +1 -0
  74. package/dist/resolver/auto-layout.d.ts +20 -0
  75. package/dist/resolver/auto-layout.js +195 -0
  76. package/dist/resolver/auto-layout.js.map +1 -0
  77. package/dist/resolver/chord-resolver.d.ts +8 -0
  78. package/dist/resolver/chord-resolver.js +172 -0
  79. package/dist/resolver/chord-resolver.js.map +1 -0
  80. package/dist/resolver/scale-resolver.d.ts +9 -0
  81. package/dist/resolver/scale-resolver.js +45 -0
  82. package/dist/resolver/scale-resolver.js.map +1 -0
  83. package/dist/themes/boomwhacker.d.ts +2 -0
  84. package/dist/themes/boomwhacker.js +35 -0
  85. package/dist/themes/boomwhacker.js.map +1 -0
  86. package/dist/themes/crf.d.ts +19 -0
  87. package/dist/themes/crf.js +34 -0
  88. package/dist/themes/crf.js.map +1 -0
  89. package/dist/themes/index.d.ts +3 -0
  90. package/dist/themes/index.js +25 -0
  91. package/dist/themes/index.js.map +1 -0
  92. package/dist/themes/simple.d.ts +2 -0
  93. package/dist/themes/simple.js +13 -0
  94. package/dist/themes/simple.js.map +1 -0
  95. package/dist/theory/chord-tones.d.ts +56 -0
  96. package/dist/theory/chord-tones.js +215 -0
  97. package/dist/theory/chord-tones.js.map +1 -0
  98. package/dist/theory/degree-labels.d.ts +31 -0
  99. package/dist/theory/degree-labels.js +74 -0
  100. package/dist/theory/degree-labels.js.map +1 -0
  101. package/dist/types.d.ts +123 -0
  102. package/dist/types.js +2 -0
  103. package/dist/types.js.map +1 -0
  104. package/package.json +37 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"note-spelling.js","sourceRoot":"","sources":["../../src/engine/note-spelling.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI;CACjD,CAAC;AAEF,0DAA0D;AAC1D,MAAM,CAAC,MAAM,aAAa,GAA2B;IACnD,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CAC3D,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC;IAC/B,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI;CACxC,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;AACrC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,EAAU,EAAE,GAAW;IACjD,IAAI,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;IACjC,CAAC;IACD,OAAO,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;AACjC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mBAAmB,CACjC,IAAY,EACZ,GAAW,EACX,aAAsB,KAAK;IAE3B,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACrC,CAAC;IACD,OAAO,WAAW,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;AAChC,CAAC;AAED,0EAA0E;AAE1E;;;GAGG;AACH,MAAM,CAAC,MAAM,YAAY,GAA2B;IAClD,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IACpB,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IACpB,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC;IACpB,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IACpB,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC;IACpB,CAAC,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE;IACtB,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;CACvB,CAAC;AAEF,8DAA8D;AAC9D,MAAM,CAAC,MAAM,OAAO,GAAG,EAAE,CAAC;AAE1B;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CACpC,KAAe,EACf,UAAkB,EAClB,UAAkB,CAAC;IAEnB,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAElC,IAAI,MAAM,GAAG,UAAU,CAAC;IACxB,IAAI,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IAE3C,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAChC,MAAM,IAAI,GAAG,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAClC,IAAI,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC9B,MAAM,EAAE,CAAC;QACX,CAAC;QACD,QAAQ,GAAG,IAAI,CAAC;QAChB,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,CAAC,CAAC,CAAC;IAEH,6DAA6D;IAC7D,IAAI,OAAO,GAAG,CAAC,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC;QAC7E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,MAAM,QAAQ,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,EAAE,CAAC;YAC7E,IAAI,QAAQ,GAAG,QAAQ,GAAG,OAAO,IAAI,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;gBACzE,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Scale fingering lookup for piano.
3
+ *
4
+ * Standard fingerings from established piano pedagogy (Hanon, Czerny, ABRSM).
5
+ * Core rule: thumb always crosses to a white key.
6
+ *
7
+ * Each entry is one octave ascending. For multi-octave scales, the pattern
8
+ * repeats with the last finger of one octave becoming the first of the next.
9
+ * The final note of the last octave always uses finger 5 (RH) or 1 (LH).
10
+ */
11
+ export type ScaleHand = "rh" | "lh";
12
+ /**
13
+ * Get scale fingering for a given root and scale type.
14
+ *
15
+ * @param root - Root note (e.g. "C", "Bb", "F#")
16
+ * @param scaleType - Scale type (e.g. "major", "minor", "harmonic minor", "melodic minor", "dorian")
17
+ * @param hand - "rh" (default) or "lh"
18
+ * @param octaves - Number of octaves (default 1)
19
+ * @returns Array of finger numbers, one per note. Empty array if no fingering available.
20
+ */
21
+ export declare function scaleAutoFingering(root: string, scaleType: string, hand?: ScaleHand, octaves?: number): number[];
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Scale fingering lookup for piano.
3
+ *
4
+ * Standard fingerings from established piano pedagogy (Hanon, Czerny, ABRSM).
5
+ * Core rule: thumb always crosses to a white key.
6
+ *
7
+ * Each entry is one octave ascending. For multi-octave scales, the pattern
8
+ * repeats with the last finger of one octave becoming the first of the next.
9
+ * The final note of the last octave always uses finger 5 (RH) or 1 (LH).
10
+ */
11
+ // ── Major scale fingerings ────────────────────────────────────────
12
+ const MAJOR_FINGERINGS = {
13
+ // White-key scales: standard 1-2-3, 1-2-3-4-5
14
+ C: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
15
+ G: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
16
+ D: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
17
+ A: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
18
+ E: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
19
+ B: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [4, 3, 2, 1, 4, 3, 2, 1] },
20
+ // F major: thumb on C after Bb
21
+ F: { rh: [1, 2, 3, 4, 1, 2, 3, 4], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
22
+ // Flat-key scales: thumb avoids black keys
23
+ Bb: { rh: [2, 1, 2, 3, 1, 2, 3, 4], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
24
+ Eb: { rh: [2, 1, 2, 3, 4, 1, 2, 3], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
25
+ Ab: { rh: [2, 3, 1, 2, 3, 1, 2, 3], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
26
+ Db: { rh: [2, 3, 1, 2, 3, 4, 1, 2], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
27
+ Gb: { rh: [2, 3, 4, 1, 2, 3, 1, 2], lh: [4, 3, 2, 1, 3, 2, 1, 4] },
28
+ // Enharmonic equivalents
29
+ "F#": { rh: [2, 3, 4, 1, 2, 3, 1, 2], lh: [4, 3, 2, 1, 3, 2, 1, 4] },
30
+ "C#": { rh: [2, 3, 1, 2, 3, 4, 1, 2], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
31
+ };
32
+ // ── Minor scale fingerings (natural minor) ────────────────────────
33
+ // Harmonic and melodic minor use the same fingerings.
34
+ const MINOR_FINGERINGS = {
35
+ A: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
36
+ E: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
37
+ B: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [4, 3, 2, 1, 4, 3, 2, 1] },
38
+ D: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
39
+ G: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
40
+ C: { rh: [1, 2, 3, 1, 2, 3, 4, 5], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
41
+ F: { rh: [1, 2, 3, 4, 1, 2, 3, 4], lh: [5, 4, 3, 2, 1, 3, 2, 1] },
42
+ "F#": { rh: [2, 3, 1, 2, 3, 1, 2, 3], lh: [4, 3, 2, 1, 3, 2, 1, 4] },
43
+ "C#": { rh: [2, 3, 1, 2, 3, 1, 2, 3], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
44
+ "G#": { rh: [2, 3, 1, 2, 3, 1, 2, 3], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
45
+ Bb: { rh: [2, 1, 2, 3, 1, 2, 3, 4], lh: [2, 1, 3, 2, 1, 4, 3, 2] },
46
+ Eb: { rh: [2, 1, 2, 3, 4, 1, 2, 3], lh: [2, 1, 4, 3, 2, 1, 3, 2] },
47
+ Ab: { rh: [2, 3, 1, 2, 3, 1, 2, 3], lh: [3, 2, 1, 4, 3, 2, 1, 3] },
48
+ };
49
+ // ── Normalize note name ───────────────────────────────────────────
50
+ const FLAT_TO_SHARP = {
51
+ Db: "C#", Eb: "D#", Gb: "F#", Ab: "G#", Bb: "A#",
52
+ };
53
+ function normalizeRoot(root) {
54
+ // Keep the original if it's in the lookup; otherwise try sharp equivalent
55
+ return root;
56
+ }
57
+ // ── Public API ────────────────────────────────────────────────────
58
+ /**
59
+ * Get scale fingering for a given root and scale type.
60
+ *
61
+ * @param root - Root note (e.g. "C", "Bb", "F#")
62
+ * @param scaleType - Scale type (e.g. "major", "minor", "harmonic minor", "melodic minor", "dorian")
63
+ * @param hand - "rh" (default) or "lh"
64
+ * @param octaves - Number of octaves (default 1)
65
+ * @returns Array of finger numbers, one per note. Empty array if no fingering available.
66
+ */
67
+ export function scaleAutoFingering(root, scaleType, hand = "rh", octaves = 1) {
68
+ const type = scaleType.toLowerCase().replace(/\s+/g, " ").trim();
69
+ // Map scale types to fingering tables
70
+ let table;
71
+ if (type === "major" || type === "ionian") {
72
+ table = MAJOR_FINGERINGS;
73
+ }
74
+ else if (type === "minor" || type === "natural minor" ||
75
+ type === "harmonic minor" || type === "minor harmonic" ||
76
+ type === "melodic minor" || type === "minor melodic" ||
77
+ type === "aeolian") {
78
+ table = MINOR_FINGERINGS;
79
+ }
80
+ else if (type === "dorian" || type === "mixolydian" || type === "phrygian" ||
81
+ type === "lydian" || type === "locrian") {
82
+ // Modal scales use the fingering of their parent major/minor key.
83
+ // For simplicity, use the relative major fingering pattern rotated.
84
+ // This is an approximation — use the minor table as a reasonable default.
85
+ table = MINOR_FINGERINGS;
86
+ }
87
+ else {
88
+ // Pentatonic, blues, whole tone, etc. — no standard fingering
89
+ return [];
90
+ }
91
+ // Look up the pattern: try original root, then flat equivalent, then sharp
92
+ let pattern = table[root];
93
+ if (!pattern) {
94
+ const sharp = FLAT_TO_SHARP[root];
95
+ if (sharp)
96
+ pattern = table[sharp];
97
+ }
98
+ if (!pattern) {
99
+ // Try reverse: if root is sharp, check if flat version exists
100
+ for (const [flat, sharp] of Object.entries(FLAT_TO_SHARP)) {
101
+ if (sharp === root) {
102
+ pattern = table[flat];
103
+ break;
104
+ }
105
+ }
106
+ }
107
+ if (!pattern)
108
+ return [];
109
+ const oneOctave = hand === "rh" ? pattern.rh : pattern.lh;
110
+ if (octaves <= 1)
111
+ return oneOctave;
112
+ // Multi-octave: repeat the inner pattern (notes 1-7), then cap with final finger.
113
+ // Pattern is 8 notes: [start...middle...end]. For continuation:
114
+ // - Octave 1: notes 0-6 (drop the 8th — it becomes the 1st of next octave)
115
+ // - Octave 2..N-1: same
116
+ // - Final octave: full 8 notes
117
+ const result = [];
118
+ for (let oct = 0; oct < octaves; oct++) {
119
+ if (oct < octaves - 1) {
120
+ // Not the last octave: use first 7 fingers (skip the tonic repeat)
121
+ result.push(...oneOctave.slice(0, 7));
122
+ }
123
+ else {
124
+ // Last octave: use all 8 fingers
125
+ result.push(...oneOctave);
126
+ }
127
+ }
128
+ return result;
129
+ }
130
+ //# sourceMappingURL=scale-fingering.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scale-fingering.js","sourceRoot":"","sources":["../../src/engine/scale-fingering.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAWH,qEAAqE;AAErE,MAAM,gBAAgB,GAA0C;IAC9D,8CAA8C;IAC9C,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,+BAA+B;IAC/B,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,2CAA2C;IAC3C,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,yBAAyB;IACzB,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACtD,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;CACvD,CAAC;AAEF,qEAAqE;AACrE,sDAAsD;AAEtD,MAAM,gBAAgB,GAA0C;IAC9D,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,CAAC,EAAG,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACtD,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACtD,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACtD,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,CAAC,EAAE;IACpD,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CAAC,EAAC,CA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"}
@@ -0,0 +1,16 @@
1
+ export declare const STAFF_LINE_SPACING = 8;
2
+ export declare const HALF_STAFF_SPACING = 4;
3
+ export declare const STAFF_WIDTH = 120;
4
+ export declare const CLEF_AREA_WIDTH = 30;
5
+ export declare const NOTE_COLUMN_X = 75;
6
+ export declare const NOTE_HEAD_RX = 6.75;
7
+ export declare const ACCIDENTAL_OFFSET = 14;
8
+ export declare const SECOND_OFFSET: number;
9
+ export declare const ACCIDENTAL_COL_WIDTH = 10;
10
+ export declare const LEDGER_LINE_EXTEND = 7;
11
+ export declare const LEDGER_LINE_STROKE = 1;
12
+ export declare const STAFF_GAP = 20;
13
+ export declare const STAFF_TOP_MARGIN = 22;
14
+ export declare const STAFF_BOTTOM_MARGIN = 10;
15
+ export declare const STAFF_LINE_STROKE = 0.8;
16
+ export declare const BRACE_WIDTH = 8;
@@ -0,0 +1,20 @@
1
+ // Staff notation dimensions (SVG pixels)
2
+ export const STAFF_LINE_SPACING = 8;
3
+ export const HALF_STAFF_SPACING = 4; // one diatonic step
4
+ export const STAFF_WIDTH = 120;
5
+ export const CLEF_AREA_WIDTH = 30;
6
+ export const NOTE_COLUMN_X = 75;
7
+ // Half-width of the notehead glyph (used for ledger line extent and second offsets).
8
+ // Bravura wholeNote: 422 font units wide, scaled to STAFF_LINE_SPACING height (250→8px) = 13.5px → rx≈6.75
9
+ export const NOTE_HEAD_RX = 6.75;
10
+ export const ACCIDENTAL_OFFSET = 14;
11
+ export const SECOND_OFFSET = NOTE_HEAD_RX * 2; // horizontal shift for seconds
12
+ export const ACCIDENTAL_COL_WIDTH = 10; // width of one accidental column
13
+ export const LEDGER_LINE_EXTEND = 7;
14
+ export const LEDGER_LINE_STROKE = 1;
15
+ export const STAFF_GAP = 20;
16
+ export const STAFF_TOP_MARGIN = 22;
17
+ export const STAFF_BOTTOM_MARGIN = 10;
18
+ export const STAFF_LINE_STROKE = 0.8;
19
+ export const BRACE_WIDTH = 8;
20
+ //# sourceMappingURL=staff-constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staff-constants.js","sourceRoot":"","sources":["../../src/engine/staff-constants.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,CAAC,oBAAoB;AACzD,MAAM,CAAC,MAAM,WAAW,GAAG,GAAG,CAAC;AAC/B,MAAM,CAAC,MAAM,eAAe,GAAG,EAAE,CAAC;AAClC,MAAM,CAAC,MAAM,aAAa,GAAG,EAAE,CAAC;AAChC,qFAAqF;AACrF,2GAA2G;AAC3G,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,CAAC;AACjC,MAAM,CAAC,MAAM,iBAAiB,GAAG,EAAE,CAAC;AACpC,MAAM,CAAC,MAAM,aAAa,GAAG,YAAY,GAAG,CAAC,CAAC,CAAC,+BAA+B;AAC9E,MAAM,CAAC,MAAM,oBAAoB,GAAG,EAAE,CAAC,CAAC,iCAAiC;AACzE,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC;AACpC,MAAM,CAAC,MAAM,SAAS,GAAG,EAAE,CAAC;AAC5B,MAAM,CAAC,MAAM,gBAAgB,GAAG,EAAE,CAAC;AACnC,MAAM,CAAC,MAAM,mBAAmB,GAAG,EAAE,CAAC;AACtC,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,CAAC;AACrC,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface StaffGlyphSet {
2
+ name: string;
3
+ fontFamily: string;
4
+ glyphs: {
5
+ trebleClef: string;
6
+ bassClef: string;
7
+ sharp: string;
8
+ flat: string;
9
+ natural: string;
10
+ wholeNote: string;
11
+ };
12
+ brace: (height: number) => string;
13
+ }
14
+ export declare const BRAVURA_GLYPHS: StaffGlyphSet;
15
+ export declare const PETALUMA_GLYPHS: StaffGlyphSet;
16
+ export declare function getDefaultGlyphs(): StaffGlyphSet;
17
+ export declare function setDefaultGlyphs(glyphs: StaffGlyphSet): void;
@@ -0,0 +1,59 @@
1
+ // SMuFL (Standard Music Font Layout) glyph sets.
2
+ //
3
+ // Glyphs are addressed by Unicode codepoint and rendered as <text> with the
4
+ // matching font-family. SMuFL fonts are designed so that 1 em = 4 staff
5
+ // spaces, which means setting font-size = 4 * staffLineSpacing makes glyphs
6
+ // render at the correct staff size with no per-glyph scaling.
7
+ //
8
+ // Required @font-face: consumers must load 'Bravura' / 'Petaluma' (or any
9
+ // other SMuFL-compliant font) before rendering. The dev playground loads
10
+ // woff2 files from /fonts/. See dev/index.html.
11
+ const SMUFL = {
12
+ gClef: "",
13
+ fClef: "",
14
+ noteheadWhole: "",
15
+ accidentalSharp: "",
16
+ accidentalFlat: "",
17
+ accidentalNatural: "",
18
+ };
19
+ function synthesizedBrace(curl) {
20
+ return (height) => {
21
+ const mid = height / 2;
22
+ const q = height / 4;
23
+ return `M ${curl} 0 C ${curl - 4} ${q} 0 ${mid - 4} 0 ${mid} C 0 ${mid + 4} ${curl - 4} ${mid + q} ${curl} ${height}`;
24
+ };
25
+ }
26
+ export const BRAVURA_GLYPHS = {
27
+ name: "Bravura",
28
+ fontFamily: "Bravura, serif",
29
+ glyphs: {
30
+ trebleClef: SMUFL.gClef,
31
+ bassClef: SMUFL.fClef,
32
+ sharp: SMUFL.accidentalSharp,
33
+ flat: SMUFL.accidentalFlat,
34
+ natural: SMUFL.accidentalNatural,
35
+ wholeNote: SMUFL.noteheadWhole,
36
+ },
37
+ brace: synthesizedBrace(6),
38
+ };
39
+ export const PETALUMA_GLYPHS = {
40
+ name: "Petaluma",
41
+ fontFamily: "Petaluma, serif",
42
+ glyphs: {
43
+ trebleClef: SMUFL.gClef,
44
+ bassClef: SMUFL.fClef,
45
+ sharp: SMUFL.accidentalSharp,
46
+ flat: SMUFL.accidentalFlat,
47
+ natural: SMUFL.accidentalNatural,
48
+ wholeNote: SMUFL.noteheadWhole,
49
+ },
50
+ brace: synthesizedBrace(6),
51
+ };
52
+ let _defaultGlyphs = BRAVURA_GLYPHS;
53
+ export function getDefaultGlyphs() {
54
+ return _defaultGlyphs;
55
+ }
56
+ export function setDefaultGlyphs(glyphs) {
57
+ _defaultGlyphs = glyphs;
58
+ }
59
+ //# sourceMappingURL=staff-glyphs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staff-glyphs.js","sourceRoot":"","sources":["../../src/engine/staff-glyphs.ts"],"names":[],"mappings":"AAAA,iDAAiD;AACjD,EAAE;AACF,4EAA4E;AAC5E,wEAAwE;AACxE,4EAA4E;AAC5E,8DAA8D;AAC9D,EAAE;AACF,0EAA0E;AAC1E,yEAAyE;AACzE,gDAAgD;AAgBhD,MAAM,KAAK,GAAG;IACZ,KAAK,EAAE,GAAG;IACV,KAAK,EAAE,GAAG;IACV,aAAa,EAAE,GAAG;IAClB,eAAe,EAAE,GAAG;IACpB,cAAc,EAAE,GAAG;IACnB,iBAAiB,EAAE,GAAG;CACd,CAAC;AAEX,SAAS,gBAAgB,CAAC,IAAY;IACpC,OAAO,CAAC,MAAc,EAAE,EAAE;QACxB,MAAM,GAAG,GAAG,MAAM,GAAG,CAAC,CAAC;QACvB,MAAM,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;QACrB,OAAO,KAAK,IAAI,QAAQ,IAAI,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,GAAG,QAAQ,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,IAAI,MAAM,EAAE,CAAC;IACxH,CAAC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,cAAc,GAAkB;IAC3C,IAAI,EAAE,SAAS;IACf,UAAU,EAAE,gBAAgB;IAC5B,MAAM,EAAE;QACN,UAAU,EAAE,KAAK,CAAC,KAAK;QACvB,QAAQ,EAAE,KAAK,CAAC,KAAK;QACrB,KAAK,EAAE,KAAK,CAAC,eAAe;QAC5B,IAAI,EAAE,KAAK,CAAC,cAAc;QAC1B,OAAO,EAAE,KAAK,CAAC,iBAAiB;QAChC,SAAS,EAAE,KAAK,CAAC,aAAa;KAC/B;IACD,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC;CAC3B,CAAC;AAEF,MAAM,CAAC,MAAM,eAAe,GAAkB;IAC5C,IAAI,EAAE,UAAU;IAChB,UAAU,EAAE,iBAAiB;IAC7B,MAAM,EAAE;QACN,UAAU,EAAE,KAAK,CAAC,KAAK;QACvB,QAAQ,EAAE,KAAK,CAAC,KAAK;QACrB,KAAK,EAAE,KAAK,CAAC,eAAe;QAC5B,IAAI,EAAE,KAAK,CAAC,cAAc;QAC1B,OAAO,EAAE,KAAK,CAAC,iBAAiB;QAChC,SAAS,EAAE,KAAK,CAAC,aAAa;KAC/B;IACD,KAAK,EAAE,gBAAgB,CAAC,CAAC,CAAC;CAC3B,CAAC;AAEF,IAAI,cAAc,GAAkB,cAAc,CAAC;AAEnD,MAAM,UAAU,gBAAgB;IAC9B,OAAO,cAAc,CAAC;AACxB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAqB;IACpD,cAAc,GAAG,MAAM,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,28 @@
1
+ export interface StaffNote {
2
+ pitchClass: string;
3
+ octave: number;
4
+ staff: "treble" | "bass";
5
+ y: number;
6
+ noteX: number;
7
+ accidental: "sharp" | "flat" | null;
8
+ accidentalX: number;
9
+ ledgerLines: number[];
10
+ diatonicPos: number;
11
+ }
12
+ export interface StaffLayoutResult {
13
+ notes: StaffNote[];
14
+ staffMode: "treble" | "bass" | "grand";
15
+ totalHeight: number;
16
+ totalWidth: number;
17
+ trebleTopY: number;
18
+ bassTopY: number;
19
+ }
20
+ export interface StaffLayoutOptions {
21
+ lhNotes?: string[];
22
+ rhOctave?: number;
23
+ lhOctave?: number;
24
+ /** Pre-resolved octave-qualified notes (e.g. from keyboard layout).
25
+ * Format: "C:4", "G#:5". Bypasses internal octave assignment. */
26
+ octaveQualifiedNotes?: string[];
27
+ }
28
+ export declare function computeStaffLayout(notes: string[], options?: StaffLayoutOptions): StaffLayoutResult;
@@ -0,0 +1,238 @@
1
+ import { normalizeToSharps } from "./note-spelling";
2
+ import { STAFF_LINE_SPACING, HALF_STAFF_SPACING, STAFF_WIDTH, STAFF_GAP, STAFF_TOP_MARGIN, STAFF_BOTTOM_MARGIN, NOTE_COLUMN_X, ACCIDENTAL_OFFSET, SECOND_OFFSET, ACCIDENTAL_COL_WIDTH, } from "./staff-constants";
3
+ function parseOctaveQualified(notes) {
4
+ return notes.map((n) => {
5
+ const [pc, oct] = n.split(":");
6
+ return { pitchClass: normalizePitchClass(pc), octave: parseInt(oct, 10) };
7
+ });
8
+ }
9
+ const DIATONIC_INDEX = {
10
+ C: 0, D: 1, E: 2, F: 3, G: 4, A: 5, B: 6,
11
+ };
12
+ const TREBLE_BOTTOM_LINE_POS = 30; // E4
13
+ const BASS_BOTTOM_LINE_POS = 18; // G2
14
+ function normalizePitchClass(note) {
15
+ return normalizeToSharps(note);
16
+ }
17
+ function letterFromPitchClass(pc) {
18
+ return pc.replace("#", "").replace("b", "");
19
+ }
20
+ function noteToMidi(pitchClass, octave) {
21
+ const letter = letterFromPitchClass(pitchClass);
22
+ const chromaticBase = {
23
+ C: 0, D: 2, E: 4, F: 5, G: 7, A: 9, B: 11,
24
+ };
25
+ const base = chromaticBase[letter] ?? 0;
26
+ const acc = pitchClass.includes("#") ? 1 : pitchClass.includes("b") ? -1 : 0;
27
+ return (octave + 1) * 12 + base + acc;
28
+ }
29
+ function absoluteDiatonicPos(pitchClass, octave) {
30
+ const letter = letterFromPitchClass(pitchClass);
31
+ return octave * 7 + (DIATONIC_INDEX[letter] ?? 0);
32
+ }
33
+ function computeY(absolutePos, staffBottomLineY, refPos) {
34
+ return staffBottomLineY - (absolutePos - refPos) * HALF_STAFF_SPACING;
35
+ }
36
+ function computeLedgerLines(absolutePos, staffBottomLinePos, staffBottomLineY) {
37
+ const staffTopLinePos = staffBottomLinePos + 8;
38
+ const ledgers = [];
39
+ if (absolutePos < staffBottomLinePos) {
40
+ for (let pos = staffBottomLinePos - 2; pos >= absolutePos; pos -= 2) {
41
+ ledgers.push(computeY(pos, staffBottomLineY, staffBottomLinePos));
42
+ }
43
+ }
44
+ else if (absolutePos > staffTopLinePos) {
45
+ for (let pos = staffTopLinePos + 2; pos <= absolutePos; pos += 2) {
46
+ ledgers.push(computeY(pos, staffBottomLineY, staffBottomLinePos));
47
+ }
48
+ }
49
+ return ledgers;
50
+ }
51
+ function assignOctaves(notes, baseOctave) {
52
+ const result = [];
53
+ let currentOctave = baseOctave;
54
+ let prevDiatonic = -1;
55
+ for (const note of notes) {
56
+ const pc = normalizePitchClass(note);
57
+ const letter = letterFromPitchClass(pc);
58
+ const diatonic = DIATONIC_INDEX[letter] ?? 0;
59
+ if (prevDiatonic >= 0 && diatonic <= prevDiatonic) {
60
+ currentOctave++;
61
+ }
62
+ prevDiatonic = diatonic;
63
+ result.push({ pitchClass: pc, octave: currentOctave });
64
+ }
65
+ return result;
66
+ }
67
+ /**
68
+ * Standard engraving: when two adjacent notes form a second (1 diatonic step),
69
+ * the higher note shifts right so the noteheads sit side-by-side.
70
+ *
71
+ * Process bottom-to-top. When a note is exactly 1 diatonic step above
72
+ * the previous, and the previous was NOT offset, offset this one right.
73
+ * If the previous was already offset, don't offset this one (alternating pattern).
74
+ */
75
+ function resolveNoteheadOffsets(notes) {
76
+ // Sort by diatonic position ascending (lowest first)
77
+ const sorted = [...notes].sort((a, b) => a.diatonicPos - b.diatonicPos);
78
+ const offsetSet = new Set();
79
+ for (let i = 1; i < sorted.length; i++) {
80
+ const gap = sorted[i].diatonicPos - sorted[i - 1].diatonicPos;
81
+ if (gap === 1) {
82
+ // Second interval — the upper note gets offset, unless the lower was already offset
83
+ if (!offsetSet.has(sorted[i - 1])) {
84
+ offsetSet.add(sorted[i]);
85
+ sorted[i].noteX = NOTE_COLUMN_X + SECOND_OFFSET;
86
+ }
87
+ // If lower was offset, upper stays normal (alternating)
88
+ }
89
+ }
90
+ }
91
+ /**
92
+ * Standard engraving accidental placement.
93
+ *
94
+ * Process notes top-to-bottom (highest pitch first). Each accidental
95
+ * tries the closest column to the notehead first (column 0 = just left of note).
96
+ * If that column is occupied by an accidental whose Y is too close (within
97
+ * ~3 staff spaces), try the next column further left.
98
+ *
99
+ * Also: if a note's notehead is offset right (second), its accidental
100
+ * must clear the offset notehead — so it starts from column 0 relative
101
+ * to the LEFT notehead position (normal noteX).
102
+ */
103
+ function resolveAccidentalPositions(notes) {
104
+ const accNotes = notes
105
+ .filter((n) => n.accidental !== null)
106
+ .sort((a, b) => a.y - b.y); // top-to-bottom (lower Y = higher on staff)
107
+ if (accNotes.length === 0)
108
+ return;
109
+ // Track occupied columns: array of { column, y } entries
110
+ const occupied = [];
111
+ // Minimum Y distance before two accidentals can share a column
112
+ const minYGap = STAFF_LINE_SPACING * 2.5;
113
+ for (const note of accNotes) {
114
+ // Base X: just left of the notehead. If any note is offset right,
115
+ // accidentals should clear it by starting further left.
116
+ const hasOffsetNeighbor = notes.some((n) => n.noteX > NOTE_COLUMN_X && Math.abs(n.y - note.y) < STAFF_LINE_SPACING * 2);
117
+ const startCol = hasOffsetNeighbor ? 1 : 0;
118
+ let col = startCol;
119
+ // eslint-disable-next-line no-constant-condition
120
+ while (true) {
121
+ const conflict = occupied.some((o) => o.col === col && Math.abs(o.y - note.y) < minYGap);
122
+ if (!conflict)
123
+ break;
124
+ col++;
125
+ }
126
+ occupied.push({ col, y: note.y });
127
+ note.accidentalX = NOTE_COLUMN_X - ACCIDENTAL_OFFSET - col * ACCIDENTAL_COL_WIDTH;
128
+ }
129
+ }
130
+ export function computeStaffLayout(notes, options = {}) {
131
+ const { lhNotes, rhOctave = 4, lhOctave = 3, octaveQualifiedNotes } = options;
132
+ let allWithOctaves;
133
+ let lhNotesList;
134
+ if (octaveQualifiedNotes) {
135
+ // Use pre-resolved octaves — bypass internal assignment
136
+ allWithOctaves = parseOctaveQualified(octaveQualifiedNotes);
137
+ lhNotesList = lhNotes ?? [];
138
+ }
139
+ else {
140
+ const rhNotesList = lhNotes
141
+ ? notes.filter((n) => !lhNotes.includes(n))
142
+ : notes;
143
+ lhNotesList = lhNotes ?? [];
144
+ const rhWithOctaves = assignOctaves(rhNotesList, rhOctave);
145
+ const lhWithOctaves = assignOctaves(lhNotesList, lhOctave);
146
+ allWithOctaves = [...lhWithOctaves, ...rhWithOctaves];
147
+ }
148
+ // Determine clef based on where the majority of notes sit.
149
+ // A3 = MIDI 57, C4 = MIDI 60.
150
+ // If explicitly split (LH/RH), use grand staff.
151
+ // Otherwise, use predominance: count notes above vs at-or-below the midpoint.
152
+ const hasExplicitSplit = lhNotes && lhNotes.length > 0;
153
+ const midpoint = 57; // A3 — notes above here lean treble, at/below lean bass
154
+ const trebleCount = allWithOctaves.filter((n) => noteToMidi(n.pitchClass, n.octave) > midpoint).length;
155
+ const bassCount = allWithOctaves.filter((n) => noteToMidi(n.pitchClass, n.octave) <= midpoint).length;
156
+ let staffMode;
157
+ if (hasExplicitSplit) {
158
+ // Explicit LH/RH split → grand staff
159
+ staffMode = "grand";
160
+ }
161
+ else if (trebleCount > 0 && bassCount > 0) {
162
+ // Notes span both ranges — use predominance
163
+ staffMode = trebleCount >= bassCount ? "treble" : "bass";
164
+ }
165
+ else if (trebleCount > 0) {
166
+ staffMode = "treble";
167
+ }
168
+ else {
169
+ staffMode = "bass";
170
+ }
171
+ const trebleBottomLineY = STAFF_TOP_MARGIN + STAFF_LINE_SPACING * 4;
172
+ const bassTopLineY = staffMode === "grand"
173
+ ? trebleBottomLineY + STAFF_GAP
174
+ : staffMode === "bass"
175
+ ? STAFF_TOP_MARGIN
176
+ : -1;
177
+ const bassBottomLineY = bassTopLineY >= 0 ? bassTopLineY + STAFF_LINE_SPACING * 4 : -1;
178
+ const trebleTopY = staffMode !== "bass" ? STAFF_TOP_MARGIN : -1;
179
+ const bassTopY = bassTopLineY;
180
+ const staffNotes = allWithOctaves.map((n) => {
181
+ const midi = noteToMidi(n.pitchClass, n.octave);
182
+ const isLH = lhNotes
183
+ ? lhNotesList.some((lh) => normalizePitchClass(lh) === n.pitchClass)
184
+ : midi < 60;
185
+ let staff;
186
+ let bottomLineY;
187
+ let bottomLinePos;
188
+ if (isLH && staffMode !== "treble") {
189
+ staff = "bass";
190
+ bottomLineY = bassBottomLineY;
191
+ bottomLinePos = BASS_BOTTOM_LINE_POS;
192
+ }
193
+ else {
194
+ staff = "treble";
195
+ bottomLineY = trebleBottomLineY;
196
+ bottomLinePos = TREBLE_BOTTOM_LINE_POS;
197
+ }
198
+ const diatonicPos = absoluteDiatonicPos(n.pitchClass, n.octave);
199
+ const y = computeY(diatonicPos, bottomLineY, bottomLinePos);
200
+ const ledgerLines = computeLedgerLines(diatonicPos, bottomLinePos, bottomLineY);
201
+ const accidental = n.pitchClass.includes("#")
202
+ ? "sharp"
203
+ : n.pitchClass.includes("b")
204
+ ? "flat"
205
+ : null;
206
+ return {
207
+ pitchClass: n.pitchClass,
208
+ octave: n.octave,
209
+ staff,
210
+ y,
211
+ noteX: NOTE_COLUMN_X,
212
+ accidental,
213
+ accidentalX: NOTE_COLUMN_X - ACCIDENTAL_OFFSET,
214
+ ledgerLines,
215
+ diatonicPos,
216
+ };
217
+ });
218
+ // Resolve notehead offsets for seconds
219
+ resolveNoteheadOffsets(staffNotes);
220
+ // Resolve accidental column positions
221
+ resolveAccidentalPositions(staffNotes);
222
+ // Total height
223
+ const lastLineY = staffMode === "bass" || staffMode === "grand"
224
+ ? bassBottomLineY
225
+ : trebleBottomLineY;
226
+ const maxNoteY = Math.max(lastLineY, ...staffNotes.map((n) => n.y));
227
+ const maxLedgerY = Math.max(lastLineY, ...staffNotes.flatMap((n) => n.ledgerLines));
228
+ const totalHeight = Math.max(maxNoteY, maxLedgerY) + STAFF_BOTTOM_MARGIN + HALF_STAFF_SPACING;
229
+ return {
230
+ notes: staffNotes,
231
+ staffMode,
232
+ totalHeight,
233
+ totalWidth: STAFF_WIDTH,
234
+ trebleTopY,
235
+ bassTopY,
236
+ };
237
+ }
238
+ //# sourceMappingURL=staff-layout.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"staff-layout.js","sourceRoot":"","sources":["../../src/engine/staff-layout.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ export declare const WHITE_KEY_WIDTH = 23;
2
+ export declare const WHITE_KEY_WIDTH_EXACT = 25.3;
3
+ export declare const WHITE_KEY_HEIGHT_COMPACT = 65;
4
+ export declare const WHITE_KEY_HEIGHT_EXACT = 120;
5
+ export declare const WHITE_KEY_RY = 3;
6
+ export declare const BLACK_KEY_WIDTH = 13;
7
+ export declare const BLACK_KEY_WIDTH_EXACT = 14.3;
8
+ export declare const BLACK_KEY_HEIGHT_COMPACT = 40;
9
+ export declare const BLACK_KEY_HEIGHT_EXACT = 80;
10
+ export declare const BLACK_KEY_RY = 1;
11
+ export declare const DEFAULT_WHITE_FILL = "#fafafa";
12
+ export declare const DEFAULT_BLACK_FILL = "#222222";
13
+ export declare const DEFAULT_STROKE = "#333333";
14
+ export declare const DEFAULT_STROKE_WIDTH = 1;
15
+ export declare const BLACK_KEY_OFFSETS: Record<string, number>;
16
+ export declare const BLACK_KEY_OFFSETS_EXACT: Record<string, number>;
17
+ export declare const WHITE_NOTES_WITH_SHARPS: Set<string>;
18
+ export declare const FLAT_TO_SHARP: Record<string, string>;
19
+ export declare const WHITE_NOTE_ORDER: readonly ["C", "D", "E", "F", "G", "A", "B"];
@@ -0,0 +1,40 @@
1
+ export const WHITE_KEY_WIDTH = 23;
2
+ export const WHITE_KEY_WIDTH_EXACT = 25.3;
3
+ export const WHITE_KEY_HEIGHT_COMPACT = 65;
4
+ export const WHITE_KEY_HEIGHT_EXACT = 120;
5
+ export const WHITE_KEY_RY = 3;
6
+ export const BLACK_KEY_WIDTH = 13;
7
+ export const BLACK_KEY_WIDTH_EXACT = 14.3;
8
+ export const BLACK_KEY_HEIGHT_COMPACT = 40;
9
+ export const BLACK_KEY_HEIGHT_EXACT = 80;
10
+ export const BLACK_KEY_RY = 1;
11
+ export const DEFAULT_WHITE_FILL = "#fafafa";
12
+ export const DEFAULT_BLACK_FILL = "#222222";
13
+ export const DEFAULT_STROKE = "#333333";
14
+ export const DEFAULT_STROKE_WIDTH = 1;
15
+ // Black key x-offsets relative to the left edge of the parent white key
16
+ export const BLACK_KEY_OFFSETS = {
17
+ C: 14.33,
18
+ D: 18.67,
19
+ F: 13.25,
20
+ G: 16.25,
21
+ A: 19.75,
22
+ };
23
+ export const BLACK_KEY_OFFSETS_EXACT = {
24
+ C: 15.76,
25
+ D: 20.54,
26
+ F: 14.58,
27
+ G: 17.88,
28
+ A: 21.73,
29
+ };
30
+ // Which white notes have a black key to their right
31
+ export const WHITE_NOTES_WITH_SHARPS = new Set(["C", "D", "F", "G", "A"]);
32
+ export const FLAT_TO_SHARP = {
33
+ Db: "C#",
34
+ Eb: "D#",
35
+ Gb: "F#",
36
+ Ab: "G#",
37
+ Bb: "A#",
38
+ };
39
+ export const WHITE_NOTE_ORDER = ["C", "D", "E", "F", "G", "A", "B"];
40
+ //# sourceMappingURL=svg-constants.js.map