Skip to content

Electron 43, NixOS packaging, Figma Motion export fix - #43

Merged
arximus88 merged 14 commits into
stagingfrom
workspace
Aug 6, 2026
Merged

Electron 43, NixOS packaging, Figma Motion export fix#43
arximus88 merged 14 commits into
stagingfrom
workspace

Conversation

@arximus88

Copy link
Copy Markdown
Owner

Collected work from workspace. Every item below was verified on a running build, not just compiled.

Electron 43.3.0

The project was pinned to 42.0.1 because 42.3.0 broke /app_auth/redeem — Figma rejected that Chromium roll's request headers and returned login HTML instead of Set-Cookie, killing first-login and add-account.

Verified against the bundled binary from node_modules (Chromium 150.0.7871.212), which is what electron-builder ships — a distro Electron would not have proven anything, since those are rebuilt from source without the same closed-source components:

  • first login on clean storage completes; figma.auth_id lands 8s after the redeem redirect
  • the session survives restarts
  • image paste still correct after 43's sRGB normalisation in nativeImage.toBitmap()
  • frameless window decorations unchanged despite 43's rounded-corners default on Linux CSD

Also brings three months of Chromium security fixes, a faster boot (startup snapshot for main, bytecode-cached preloads) and a newer WebGPU stack.

NixOS support

Flake from @iamcalledrob (#42), reworked so version and both platform hashes live in one release block that CI rewrites as a unit after each release — the hashes only exist once the binaries are built, so this cannot be part of bump_version.pl.

The new flake job pushes the pinned flake to dev first (where Nix resolves the input from) and mirrors it to staging, using RELEASE_PAT because GITHUB_TOKEN cannot push to a protected branch.

Figma Motion export queue (#41)

"Export video" opened figma.com/export/<key> in the system browser, which always showed an empty queue — the queue lives in the app's session. /export/ is now a recognised in-app path with its own tab dedup key, so repeated exports reuse the tab instead of stacking or hijacking the design tab.

Also

  • WebGPU now follows the enableWebGPU toggle on X11 instead of being forced on for every X11 session
  • AUR PKGBUILD license is rewritten from package.json each release (was hardcoded MIT, project is GPL-2.0-only)
  • doc corrections across CLAUDE.md, the build skill and README.md

Checks

bun test 213 pass · tsc --noEmit clean · biome check clean · svelte-check 0 errors

Known follow-up, not in this PR

Electron 44 removes the clipboard module from the renderer process. src/renderer/DesktopAPI/webBinding.ts uses it in eight places, and the AUR figma-linux-next package depends on the floating electron meta-package — so it will move to 44 on its own. Either pin electron43 there or move clipboard reads into main before 44 lands.

arximus88 and others added 14 commits June 26, 2026 13:33
chore(release): v0.15.0
enable-unsafe-webgpu was applied on any X11 session (!isWayland),
leaving WebGPU silently ON for X11 users who had the enableWebGPU
toggle OFF — contradicting the setting. Figma probes navigator.gpu
(exposed by enable-unsafe-webgpu) to switch on its Shader/Halftone/
Noise effects, so the flag belongs behind the toggle alongside the
shaders.

Now gate it on shadersActive (X11 + enableWebGPU) with the existing
userForcesVulkan escape hatch preserved. Only the X11 + toggle-off
quadrant changes; X11/Wayland toggle-on and Wayland toggle-off are
unaffected. The change is scoped to WebGPU only — ignore-gpu-blocklist
and enable-webgl stay on X11, so the normal WebGL canvas keeps its
hardware acceleration; a toggle-off X11 user loses only the shader
effects.

Update the truth-table tests to lock all four quadrants.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QWRSUEUKBsLy4paZR4noBb
"Export video" calls window.open("https://www.figma.com/export/<fileKey>?fuid=…").
/export/ was missing from isFigmaRunUrl's validPaths, so the URL fell through to
shell.openExternal and landed in the system browser — where the render queue is
always empty, because it lives in the app's session. Logging in there does not
help, as reported in #41.

- add /^\/export\// to validPaths so the queue opens as an in-app tab
- give export tabs their own dedup prefix (export:<key>), so a repeated
  "Export video" click reuses the queue tab and cannot collide with the
  design tab for the same file
- log every window.open with url/frameName/disposition/features — Tab had no
  logging at all here, which is why this took a live capture to find
- route only http(s) to shell.openExternal; other schemes were passed through
  as a silent no-op and are now logged as blocked

Verified against a live capture: the export URL above, and the Linear plugin's
OAuth (response_type=stringauth, redirect_uri=figma-plugin.linear.app/callback),
which completes in the browser and returns through Linear's own callback.

Refs #41
The flake read its version from package.json but carried hard-coded sha256
hashes, so every `perl scripts/bump_version.pl` left it naming a release whose
binaries it could not hash — `nix build` then failed on a hash mismatch until
someone recomputed both by hand. The PR shipped with a "Chore: update hashes
when release binaries change" comment; this replaces the comment with the
mechanism.

- flake.nix: version and both hashes live in one `release` block, so they are
  rewritten as a unit and cannot drift
- scripts/update_flake_release.py: rewrites that block, converting sha256sum
  hex digests to the SRI form Nix expects; fails loudly if the layout moved
- release.yml: new `flake` job hashes both release zips after the release is
  published and commits the pinned flake to staging (dev is protected, so the
  flake there trails by one release)
- README: note that the flake installs prebuilt binaries and how to pin a tag
- CLAUDE.md, build skill: document that flake.nix is CI-owned, never bumped
  by hand

Not verified with `nix build` — no Nix on this machine.

Follow-up to #42
Nix resolves `github:arximus88/figma-linux-next` from the default branch, which
is dev. Committing the release hashes only to staging meant NixOS installed
whatever dev still named — always the previous release, since staging reaches
dev with the next release PR.

The flake job now checks out dev with RELEASE_PAT (fine-grained, Contents:write
on this repo only) and pushes there first, then mirrors the same change to
staging. The default GITHUB_TOKEN cannot do this: it is refused by the branch
protection on dev.

The job still runs last and depends on `release`, so a rejected push leaves the
release, its binaries and both AUR packages already published — the only
casualty is the flake update, and the failure is visible in the run.

Token expiry (2027-08-05) is recorded in CLAUDE.md and the build skill, because
a 403 on that push is the sole symptom and would otherwise be a blind diagnosis.
The gemini-cli copy under .agent was byte-identical to the global
~/.claude/skills/gemini-cli. The .gemini skills duplicated capabilities
already available (frontend-design, the Figma MCP workflows, generic
refactoring smells) or contradicted this project: electron-app-planning
prescribes raw ipcMain.handle and electron-updater, neither of which
applies here. .gemini/settings.json listed the same MCP servers as
.mcp.json plus figma-remote.

One item survives as a CLAUDE.md note instead of a file:
`bunx @sveltejs/mcp svelte-autofixer <file>` catches Svelte 5 rune
antipatterns that svelte-check misses, which matters because Biome
does not lint .svelte.

The gitignore "Agents" block matched only .gemini/settings.*, so the
skills stayed tracked despite it; widened to .gemini and dropped the
duplicate .agent/skills entry.
… Nix section

The Nix material was already current — the skill was written alongside
358ada0/75b23e4. Verifying it line by line against release.yml,
update_flake_release.py and flake.nix surfaced five other divergences:

- The release checklist pushed the tag together with the branch, ahead of
  the PR steps, contradicting the rule stated at the top of the same file.
  Following it literally would publish a release before dev was updated.
- push_aur_dev_git.yml was listed as an existing workflow; 3c3a762 deleted it.
- RELEASE_PAT was described in prose but missing from the secrets table,
  so its 2027-08-05 expiry was not where someone would look for it.
- The aur/aur-bin/flake pre-release guard from e011888 was undocumented:
  an -rc tag produces a GitHub Release and no AUR or flake update.
- Key Files listed no flake file at all — neither flake.nix nor
  scripts/update_flake_release.py.
CLAUDE.md:
- Critical Files pointed at src/utils/Render/frameConfig.ts and
  frameStyles.ts; neither exists. The icon/component config is
  frameTheme.ts and the frames themselves are Svelte components under
  src/renderer/Panel/frames/.
- Utils/Render/defaultSettings.ts was called the authoritative settings
  schema. It is a four-line re-export whose own comment calls itself a
  placeholder; the values live in Utils/Common/defaultSettings.ts as
  BASE_DEFAULT_SETTINGS. Documented all three same-named files so
  "add a new setting" lands in the right one.
- The path-alias example imported a symbol named `defaultSettings`,
  which nothing exports.
- FrameStyle was listed as three values; the union in
  src/types/Common/index.d.ts has four (kde was missing) and the
  default is gnome.
- ci.yml was described as PRs to dev; it runs on push and PR to both
  staging and dev.

README.md:
- The AppImage snippet globbed figma-linux-next-*.AppImage with a dash.
  electron-builder names artifacts ${name}_${version}_${platform}_${arch},
  so the glob matched nothing.
- The NixOS section set programs.figma-linux-next.enable without
  importing nixosModules.default, which fails evaluation with an
  undefined option.
Both AUR packages publish license=('MIT') while the project is
GPL-2.0-only — LICENSE is GNU GPL v2, and package.json, src/package.json
and flake.nix all say so. Verified against the live AUR RPC:
figma-linux-next 0.15.0-1 and figma-linux-next-bin both report
License: ["MIT"].

The line drifted because the aur and aur-bin jobs rewrite pkgver, pkgrel
and sha256sums and nothing else, so whatever license the AUR repo was
seeded with survived every release. Deriving it from package.json means
the two can no longer disagree; the value there is already an exact SPDX
identifier, so it drops into the PKGBUILD verbatim.

python3 is used rather than jq because the archlinux container installs
python and not jq.

Verified: actionlint clean, YAML parses, and the sed produces
license=('GPL-2.0-only') against a real PKGBUILD.
A clone under /home/arx/aur/ had drifted five releases behind live AUR
(0.13.1 vs 0.15.0) while still looking like a working copy. Pushing it
would have rolled both packages back, and CI would not have caught it —
each run clones whatever AUR currently holds and edits that in place.

Also records which fields CI rewrites (now including license) versus the
ones that only change by hand, and that AUR maintenance takes down the
SSH endpoint alone: push fails while the web UI and HTTPS git stay up.
The project sat on 42.0.1 because 42.3.0 broke `/app_auth/redeem` — Figma
rejected the request headers from that Chromium roll and returned login HTML
instead of Set-Cookie, killing first-login and add-account.

Verified against the bundled 43.3.0 binary (Chromium 150.0.7871.212), which is
what electron-builder ships: first login on clean storage completes, the
figma:// redeem redirect lands, and the session survives restarts. Image paste
and frameless window decorations also check out, covering the two behaviour
changes in 43 that touch us — sRGB normalisation in nativeImage.toBitmap() and
rounded corners on Linux CSD.

Chromium 148 -> 150 also brings three months of security fixes, a faster boot
(startup snapshot for main, bytecode-cached preloads) and a newer WebGPU stack.

CLAUDE.md now records how to run the OAuth test correctly: use the bundled
binary rather than a distro Electron, carry mimeapps.list into the isolated
config, and shadow the installed .desktop so the redirect comes back.
@arximus88
arximus88 merged commit fba22d3 into staging Aug 6, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants