@real-music-packages/web-core 0.42.2 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/scene/index.d.ts +23 -5
- package/dist/scene/index.js +47 -8
- package/dist/scene/index.js.map +1 -1
- package/package.json +1 -1
package/dist/scene/index.d.ts
CHANGED
|
@@ -891,10 +891,23 @@ declare const portraitFactory: LayerFactory<PortraitProps>;
|
|
|
891
891
|
interface BrandingProps {
|
|
892
892
|
/** Wordmark to draw. Default theme.brand. */
|
|
893
893
|
logo?: string;
|
|
894
|
+
/** Optional second line under the wordmark (e.g. a domain) — the brand-card
|
|
895
|
+
* form used for an end-of-clip mark: wordmark + URL, nothing else. Omit
|
|
896
|
+
* for the original single-line chrome mark. */
|
|
897
|
+
sub?: string;
|
|
898
|
+
/** Sub-line font size in px. Default size*0.5. */
|
|
899
|
+
subSize?: number;
|
|
900
|
+
/** Sub-line colour. Default color/theme.sepia at reduced alpha handled by
|
|
901
|
+
* the caller's theme choice (no alpha applied here so callers stay in
|
|
902
|
+
* control of exact tone). */
|
|
903
|
+
subColor?: string;
|
|
904
|
+
/** Gap between wordmark baseline and sub-line baseline, px. Default size*0.85. */
|
|
905
|
+
gap?: number;
|
|
894
906
|
/** Show the safe-zone debug overlay on top (apps' ?safe=1). Default false. */
|
|
895
907
|
safezone?: boolean;
|
|
896
908
|
/** Vertical anchor as a fraction of safeBox height from its TOP. Default 1
|
|
897
|
-
* (bottom edge of the safe box).
|
|
909
|
+
* (bottom edge of the safe box). With `sub` set, this anchors the WORDMARK
|
|
910
|
+
* line and the sub-line is drawn `gap` px below it. */
|
|
898
911
|
yFrac?: number;
|
|
899
912
|
/** Font size in px. Default 34. */
|
|
900
913
|
size?: number;
|
|
@@ -1731,10 +1744,15 @@ interface CompositeRhythmProps {
|
|
|
1731
1744
|
tickH?: number;
|
|
1732
1745
|
/** Merged-mark radius (world px). Default 12. */
|
|
1733
1746
|
mergeR?: number;
|
|
1734
|
-
/** Reference subdivision
|
|
1735
|
-
*
|
|
1736
|
-
*
|
|
1737
|
-
|
|
1747
|
+
/** Reference subdivision rows, drawn as faint rows ABOVE the LH row. Two
|
|
1748
|
+
* forms per entry: a plain number N divides `windowMs` into N EQUAL ticks
|
|
1749
|
+
* (e.g. `3` for a triplet feel, `2` for straight eighths — a 3-against-2
|
|
1750
|
+
* bar is `grids: [3, 2]`); an array of positive weights draws ticks at
|
|
1751
|
+
* each GROUP's start per those relative durations (e.g. `[3, 3, 2]` for a
|
|
1752
|
+
* 3-3-2 clave bar — ticks at fractions 0, 3/8, 6/8, labeled "3+3+2") — for
|
|
1753
|
+
* asymmetric groupings the rhythm montage needs that an equal-N grid can't
|
|
1754
|
+
* represent. Default none. */
|
|
1755
|
+
grids?: Array<number | number[]>;
|
|
1738
1756
|
/** Onsets within this many ms of each other collapse into ONE composite
|
|
1739
1757
|
* mark. Default 60. */
|
|
1740
1758
|
mergeWindowMs?: number;
|
package/dist/scene/index.js
CHANGED
|
@@ -1245,6 +1245,10 @@ var spectrumFactory = {
|
|
|
1245
1245
|
// src/scene/layers/branding.ts
|
|
1246
1246
|
function brandingLayer() {
|
|
1247
1247
|
let logo;
|
|
1248
|
+
let sub;
|
|
1249
|
+
let subSize = 0;
|
|
1250
|
+
let subColor;
|
|
1251
|
+
let gap = 0;
|
|
1248
1252
|
let safezone = false;
|
|
1249
1253
|
let yFrac = 1;
|
|
1250
1254
|
let size = 34;
|
|
@@ -1253,10 +1257,14 @@ function brandingLayer() {
|
|
|
1253
1257
|
key: "branding",
|
|
1254
1258
|
init(_ctx, props) {
|
|
1255
1259
|
logo = props.logo;
|
|
1260
|
+
sub = props.sub;
|
|
1256
1261
|
safezone = props.safezone ?? false;
|
|
1257
1262
|
yFrac = props.yFrac ?? 1;
|
|
1258
1263
|
size = props.size ?? 34;
|
|
1264
|
+
subSize = props.subSize ?? size * 0.5;
|
|
1265
|
+
gap = props.gap ?? size * 0.85;
|
|
1259
1266
|
color = props.color;
|
|
1267
|
+
subColor = props.subColor;
|
|
1260
1268
|
},
|
|
1261
1269
|
draw(ctx) {
|
|
1262
1270
|
const c = ctx.ctx2d;
|
|
@@ -1266,8 +1274,14 @@ function brandingLayer() {
|
|
|
1266
1274
|
c.textAlign = "center";
|
|
1267
1275
|
c.font = `italic ${size}px ${ctx.theme.fontBody}`;
|
|
1268
1276
|
c.fillStyle = color ?? ctx.theme.sepia;
|
|
1269
|
-
const
|
|
1277
|
+
const pairShift = sub ? gap / 2 : 0;
|
|
1278
|
+
const y = sb.top + sb.h * yFrac - (yFrac >= 1 ? size * 0.3 : 0) - pairShift;
|
|
1270
1279
|
c.fillText(text, sb.cx, y);
|
|
1280
|
+
if (sub) {
|
|
1281
|
+
c.font = `${subSize}px ${ctx.theme.fontBody}`;
|
|
1282
|
+
c.fillStyle = subColor ?? color ?? ctx.theme.sepia;
|
|
1283
|
+
c.fillText(sub, sb.cx, y + gap);
|
|
1284
|
+
}
|
|
1271
1285
|
c.restore();
|
|
1272
1286
|
if (safezone) drawSafeGuides(c);
|
|
1273
1287
|
}
|
|
@@ -1281,6 +1295,10 @@ var brandingFactory = {
|
|
|
1281
1295
|
const p = props;
|
|
1282
1296
|
const errs = [];
|
|
1283
1297
|
if (p.logo != null && typeof p.logo !== "string") errs.push("branding.logo must be a string");
|
|
1298
|
+
if (p.sub != null && typeof p.sub !== "string") errs.push("branding.sub must be a string");
|
|
1299
|
+
if (p.subSize != null && (typeof p.subSize !== "number" || p.subSize <= 0)) errs.push("branding.subSize must be a positive number");
|
|
1300
|
+
if (p.subColor != null && typeof p.subColor !== "string") errs.push("branding.subColor must be a string");
|
|
1301
|
+
if (p.gap != null && typeof p.gap !== "number") errs.push("branding.gap must be a number");
|
|
1284
1302
|
if (p.safezone != null && typeof p.safezone !== "boolean") errs.push("branding.safezone must be a boolean");
|
|
1285
1303
|
if (p.yFrac != null && typeof p.yFrac !== "number") errs.push("branding.yFrac must be a number");
|
|
1286
1304
|
if (p.size != null && (typeof p.size !== "number" || p.size <= 0)) errs.push("branding.size must be a positive number");
|
|
@@ -4416,8 +4434,11 @@ function compositeRhythmLayer() {
|
|
|
4416
4434
|
const lhY = yCenter - rowGap;
|
|
4417
4435
|
const rhY = yCenter + rowGap;
|
|
4418
4436
|
c.save();
|
|
4419
|
-
grids.forEach((
|
|
4420
|
-
|
|
4437
|
+
grids.forEach((entry, gi) => {
|
|
4438
|
+
const isGrouping = Array.isArray(entry);
|
|
4439
|
+
const weights = isGrouping ? entry.filter((w) => w > 0) : [];
|
|
4440
|
+
if (isGrouping && weights.length === 0) return;
|
|
4441
|
+
if (!isGrouping && entry <= 0) return;
|
|
4421
4442
|
const gy = lhY - rowGap * (grids.length - gi);
|
|
4422
4443
|
c.strokeStyle = "rgba(26,22,20,0.22)";
|
|
4423
4444
|
c.lineWidth = 2;
|
|
@@ -4425,8 +4446,20 @@ function compositeRhythmLayer() {
|
|
|
4425
4446
|
c.moveTo(sb.left, gy);
|
|
4426
4447
|
c.lineTo(sb.left + sb.w, gy);
|
|
4427
4448
|
c.stroke();
|
|
4428
|
-
|
|
4429
|
-
|
|
4449
|
+
const starts = [];
|
|
4450
|
+
if (isGrouping) {
|
|
4451
|
+
const total = weights.reduce((a, b) => a + b, 0);
|
|
4452
|
+
let acc = 0;
|
|
4453
|
+
for (const w of weights) {
|
|
4454
|
+
starts.push(acc / total);
|
|
4455
|
+
acc += w;
|
|
4456
|
+
}
|
|
4457
|
+
} else {
|
|
4458
|
+
const n = entry;
|
|
4459
|
+
for (let i = 0; i < n; i++) starts.push(i / n);
|
|
4460
|
+
}
|
|
4461
|
+
for (const f of starts) {
|
|
4462
|
+
const t = w0 + (w1 - w0) * f;
|
|
4430
4463
|
if (!revealed(t)) continue;
|
|
4431
4464
|
const gx = x(t);
|
|
4432
4465
|
c.strokeStyle = "rgba(26,22,20,0.38)";
|
|
@@ -4440,7 +4473,7 @@ function compositeRhythmLayer() {
|
|
|
4440
4473
|
c.font = "600 22px system-ui, sans-serif";
|
|
4441
4474
|
c.textAlign = "right";
|
|
4442
4475
|
c.textBaseline = "middle";
|
|
4443
|
-
c.fillText(String(
|
|
4476
|
+
c.fillText(isGrouping ? weights.join("+") : String(entry), sb.left - 10, gy);
|
|
4444
4477
|
});
|
|
4445
4478
|
const drawTicks = (ticks, y, color) => {
|
|
4446
4479
|
c.fillStyle = color;
|
|
@@ -4532,8 +4565,14 @@ var compositeRhythmFactory = {
|
|
|
4532
4565
|
if (p.rowGap != null && (typeof p.rowGap !== "number" || p.rowGap <= 0)) errs.push("composite-rhythm.rowGap must be a positive number");
|
|
4533
4566
|
if (p.tickH != null && (typeof p.tickH !== "number" || p.tickH <= 0)) errs.push("composite-rhythm.tickH must be a positive number");
|
|
4534
4567
|
if (p.mergeR != null && (typeof p.mergeR !== "number" || p.mergeR <= 0)) errs.push("composite-rhythm.mergeR must be a positive number");
|
|
4535
|
-
if (p.grids != null
|
|
4536
|
-
|
|
4568
|
+
if (p.grids != null) {
|
|
4569
|
+
const gridsValid = Array.isArray(p.grids) && p.grids.every((v) => {
|
|
4570
|
+
if (typeof v === "number") return v > 0;
|
|
4571
|
+
if (Array.isArray(v)) return v.length > 0 && v.every((w) => typeof w === "number" && w > 0);
|
|
4572
|
+
return false;
|
|
4573
|
+
});
|
|
4574
|
+
if (!gridsValid) errs.push("composite-rhythm.grids must be an array of positive numbers or arrays of positive-number weights");
|
|
4575
|
+
}
|
|
4537
4576
|
if (p.mergeWindowMs != null && (typeof p.mergeWindowMs !== "number" || p.mergeWindowMs < 0))
|
|
4538
4577
|
errs.push("composite-rhythm.mergeWindowMs must be a non-negative number");
|
|
4539
4578
|
if (p.mergeColor != null && typeof p.mergeColor !== "string") errs.push("composite-rhythm.mergeColor must be a string");
|