transfer
Source: transfer.js:43
Ghostyle Transfer Lab
Project Objective
The goal of this browser-only experiment is to let a user capture a painted visual style from one face and preview it on another face without sending images to a server. Instead of treating the transfer as a black box, the page exposes the practical stages of the process: choosing source and target images, marking face regions, extracting a transparent paint matte, previewing that matte, and compositing the result with adjustable blend controls.
Technical Stack
The module is written in JavaScript and uses the DOM for the control surface, the Canvas 2D API for pixel extraction, matte generation, preview drawing, affine triangle warping, and final compositing, and @vladmandic/face-api for optional 68-point landmark detection. All image processing happens in the browser runtime.
Interface Model
The UI is organized around three upload slots: an optional before image, a required painted after image, and a required target image. Each slot renders a fitted preview canvas where the user draws a face box in image coordinates. A side matte preview shows the extracted paint layer, while the result panel displays the final target composite and enables download once a transfer has completed.
Functional Workflow
The transfer starts in a setup state until the after and target slots both have images and face boxes. Running the transfer normalizes the after face crop into a canonical square, subtracts either the matching before crop or a sampled reference color, feathers the resulting alpha plane, and then places the matte onto the target. When landmarks are available and mesh mode is enabled, corresponding face points are triangulated and the matte is warped triangle by triangle; otherwise the system falls back to direct box placement with a status note that explains which mode was used.
Instance Methods
byId(id: string): HTMLElement
Resolve a required DOM element by id.
Parameters
id(string) — DOM id.
Returns
HTMLElement— Matching element.
Throws
Error— When the expected element is missing from the page.
ctx2d(canvas: HTMLCanvasElement): CanvasRenderingContext2D
Resolve a canvas rendering context with a clear failure mode.
Parameters
canvas(HTMLCanvasElement) — Canvas to draw into.
Returns
CanvasRenderingContext2D— Two-dimensional context.
Throws
Error— When the browser cannot allocate a 2D context.
clamp(value: number, min: number, max: number): number
Clamp a numeric value to a closed interval.
Parameters
value(number) — Candidate value.min(number) — Inclusive lower bound.max(number) — Inclusive upper bound.
Returns
number— Clamped value.
setMessage(
key: string,
params?: Record.<string, (string|number)>,
): void
Change the currently displayed status message.
Parameters
key(string) — Translation key.params(Record.<string, (string|number)>, optional) — Optional interpolation values.
Returns
void
setEngineState(key: string, ready: boolean): void
Change the engine availability badge.
Parameters
key(string) — Translation key for the badge text.ready(boolean) — Whether to render the badge as ready.
Returns
void
renderModeNote(): void
Render the placement mode note. Wrapped modes read as "Placed using: {mode}", while setup states are shown directly.
Returns
void
setModeState(
key: string,
params?: Record.<string, (string|number)>,
placed?: boolean,
): void
Change the placement mode note.
Parameters
key(string) — Translation key for the mode.params(Record.<string, (string|number)>, optional) — Optional interpolation values.placed(boolean, optional, default: false) — Whether to prefix with the placement wrapper.
Returns
void
renderResultEmpty(): void
Re-render the empty result placeholder.
Returns
void
refreshLocalizedState(): void
Re-apply locale-dependent runtime text that is not covered by static data-i18n attributes.
Returns
void
initFaceapi(): Promise.<void>
Load the optional landmark models. The transfer remains usable in box mode when the CDN or model download fails.
Returns
Promise.<void>— Resolves after the best-effort setup.
fitPreview(name: 'before' | 'after' | 'target'): void
Fit a source image into its square preview stage and bind box drawing to the generated canvas.
Parameters
name('before' | 'after' | 'target') — Slot to render.
Returns
void
redrawSlot(
name: 'before' | 'after' | 'target',
canvas: HTMLCanvasElement,
): void
Draw a slot image and the current crop box into its preview canvas.
Parameters
name('before' | 'after' | 'target') — Slot to draw.canvas(HTMLCanvasElement) — Preview canvas.
Returns
void
attachBoxDrawing(
name: 'before' | 'after' | 'target',
canvas: HTMLCanvasElement,
): void
Attach pointer handlers that let the user draw a face box in image coordinates while seeing the box in preview coordinates.
Parameters
name('before' | 'after' | 'target') — Slot being edited.canvas(HTMLCanvasElement) — Interactive preview canvas.
Returns
void
refreshSlotNote(name: string): void
Update a single slot note from its current image and box state.
Parameters
name(string) — Slot name.
Returns
void
refreshState(): void
Recompute readiness and related user-facing prompts after image or box changes.
Returns
void
loadFile(
name: 'before' | 'after' | 'target',
file: File,
): Promise.<HTMLImageElement>
Load an image file selected or dropped by the user.
Parameters
name('before' | 'after' | 'target') — Destination slot.file(File) — Browser file object.
Returns
Promise.<HTMLImageElement>— Loaded image element.
loadURL(
name: 'before' | 'after' | 'target',
url: string,
): Promise.<HTMLImageElement>
Load an image URL into a slot. Exposed through window.GT for automated checks and demos.
Parameters
name('before' | 'after' | 'target') — Destination slot.url(string) — Image URL.
Returns
Promise.<HTMLImageElement>— Loaded image element.
boxToCanon(
name: 'before' | 'after' | 'target',
): HTMLCanvasElement
Draw a slot crop into the canonical transfer coordinate space.
Parameters
name('before' | 'after' | 'target') — Slot to crop.
Returns
HTMLCanvasElement— Canonical face-frame canvas.
extractMatte(
threshold: number,
feather: number,
): HTMLCanvasElement
Extract the painted pixels as an RGBA matte in canonical face coordinates. With a before image, RGB distance is measured against that before crop. When no before is present, a coarse median color approximation is used instead.
Parameters
threshold(number) — RGB distance threshold for paint extraction.feather(number) — Blur radius for softening the matte alpha.
Returns
HTMLCanvasElement— Canonical paint matte.
medianColor(imageData: ImageData): RgbTuple
Approximate the dominant skin/reference color by sparse sampling.
Parameters
imageData(ImageData) — Canonical source image data.
Returns
RgbTuple— Average RGB tuple.
boxBlur(
alpha: Float32Array,
width: number,
height: number,
radius: number,
): void
Apply two-pass box blur to a float alpha plane.
Parameters
alpha(Float32Array) — Alpha plane, mutated in place.width(number) — Plane width.height(number) — Plane height.radius(number) — Blur radius.
Returns
void
detectLandmarks(
name: 'after' | 'target',
): Promise.<(Array.<Point>|null)>
Detect 68 face landmarks inside a user-provided slot box, mapping the result back into original image coordinates.
Parameters
name('after' | 'target') — Slot to analyze.
Returns
Promise.<(Array.<Point>|null)>— Landmark points, or null when detection fails.
landmarksToCanon(points: Array.<Point>, box: Box): Array.<Point>
Convert image-coordinate landmarks to canonical face-frame coordinates.
Parameters
points(Array.<Point>) — Source landmarks.box(Box) — Face box used as canonical frame.
Returns
Array.<Point>— Canonical points.
triangulate(points: Array.<Point>): Array.<Array.<number>>
Build a Delaunay-like triangulation with Bowyer-Watson. This keeps the mesh dependency-free for a small 68-point landmark set.
Parameters
points(Array.<Point>) — Points to triangulate.
Returns
Array.<Array.<number>>— Triples of point indices.
warpTriangle(
ctx: CanvasRenderingContext2D,
source: HTMLCanvasElement,
s0: Point,
s1: Point,
s2: Point,
d0: Point,
d1: Point,
d2: Point,
): void
Warp the source canvas through a single affine triangle into the target rendering context.
Parameters
ctx(CanvasRenderingContext2D) — Target rendering context.source(HTMLCanvasElement) — Source matte canvas.s0(Point) — First source point.s1(Point) — Second source point.s2(Point) — Third source point.d0(Point) — First destination point.d1(Point) — Second destination point.d2(Point) — Third destination point.
Returns
void
readParams(): Object
Read the current transfer controls as typed values.
Returns
Object— Transfer parameters.
drawMattePreview(matte: HTMLCanvasElement): void
Draw the extracted matte into the side preview canvas.
Parameters
matte(HTMLCanvasElement) — Canonical matte canvas.
Returns
void
transfer(): Promise.<string>
Run extraction and compositing, using mesh warping when landmarks are available and falling back to direct box placement otherwise.
Returns
Promise.<string>— Translation key for the mode used.
resetTransfer(): void
Reset images, boxes, previews, output, and controls that are derived from the last transfer.
Returns
void
setupTransferPage(): void
Wire DOM events for file loading, drag-and-drop, controls, commands, locale changes, and the lightweight test API.
Returns
void
Other
RgbTuple: Object
Two-dimensional point in image or canvas coordinates.
Properties
x(number) — Horizontal coordinate.y(number) — Vertical coordinate.Rectangular face selection in original image coordinates.x(number) — Left edge.y(number) — Top edge.w(number) — Width.h(number) — Height.State tracked for one upload slot and its preview canvas.img(HTMLImageElement) — Loaded source image, or null before load.box(Box) — User-selected face box, or null until selected.scale(number) — Ratio from preview pixels to original image pixels.dispW(number) — Preview image width in CSS pixels.dispH(number) — Preview image height in CSS pixels.Three-channel average color stored as red, green, and blue values.