hyperframes 0.7.21 → 0.7.22

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.
@@ -473,11 +473,37 @@
473
473
  return a.contains(b) || b.contains(a);
474
474
  }
475
475
 
476
+ function isInFlow(element) {
477
+ const position = getComputedStyle(element).position;
478
+ return position === "static" || position === "relative" || position === "sticky";
479
+ }
480
+
481
+ function nearestFlexGridAncestor(element) {
482
+ for (let parent = element.parentElement; parent; parent = parent.parentElement) {
483
+ const display = getComputedStyle(parent).display;
484
+ if (display.includes("flex") || display.includes("grid")) return parent;
485
+ }
486
+ return null;
487
+ }
488
+
489
+ // Two in-flow text blocks governed by the same flex/grid container are placed
490
+ // by the layout engine, which reserves space for each — they cannot visually
491
+ // collide. Any measured text-rect overlap between them is line-box / leading
492
+ // slop (tight stacks, number lockups, super/subscript units), not a collision.
493
+ // A real overlap bug needs free positioning (absolute/fixed), which keeps a
494
+ // different formatting context and is still flagged.
495
+ function isManagedFlowOverlap(a, b) {
496
+ if (!isInFlow(a) || !isInFlow(b)) return false;
497
+ const container = nearestFlexGridAncestor(a);
498
+ return !!container && container === nearestFlexGridAncestor(b);
499
+ }
500
+
476
501
  // Two solid text blocks whose boxes overlap by more than a fifth of the
477
502
  // smaller block read as a collision — unreadable, and invisible to the
478
503
  // overflow checks, which only compare an element against its container.
479
504
  function overlapIssue(a, b, time) {
480
505
  if (isNested(a.element, b.element)) return null;
506
+ if (isManagedFlowOverlap(a.element, b.element)) return null;
481
507
  const area = intersectionArea(a.rect, b.rect);
482
508
  if (area <= Math.min(rectArea(a.rect), rectArea(b.rect)) * 0.2) return null;
483
509
  return {
@@ -537,13 +563,30 @@
537
563
  return !!hit && hit !== element && !element.contains(hit) && !hit.contains(element);
538
564
  }
539
565
 
566
+ // During a scene-to-scene crossfade the incoming scene paints over the
567
+ // outgoing scene's still-visible text at >= 0.6 opacity — and `--at-transitions`
568
+ // samples exactly that midpoint. That overlap is the transition doing its job,
569
+ // not an occlusion bug. Detect it: the occluder lives in a DIFFERENT composition
570
+ // mount ([data-composition-id]) than the text, and at least one of the two scenes
571
+ // is mid-fade (effective opacity < 1). Two fully-settled scenes overlapping
572
+ // (both opacity 1) is NOT suppressed — that is a real layering bug.
573
+ function isCrossSceneTransitionOverlap(textEl, occluder) {
574
+ const textScene = textEl.closest("[data-composition-id]");
575
+ const occluderScene = occluder.closest("[data-composition-id]");
576
+ if (!textScene || !occluderScene || textScene === occluderScene) return false;
577
+ return Math.min(opacityChain(textScene), opacityChain(occluderScene)) < 0.999;
578
+ }
579
+
540
580
  // The opaque element painted over (x, y), or null when the topmost element
541
- // there is related to the text or non-opaque.
581
+ // there is related to the text, non-opaque, or a transient crossfade overlap.
582
+ // fallow-ignore-next-line complexity
542
583
  function occluderAt(element, x, y) {
543
584
  if (typeof document.elementFromPoint !== "function") return null;
544
585
  const hit = document.elementFromPoint(x, y);
545
586
  if (!isForeignElement(element, hit)) return null;
546
- return isOpaqueOccluder(hit) ? hit : null;
587
+ if (!isOpaqueOccluder(hit)) return null;
588
+ if (isCrossSceneTransitionOverlap(element, hit)) return null;
589
+ return hit;
547
590
  }
548
591
 
549
592
  // Sweep a grid across the text box (three rows, not just the mid-line, so
@@ -151,6 +151,8 @@ npx hyperframes feedback --rating 3 --comment "bg <video> renders grey in multi-
151
151
 
152
152
  `--rating` is 1-5 (required); `--comment` is free text — use it for any bug, workaround, missing feature, or confusing behaviour, plus the composition pattern that triggered it and what you tried. Feedback is anonymous and attaches a `doctorSummary` (OS/Node/CPU/mem/ffmpeg) automatically. No-ops when telemetry is disabled.
153
153
 
154
+ Hit a reproducible bug? Add `--file-issue` (optionally `--dir <project>` and `--yes` for non-interactive shells) to also publish a minimal repro to a public URL and open a pre-filled GitHub `bug` issue draft for a maintainer to file. This publishes the project publicly, so it is opt-in and consent-gated; the issue is never auto-submitted.
155
+
154
156
  ## publish
155
157
 
156
158
  ```bash