screengraft 0.54.7 → 0.54.8
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 +44 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "screengraft",
|
|
3
|
-
"version": "0.54.
|
|
3
|
+
"version": "0.54.8",
|
|
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
|
@@ -2920,9 +2920,38 @@ function swingText(mode){
|
|
|
2920
2920
|
if (mode === 'rotB') return 'the left end swings, pivot on the right';
|
|
2921
2921
|
return 'flat on the rule means aligned';
|
|
2922
2922
|
}
|
|
2923
|
+
/* A corner under the pointer gets a plain magnified view instead of the
|
|
2924
|
+
rectified strip: the strip straightens ONE edge, and a corner is where two
|
|
2925
|
+
meet, so straightening either would bend the other. Same magnification as
|
|
2926
|
+
the strip (H / 2·stripHalf, so the ± buttons work here too), centred on the
|
|
2927
|
+
corner, unrotated, with both edges drawn through it and the ring at the
|
|
2928
|
+
centre. Requested 13 Sep 2026; edges keep the strip as it is. */
|
|
2929
|
+
function paintCorner(c, W, H, i){
|
|
2930
|
+
c.setTransform(1,0,0,1,0,0);
|
|
2931
|
+
c.fillStyle = '#0c0c0b'; c.fillRect(0,0,W,H);
|
|
2932
|
+
const P = st.corners[i], M = H / (2*stripHalf);
|
|
2933
|
+
c.save();
|
|
2934
|
+
c.setTransform(M, 0, 0, M, W/2 - P[0]*M, H/2 - P[1]*M);
|
|
2935
|
+
c.imageSmoothingEnabled = true;
|
|
2936
|
+
c.drawImage(img, 0, 0);
|
|
2937
|
+
c.restore();
|
|
2938
|
+
if (stripHC) stretchContrast(c, W, H);
|
|
2939
|
+
const toS = q => [W/2 + (q[0]-P[0])*M, H/2 + (q[1]-P[1])*M];
|
|
2940
|
+
const prev = st.corners[(i+3)%4], next = st.corners[(i+1)%4];
|
|
2941
|
+
for (const q of [prev, next]){
|
|
2942
|
+
const e = toS(q), d = unit(sub(e, [W/2, H/2]));
|
|
2943
|
+
const s0 = add([W/2, H/2], mul(d, HANDLE_GAP_S)), s1 = add([W/2, H/2], mul(d, 4000));
|
|
2944
|
+
cased(c, () => { c.beginPath(); c.moveTo(s0[0], s0[1]); c.lineTo(s1[0], s1[1]); }, QUAD_W, CORE_QUAD);
|
|
2945
|
+
}
|
|
2946
|
+
casedRing(c, W/2, H/2, 4, CORE_QUAD);
|
|
2947
|
+
c.font = '600 11px system-ui'; c.textBaseline = 'middle';
|
|
2948
|
+
casedText(c, LBL[i], W/2 + 12, H/2 - 12, 'rgba(255,255,255,.95)');
|
|
2949
|
+
}
|
|
2950
|
+
const HANDLE_GAP_S = 4 + 1 + CASE_PAD/2 + 1; // the same break the canvas leaves around a ring
|
|
2923
2951
|
function drawStrip(){
|
|
2924
2952
|
const a = drag || hover || pick;
|
|
2925
|
-
const has = !!(st.corners && a && a.kind === 'edge' && img.naturalWidth);
|
|
2953
|
+
const has = !!(st.corners && a && (a.kind === 'edge' || a.kind === 'corner') && img.naturalWidth);
|
|
2954
|
+
const corner = has && a.kind === 'corner';
|
|
2926
2955
|
$('#stripZ').textContent = '±' + stripHalf + 'px';
|
|
2927
2956
|
if (loupeMode === 'dock'){
|
|
2928
2957
|
$('#floatLoupe').classList.remove('on');
|
|
@@ -2932,13 +2961,23 @@ function drawStrip(){
|
|
|
2932
2961
|
$('#stripSt').textContent = 'Hover or drag an edge — this straightens it, so misalignment shows as a wedge.';
|
|
2933
2962
|
return;
|
|
2934
2963
|
}
|
|
2935
|
-
|
|
2936
|
-
|
|
2964
|
+
if (corner){
|
|
2965
|
+
paintCorner(sctx, W, H, a.i);
|
|
2966
|
+
$('#stripSt').textContent = `${LBL[a.i]} corner · ${(H/(2*stripHalf)).toFixed(1)}× — where the two edges meet`;
|
|
2967
|
+
} else {
|
|
2968
|
+
paintStrip(sctx, W, H, a.i, a.mode);
|
|
2969
|
+
$('#stripSt').textContent = `${EDGE_LBL[a.i]} edge · ±${stripHalf}px · ${(H/(2*stripHalf)).toFixed(1)}× across the boundary — ${swingText(a.mode)}`;
|
|
2970
|
+
}
|
|
2937
2971
|
} else {
|
|
2938
2972
|
const fl = $('#floatLoupe');
|
|
2939
2973
|
if (!has){ fl.classList.remove('on'); return; }
|
|
2940
|
-
|
|
2941
|
-
|
|
2974
|
+
if (corner){
|
|
2975
|
+
paintCorner(fctx, stripF.width, stripF.height, a.i);
|
|
2976
|
+
$('#stripFCap').textContent = `${LBL[a.i]} corner · ${(stripF.height/(2*stripHalf)).toFixed(1)}× — where the two edges meet`;
|
|
2977
|
+
} else {
|
|
2978
|
+
paintStrip(fctx, stripF.width, stripF.height, a.i, a.mode);
|
|
2979
|
+
$('#stripFCap').textContent = `${EDGE_LBL[a.i]} edge · ±${stripHalf}px — ${swingText(a.mode)}`;
|
|
2980
|
+
}
|
|
2942
2981
|
fl.classList.add('on');
|
|
2943
2982
|
const w = fl.offsetWidth || 356, h = fl.offsetHeight || 130;
|
|
2944
2983
|
let x = lastPointer[0] + 26, y = lastPointer[1] - h - 18;
|