screengraft 0.54.0 → 0.54.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/package.json +1 -1
- package/ui/index.html +43 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "screengraft",
|
|
3
|
-
"version": "0.54.
|
|
3
|
+
"version": "0.54.2",
|
|
4
4
|
"description": "Put a UI screenshot or screen recording onto a photographed device screen with the perspective exactly right \u2014 a homography you confirm by hand, not a generative guess.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mockup",
|
package/ui/index.html
CHANGED
|
@@ -584,14 +584,16 @@
|
|
|
584
584
|
button.switch:hover{background:none}
|
|
585
585
|
button.switch:active{background:none;border:none;box-shadow:none;transform:none}
|
|
586
586
|
|
|
587
|
-
|
|
587
|
+
/* Track 48×20 inside a 48×28 hit area (Figma 17:61): the button keeps the
|
|
588
|
+
full 28px for the pointer, the drawn track is 20px. Was 22px. */
|
|
589
|
+
.sw-track{position:relative;display:block;width:48px;height:20px;border-radius:6px;
|
|
588
590
|
background:var(--bg);border:1px solid var(--edge);
|
|
589
591
|
transition:var(--t-all), box-shadow var(--t)}
|
|
590
592
|
.sw-handle{position:absolute;top:1px;bottom:1px;left:1px;width:24px;border-radius:4px;
|
|
591
593
|
background:var(--raise-hi);
|
|
592
594
|
transition:left var(--t), right var(--t), width var(--t), background-color var(--t), opacity var(--t)}
|
|
593
595
|
.sw-grip{position:absolute;border-radius:1px;background:var(--sunk);
|
|
594
|
-
left:11px;width:4px;top:
|
|
596
|
+
left:11px;width:4px;top:7px;bottom:7px;
|
|
595
597
|
transition:left var(--t), width var(--t), top var(--t), bottom var(--t), background-color var(--t)}
|
|
596
598
|
|
|
597
599
|
/* --- OFF ------------------------------------------------------------- */
|
|
@@ -602,7 +604,7 @@
|
|
|
602
604
|
/* --- ON -------------------------------------------------------------- */
|
|
603
605
|
button.switch[aria-checked="true"] .sw-track{background:var(--acc-btn-rest);border-color:var(--acc-stroke)}
|
|
604
606
|
button.switch[aria-checked="true"] .sw-handle{left:auto;right:1px;background:var(--acc-ink)}
|
|
605
|
-
button.switch[aria-checked="true"] .sw-grip{left:32px;width:2px;top:
|
|
607
|
+
button.switch[aria-checked="true"] .sw-grip{left:32px;width:2px;top:4px;bottom:4px;
|
|
606
608
|
background:var(--acc-btn-rest)}
|
|
607
609
|
button.switch[aria-checked="true"]:hover .sw-track{background:var(--acc);border-color:var(--acc-stroke)}
|
|
608
610
|
button.switch[aria-checked="true"]:hover .sw-grip{background:var(--acc)}
|
|
@@ -2653,6 +2655,10 @@ $('#dofMeasure').onclick = measureDof;
|
|
|
2653
2655
|
const gz = $('#dofGizmo');
|
|
2654
2656
|
const SIGMA_FULL_FRAC = 0.02; // mirrors dof.DOF_MAX_FRAC -- keep in step
|
|
2655
2657
|
let dofEnd = parseFloat(recall('dofEnd','1')); if (!(dofEnd > 0)) dofEnd = 1;
|
|
2658
|
+
// Where along the lines the handles sit (0..1 across the screen's extent).
|
|
2659
|
+
// Page-only: it changes nothing in the render. Turning re-derives it so the
|
|
2660
|
+
// handle stays on the point you turned about instead of sliding along the line.
|
|
2661
|
+
let dofK = 0.5;
|
|
2656
2662
|
// The near limit. null = one-sided (the plane of focus at the screen's edge).
|
|
2657
2663
|
let dofEnd2 = recall('dofEnd2','') === '' ? null : parseFloat(recall('dofEnd2','')); if (dofEnd2 !== null && !(dofEnd2 < 1)) dofEnd2 = null;
|
|
2658
2664
|
function dofEndV(){ return dofOn ? dofEnd : 1; }
|
|
@@ -2693,10 +2699,10 @@ function paintGizmo(){
|
|
|
2693
2699
|
const k = W / Math.max(im.clientWidth, 1); // photo px per screen px
|
|
2694
2700
|
const g = gizmoGeom(); if (!g.H || !g.Hi) return;
|
|
2695
2701
|
const P = (f, q) => applyH(g.H, gzPt(g, f, q));
|
|
2696
|
-
const a0 = P(dofStart, -0.06), a1 = P(dofStart, 1.06), ac = P(dofStart,
|
|
2697
|
-
const b0 = P(dofEnd, -0.06), b1 = P(dofEnd, 1.06), bc = P(dofEnd,
|
|
2702
|
+
const a0 = P(dofStart, -0.06), a1 = P(dofStart, 1.06), ac = P(dofStart, dofK);
|
|
2703
|
+
const b0 = P(dofEnd, -0.06), b1 = P(dofEnd, 1.06), bc = P(dofEnd, dofK);
|
|
2698
2704
|
const two = dofEnd2 !== null;
|
|
2699
|
-
const c0 = two ? P(dofEnd2, -0.06) : null, c1 = two ? P(dofEnd2, 1.06) : null, cc = two ? P(dofEnd2,
|
|
2705
|
+
const c0 = two ? P(dofEnd2, -0.06) : null, c1 = two ? P(dofEnd2, 1.06) : null, cc = two ? P(dofEnd2, dofK) : null;
|
|
2700
2706
|
const th = P(dofEnd, 0.08 + 0.84 * dofStr); // the strength thumb slides along the dashed line
|
|
2701
2707
|
const sigma = dofStr * SIGMA_FULL_FRAC * g.side;
|
|
2702
2708
|
const r = 6 * k, rp = 4 * k, fs11 = 11 * k, off = 14 * k;
|
|
@@ -2731,7 +2737,19 @@ let gzDrag = null;
|
|
|
2731
2737
|
gz.addEventListener('pointerdown', e => {
|
|
2732
2738
|
const h = e.target.dataset && e.target.dataset.h; if (!h) return;
|
|
2733
2739
|
e.preventDefault(); gz.setPointerCapture(e.pointerId);
|
|
2734
|
-
gzDrag = {h};
|
|
2740
|
+
gzDrag = {h};
|
|
2741
|
+
if (h === 'rotA' || h === 'rotB'){
|
|
2742
|
+
// Turning keeps the SHARP line's centre where it is on the screen and the
|
|
2743
|
+
// limits at their distances from it, in screenshot pixels. The stored
|
|
2744
|
+
// numbers are fractions of the screen's extent along the direction, and
|
|
2745
|
+
// that extent changes with the angle -- so turning on the fractions alone
|
|
2746
|
+
// slid every line as it turned (reported 13 Sep 2026).
|
|
2747
|
+
const g = gizmoGeom();
|
|
2748
|
+
gzDrag.pivot = gzPt(g, dofStart, dofK);
|
|
2749
|
+
gzDrag.dFar = (dofEnd - dofStart) * (g.hi - g.lo);
|
|
2750
|
+
gzDrag.dNear = dofEnd2 === null ? null : (dofStart - dofEnd2) * (g.hi - g.lo);
|
|
2751
|
+
}
|
|
2752
|
+
gz.classList.add('drag');
|
|
2735
2753
|
});
|
|
2736
2754
|
gz.addEventListener('pointermove', e => {
|
|
2737
2755
|
if (!gzDrag) return;
|
|
@@ -2750,11 +2768,26 @@ gz.addEventListener('pointermove', e => {
|
|
|
2750
2768
|
} else {
|
|
2751
2769
|
// Turn about the SHARP line's centre -- the plane of focus is what turns;
|
|
2752
2770
|
// the pip under the pointer follows.
|
|
2753
|
-
const c =
|
|
2771
|
+
const c = gzDrag.pivot;
|
|
2754
2772
|
const v = [p[0]-c[0], p[1]-c[1]];
|
|
2755
2773
|
const sign = gzDrag.h === 'rotB' ? 1 : -1; // rotB sits at +u, rotA at -u
|
|
2756
|
-
|
|
2757
|
-
if (e.shiftKey)
|
|
2774
|
+
let ang = ((Math.atan2(v[1]*sign, v[0]*sign) * 180 / Math.PI - 90) % 360 + 360) % 360;
|
|
2775
|
+
if (e.shiftKey) ang = Math.round(ang / 15) * 15;
|
|
2776
|
+
else {
|
|
2777
|
+
// Magnetic to the screen's own axes: within 4° of 0/90/180/270 the lines
|
|
2778
|
+
// run exactly along the screen's edges, which is what "along the phone"
|
|
2779
|
+
// means in the photograph once the perspective is applied.
|
|
2780
|
+
const near = Math.round(ang / 90) * 90;
|
|
2781
|
+
if (Math.abs(((ang - near) + 180) % 360 - 180) < 4) ang = near % 360;
|
|
2782
|
+
}
|
|
2783
|
+
dofAng = ang;
|
|
2784
|
+
// Re-express the lines against the new extent so nothing moves but the angle.
|
|
2785
|
+
const g2 = gizmoGeom();
|
|
2786
|
+
const f0 = (c[0]*g2.d[0] + c[1]*g2.d[1] - g2.lo) / (g2.hi - g2.lo);
|
|
2787
|
+
dofStart = Math.max(0, Math.min(0.95, f0));
|
|
2788
|
+
dofK = Math.max(0.05, Math.min(0.95, (c[0]*g2.u[0] + c[1]*g2.u[1] - g2.ulo) / (g2.uhi - g2.ulo)));
|
|
2789
|
+
dofEnd = Math.max(dofStart + 0.05, Math.min(1.5, dofStart + gzDrag.dFar / (g2.hi - g2.lo)));
|
|
2790
|
+
if (dofEnd2 !== null) dofEnd2 = Math.max(-0.5, Math.min(dofStart - 0.05, dofStart - gzDrag.dNear / (g2.hi - g2.lo)));
|
|
2758
2791
|
}
|
|
2759
2792
|
paintDof(); paintGizmo(); autoPreview();
|
|
2760
2793
|
});
|