11import { Application , Graphics , Sprite } from "pixi.js" ;
22import { drawSquircleOnGraphics } from "@/lib/geometry/squircle" ;
3- import type { CropRegion , Padding } from "../types" ;
3+ import { ADVANCED_VERTICAL_PADDING_MAX , type CropRegion , type Padding } from "../types" ;
44
55export const PADDING_SCALE_FACTOR = 0.2 ;
66export const BASE_PREVIEW_WIDTH = 1920 ;
77export const BASE_PREVIEW_HEIGHT = 1080 ;
88
9- export function scalePreviewBorderRadius (
10- width : number ,
11- height : number ,
12- borderRadius = 0 ,
13- ) : number {
9+ export function scalePreviewBorderRadius ( width : number , height : number , borderRadius = 0 ) : number {
1410 if ( width <= 0 || height <= 0 ) {
1511 return 0 ;
1612 }
@@ -23,12 +19,7 @@ export function isZeroPadding(padding: Padding | number): boolean {
2319 if ( typeof padding === "number" ) {
2420 return padding === 0 ;
2521 }
26- return (
27- padding . top === 0 &&
28- padding . bottom === 0 &&
29- padding . left === 0 &&
30- padding . right === 0
31- ) ;
22+ return padding . top === 0 && padding . bottom === 0 && padding . left === 0 && padding . right === 0 ;
3223}
3324
3425export interface PaddedLayoutResult {
@@ -64,13 +55,21 @@ export function computePaddedLayout(params: {
6455 ? { top : padding , bottom : padding , left : padding , right : padding }
6556 : padding ;
6657
67- // Padding is a percentage (0-100)
68- // Clamp to ensure we don't have overlapping padding that exceeds 100% of a dimension
69- const clampPercent = ( v : number ) => Math . min ( 100 , Math . max ( 0 , v ) ) ;
70- const leftPadFrac = ( clampPercent ( p . left ) / 100 ) * PADDING_SCALE_FACTOR ;
71- const rightPadFrac = ( clampPercent ( p . right ) / 100 ) * PADDING_SCALE_FACTOR ;
72- const topPadFrac = ( clampPercent ( p . top ) / 100 ) * PADDING_SCALE_FACTOR ;
73- const bottomPadFrac = ( clampPercent ( p . bottom ) / 100 ) * PADDING_SCALE_FACTOR ;
58+ // Padding is a percentage. Linked padding keeps the original 0-100 scaling
59+ // behavior; advanced vertical padding gets extra range for positioning.
60+ const isAdvancedPadding = typeof padding !== "number" && padding . linked === false ;
61+ const clampPercent = ( v : number , max = 100 ) => Math . min ( max , Math . max ( 0 , v ) ) ;
62+ const leftPercent = clampPercent ( p . left ) ;
63+ const rightPercent = clampPercent ( p . right ) ;
64+ const topPercent = clampPercent ( p . top , isAdvancedPadding ? ADVANCED_VERTICAL_PADDING_MAX : 100 ) ;
65+ const bottomPercent = clampPercent (
66+ p . bottom ,
67+ isAdvancedPadding ? ADVANCED_VERTICAL_PADDING_MAX : 100 ,
68+ ) ;
69+ const leftPadFrac = ( leftPercent / 100 ) * PADDING_SCALE_FACTOR ;
70+ const rightPadFrac = ( rightPercent / 100 ) * PADDING_SCALE_FACTOR ;
71+ const topPadFrac = ( Math . min ( topPercent , 100 ) / 100 ) * PADDING_SCALE_FACTOR ;
72+ const bottomPadFrac = ( Math . min ( bottomPercent , 100 ) / 100 ) * PADDING_SCALE_FACTOR ;
7473
7574 const availableFracW = Math . max ( 0 , 1.0 - leftPadFrac - rightPadFrac ) ;
7675 const availableFracH = Math . max ( 0 , 1.0 - topPadFrac - bottomPadFrac ) ;
@@ -103,17 +102,24 @@ export function computePaddedLayout(params: {
103102 const fullFrameDisplayH = fullFrameVideoH * scale ;
104103
105104 const availableCenterX = leftPadFrac * width + maxDisplayWidth / 2 ;
106- const availableCenterY = topPadFrac * height + maxDisplayHeight / 2 ;
105+ const availableCenterY = isAdvancedPadding
106+ ? ( ( ) => {
107+ const verticalTravel = Math . max ( 0 , height - fullFrameDisplayH ) ;
108+ const centeredOffsetY = verticalTravel / 2 ;
109+ const directionalOffsetY =
110+ centeredOffsetY +
111+ ( ( topPercent - bottomPercent ) / ADVANCED_VERTICAL_PADDING_MAX ) *
112+ centeredOffsetY ;
113+ const frameOffsetY = Math . min ( verticalTravel , Math . max ( 0 , directionalOffsetY ) ) ;
114+ return frameOffsetY + fullFrameDisplayH / 2 ;
115+ } ) ( )
116+ : topPadFrac * height + maxDisplayHeight / 2 ;
107117
108118 const frameCenterX = availableCenterX - fullFrameDisplayW / 2 ;
109119 const frameCenterY = availableCenterY - fullFrameDisplayH / 2 ;
110120
111- const centerOffsetX = insets
112- ? frameCenterX + insets . left * fullFrameDisplayW
113- : frameCenterX ;
114- const centerOffsetY = insets
115- ? frameCenterY + insets . top * fullFrameDisplayH
116- : frameCenterY ;
121+ const centerOffsetX = insets ? frameCenterX + insets . left * fullFrameDisplayW : frameCenterX ;
122+ const centerOffsetY = insets ? frameCenterY + insets . top * fullFrameDisplayH : frameCenterY ;
117123
118124 const spriteX = centerOffsetX - crop . x * fullVideoDisplayWidth ;
119125 const spriteY = centerOffsetY - crop . y * fullVideoDisplayHeight ;
0 commit comments