Keep transforms as coordinates / original
DEVELOPMENT JOURNAL / 27
Photoshot
CODE × UI
Building a free Photoshop alternative

Keep transforms as coordinates

We reopened Part 26’s AI original and warped it using two connected planes. This demonstration examines shared boundaries and original preservation rather than portrait beautification.

PHOTOSHOT DEVELOPMENT JOURNAL / 27

AI-generated study photograph. Editor captures and outputs show Photoshot in use.

PhotoshotDEVELOPMENT JOURNAL / 27FOUNDATION

From the source.

Distinguish the rendered view from the retained original

Saving only a warped view makes the basis for later edits unclear. Connected planes retain both the original src and gridWarp.planes. Rendering maps positions from the original plane to its destination.

We used the default two-rectangle layout and moved the shared top and bottom points inward for an obvious change. These are diagnostic coordinates, not recommended portrait-retouching values.

Adjacent planes reference the same vertices

initialPlanes creates six points and two quads. Both quads reference the same middle top and bottom indices. Editing one shared point therefore moves the neighboring boundary, rather than merely trying to match two separate coordinates.

On October 22, 2026, Plane 1’s middle top became x 50%, y 12%, and the middle bottom x 50%, y 88%. Switching to Plane 2 showed the same values at Corner 1 and Corner 4, verifying the connection in the UI.

app/studio/grid-warp.ts · SHA-256 809558da5767 · L4–11Photoshot implementation ↗
export type GridWarp={planes?:ConnectedPlanes;enabled:boolean;points:WarpPoint[]};
export function rectangleWarp(x=0,y=0,width=1,height=1):GridWarp{return{enabled:true,points:Array.from({length:16},(_,i)=>({x:x+(i%4)/3*width,y:y+Math.floor(i/4)/3*height}))};}
export function validateGridWarp(w:GridWarp){if(w?.planes)validateConnectedPlanes(w.planes);if(!w||typeof w.enabled!=='boolean'||!Array.isArray(w.points)||w.points.length!==16||w.points.some(p=>!p||[p.x,p.y].some(n=>!Number.isFinite(n)||n<0||n>1)))throw Error('Invalid custom warp.');}
export function gridWarpIdentity(w?:GridWarp){return !w?.enabled||!w.planes&&w.points.every((p,i)=>Math.abs(p.x-(i%4)/3)<1e-10&&Math.abs(p.y-Math.floor(i/4)/3)<1e-10);}
const weights=(t:number)=>[(1-t)**3,3*t*(1-t)**2,3*t*t*(1-t),t**3];
// Bicubic Bezier surface: moving a control point bends the continuous image surface.
export function warpPoint(w:GridWarp,u:number,v:number){const a=weights(u),b=weights(v);let x=0,y=0;for(let j=0;j<4;j++)for(let i=0;i<4;i++){const p=w.points[j*4+i],weight=a[i]*b[j];x+=p.x*weight;y+=p.y*weight;}return{x,y};}
export function gridWarpMesh(w:GridWarp,width:number,height:number){const nx=40,ny=40,points=[];for(let j=0;j<=ny;j++)for(let i=0;i<=nx;i++){const p=warpPoint(w,i/nx,j/ny);points.push({x:i/nx*width,y:j/ny*height,tx:p.x*width,ty:p.y*height});}return{nx,ny,points};}
PhotoshotDEVELOPMENT JOURNAL / 27IMPLEMENTATION

Inside the
calculation.

Reject folded planes and out-of-range coordinates

connected-planes.ts limits coordinates to 0–1 inside the layer, with at most 40 points and eight planes. Quads must remain convex and consistently oriented. Splitting locates shared edge midpoints and propagates connections to neighbors.

Rendering maps destination coordinates back to the source and interpolates with alpha weighting. Transparent-edge artifacts require color and alpha to be handled together. This demonstration used only the two default planes.

Reopen the project and compare original bytes

After applying the warp, we saved, reopened and saved the project again. The complete layer data matched the earlier file, and the PNG bytes decoded from src exactly matched original.png. This checks preservation beyond visual resemblance.

Moving the middle top and bottom inward leaves transparent checkerboard areas; no new background was filled. No mask was added in this photograph, so its mask behavior is not claimed as directly tested.

PHOTOSHOT / SOURCE NOTES27

Read the code.

app/studio/connected-planes.ts · SHA-256 5c950db23324 · L2–5Photoshot implementation ↗
export type ConnectedPlanes={layout:{x:number;y:number}[];destination:{x:number;y:number}[];quads:[number,number,number,number][]};
export const initialPlanes=():ConnectedPlanes=>({layout:[{x:0,y:0},{x:.5,y:0},{x:1,y:0},{x:0,y:1},{x:.5,y:1},{x:1,y:1}],destination:[{x:0,y:0},{x:.5,y:0},{x:1,y:0},{x:0,y:1},{x:.5,y:1},{x:1,y:1}],quads:[[0,1,4,3],[1,2,5,4]]});
const convex=(q:{x:number;y:number}[])=>q.every((p,i)=>{const b=q[(i+1)%4],c=q[(i+2)%4];return (b.x-p.x)*(c.y-b.y)-(b.y-p.y)*(c.x-b.x)>1e-6;});
export function validateConnectedPlanes(p:ConnectedPlanes){if(!p||!Array.isArray(p.layout)||!Array.isArray(p.destination)||p.layout.length!==p.destination.length||p.layout.length<4||p.layout.length>40||!Array.isArray(p.quads)||!p.quads.length||p.quads.length>8||[...p.layout,...p.destination].some(v=>!v||[v.x,v.y].some(n=>!Number.isFinite(n)||n<0||n>1)))throw Error('Connected plane points must stay inside the layer bounds.');for(const q of p.quads){if(q.length!==4||new Set(q).size!==4||q.some(i=>!Number.isInteger(i)||i<0||i>=p.layout.length)||!convex(q.map(i=>p.layout[i]))||!convex(q.map(i=>p.destination[i])))throw Error('Keep each connected plane convex and clockwise.');}}
app/studio/precision-warp.ts · SHA-256 48a2cf67ff77 · L8–9Photoshot implementation ↗
export function planesPrecision(source:PrecisionRaster,p:ConnectedPlanes){validateConnectedPlanes(p);const {width,height}=source,{sample,result,stride}=sampler(source);for(const indices of p.quads){const layout=indices.map(i=>p.layout[i]) as Quad,dest=indices.map(i=>p.destination[i]) as Quad,a=homography(layout),b=inverse(homography(dest)),x0=Math.max(0,Math.floor(Math.min(...dest.map(v=>v.x))*width)),x1=Math.min(width-1,Math.ceil(Math.max(...dest.map(v=>v.x))*width)),y0=Math.max(0,Math.floor(Math.min(...dest.map(v=>v.y))*height)),y1=Math.min(height-1,Math.ceil(Math.max(...dest.map(v=>v.y))*height));for(let y=y0;y<=y1;y++)for(let x=x0;x<=x1;x++){const uv=mapMatrix(b,(x+.5)/width,(y+.5)/height);if(uv.x< -1e-7||uv.x>1+1e-7||uv.y< -1e-7||uv.y>1+1e-7)continue;const at=mapMatrix(a,uv.x,uv.y);sample(at.x*width-.5,at.y*height-.5,(y*width+x)*stride);}}return result;}
export function warpPrecision(source:PrecisionRaster,grid?:GridWarp,puppet?:PuppetWarp){let r=source;if(grid?.enabled&&!gridWarpIdentity(grid))r=grid.planes?planesPrecision(r,grid.planes):meshPrecision(r,gridWarpMesh(grid,r.width,r.height));if(puppet?.enabled&&!warpIdentity(puppet))r=meshPrecision(r,puppetMesh(puppet,r.width,r.height));return r;}
app/studio/projective-path.ts · SHA-256 5b98aac97a07 · L4–7Photoshot implementation ↗
/** Projected cubic curves are rational; adaptively subdivide only when perspective is present. */
export function projectPath(p:PathShape,forward:number[],width=1,height=1):PathShape{
 const map=(p:Point)=>{const q=mapMatrix(forward,p.x,p.y);return {x:q.x*width,y:q.y*height};};
 const checkRegion=(points:Point[])=>{const z=points.map(p=>forward[6]*p.x+forward[7]*p.y+forward[8]);if(z.some(v=>Math.abs(v)<1e-7)||z.some(v=>v*z[0]<0))throw Error('The perspective horizon crosses a path.');};
PhotoshotDEVELOPMENT JOURNAL / 27IN PRACTICE

In the editor.

Keep transforms as coordinates / workspace
Actual Photoshot workspace. Settings and the image are shown together.

Grid, puppet and perspective crop are separate paths

Ordinary Grid Warp uses a bicubic Bezier surface with 16 control points and a 40×40 mesh. precision-warp can apply puppet deformation after a grid or connected-plane warp. Perspective crop adaptively subdivides projected curves and checks horizon crossings and anchor limits through a separate path.

Stored connected-planes reports cover splitting, cancellation, shared edges, PSD/PSB and masks. That full suite was not rerun here. Today’s direct checks concern two-plane coordinates and project roundtrip. The portrait is an AI-generated fictional adult. Part 28 covers content-aware fill and scaling.

PhotoshotDEVELOPMENT JOURNAL / 27BEFORE / AFTER

Original and connected-plane warp.

Keep transforms as coordinates / original
01 / AI-generated demonstration original
Keep transforms as coordinates / result
02 / Two-plane warp · project reopened

AI-generated study photograph. Editor captures and outputs show Photoshot in use.