---
title: Alpha Noise Masks & Specular Tracking
description: "Overcoming dirty greys from overlay blending via mask-composite: intersect, generating physical card cursor specular reflections, and the spring that lets TxCard's refraction light follow the pointer."
---

# Alpha Noise Masks & Specular Tracking

In realistic material design, grain and specular highlights grant physical tactile qualities to a surface, but improper blending ruins color purity.

## Why Overlay Blending Turns Faint Tints Grey

Designers frequently blend a 5% noise layer over frosted cards using CSS `mix-blend-mode: overlay`.
Over faint washes (at roughly 16% alpha), the overlay formula:
$$\text{Overlay}(A, B) = \begin{cases} 2AB & B < 0.5 \\ 1 - 2(1-A)(1-B) & B \ge 0.5 \end{cases}$$
shifts pixel luminance toward middle grey, creating a muddy, speckled smudge across high-DPI Retina screens.

## The mask-composite: intersect Solution

TuffEx avoids modifying pixel RGB values entirely, instead **encoding fractal noise directly into the alpha mask**:

:::TuffCodeBlock{lang="scss"}
---
code: |
  @supports (mask-composite: intersect) {
    .tx-status-hint__wash {
      background-color: var(--tx-status-hint-accent, #67c23a);
      // Mask image intersects linear wash and fractal noise
      mask-image:
        linear-gradient(
          to right,
          rgb(0 0 0 / var(--tx-status-hint-wash-strength, 0.26)),
          rgb(0 0 0 / calc(var(--tx-status-hint-wash-strength, 0.26) * 0.45)) 38%,
          transparent
        ),
        $grain; // A 140px feTurbulence fractal-noise SVG
      mask-size: 100% 100%, 140px 140px;
      mask-repeat: no-repeat, repeat;
      mask-composite: intersect;
    }
  }
---
:::

The noise governs purely "how much light passes through"; the underlying canvas color stays completely clean. The noise alpha averages about 0.6, so the 0.26 strength at the leading edge comes to roughly 16% in light themes; dark themes take 0.2, because the same tint reads louder on a dark page.

:::TuffDemoWrapper{demo="ConceptNoiseMaskDemo"}
:::

## Card Specular Light Cursor Tracking

On `TxCard`, moving the pointer draws a faint radial specular highlight that travels with the cursor across the card's surface and along its edge. The `specular` prop controls it: left unset it follows `clickable`, so clickable cards have it by default, and disabled cards never draw it.

- **Normalized Coordinates**: as the pointer moves over the card, the component converts its position to percentages within the card and writes them to the specular layer as `--tx-card-light-x` and `--tx-card-light-y`.
- **Subtle Ambient Alpha**: the highlight is one 600px circular radial gradient, 6% white at its centre and fully transparent at 40%. Its strength is held at `0.06`, and it is drawn in dark themes only (6% white does not read on a light ground) and not at all in high contrast, so it casts a soft sheen without competing with the card's text. It fades in over 240ms when the pointer enters and out when it leaves.

## Damped Smoothing & Normal Map Illusion

To keep the highlight from jumping mechanically during rapid pointer travel, the light does not jump to the cursor; every frame it closes part of the gap:
$$\vec{P}_{\text{render}}(t) = \vec{P}_{\text{render}}(t-1) + \alpha' \cdot \left(\vec{P}_{\text{cursor}}(t) - \vec{P}_{\text{render}}(t-1)\right), \qquad \alpha' = 1 - (1 - \alpha)^{\Delta}$$
α = 0.18 is the share one 60Hz frame closes, and Δ is the frame interval divided by 16.67ms (clamped to 0.1–2). Compounded over Δ, the light travels on a 120Hz or 144Hz display as it does at 60Hz; worked out at 60Hz, a jump is 95% covered after 16 frames (about 267ms). When the pointer enters the card the light starts right under it, rather than sliding over from where it last went out; with reduce motion on, the light always jumps straight to the cursor and does not fade.

As the highlight glances off the card's 1px boundary, the ring the border occupies draws a second, tighter and brighter light, 240px with 30% white at its centre, cut down to the border by `mask-composite: exclude`; it creates the optical illusion of light grazing a physical bevel (Normal Map Illusion), heightening spatial depth. Only the solid border of a `solid` card draws this ring: a `dashed` border would light up its gaps along with its dashes, so it draws none, and a `plain` card has no border.

:::TuffDemoWrapper{demo="ConceptCardSpecularDemo"}
:::

## Refraction Light Follow

A second light that follows the pointer belongs to the refraction material itself. `TxCard`'s refraction light follow is off by default and works only with `background="refraction"` and `refraction-light-follow-mouse` turned on:

- **Normalized Coordinates**: as the pointer moves over the card, the component converts its position to 0–1 coordinates within the card and uses them as the light's target; when the pointer leaves, the target returns to the centre (0.5, 0.5).
- **Moving the Refraction's Light Point**: the light point goes through `TxBaseSurface`'s `refraction-light-x/y` into `--tx-surface-refraction-light-x/y`, which places several radial glows on the refraction's filter and tint layers, one of them at the mirrored point in the opposite corner. This path adds no white highlight of its own; that is `specular`, above.
- **Strength and Angle Follow the Pointer**: the farther the light is from the centre, the more refraction strength it adds, up to 16 × `refraction-light-follow-intensity` (0.45 by default, so at most +7.2); the refraction angle is interpolated toward the pointer by the same factor.

## Spring Smoothing

To keep the light from jumping mechanically when the pointer moves fast, the light point does not jump to the target; a spring integrated every frame carries it there:
$$v \leftarrow \left(v + k\,(P_{\text{target}} - P)\,\Delta\right) c^{\Delta}, \qquad P \leftarrow \operatorname{clamp}(P + v\,\Delta,\ 0,\ 1)$$
k is `refraction-light-spring-stiffness` (0.15 by default, clamped to 0.01–0.55), c is `refraction-light-spring-damping` (0.6 by default, clamped to 0.55–0.99), and Δ is the frame interval divided by 16.67ms (clamped to 0.1–2, and 1 on the first frame). Once both the remaining distance and the velocity are below 0.002 the light counts as settled and the loop stops. With `refraction-light-spring` off, the light point jumps straight to the target. Worked out at 60Hz, a jump at the defaults swings past the target by only about 3% and stays within 5% after about 130ms. The position step takes Δ too, so on a 120Hz or 144Hz display the light moves much as it does at 60Hz.

:::TuffDemoWrapper{demo="ConceptSpecularLightDemo"}
:::
