- A catalogue of what can be chosen: no effect, blur, and two shipped
backgrounds, the app's own gradients flattened onto its canvas colour.
Their ids are what a saved choice stores, so they are named for the
pictures.
- One setting for the choice, typed as the ids an effect can have and
defaulting to blur for anyone who had it on. A stored value we no
longer ship, or one that isn't even a string, reads as no effect: it
comes from storage another build or a hand may have written.
- The pipeline follows it, switching in place to a picture as readily as
to blur, and the camera menu's blur toggle reads and writes it.
- So does Settings' blur checkbox: a picture reads as blur off, and
checking it replaces the picture with blur. The old on/off setting is
only read, to carry blur over. First tests for the Settings modal,
which fail with the checkbox on the old setting.
- The transformer's own init loads a picture chosen before it was built,
as the base init does and it had not: the first effect always is, and
the picture was drawn black.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Brings design's blur icon, which the background effects grid uses.
- Of the icons the release redrew, guest and zoom-in, Element Call uses
neither, and none of the icons it removed are used here.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- AppViewModel creates them, next to its media devices, as review asked;
BackgroundEffectsProvider takes them as a prop rather than building
them in an effect.
- The component build, which has no AppViewModel of its own, now makes one
in the effect that made its media devices, so both builds get their
state the same way.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The pipeline's switches run through reconcile, which already runs them
one at a time and skips those overtaken, in place of a queue of our own.
- A failed switch is logged and the next still runs, now tested.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- BackgroundEffects is an interface, built by createBackgroundEffects,
following the convention for state holders, as review asked.
- Same behaviour: the body moves from the constructor unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- One name, as review asked: TrackProcessorContext becomes
BackgroundEffectsContext, with BackgroundEffectsProvider,
BackgroundEffectsState, useBackgroundEffects,
useBackgroundEffectsState$ and useSyncBackgroundEffects.
- The state's Behavior is backgroundEffectsState$ wherever it is passed,
in place of trackProcessorState$, trackerProcessorState$ and
processorState$.
- Renames only: nothing changes in behaviour.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The one support check asks for a desktop again, as #4059 had the
pipeline do: menu and pipeline still agree, so a phone is neither
offered blur nor refused it.
- Lifting it moves to the PR that tells the user where effects run
slowly, so it is their choice to make.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The Vite transform wrapper takes Vite's own types, with no cast.
- The pipeline's options are compared with deepCompare, not as JSON.
- Renames `attached` to `enable` and shortens the pipeline's doc comment.
- Drops a comment that blamed an ended track on the pipeline's queue.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The menu asked the browser; the pipeline asked the browser and for a
desktop. On a phone whose browser can run them, blur was offered and
then refused: the toggle moved and the video did not change.
- Both now ask one function, and it asks the browser alone. The platform
was the wrong measure: a phone on the fast route held 99% of its frame
rate and was refused, a desktop on the slow one held 73% and was
allowed.
- The in-call device switcher is still withheld on a phone; that is the
device menu's own rule and is unchanged.
- The provider tests run as a phone, and fail with the desktop test back.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- One pipeline, shared by the pre-join preview and the call, attached the
first time an effect is wanted and never detached after; turning blur
off switches it to a disabled mode in place. Main dropped the processor
whenever blur went off, and a pipeline taken off the camera is destroyed
and re-primed, so each time blur came back one unprocessed frame went
out. Built once, the priming frame is spent once.
- Still driven by the existing blur setting: nothing a user sees changes.
- Its logic is BackgroundEffects in src/state/, which the provider only
builds, so the tests drive it without rendering anything.
- Disabled drops the blur radius too. The SDK's disabled mode keeps it,
and with a radius every frame is still segmented and thrown away; with
neither a radius nor a picture, frames pass untouched.
- Switches run one at a time and skip any overtaken, so an earlier,
slower switch can't land after a later choice.
- Builds, rebuilds and teardowns of the pipeline run one at a time
(OneStepPipeline). The preview's and the call's tracks attach and stop
it independently, and the SDK's wrapper holds one track's streams: two
builds at once overwrite each other's, and a stop during a build does
nothing.
- Every camera track starts with the pipeline on: the room's capture
defaults follow it, and a camera turned off before the first effect is
replaced on turning it on, since a stopped track can't take one. One
attached after publishing lets the room through while it is built.
- BlurBackgroundTransformer becomes BackgroundEffectTransformer: it also
sits disabled, and its init applies that state as the SDK's would.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- nodePolyfills rewrites any module that mentions process, and MediaPipe's
WASM loader does. The loader is a classic script that sets
self.ModuleFactory; as a module it sets nothing, so under pnpm dev the
segmenter failed with "ModuleFactory not set". Blur on main fails the
same way there. Production is unaffected: the loader ships as a static
asset.
- The plugin's transform now skips that loader. Checked with main's own
BlurBackgroundTransformer: it initialises with this and fails without.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- Compound 10.3.0 bounds a menu by the space it has and scrolls what
doesn't fit, within a boundary the app passes. The menus pass the call
area, 16px in from its sides, rather than measuring its width.
- The 296px width is the menu's own style. Compound gives that style only
to the dropdown, so menuIsDrawer, which copied its phone rule, goes.
- Compound draws the menu's frame over its content, so nothing that
scrolls can hide it in Safari: the list, headings and meter no longer
keep a border width clear of it, and the checks that they did go.
- The device list is Compound's scroll area, so it fades out at the
foot with Compound's chevron while there is more below.
- The microphone menu's meter sticks at that foot, with rows scrolling
under it as before, so the list has no fade above it: Compound's is a
mask fixed to the list's edge, while a bounce at the top carries the
meter with the rows. The band under the meter is filled, or rows would
show there. The edge fades from where the chevron starts, so a bounce
fades the meter out before it reaches the chevron. A row reached by
keyboard stays above the meter.
- The list's height is still its share of the call.
- The component harness leaves the host's stylesheets unscoped, Compound's
among them, as a host does: scoped, they never reached the menu, which is
portalled out of Element Call's root.
- Its specs check only Element Call's own document styles on the host
page, and find the device list within Compound's scroll area.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- The camera and microphone menus were as wide as their longest device
name, so a long one widened the menu over more of the call: 340px for a
long speaker name. Both are now 296px, as design sets them, and a long
name wraps.
- Narrower only where the call area is, so the menu still fits inside it:
268px in a 300px call. Taken from the observation of the call area that
already bounds the list's height.
- Held only for the dropdown. On Android and iOS Compound renders the menu
as a drawer as wide as the screen; menuIsDrawer follows its rule.
- Once the list is long enough to scroll, Safari paints it above the
outline the menu is framed with, and the frame vanished down both sides
of it: 384px of it on the many-devices microphone menu, in WebKit. The
list now keeps a border width clear of the frame, so the headings and
the meter inside it no longer need their own.
- Guarded with a long speaker name, which fails at 340px on main's sizing;
a unit test run as a phone, which fails with the width held there; and
the many-devices story's inset, which fails on the old stylesheet, since
the stories run in Chromium, which never showed the Safari bug.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
I learned that makeKeyDelay has been deprecated in matrix-js-sdk ever since the switch to the new encryption manager, so this config option has no effect.