diff --git a/src/index.html b/src/index.html index add6ef1..6808551 100644 --- a/src/index.html +++ b/src/index.html @@ -9999,23 +9999,39 @@ if (p.x > maxX) maxX = p.x; if (p.y > maxY) maxY = p.y; } - // No-op unless we're outside [0, 100] on any side. A bit of - // tolerance to avoid micro-jiggle during normal in-bounds drags. + // Layer viewBox is 0-100 × 0-vbH where vbH = 100*layer.h/layer.w + // — the renderer's hard-coded formula. We want nodes to fit + // x:[0,100] and y:[0,vbH], matching the layer's actual aspect + // ratio after refit. The current viewBox-y bound is implied + // by what the renderer would compute given new layer.w/h. + // + // No-op unless we're outside the current viewBox on any side + // (with a small tolerance to avoid micro-jiggle during normal + // in-bounds drags). The current viewBox y-max is `vbH` computed + // from existing layer w/h. + const currentVbH = layer.w > 0 ? 100 * layer.h / layer.w : 100; const EPS = 0.5; - if (minX > -EPS && minY > -EPS && maxX < 100 + EPS && maxY < 100 + EPS) return; + if (minX > -EPS && minY > -EPS && maxX < 100 + EPS && maxY < currentVbH + EPS) return; const newW = Math.max(EPS, maxX - minX); const newH = Math.max(EPS, maxY - minY); + // Layer scales: in inches, layer.w grows in proportion to + // newW vs current viewBox-x (always 100); layer.h grows in + // proportion to newH vs the existing vbH. const sx = newW / 100; - const sy = newH / 100; + const sy = newH / currentVbH; // Layer position shifts in inches by the bbox offset scaled // to the existing layer w/h. layer.x = layer.x + (minX / 100) * layer.w; - layer.y = layer.y + (minY / 100) * layer.h; + layer.y = layer.y + (minY / currentVbH) * layer.h; layer.w = Math.max(0.01, layer.w * sx); layer.h = Math.max(0.01, layer.h * sy); + // Uniform-scale remap so the new node range matches the new + // viewBox aspect exactly — no stretching when the SVG paints + // into the refitted layer rectangle. + const remapScale = 100 / newW; const remap = (p) => ({ - x: (p.x - minX) / newW * 100, - y: (p.y - minY) / newH * 100, + x: (p.x - minX) * remapScale, + y: (p.y - minY) * remapScale, }); for (const n of nodes) { const r = remap(n); @@ -10113,8 +10129,13 @@ clearPenDraftRender(); const dims = currentCanvasDims(); const unit = Math.max(dims.w, dims.h); - const lineW = unit * 0.003; - const dotR = unit * 0.013; + // Smaller, less prominent anchors/handles — earlier sizes + // (0.003 stroke, 0.013 anchor) rendered ~25px dots on a + // 1920px-wide preview, which obscured short paths and made + // the canvas feel cluttered. ~50% smaller reads as deliberate + // editing UI without dominating. + const lineW = unit * 0.0018; + const dotR = unit * 0.0075; const nodes = layer.shape.pen.nodes; nodes.forEach((n, i) => { const a = penNodeToInch(layer, n); @@ -10469,7 +10490,14 @@ if (n.hOut) allPts.push(n.hOut); } const bbox = pointsBbox(allPts); - const remap = (pt) => ({ x: (pt.x - bbox.x) / bbox.w * 100, y: (pt.y - bbox.y) / bbox.h * 100 }); + // Uniform scaling: divide both x and y by bbox.w so nodes land + // in 0-100 × 0-(100*h/w) — matching the renderer's vbH formula + // (= 100 * layer.h / layer.w). Independent x/y scaling here + // forces a 0-100×0-100 node range into a non-square viewBox + // later, stretching curves and varying stroke widths around + // the path. Uniform scaling keeps strokes a constant width. + const scale = bbox.w > 0 ? 100 / bbox.w : 1; + const remap = (pt) => ({ x: (pt.x - bbox.x) * scale, y: (pt.y - bbox.y) * scale }); const normNodes = nodes.map(n => ({ x: remap(n).x, y: remap(n).y, hIn: n.hIn ? remap(n.hIn) : null, @@ -10515,8 +10543,10 @@ clearPenDraftRender(); const dims = currentCanvasDims(); const unit = Math.max(dims.w, dims.h); - const lineW = unit * 0.004; - const dotR = unit * 0.012; + // Sized to match renderPenEditHandles so the in-progress + // draw and the post-commit edit handles look consistent. + const lineW = unit * 0.0025; + const dotR = unit * 0.0075; if (_penDraft.tool === 'pencil') { const pts = _penDraft.points;