# How Shadow Intensity, Border Radius, and Padding Work as Visual Effects in OpenScreen

> Learn how OpenScreen applies shadow intensity border radius and padding as visual effects using CSS drop-shadow filters PixiJS masks and viewport scaling for stunning graphics.

- Repository: [Sid/openscreen](https://github.com/siddharthvaddem/openscreen)
- Tags: deep-dive
- Published: 2026-04-03

---

**OpenScreen applies shadow intensity through layered CSS `drop-shadow` filters, border radius via PixiJS `Graphics` masks that clip the video sprite, and padding through viewport scaling calculations that inset content from container edges.**

OpenScreen is an open-source video editing tool that renders composite video layouts using React and PixiJS. The application exposes three key visual effects—**shadow intensity**, **border radius**, and **padding**—through its Settings panel, transforming numeric slider values into layered CSS filters and geometric masks. These effects are implemented across the `VideoPlayback` component and the `layoutVideoContent` utility to create polished, professional video exports.

## Shadow Intensity Implementation

The shadow effect is rendered as a CSS filter on the container element that holds the Pixi canvas. In [`src/components/video-editor/VideoPlayback.tsx`](https://github.com/siddharthvaddem/openscreen/blob/main/src/components/video-editor/VideoPlayback.tsx), the component constructs a multi-layered `drop-shadow` chain when `showShadow` is enabled and `shadowIntensity` exceeds zero.

The implementation calculates three nested shadow layers with offsets and blur radii proportional to the intensity value (range `0` to `1`):

```tsx
<div
  ref={containerRef}
  className="absolute inset-0"
  style={{
    filter:
      showShadow && shadowIntensity > 0
        ? `drop-shadow(0 ${shadowIntensity * 12}px ${shadowIntensity * 48}px rgba(0,0,0,${shadowIntensity * 0.7}))
           drop-shadow(0 ${shadowIntensity * 4}px  ${shadowIntensity * 16}px rgba(0,0,0,${shadowIntensity * 0.5}))
           drop-shadow(0 ${shadowIntensity * 2}px  ${shadowIntensity * 8}px  rgba(0,0,0,${shadowIntensity * 0.3}))`
        : "none",
  }}
/>

```

- **First layer**: Vertical offset of `shadowIntensity * 12px` with blur of `shadowIntensity * 48px` and opacity `0.7`
- **Second layer**: Offset of `shadowIntensity * 4px` with blur of `shadowIntensity * 16px` and opacity `0.5`  
- **Third layer**: Offset of `shadowIntensity * 2px` with blur of `shadowIntensity * 8px` and opacity `0.3`

When `shadowIntensity` is `0`, the filter resolves to `"none"` and no shadow is drawn.

## Border Radius Application

Border radius is applied through a PixiJS mask that clips the video content to a rounded rectangle. The `layoutVideoContent` function in [`src/components/video-editor/videoPlayback/layoutUtils.ts`](https://github.com/siddharthvaddem/openscreen/blob/main/src/components/video-editor/videoPlayback/layoutUtils.ts) receives the `borderRadius` parameter and applies it to a `Graphics` object that masks the video sprite.

```ts
maskGraphics.clear();
maskGraphics.roundRect(
  screenRect.x,
  screenRect.y,
  screenRect.width,
  screenRect.height,
  compositeLayout.screenCover ? 0 : borderRadius,
);
maskGraphics.fill({ color: 0xffffff });

```

The `roundRect` method draws a white fill that serves as the mask geometry. If `compositeLayout.screenCover` is true, the radius is forced to `0` to maintain sharp corners; otherwise, the supplied `borderRadius` value (maximum `16` pixels according to the Settings UI) rounds the corners of the visible video area. This mask clips both the main video and any webcam picture-in-picture elements.

## Padding Calculation and Viewport Scaling

Padding creates a letterbox effect by scaling down the maximum display dimensions before the video is fitted to the viewport. The logic in [`src/components/video-editor/videoPlayback/layoutUtils.ts`](https://github.com/siddharthvaddem/openscreen/blob/main/src/components/video-editor/videoPlayback/layoutUtils.ts) converts the percentage-based padding value into a scale factor.

```ts
const effectivePadding = webcamLayoutPreset === "vertical-stack" ? 0 : padding;
const paddingScale = 1.0 - (effectivePadding / 100) * 0.4;
const maxDisplayWidth  = width  * paddingScale;
const maxDisplayHeight = height * paddingScale;

```

- **Effective padding**: Forced to `0` when using the **vertical-stack** webcam preset (full-bleed layout), otherwise uses the slider value (`0` to `100`)
- **Scale calculation**: `paddingScale = 1.0 - (effectivePadding / 100) * 0.4`, creating a shrink factor between `1.0` and `0.6`
- **Viewport application**: The scaled dimensions are fed into the composite layout algorithm, which determines the final sprite scale

This approach ensures the video appears inset from the container edges while maintaining aspect ratio.

## Settings UI Integration

The Settings panel in [`src/components/video-editor/SettingsPanel.tsx`](https://github.com/siddharthvaddem/openscreen/blob/main/src/components/video-editor/SettingsPanel.tsx) provides sliders that forward values to the `VideoEditor` component, which then passes them as props to `VideoPlayback`:

```tsx
<VideoPlayback
  showShadow={shadowIntensity > 0}
  shadowIntensity={shadowIntensity}
  borderRadius={borderRadius}
  padding={padding}
  webcamLayoutPreset={webcamLayoutPreset}
  // ... other props
/>

```

The UI enforces constraints through the slider components:
- **Border radius**: Range `0` to `16` with `0.5` step increments
- **Padding**: Range `0` to `100` percent, disabled when `webcamLayoutPreset === "vertical-stack"`
- **Shadow intensity**: Range `0` to `1` (implied by the multiplication factors)

## Summary

- **Shadow intensity** uses three nested CSS `drop-shadow` filters in [`VideoPlayback.tsx`](https://github.com/siddharthvaddem/openscreen/blob/main/VideoPlayback.tsx) with blur and opacity values calculated as multiples of the intensity slider (0–1)
- **Border radius** creates a clipping mask via `maskGraphics.roundRect()` in [`layoutUtils.ts`](https://github.com/siddharthvaddem/openscreen/blob/main/layoutUtils.ts), rounding video corners when not in screen-cover mode
- **Padding** applies a `paddingScale` factor (1.0 to 0.6) to the viewport dimensions before layout calculations, creating inset margins
- The **vertical-stack** preset disables padding while preserving shadow and radius effects
- All visual parameters flow from [`SettingsPanel.tsx`](https://github.com/siddharthvaddem/openscreen/blob/main/SettingsPanel.tsx) through `VideoEditor` to the rendering components

## Frequently Asked Questions

### What is the maximum shadow intensity value and how does it affect the blur radius?

The maximum shadow intensity is `1.0` (100%), which produces a blur radius of `48px` on the primary shadow layer, `16px` on the secondary layer, and `8px` on the tertiary layer. These values are calculated by multiplying the intensity by fixed constants (12, 48, 4, 16, 2, and 8 respectively) to create a layered depth effect.

### Why is the padding control disabled when using the vertical-stack preset?

The vertical-stack preset enforces a full-bleed layout where the webcam and content occupy distinct vertical regions without margins. The code explicitly sets `effectivePadding` to `0` when `webcamLayoutPreset === "vertical-stack"` to prevent the letterbox effect from interfering with the stacked layout geometry.

### How does border radius actually clip the video content if it's just a CSS property elsewhere?

Unlike standard CSS border-radius, OpenScreen implements clipping through a PixiJS `Graphics` mask. The `maskGraphics.roundRect()` call draws a white shape that serves as an alpha mask for the video sprite. Only pixels within the rounded rectangle are visible, physically clipping the video texture rather than just styling the container corners.

### Which source files should I modify to change how these visual effects are calculated?

To modify the shadow rendering, edit [`src/components/video-editor/VideoPlayback.tsx`](https://github.com/siddharthvaddem/openscreen/blob/main/src/components/video-editor/VideoPlayback.tsx) around lines 1152–1155 where the `style.filter` prop is constructed. For border radius and padding logic, modify [`src/components/video-editor/videoPlayback/layoutUtils.ts`](https://github.com/siddharthvaddem/openscreen/blob/main/src/components/video-editor/videoPlayback/layoutUtils.ts), specifically the `layoutVideoContent` function at lines 29–37 for masking and lines 84–90 for padding calculations.