Screenshot als 3-D-Karte
Skaliert das Bild, kippt die rechte Kante nach hinten und legt einen weichen Schatten darunter — der Auftritt, den Produktseiten und Folien für Screenshots verwenden. RECEDE steuert, wie stark die Karte sich neigt.
INPUT
OUTPUT
JavaScript
// 3-D card look — resize, tilt the right edge away, drop a soft shadow.
// demo_3d_card.js
//!TITLE: Screenshot als 3-D-Karte
//!DESC: Skaliert das Bild auf MAX_SIZE, kippt die rechte Kante
//!DESC: nach hinten und legt einen weichen Schatten darunter.
//!DESC: Fuer Produktbilder und Praesentationsfolien gedacht —
//!DESC: RECEDE steuert, wie stark die Karte sich neigt.
//!INPUT: INPUT
//!OUTPUT: OUTPUT
//!PARAM: MAX_SIZE:integer=900,min=200,max=3000
//!PARAM: RECEDE:number=0.14,min=0,max=0.45
//!PARAM: SHADOW_DX:number=26,min=-120,max=120
//!PARAM: SHADOW_DY:number=30,min=-120,max=120
//!PARAM: SHADOW_BLUR:number=24,min=2,max=80
//!PARAM: SHADOW_STRENGTH:number=0.45,min=0,max=1
//!PARAM: BG:string=#f4f5f7
// Turns a flat image into a lightly-3D "card": the left edge keeps its
// full height while the right edge foreshortens (recedes into the
// screen), and the whole card sits on a soft drop shadow. Built from
// two primitives — stampAt (4-point perspective) + dropShadow.
// 1 — load and clamp to MAX_SIZE on the longest edge (keep aspect).
const src = Engine.loadImage(INPUT);
{
const long = Math.max(src.width, src.height);
if (long > MAX_SIZE) {
const s = MAX_SIZE / long;
src.resize(Math.round(src.width * s), Math.round(src.height * s), Interp.Bilinear);
}
}
// stampAt anti-aliases the tilted edges by default
// (WarpBorder.Transparent) — no manual padding needed.
const w = src.width;
const h = src.height;
// 2 — transparent canvas with margin so the shadow has room to spread
// into (dropShadow does NOT grow the canvas).
const recede = Math.round(h * RECEDE);
const padX = Math.round(SHADOW_BLUR * 2 + Math.abs(SHADOW_DX) + 24);
const padY = Math.round(SHADOW_BLUR * 2 + Math.abs(SHADOW_DY) + 24);
const cw = w + padX * 2;
const ch = h + padY * 2;
const card = Engine.createImage(cw, ch); // transparent
// 3 — perspective quad [TL, TR, BR, BL]: left edge full height, right
// edge inset top+bottom by `recede` so it reads as tilted away.
const x0 = padX;
const x1 = padX + w;
const yt = padY;
const yb = padY + h;
card.stampAt(src, [
px(x0, yt), // TL
px(x1, yt + recede), // TR
px(x1, yb - recede), // BR
px(x0, yb), // BL
], 1.0, BlendMode.Over, Interp.Bilinear);
// 4 — soft drop shadow behind the tilted card.
card.dropShadow(SHADOW_DX, SHADOW_DY, SHADOW_BLUR, '#000000', SHADOW_STRENGTH);
// 5 — flatten onto the background (or keep alpha if BG=transparent).
if (BG.toLowerCase() === 'transparent') {
card.save(OUTPUT);
card.free();
} else {
const bg = Engine.createColoredImage(cw, ch, BG);
bg.blendAt(card, px(0, 0), 1.0, BlendMode.Over);
bg.save(OUTPUT);
bg.free();
card.free();
}
src.free();
// © 2026 Michael Lechner · mlc OpticScript · https://mlcgo.eu · Elastic License 2.0