mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-26 15:55:35 +00:00
Make webcam rounding and shadows more pronounced
This commit is contained in:
@@ -12,10 +12,7 @@ import {
|
||||
useState,
|
||||
} from "react";
|
||||
import { getAssetPath, getRenderableAssetUrl, getRenderableVideoUrl } from "@/lib/assetPath";
|
||||
import {
|
||||
getWebcamShadowStrength,
|
||||
WEBCAM_SHADOW_LAYER_PROFILES,
|
||||
} from "@/lib/exporter/shadowProfile";
|
||||
import { getWebcamShadowFilter } from "@/lib/exporter/shadowProfile";
|
||||
import {
|
||||
clampMediaTimeToDuration,
|
||||
enablePitchPreservingPlayback,
|
||||
@@ -799,8 +796,6 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
const webcamCorner = webcam?.corner ?? "bottom-right";
|
||||
const webcamRoundness = webcam?.roundness ?? DEFAULT_WEBCAM_ROUNDNESS;
|
||||
const webcamShadow = webcam?.shadow ?? DEFAULT_WEBCAM_SHADOW;
|
||||
const webcamShadowStrength = getWebcamShadowStrength(webcamShadow);
|
||||
const webcamShadowProfile = WEBCAM_SHADOW_LAYER_PROFILES[0];
|
||||
const webcamTimeOffsetMs = webcam?.timeOffsetMs;
|
||||
const webcamCropRegion = webcam?.cropRegion;
|
||||
const webcamMirror = webcam?.mirror ?? false;
|
||||
@@ -891,15 +886,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
radius: scaledRadius,
|
||||
});
|
||||
const shadowSize = Math.min(scaledDimensions.width, scaledDimensions.height);
|
||||
const shadowOffset =
|
||||
shadowSize * webcamShadowProfile.offsetScale * webcamShadowStrength;
|
||||
const shadowBlur =
|
||||
shadowSize * webcamShadowProfile.blurScale * webcamShadowStrength;
|
||||
const shadowAlpha = webcamShadowProfile.alphaScale * webcamShadowStrength;
|
||||
bubble.style.filter =
|
||||
webcamShadowStrength > 0
|
||||
? `drop-shadow(0 ${shadowOffset}px ${shadowBlur}px rgba(0, 0, 0, ${shadowAlpha}))`
|
||||
: "none";
|
||||
bubble.style.filter = getWebcamShadowFilter(shadowSize, webcamShadow);
|
||||
bubble.style.borderRadius = "0px";
|
||||
bubble.style.boxShadow = "none";
|
||||
|
||||
@@ -918,7 +905,7 @@ const VideoPlayback = forwardRef<VideoPlaybackRef, VideoPlaybackProps>(
|
||||
webcamPositionX,
|
||||
webcamPositionY,
|
||||
webcamReactToZoom,
|
||||
webcamShadowStrength,
|
||||
webcamShadow,
|
||||
webcamHeight,
|
||||
webcamVideoPath,
|
||||
webcamWidth,
|
||||
|
||||
@@ -12,9 +12,10 @@ import {
|
||||
} from "./webcamOverlay";
|
||||
|
||||
describe("webcam roundness", () => {
|
||||
it("uses a percentage of the maximum radius", () => {
|
||||
it("uses a stronger response curve while preserving the endpoints", () => {
|
||||
expect(getWebcamCornerRadiusPx(0, 640, 360)).toBe(0);
|
||||
expect(getWebcamCornerRadiusPx(50, 640, 360)).toBe(90);
|
||||
expect(getWebcamCornerRadiusPx(25, 640, 360)).toBe(90);
|
||||
expect(getWebcamCornerRadiusPx(50, 640, 360)).toBeCloseTo(127.28, 1);
|
||||
expect(getWebcamCornerRadiusPx(100, 640, 360)).toBe(180);
|
||||
});
|
||||
|
||||
|
||||
@@ -20,7 +20,8 @@ export function getWebcamCornerRadiusPx(
|
||||
height: number,
|
||||
): number {
|
||||
const safeRoundness = Number.isFinite(roundnessPercent) ? clamp(roundnessPercent, 0, 100) : 0;
|
||||
return (Math.max(0, Math.min(width, height)) / 2) * (safeRoundness / 100);
|
||||
const strengthenedRoundness = Math.sqrt(safeRoundness / 100);
|
||||
return (Math.max(0, Math.min(width, height)) / 2) * strengthenedRoundness;
|
||||
}
|
||||
|
||||
export function convertLegacyWebcamRadiusToRoundness(
|
||||
|
||||
@@ -59,7 +59,7 @@ import {
|
||||
scaleWebcamOverlayPixels,
|
||||
} from "@/components/video-editor/webcamOverlay";
|
||||
import { getAssetPath, getExportableVideoUrl, getRenderableAssetUrl } from "@/lib/assetPath";
|
||||
import { getWebcamShadowStrength } from "@/lib/exporter/shadowProfile";
|
||||
import { getWebcamShadowFilter } from "@/lib/exporter/shadowProfile";
|
||||
import { drawSquircleOnCanvas, drawSquircleOnGraphics } from "@/lib/geometry/squircle";
|
||||
import {
|
||||
clampMediaTimeToDuration,
|
||||
@@ -2166,10 +2166,9 @@ export class FrameRenderer {
|
||||
bubbleCtx.restore();
|
||||
|
||||
if ((webcam.shadow ?? 0) > 0) {
|
||||
const shadow = getWebcamShadowStrength(webcam.shadow);
|
||||
const shadowSize = Math.min(dimensions.width, dimensions.height);
|
||||
ctx.save();
|
||||
ctx.filter = `drop-shadow(0 ${Math.round(shadowSize * 0.06)}px ${Math.round(shadowSize * 0.22)}px rgba(0,0,0,${shadow}))`;
|
||||
ctx.filter = getWebcamShadowFilter(shadowSize, webcam.shadow);
|
||||
ctx.drawImage(bubbleCanvas, x, y, dimensions.width, dimensions.height);
|
||||
ctx.restore();
|
||||
return;
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { getWebcamShadowStrength } from "./shadowProfile";
|
||||
import {
|
||||
getWebcamShadowFilter,
|
||||
getWebcamShadowStrength,
|
||||
WEBCAM_SHADOW_LAYER_PROFILES,
|
||||
} from "./shadowProfile";
|
||||
|
||||
describe("getWebcamShadowStrength", () => {
|
||||
it("doubles the webcam shadow response and clamps it", () => {
|
||||
@@ -8,4 +12,13 @@ describe("getWebcamShadowStrength", () => {
|
||||
expect(getWebcamShadowStrength(0.5)).toBe(1);
|
||||
expect(getWebcamShadowStrength(1)).toBe(1);
|
||||
});
|
||||
|
||||
it("adds a tighter contact shadow so strength also increases density", () => {
|
||||
expect(WEBCAM_SHADOW_LAYER_PROFILES).toHaveLength(2);
|
||||
expect(getWebcamShadowFilter(100, 0)).toBe("none");
|
||||
const filter = getWebcamShadowFilter(100, 0.5);
|
||||
expect(filter.match(/drop-shadow/g)).toHaveLength(2);
|
||||
expect(filter).toContain("rgba(0, 0, 0, 0.9)");
|
||||
expect(filter).toContain("rgba(0, 0, 0, 0.8)");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,13 +11,28 @@ export const VIDEO_SHADOW_LAYER_PROFILES: ReadonlyArray<ShadowLayerProfile> = Ob
|
||||
]);
|
||||
|
||||
export const WEBCAM_SHADOW_LAYER_PROFILES: ReadonlyArray<ShadowLayerProfile> = Object.freeze([
|
||||
{ offsetScale: 0.06, alphaScale: 1, blurScale: 0.22 },
|
||||
{ offsetScale: 0.06, alphaScale: 0.9, blurScale: 0.22 },
|
||||
{ offsetScale: 0.025, alphaScale: 0.8, blurScale: 0.07 },
|
||||
]);
|
||||
|
||||
export function getWebcamShadowStrength(value: number): number {
|
||||
return Math.min(1, Math.max(0, Number.isFinite(value) ? value * 2 : 0));
|
||||
}
|
||||
|
||||
export function getWebcamShadowFilter(shadowSize: number, value: number): string {
|
||||
const strength = getWebcamShadowStrength(value);
|
||||
if (strength <= 0) {
|
||||
return "none";
|
||||
}
|
||||
|
||||
return WEBCAM_SHADOW_LAYER_PROFILES.map((profile) => {
|
||||
const offset = Math.max(0, shadowSize) * profile.offsetScale * strength;
|
||||
const blur = Math.max(0, shadowSize) * profile.blurScale * strength;
|
||||
const alpha = Math.min(1, profile.alphaScale * strength);
|
||||
return `drop-shadow(0 ${offset}px ${blur}px rgba(0, 0, 0, ${alpha}))`;
|
||||
}).join(" ");
|
||||
}
|
||||
|
||||
export function getShadowFilterPadding(blur: number, offsetY: number): number {
|
||||
return Math.ceil(Math.max(0, blur * 2 + Math.abs(offsetY)));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user