diff --git a/.branding b/.branding
index 2c4bb8aab9..1e29c19dff 100644
--- a/.branding
+++ b/.branding
@@ -1,2 +1,2 @@
-https://github.com/Keavon/graphite-branded-assets/archive/f8b02e68c92f5bbd27626bdd7a51102303b70a40.tar.gz
-d06fd7b79fa9b7509c23072fa56745415fdc6eb98575d15214b0acc47ea4dd42
+https://github.com/Keavon/graphite-branded-assets/archive/8ae15dc9c51a3855475d8cab1d0f29d9d9bc622c.tar.gz
+c19abe4ac848f3c835e43dc065c59e20e60233ae023ea0a064c5fed442be2d3d
diff --git a/.envrc b/.envrc
index 930f30ba2a..3550a30f2d 100644
--- a/.envrc
+++ b/.envrc
@@ -1 +1 @@
-use flake .nix
+use flake
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
index 4662c5521a..b758bce647 100644
--- a/.github/pull_request_template.md
+++ b/.github/pull_request_template.md
@@ -1,3 +1,13 @@
-
+
diff --git a/.github/workflows/build-linux-bundle.yml b/.github/workflows/build-linux-bundle.yml
new file mode 100644
index 0000000000..d5584f3542
--- /dev/null
+++ b/.github/workflows/build-linux-bundle.yml
@@ -0,0 +1,75 @@
+name: Build Linux Bundle
+
+on:
+ push:
+ branches:
+ - master
+ workflow_dispatch:
+ inputs:
+ push_to_cache:
+ description: "Push to Nix Cache"
+ required: false
+ type: boolean
+ default: false
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/nix-installer-action@main
+
+ - name: Free disk space
+ run: sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache
+
+ - name: Build Nix Package
+ run: nix build --no-link --print-out-paths
+
+ - name: Push to Nix Cache
+ if: github.ref == 'refs/heads/master' || inputs.push_to_cache == true
+ env:
+ NIX_CACHE_AUTH_TOKEN: ${{ secrets.NIX_CACHE_AUTH_TOKEN }}
+ run: |
+ nix run nixpkgs#cachix -- authtoken $NIX_CACHE_AUTH_TOKEN
+ nix build --no-link --print-out-paths | nix run nixpkgs#cachix -- push graphite
+
+ - name: Build Linux Bundle
+ run: nix build .#graphite-bundle.tar.xz && cp ./result ./graphite-linux-bundle.tar.xz
+
+ - name: Upload Linux Bundle
+ uses: actions/upload-artifact@v4
+ with:
+ name: graphite-linux-bundle
+ path: graphite-linux-bundle.tar.xz
+ compression-level: 0
+
+ - name: Setup Flatpak Tooling
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y flatpak flatpak-builder
+ flatpak --user remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo
+
+ - name: Build Flatpak
+ run: |
+ nix build .#graphite-flatpak-manifest
+
+ rm -rf .flatpak
+ mkdir -p .flatpak
+
+ cp ./result .flatpak/manifest.json
+
+ cd .flatpak
+ mkdir -p repo
+
+ flatpak-builder --user --force-clean --install-deps-from=flathub --repo=repo build ./manifest.json
+
+ flatpak build-bundle repo Graphite.flatpak art.graphite.Graphite --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo
+
+ - name: Upload Flatpak
+ uses: actions/upload-artifact@v4
+ with:
+ name: graphite-flatpak
+ path: .flatpak/Graphite.flatpak
+ compression-level: 0
diff --git a/.github/workflows/build-mac-bundle.yml b/.github/workflows/build-mac-bundle.yml
new file mode 100644
index 0000000000..b11eba7954
--- /dev/null
+++ b/.github/workflows/build-mac-bundle.yml
@@ -0,0 +1,157 @@
+name: Build Mac Bundle
+
+on:
+ workflow_dispatch: {}
+ push:
+ branches:
+ - master
+
+jobs:
+ build:
+ runs-on: macos-latest
+
+ env:
+ WASM_BINDGEN_CLI_VERSION: "0.2.100"
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Rust
+ uses: actions-rust-lang/setup-rust-toolchain@v1
+ with:
+ toolchain: stable
+ override: true
+ rustflags: ""
+ target: wasm32-unknown-unknown
+
+ - name: Cache Cargo
+ uses: actions/cache@v4
+ with:
+ path: |
+ ~/.cargo/registry
+ ~/.cargo/git
+ target
+ key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: .nvmrc
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ frontend/package-lock.json
+
+ - name: Install Native Dependencies
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ BINSTALL_DISABLE_TELEMETRY: "true"
+ run: |
+ brew update
+ brew install \
+ pkg-config \
+ openssl@3 \
+ binaryen \
+ llvm \
+ cargo-binstall
+
+ echo "OPENSSL_DIR=$(brew --prefix openssl@3)" >> $GITHUB_ENV
+ echo "PKG_CONFIG_PATH=$(brew --prefix openssl@3)/lib/pkgconfig" >> $GITHUB_ENV
+ echo "$(brew --prefix llvm)/bin" >> $GITHUB_PATH
+
+ cargo binstall --no-confirm --force wasm-pack
+ cargo binstall --no-confirm --force cargo-about
+ cargo binstall --no-confirm --force "wasm-bindgen-cli@${WASM_BINDGEN_CLI_VERSION}"
+
+ - name: Build Mac Bundle
+ env:
+ CARGO_TERM_COLOR: always
+ run: cargo run build desktop
+
+ - name: Stage Artifacts
+ shell: bash
+ run: |
+ rm -rf target/artifacts
+ mkdir -p target/artifacts
+ cp -R target/release/Graphite.app target/artifacts/Graphite.app
+
+ - name: Upload Mac Bundle
+ uses: actions/upload-artifact@v4
+ with:
+ name: graphite-mac-bundle
+ path: target/artifacts
+
+ - name: Sign and Notarize Mac Bundle Preparation
+ if: github.ref == 'refs/heads/master'
+ env:
+ APPLE_CERT_BASE64: ${{ secrets.APPLE_CERT_BASE64 }}
+ APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }}
+ run: |
+ mkdir -p .sign
+ echo "$APPLE_CERT_BASE64" | base64 --decode > .sign/certificate.p12
+
+ security create-keychain -p "" .sign/main.keychain
+ security default-keychain -s .sign/main.keychain
+ security unlock-keychain -p "" .sign/main.keychain
+ security set-keychain-settings -t 3600 -u .sign/main.keychain
+
+ security import .sign/certificate.p12 -k .sign/main.keychain -P "$APPLE_CERT_PASSWORD" -T /usr/bin/codesign -T /usr/bin/productsign
+ security set-key-partition-list -S apple-tool:,apple: -s -k "" .sign/main.keychain
+
+ cat > .sign/entitlements.plist <<'EOF'
+
+
+
+
+ com.apple.security.cs.allow-jit
+
+ com.apple.security.cs.allow-unsigned-executable-memory
+
+ com.apple.security.cs.disable-executable-page-protection
+
+ com.apple.security.cs.disable-library-validation
+
+
+
+ EOF
+
+ - name: Sign and Notarize Mac Bundle
+ if: github.ref == 'refs/heads/master'
+ env:
+ APPLE_EMAIL: ${{ secrets.APPLE_EMAIL }}
+ APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
+ APPLE_PASSWORD: ${{ secrets.APPLE_PASSWORD }}
+ APPLE_CERT_NAME: ${{ secrets.APPLE_CERT_NAME }}
+ run: |
+ CERTIFICATE="$APPLE_CERT_NAME"
+ ENTITLEMENTS=".sign/entitlements.plist"
+ APP_PATH="target/artifacts/Graphite.app"
+ ZIP_PATH=".sign/Graphite.zip"
+
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Graphite Helper.app"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Graphite Helper (GPU).app"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Graphite Helper (Renderer).app"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Chromium Embedded Framework.framework"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libcef_sandbox.dylib"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libEGL.dylib"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libGLESv2.dylib"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH/Contents/Frameworks/Chromium Embedded Framework.framework/Libraries/libvk_swiftshader.dylib"
+ codesign --force --options runtime --entitlements "$ENTITLEMENTS" --sign "$CERTIFICATE" "$APP_PATH" --deep
+
+ codesign --verify --deep --strict --verbose=4 "$APP_PATH"
+
+ ditto -c -k --keepParent "$APP_PATH" "$ZIP_PATH"
+ xcrun notarytool submit "$ZIP_PATH" --wait --apple-id "$APPLE_EMAIL" --team-id "$APPLE_TEAM_ID" --password "$APPLE_PASSWORD"
+ rm "$ZIP_PATH"
+
+ xcrun stapler staple -v "$APP_PATH"
+
+ spctl -a -vv "$APP_PATH"
+
+ - name: Upload Mac Bundle Signed
+ if: github.ref == 'refs/heads/master'
+ uses: actions/upload-artifact@v4
+ with:
+ name: graphite-mac-bundle-signed
+ path: target/artifacts
diff --git a/.github/workflows/build-nix-package.yml b/.github/workflows/build-nix-package.yml
index 2da86b2d34..45669d0309 100644
--- a/.github/workflows/build-nix-package.yml
+++ b/.github/workflows/build-nix-package.yml
@@ -14,4 +14,4 @@ jobs:
- uses: DeterminateSystems/magic-nix-cache-action@main
- name: Build Nix Package Dev
- run: nix build .nix#graphite-dev --print-build-logs
+ run: nix build .#graphite-dev --print-build-logs
diff --git a/.github/workflows/build-production.yml b/.github/workflows/build-production.yml
index 1be2e3e947..eae2aca9c6 100644
--- a/.github/workflows/build-production.yml
+++ b/.github/workflows/build-production.yml
@@ -52,9 +52,7 @@ jobs:
- name: ๐ Build Graphite web code
env:
NODE_ENV: production
- run: |
- cd frontend
- mold -run npm run build
+ run: mold -run cargo run build web
- name: ๐ค Publish to Cloudflare Pages
id: cloudflare
diff --git a/.github/workflows/build-win-bundle.yml b/.github/workflows/build-win-bundle.yml
new file mode 100644
index 0000000000..720bdb63a7
--- /dev/null
+++ b/.github/workflows/build-win-bundle.yml
@@ -0,0 +1,173 @@
+name: Build Windows Bundle
+
+on:
+ workflow_dispatch: {}
+ push:
+ branches:
+ - master
+
+permissions:
+ contents: read
+ id-token: write
+
+jobs:
+ build:
+ runs-on: windows-latest
+
+ env:
+ WASM_BINDGEN_CLI_VERSION: "0.2.100"
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Setup Rust
+ uses: actions-rust-lang/setup-rust-toolchain@v1
+ with:
+ toolchain: stable
+ override: true
+ rustflags: ""
+ target: wasm32-unknown-unknown
+
+ - name: Cache Cargo
+ uses: actions/cache@v4
+ with:
+ path: |
+ ${{ env.USERPROFILE }}\.cargo\registry
+ ${{ env.USERPROFILE }}\.cargo\git
+ target
+ key: cargo-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }}
+
+ - name: Setup Node
+ uses: actions/setup-node@v4
+ with:
+ node-version-file: .nvmrc
+ cache: npm
+ cache-dependency-path: |
+ package-lock.json
+ frontend/package-lock.json
+
+ - name: Setup Cargo Binstall
+ uses: cargo-bins/cargo-binstall@main
+
+ - name: Install Native Dependencies
+ shell: pwsh
+ env:
+ GITHUB_TOKEN: ${{ github.token }}
+ BINSTALL_DISABLE_TELEMETRY: "true"
+ run: |
+ winget install --id LLVM.LLVM -e --accept-package-agreements --accept-source-agreements
+ winget install --id Kitware.CMake -e --accept-package-agreements --accept-source-agreements
+ winget install --id OpenSSL.OpenSSL -e --accept-package-agreements --accept-source-agreements
+ winget install --id WebAssembly.Binaryen -e --accept-package-agreements --accept-source-agreements
+ winget install --id GnuWin32.PkgConfig -e --accept-package-agreements --accept-source-agreements
+
+ "OPENSSL_DIR=C:\Program Files\OpenSSL-Win64" | Out-File -FilePath $env:GITHUB_ENV -Append
+ "PKG_CONFIG_PATH=C:\Program Files\OpenSSL-Win64\lib\pkgconfig" | Out-File -FilePath $env:GITHUB_ENV -Append
+
+ cargo binstall --no-confirm --force wasm-pack
+ cargo binstall --no-confirm --force cargo-about
+ cargo binstall --no-confirm --force "wasm-bindgen-cli@$env:WASM_BINDGEN_CLI_VERSION"
+
+ - name: Build Windows Bundle
+ shell: bash # `cargo-about` refuses to run in powershell
+ env:
+ CARGO_TERM_COLOR: always
+ run: cargo run build desktop
+
+ - name: Stage Artifacts
+ shell: bash
+ run: |
+ rm -rf target/artifacts
+ mkdir -p target/artifacts
+ cp -R target/release/Graphite target/artifacts/Graphite
+
+ - name: Upload Windows Bundle
+ uses: actions/upload-artifact@v4
+ with:
+ name: graphite-windows-bundle
+ path: target/artifacts
+
+ - name: Azure login
+ if: github.ref == 'refs/heads/master'
+ uses: azure/login@v1
+ with:
+ client-id: ${{ secrets.AZURE_CLIENT_ID }}
+ tenant-id: ${{ secrets.AZURE_TENANT_ID }}
+ subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}
+ enable-AzPSSession: true
+
+ - name: Sign
+ if: github.ref == 'refs/heads/master'
+ uses: azure/artifact-signing-action@v1
+ with:
+ endpoint: https://eus.codesigning.azure.net/
+ signing-account-name: Graphite
+ certificate-profile-name: Graphite
+ files: |
+ ${{ github.workspace }}\target\artifacts\Graphite\Graphite.exe
+ ${{ github.workspace }}\target\artifacts\Graphite\libcef.dll
+ ${{ github.workspace }}\target\artifacts\Graphite\chrome_elf.dll
+ ${{ github.workspace }}\target\artifacts\Graphite\vulkan-1.dll
+ ${{ github.workspace }}\target\artifacts\Graphite\dxcompiler.dll
+ ${{ github.workspace }}\target\artifacts\Graphite\libEGL.dll
+ ${{ github.workspace }}\target\artifacts\Graphite\libGLESv2.dll
+ ${{ github.workspace }}\target\artifacts\Graphite\vk_swiftshader.dll
+ file-digest: SHA256
+ timestamp-rfc3161: http://timestamp.acs.microsoft.com
+ timestamp-digest: SHA256
+ correlation-id: ${{ github.sha }}
+
+ - name: Verify Signatures
+ if: github.ref == 'refs/heads/master'
+ shell: pwsh
+ run: |
+ $ErrorActionPreference = "Stop"
+
+ $TargetDir = "target\artifacts\Graphite"
+
+ if (-not (Test-Path $TargetDir)) {
+ throw "TargetDir not found: $TargetDir"
+ }
+
+ $UnsignedOrBad = @()
+
+ Get-ChildItem -Path $TargetDir -Recurse -File -Include *.exe,*.dll | ForEach-Object {
+ $sig = Get-AuthenticodeSignature -FilePath $_.FullName
+
+ if ($sig.Status -ne 'Valid') {
+ $UnsignedOrBad += "$($_.FullName) (Status=$($sig.Status))"
+ }
+ }
+
+ if ($UnsignedOrBad.Count -gt 0) {
+ Write-Host "Unsigned or invalid binaries detected:"
+ $UnsignedOrBad | ForEach-Object {
+ Write-Host "::error::$_"
+ }
+
+ if ($env:GITHUB_STEP_SUMMARY) {
+ "### โ Unsigned or invalid binaries detected" |
+ Out-File $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
+ "" | Out-File $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
+ $UnsignedOrBad | ForEach-Object {
+ "* `$_" | Out-File $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
+ }
+ }
+
+ exit 1
+ }
+
+ Write-Host "All binaries are signed and valid."
+
+ if ($env:GITHUB_STEP_SUMMARY) {
+ "### โ
All binaries are signed and valid" |
+ Out-File $env:GITHUB_STEP_SUMMARY -Append -Encoding utf8
+ }
+
+ - name: Upload Windows Bundle Signed
+ if: github.ref == 'refs/heads/master'
+ uses: actions/upload-artifact@v4
+ with:
+ name: graphite-windows-bundle-signed
+ path: target/artifacts
diff --git a/.github/workflows/cargo-deny.yml b/.github/workflows/cargo-deny.yml
index 47712103fa..4710c15554 100644
--- a/.github/workflows/cargo-deny.yml
+++ b/.github/workflows/cargo-deny.yml
@@ -7,6 +7,7 @@ on:
jobs:
cargo-deny:
+ if: github.repository == 'GraphiteEditor/Graphite' # Don't run on forks by default
runs-on: ubuntu-latest
steps:
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000000..4985abfe20
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,153 @@
+name: "CI"
+
+on:
+ pull_request: {}
+ merge_group: {}
+
+env:
+ CARGO_TERM_COLOR: always
+
+jobs:
+ # Rust format check on GitHub runner
+ rust-fmt:
+ runs-on: ubuntu-latest
+ steps:
+ - name: ๐ฅ Clone and checkout repository
+ uses: actions/checkout@v3
+
+ - name: ๐ฆ Check if CI can be skipped
+ id: skip-check
+ uses: cariad-tech/merge-queue-ci-skipper@main
+
+ - name: ๐ฆ Install the latest Rust
+ if: steps.skip-check.outputs.skip-check != 'true'
+ uses: dtolnay/rust-toolchain@stable
+ with:
+ components: rustfmt
+
+ - name: ๐ฌ Check Rust formatting
+ if: steps.skip-check.outputs.skip-check != 'true'
+ run: cargo fmt --all -- --check
+
+ # License compatibility check on GitHub runner
+ cargo-deny:
+ runs-on: ubuntu-latest
+ steps:
+ - name: ๐ฅ Clone and checkout repository
+ uses: actions/checkout@v3
+
+ - name: ๐ Check crate license compatibility for root workspace
+ uses: EmbarkStudios/cargo-deny-action@v2
+ with:
+ command: check bans licenses sources
+
+ - name: ๐ Check crate license compatibility for /libraries/rawkit
+ uses: EmbarkStudios/cargo-deny-action@v2
+ with:
+ command: check bans licenses sources
+ manifest-path: libraries/rawkit/Cargo.toml
+
+ # Build the web app on the self-hosted wasm runner
+ build:
+ runs-on: [self-hosted, target/wasm]
+ permissions:
+ contents: write
+ deployments: write
+ pull-requests: write
+ actions: write
+ env:
+ RUSTC_WRAPPER: /usr/bin/sccache
+ CARGO_INCREMENTAL: 0
+ SCCACHE_DIR: /var/lib/github-actions/.cache
+
+ steps:
+ - name: ๐ฅ Clone and checkout repository
+ uses: actions/checkout@v3
+
+ - name: ๐ฆ Check if CI can be skipped
+ id: skip-check
+ uses: cariad-tech/merge-queue-ci-skipper@main
+
+ - name: ๐ Clear wasm-bindgen cache
+ if: steps.skip-check.outputs.skip-check != 'true'
+ run: rm -r ~/.cache/.wasm-pack || true
+
+ - name: ๐ข Install the latest Node.js
+ if: steps.skip-check.outputs.skip-check != 'true'
+ uses: actions/setup-node@v4
+ with:
+ node-version: "latest"
+
+ - name: ๐ง Install build dependencies
+ if: steps.skip-check.outputs.skip-check != 'true'
+ run: |
+ cd frontend
+ npm run setup
+
+ - name: ๐ฆ Install the latest Rust
+ if: steps.skip-check.outputs.skip-check != 'true'
+ run: |
+ rustup update stable
+
+ - name: ๐ฆ Fetch Rust dependencies
+ if: steps.skip-check.outputs.skip-check != 'true'
+ run: |
+ cargo fetch --locked
+
+ - name: ๐ Build Graphite web code
+ if: steps.skip-check.outputs.skip-check != 'true'
+ env:
+ NODE_ENV: production
+ run: mold -run cargo run build web
+
+ - name: ๐ค Publish to Cloudflare Pages
+ if: steps.skip-check.outputs.skip-check != 'true'
+ uses: cloudflare/pages-action@1
+ continue-on-error: true
+ with:
+ apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+ accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
+ gitHubToken: ${{ secrets.GITHUB_TOKEN }}
+ projectName: graphite-dev
+ directory: frontend/dist
+
+ - name: ๐ Lint Graphite web formatting
+ if: steps.skip-check.outputs.skip-check != 'true'
+ env:
+ NODE_ENV: production
+ run: |
+ cd frontend
+ npm run lint
+
+ # Run the Rust tests on the self-hosted native runner
+ test:
+ runs-on: [self-hosted, target/native]
+ env:
+ RUSTC_WRAPPER: /usr/bin/sccache
+ CARGO_INCREMENTAL: 0
+ SCCACHE_DIR: /var/lib/github-actions/.cache
+
+ steps:
+ - name: ๐ฅ Clone and checkout repository
+ uses: actions/checkout@v3
+
+ - name: ๐ฆ Check if CI can be skipped
+ id: skip-check
+ uses: cariad-tech/merge-queue-ci-skipper@main
+
+ - name: ๐ฆ Install the latest Rust
+ if: steps.skip-check.outputs.skip-check != 'true'
+ run: |
+ rustup update stable
+
+ - name: ๐ฆ Fetch Rust dependencies
+ if: steps.skip-check.outputs.skip-check != 'true'
+ run: |
+ cargo fetch --locked
+
+ - name: ๐งช Run Rust tests
+ if: steps.skip-check.outputs.skip-check != 'true'
+ env:
+ RUSTFLAGS: -Dwarnings
+ run: |
+ mold -run cargo test --all-features
diff --git a/.github/workflows/comment-!build-commands.yml b/.github/workflows/comment-!build-commands.yml
index 87b8581b19..0224b7224d 100644
--- a/.github/workflows/comment-!build-commands.yml
+++ b/.github/workflows/comment-!build-commands.yml
@@ -1,7 +1,6 @@
# USAGE:
# After reviewing the code, core team members may comment on a PR with the exact text:
-# - `!build-dev` to build with debug symbols and optimizations disabled
-# - `!build-profiling` to build with debug symbols and optimizations enabled
+# - `!build-debug` to build with debug symbols and optimizations disabled
# - `!build` to build without debug symbols and optimizations enabled
# The comment may not contain any other text, not even whitespace or newlines.
name: "!build PR Command"
@@ -21,7 +20,7 @@ jobs:
if: >
github.event.issue.pull_request &&
github.event.comment.author_association == 'MEMBER' &&
- (github.event.comment.body == '!build-dev' || github.event.comment.body == '!build-profiling' || github.event.comment.body == '!build')
+ (github.event.comment.body == '!build-debug' || github.event.comment.body == '!build')
runs-on: self-hosted
permissions:
contents: read
@@ -82,22 +81,43 @@ jobs:
- name: โจ Set build command based on comment
id: build_command
run: |
- if [[ "${{ github.event.comment.body }}" == "!build-dev" ]]; then
- echo "command=build-dev" >> $GITHUB_OUTPUT
- elif [[ "${{ github.event.comment.body }}" == "!build-profiling" ]]; then
- echo "command=build-profiling" >> $GITHUB_OUTPUT
+ if [[ "${{ github.event.comment.body }}" == "!build-debug" ]]; then
+ echo "command=build web debug" >> $GITHUB_OUTPUT
elif [[ "${{ github.event.comment.body }}" == "!build" ]]; then
- echo "command=build" >> $GITHUB_OUTPUT
+ echo "command=build web" >> $GITHUB_OUTPUT
else
- echo "Failed to detect if the build command written in the comment should have been '!build-dev', '!build-profiling', or '!build'" >> $GITHUB_OUTPUT
+ echo "Failed to detect if the build command written in the comment should have been '!build-debug', or '!build'" >> $GITHUB_OUTPUT
fi
+ - name: ๐ฌ Comment Actions run link
+ id: comment_actions_run_link
+ uses: actions/github-script@v6
+ with:
+ script: |
+ github.rest.issues.updateComment({
+ comment_id: ${{ github.event.comment.id }},
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: '!build ([Run ID ' + context.runId + '](https://github.com/GraphiteEditor/Graphite/actions/runs/' + context.runId + '))'
+ });
+
- name: ๐ Build Graphite web code
env:
NODE_ENV: production
- run: |
- cd frontend
- mold -run npm run ${{ steps.build_command.outputs.command }}
+ if: ${{ success() || failure()}}
+ run: mold -run cargo run ${{ steps.build_command.outputs.command }}
+
+ - name: โ Warn on build failure
+ if: ${{ failure() }}
+ uses: actions/github-script@v6
+ with:
+ script: |
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: 'The build process has failed. Please check the [build logs](https://github.com/GraphiteEditor/Graphite/actions/runs/' + context.runId + ') for details.'
+ });
- name: ๐ค Publish to Cloudflare Pages
id: cloudflare
@@ -110,6 +130,18 @@ jobs:
projectName: graphite-dev
directory: frontend/dist
+ - name: โ Warn on publish failure
+ if: ${{ failure() }}
+ uses: actions/github-script@v6
+ with:
+ script: |
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: 'The deployment to Cloudflare Pages has failed. Please check the [build logs](https://github.com/GraphiteEditor/Graphite/actions/runs/' + context.runId + ') for details.
+ });
+
- name: ๐ฌ Comment build link
uses: actions/github-script@v6
with:
diff --git a/.github/workflows/comment-profiling-changes.yaml b/.github/workflows/comment-profiling-changes.yaml
index 76b12265a1..70877a5e41 100644
--- a/.github/workflows/comment-profiling-changes.yaml
+++ b/.github/workflows/comment-profiling-changes.yaml
@@ -3,9 +3,9 @@ name: Profiling Changes
on:
pull_request:
paths:
- - 'node-graph/**'
- - 'Cargo.toml'
- - 'Cargo.lock'
+ - "node-graph/**"
+ - "Cargo.toml"
+ - "Cargo.lock"
env:
CARGO_TERM_COLOR: always
@@ -200,7 +200,7 @@ jobs:
let commentBody = "";
function formatNumber(num) {
- return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
+ return String(num).replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
function formatPercentage(pct) {
diff --git a/.github/workflows/build-dev-and-ci.yml b/.github/workflows/deploy-master.yml
similarity index 60%
rename from .github/workflows/build-dev-and-ci.yml
rename to .github/workflows/deploy-master.yml
index 365eb76fe8..bf6c280b22 100644
--- a/.github/workflows/build-dev-and-ci.yml
+++ b/.github/workflows/deploy-master.yml
@@ -1,21 +1,20 @@
-name: "Editor: Dev & CI"
+name: "Deploy Master"
on:
push:
branches:
- master
- pull_request: {}
+
env:
CARGO_TERM_COLOR: always
INDEX_HTML_HEAD_REPLACEMENT:
jobs:
- build:
- runs-on: self-hosted
+ deploy:
+ runs-on: [self-hosted, target/wasm]
permissions:
contents: write
deployments: write
- pull-requests: write
actions: write
env:
RUSTC_WRAPPER: /usr/bin/sccache
@@ -41,29 +40,16 @@ jobs:
- name: ๐ฆ Install the latest Rust
run: |
- echo "Initial system version:"
- rustc --version
rustup update stable
- echo "Latest updated version:"
- rustc --version
-
- - name: ๐ฆ Fetch Rust dependencies
- run: |
- echo "If it fails here, the committed Cargo.lock may be out of date"
- cargo fetch --locked
- name: โ Replace template in
of index.html
run: |
- # Remove the INDEX_HTML_HEAD_REPLACEMENT environment variable for build links (not master deploys)
- git rev-parse --abbrev-ref HEAD | grep master > /dev/null || export INDEX_HTML_HEAD_REPLACEMENT=""
sed -i "s||$INDEX_HTML_HEAD_REPLACEMENT|" frontend/index.html
- name: ๐ Build Graphite web code
env:
NODE_ENV: production
- run: |
- cd frontend
- mold -run npm run build
+ run: mold -run cargo run build web
- name: ๐ค Publish to Cloudflare Pages
id: cloudflare
@@ -77,7 +63,6 @@ jobs:
directory: frontend/dist
- name: ๐ฌ Comment build link URL to commit hash page on GitHub
- if: github.ref == 'refs/heads/master'
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
@@ -89,36 +74,15 @@ jobs:
|-|
| ${{ steps.cloudflare.outputs.url }} |"
- - name: ๐ Lint Graphite web formatting
- env:
- NODE_ENV: production
- run: |
- cd frontend
- npm run lint
-
- - name: ๐ฌ Check Rust formatting
- run: |
- mold -run cargo fmt --all -- --check
-
- - name: ๐ฆ Build Rust code
- env:
- RUSTFLAGS: -Dwarnings
- run: |
- mold -run cargo build --all-features
-
- - name: ๐งช Run Rust tests
- run: |
- mold -run cargo test --all-features
-
- name: ๐ Generate code documentation info for website
- if: github.ref == 'refs/heads/master'
run: |
- cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree
+ cd tools/editor-message-tree
+ cargo run
+ cd ../..
mkdir -p artifacts-generated
- mv hierarchical_message_system_tree.txt artifacts-generated/hierarchical_message_system_tree.txt
+ mv website/generated/hierarchical_message_system_tree.txt artifacts-generated/hierarchical_message_system_tree.txt
- name: ๐ฟ Obtain cache of auto-generated code docs artifacts, to check if they've changed
- if: github.ref == 'refs/heads/master'
id: cache-website-code-docs
uses: actions/cache/restore@v3
with:
@@ -126,7 +90,6 @@ jobs:
key: website-code-docs
- name: ๐ Check if auto-generated code docs artifacts changed
- if: github.ref == 'refs/heads/master'
id: website-code-docs-changed
run: |
if ! diff --brief --recursive artifacts-generated artifacts; then
@@ -154,31 +117,3 @@ jobs:
run: |
rm -rf artifacts
gh workflow run website.yml --ref master
-
- # miri:
- # runs-on: self-hosted
-
- # steps:
- # - uses: actions/checkout@v3
-
- # - name: ๐งช Run Rust miri
- # run: |
- # mold -run cargo +nightly miri nextest run -j32 --all-features
-
- cargo-deny:
- runs-on: ubuntu-latest
-
- steps:
- - name: ๐ฅ Clone and checkout repository
- uses: actions/checkout@v3
-
- - name: ๐ Check crate license compatibility for root workspace
- uses: EmbarkStudios/cargo-deny-action@v2
- with:
- command: check bans licenses sources
-
- - name: ๐ Check crate license compatibility for /libraries/rawkit
- uses: EmbarkStudios/cargo-deny-action@v2
- with:
- command: check bans licenses sources
- manifest-path: libraries/rawkit/Cargo.toml
diff --git a/.github/workflows/provide-shaders.yml b/.github/workflows/provide-shaders.yml
new file mode 100644
index 0000000000..b6006a7b24
--- /dev/null
+++ b/.github/workflows/provide-shaders.yml
@@ -0,0 +1,31 @@
+name: Provide Shaders
+
+on:
+ push:
+ branches:
+ - master
+ workflow_dispatch: {}
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: read
+ steps:
+ - uses: actions/checkout@v4
+ - uses: DeterminateSystems/nix-installer-action@main
+ - uses: DeterminateSystems/magic-nix-cache-action@main
+
+ - name: Build graphene raster nodes shaders
+ run: nix build .#graphite-raster-nodes-shaders && cp result raster_nodes_shaders_entrypoint.wgsl
+
+ - name: Upload graphene raster nodes shaders to artifacts repository
+ run: |
+ bash .github/workflows/scripts/artifact-upload.bash \
+ ${{ vars.ARTIFACTS_REPO_OWNER }} \
+ ${{ vars.ARTIFACTS_REPO_NAME }} \
+ ${{ vars.ARTIFACTS_REPO_BRANCH }} \
+ rev/${{ github.sha }}/raster_nodes_shaders_entrypoint.wgsl \
+ raster_nodes_shaders_entrypoint.wgsl \
+ "${{ github.sha }} raster_nodes_shaders_entrypoint.wgsl" \
+ ${{ secrets.ARTIFACTS_REPO_TOKEN }}
diff --git a/.github/workflows/scripts/artifact-upload.bash b/.github/workflows/scripts/artifact-upload.bash
new file mode 100644
index 0000000000..5e8f50dec0
--- /dev/null
+++ b/.github/workflows/scripts/artifact-upload.bash
@@ -0,0 +1,89 @@
+#!/usr/bin/env bash
+set -euo pipefail
+
+usage() {
+ cat <
+
+Arguments:
+ owner : GitHub user or organization of the target repo
+ repo : Target repo name
+ branch : Branch name (e.g. main)
+ target-path : Full path (including folders + filename) in the target repo where to upload
+ artifact-file : Local file path to upload
+ commit-message : Commit message for creating/updating the file
+ github-token : GitHub token (PAT or equivalent) with write access to the target repo
+
+This will perform a GitHub API PUT to /repos/{owner}/{repo}/contents/{target-path}.
+If a file already exists at that path, it will auto-detect the SHA and update; otherwise it will create a new one.
+EOF
+ exit 1
+}
+
+if [ $# -ne 7 ]; then
+ usage
+fi
+
+OWNER="$1"
+REPO="$2"
+BRANCH="$3"
+TARGET_PATH="$4"
+ARTIFACT_PATH="$5"
+COMMIT_MSG="$6"
+TOKEN="$7"
+
+if [ ! -f "$ARTIFACT_PATH" ]; then
+ echo "Error: artifact file not found: $ARTIFACT_PATH" >&2
+ exit 1
+fi
+
+LOCAL_SHA=$(git hash-object "$ARTIFACT_PATH")
+echo "Local blob SHA: $LOCAL_SHA"
+
+GET_URL="https://api.github.com/repos/${OWNER}/${REPO}/contents/${TARGET_PATH}?ref=${BRANCH}"
+GET_RESPONSE=$(curl -s -H "Authorization: token ${TOKEN}" "$GET_URL")
+
+REMOTE_SHA=$(echo "$GET_RESPONSE" | jq -r .sha 2>/dev/null || echo "")
+
+if [ "$REMOTE_SHA" != "null" ] && [ -n "$REMOTE_SHA" ]; then
+ echo "Remote blob SHA: $REMOTE_SHA"
+ if [ "$LOCAL_SHA" = "$REMOTE_SHA" ]; then
+ echo "The remote file is identical. Skipping upload."
+ exit 0
+ else
+ echo "Remote file differs. Preparing to upload."
+ fi
+else
+ echo "No existing remote file or no SHA found. Creating."
+fi
+
+CONTENT_TMP_BASE64=$(mktemp)
+if base64 --help 2>&1 | grep -q -- "-w"; then
+ base64 -w 0 "$ARTIFACT_PATH" > "$CONTENT_TMP_BASE64"
+else
+ base64 "$ARTIFACT_PATH" | tr -d '\n' > "$CONTENT_TMP_BASE64"
+fi
+
+PAYLOAD_TMP=$(mktemp)
+jq -n \
+ --arg message "$COMMIT_MSG" \
+ --arg branch "$BRANCH" \
+ --arg sha "$REMOTE_SHA" \
+ --rawfile content "$CONTENT_TMP_BASE64" \
+ '{
+ message: $message,
+ content: $content,
+ branch: $branch
+ } + (if ($sha != "" and $sha != "null") then { sha: $sha } else {} end)' \
+ > "$PAYLOAD_TMP"
+
+UPLOAD_RESPONSE=$(curl -s -X PUT \
+ -H "Authorization: token ${TOKEN}" \
+ -H "Content-Type: application/json" \
+ -d @"$PAYLOAD_TMP" \
+ "https://api.github.com/repos/${OWNER}/${REPO}/contents/${TARGET_PATH}")
+
+echo "Upload Response:"
+echo "$UPLOAD_RESPONSE"
+
+rm -f "$CONTENT_TMP_BASE64" "$PAYLOAD_TMP"
diff --git a/.github/workflows/website.yml b/.github/workflows/website.yml
index 9cd800857a..3b8fb54eeb 100644
--- a/.github/workflows/website.yml
+++ b/.github/workflows/website.yml
@@ -37,7 +37,7 @@ jobs:
- name: ๐ธ Install Zola
uses: taiki-e/install-action@v2
with:
- tool: zola@0.20.0
+ tool: zola@0.22.0
- name: ๐ Check if `website/other` directory changed
uses: dorny/paths-filter@v3
@@ -67,19 +67,27 @@ jobs:
rustup update stable
echo "๐ฆ Latest updated version of Rust:"
rustc --version
- cargo test --package graphite-editor --lib -- messages::message::test::generate_message_tree
+ cd tools/editor-message-tree
+ cargo run
+ cd ../..
mkdir artifacts
- mv hierarchical_message_system_tree.txt artifacts/hierarchical_message_system_tree.txt
+ mv website/generated/hierarchical_message_system_tree.txt artifacts/hierarchical_message_system_tree.txt
- - name: ๐ Move `artifacts` contents to the project root
+ - name: ๐ Move `artifacts` contents to website/generated
run: |
- mv artifacts/* .
+ mkdir -p website/generated
+ mv artifacts/* website/generated/
- name: ๐ง Build auto-generated code docs artifacts into HTML
run: |
cd website
npm run generate-editor-structure
+ - name: ๐ Generate node catalog documentation
+ run: |
+ cd tools/node-docs
+ cargo run
+
- name: ๐ Build Graphite website with Zola
env:
MODE: prod
diff --git a/.gitignore b/.gitignore
index f410829a7b..06bcee0483 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,8 @@
branding/
target/
+third-party-licenses.txt*
result/
+.flatpak-builder/
*.spv
*.exrc
perf.data*
@@ -10,5 +12,3 @@ flamegraph.svg
.idea/
.direnv
.DS_Store
-hierarchical_message_system_tree.txt
-hierarchical_message_system_tree.html
diff --git a/.nix/default.nix b/.nix/default.nix
new file mode 100644
index 0000000000..e77cc4a60d
--- /dev/null
+++ b/.nix/default.nix
@@ -0,0 +1,81 @@
+inputs:
+
+let
+ systems = [
+ "x86_64-linux"
+ "aarch64-linux"
+ ];
+ forAllSystems = f: inputs.nixpkgs.lib.genAttrs systems (system: f system);
+ args =
+ system:
+ (
+ let
+ lib = inputs.nixpkgs.lib // {
+ call = p: import p args;
+ };
+
+ pkgs = import inputs.nixpkgs {
+ inherit system;
+ overlays = [ (import inputs.rust-overlay) ];
+ };
+
+ info = {
+ pname = "graphite";
+ version = "unstable";
+ src = inputs.nixpkgs.lib.cleanSourceWith {
+ src = ./..;
+ filter = path: type: !(type == "directory" && builtins.baseNameOf path == ".nix");
+ };
+ cargoVendored = deps.crane.lib.vendorCargoDeps { inherit (info) src; };
+ };
+
+ deps = {
+ crane = lib.call ./deps/crane.nix;
+ cef = lib.call ./deps/cef.nix;
+ rustGPU = lib.call ./deps/rust-gpu.nix;
+ };
+
+ args = {
+ inherit system;
+ inherit (inputs) self;
+ inherit inputs;
+ inherit pkgs;
+ inherit lib;
+ inherit info;
+ inherit deps;
+ }
+ // inputs;
+ in
+ args
+ );
+ withArgs = f: forAllSystems (system: f (args system));
+in
+{
+ packages = withArgs (
+ { lib, ... }:
+ rec {
+ default = graphite;
+ graphite = (lib.call ./pkgs/graphite.nix) { };
+ graphite-dev = (lib.call ./pkgs/graphite.nix) { dev = true; };
+ graphite-raster-nodes-shaders = lib.call ./pkgs/graphite-raster-nodes-shaders.nix;
+ graphite-branding = lib.call ./pkgs/graphite-branding.nix;
+ graphite-bundle = lib.call ./pkgs/graphite-bundle.nix;
+ graphite-flatpak-manifest = lib.call ./pkgs/graphite-flatpak-manifest.nix;
+
+ # TODO: graphene-cli = lib.call ./pkgs/graphene-cli.nix;
+
+ tools = {
+ third-party-licenses = lib.call ./pkgs/tools/third-party-licenses.nix;
+ };
+ }
+ );
+
+ devShells = withArgs (
+ { lib, ... }:
+ {
+ default = lib.call ./dev.nix;
+ }
+ );
+
+ formatter = withArgs ({ pkgs, ... }: pkgs.nixfmt-tree);
+}
diff --git a/.nix/deps/cef.nix b/.nix/deps/cef.nix
index f31219be53..c0ce387cbf 100644
--- a/.nix/deps/cef.nix
+++ b/.nix/deps/cef.nix
@@ -1,25 +1,26 @@
-{ pkgs, inputs, ... }:
+{ pkgs, ... }:
let
- cef = pkgs.cef-binary.overrideAttrs (_: _: {
+ cefPath = pkgs.cef-binary.overrideAttrs (finalAttrs: {
postInstall = ''
- strip $out/Release/*.so*
+ rm -r $out/* $out/.* || true
+ strip ./Release/*.so*
+ mv ./Release/* $out/
+ find "./Resources/locales" -maxdepth 1 -type f ! -name 'en-US.pak' -delete
+ mv ./Resources/* $out/
+ mv ./include $out/
+
+ cat ./CREDITS.html | ${pkgs.xz}/bin/xz -9 -e -c > $out/CREDITS.html.xz
+
+ echo '${
+ builtins.toJSON {
+ type = "minimal";
+ name = builtins.baseNameOf finalAttrs.src.url;
+ sha1 = "";
+ }
+ }' > $out/archive.json
'';
});
-
- cefPath = pkgs.runCommand "cef-path" {} ''
- mkdir -p $out
-
- ln -s ${cef}/include $out/include
- find ${cef}/Release -name "*" -type f -exec ln -s {} $out/ \;
- find ${cef}/Resources -name "*" -maxdepth 1 -exec ln -s {} $out/ \;
-
- echo '${builtins.toJSON {
- type = "minimal";
- name = builtins.baseNameOf cef.src.url;
- sha1 = "";
- }}' > $out/archive.json
- '';
in
{
env.CEF_PATH = cefPath;
diff --git a/.nix/deps/rust-gpu.nix b/.nix/deps/rust-gpu.nix
index 2970d515a2..a44f70b368 100644
--- a/.nix/deps/rust-gpu.nix
+++ b/.nix/deps/rust-gpu.nix
@@ -1,4 +1,4 @@
-{ pkgs, inputs, ... }:
+{ pkgs, ... }:
let
extensions = [
diff --git a/.nix/dev.nix b/.nix/dev.nix
index d80d7793e6..e9333d4940 100644
--- a/.nix/dev.nix
+++ b/.nix/dev.nix
@@ -1,16 +1,58 @@
-{
- pkgs,
- deps,
- libs,
- tools,
- ...
-}:
+{ pkgs, deps, ... }:
+let
+ libs = [
+ pkgs.wayland
+ pkgs.vulkan-loader
+ pkgs.libGL
+ pkgs.openssl
+ pkgs.libraw
+
+ # X11 Support
+ pkgs.libxkbcommon
+ pkgs.libXcursor
+ pkgs.libxcb
+ pkgs.libX11
+ ];
+in
pkgs.mkShell (
{
- packages = tools.all ++ libs.all;
+ packages = libs ++ [
+ pkgs.pkg-config
- LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath libs.all}:${deps.cef.env.CEF_PATH}";
+ pkgs.lld
+ pkgs.nodejs
+ pkgs.nodePackages.npm
+ pkgs.binaryen
+ pkgs.wasm-bindgen-cli_0_2_100
+ pkgs.wasm-pack
+ pkgs.cargo-about
+
+ pkgs.rustc
+ pkgs.cargo
+ pkgs.rust-analyzer
+ pkgs.clippy
+ pkgs.rustfmt
+
+ pkgs.git
+
+ pkgs.cargo-watch
+ pkgs.cargo-nextest
+ pkgs.cargo-expand
+
+ # Linker
+ pkgs.mold
+
+ # Profiling tools
+ pkgs.gnuplot
+ pkgs.samply
+ pkgs.cargo-flamegraph
+
+ # Plotting tools
+ pkgs.graphviz
+ ];
+
+ LD_LIBRARY_PATH = "${pkgs.lib.makeLibraryPath libs}:${deps.cef.env.CEF_PATH}";
XDG_DATA_DIRS = "${pkgs.gsettings-desktop-schemas}/share/gsettings-schemas/${pkgs.gsettings-desktop-schemas.name}:${pkgs.gtk3}/share/gsettings-schemas/${pkgs.gtk3.name}:$XDG_DATA_DIRS";
shellHook = ''
diff --git a/.nix/flake.lock b/.nix/flake.lock
deleted file mode 100644
index 2d6d42777a..0000000000
--- a/.nix/flake.lock
+++ /dev/null
@@ -1,113 +0,0 @@
-{
- "nodes": {
- "crane": {
- "locked": {
- "lastModified": 1763938834,
- "narHash": "sha256-j8iB0Yr4zAvQLueCZ5abxfk6fnG/SJ5JnGUziETjwfg=",
- "owner": "ipetkov",
- "repo": "crane",
- "rev": "d9e753122e51cee64eb8d2dddfe11148f339f5a2",
- "type": "github"
- },
- "original": {
- "owner": "ipetkov",
- "repo": "crane",
- "type": "github"
- }
- },
- "flake-compat": {
- "locked": {
- "lastModified": 1733328505,
- "narHash": "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU=",
- "rev": "ff81ac966bb2cae68946d5ed5fc4994f96d0ffec",
- "revCount": 69,
- "type": "tarball",
- "url": "https://api.flakehub.com/f/pinned/edolstra/flake-compat/1.1.0/01948eb7-9cba-704f-bbf3-3fa956735b52/source.tar.gz"
- },
- "original": {
- "type": "tarball",
- "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz"
- }
- },
- "flake-utils": {
- "inputs": {
- "systems": "systems"
- },
- "locked": {
- "lastModified": 1731533236,
- "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
- "owner": "numtide",
- "repo": "flake-utils",
- "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
- "type": "github"
- },
- "original": {
- "owner": "numtide",
- "repo": "flake-utils",
- "type": "github"
- }
- },
- "nixpkgs": {
- "locked": {
- "lastModified": 1764242076,
- "narHash": "sha256-sKoIWfnijJ0+9e4wRvIgm/HgE27bzwQxcEmo2J/gNpI=",
- "owner": "nixos",
- "repo": "nixpkgs",
- "rev": "2fad6eac6077f03fe109c4d4eb171cf96791faa4",
- "type": "github"
- },
- "original": {
- "owner": "nixos",
- "ref": "nixos-unstable",
- "repo": "nixpkgs",
- "type": "github"
- }
- },
- "root": {
- "inputs": {
- "crane": "crane",
- "flake-compat": "flake-compat",
- "flake-utils": "flake-utils",
- "nixpkgs": "nixpkgs",
- "rust-overlay": "rust-overlay"
- }
- },
- "rust-overlay": {
- "inputs": {
- "nixpkgs": [
- "nixpkgs"
- ]
- },
- "locked": {
- "lastModified": 1764297505,
- "narHash": "sha256-qrLpVu2/hA9Cu6IovMEsgh9YRyvmmWS+bSx7C1JGChA=",
- "owner": "oxalica",
- "repo": "rust-overlay",
- "rev": "9623580f8ce09ec444b9aca107566ec5db110e62",
- "type": "github"
- },
- "original": {
- "owner": "oxalica",
- "repo": "rust-overlay",
- "type": "github"
- }
- },
- "systems": {
- "locked": {
- "lastModified": 1681028828,
- "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
- "owner": "nix-systems",
- "repo": "default",
- "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
- "type": "github"
- },
- "original": {
- "owner": "nix-systems",
- "repo": "default",
- "type": "github"
- }
- }
- },
- "root": "root",
- "version": 7
-}
diff --git a/.nix/flake.nix b/.nix/flake.nix
deleted file mode 100644
index 83f8c448b2..0000000000
--- a/.nix/flake.nix
+++ /dev/null
@@ -1,159 +0,0 @@
-# This is a helper file for people using NixOS as their operating system.
-# If you don't know what this file does, you can safely ignore it.
-# This file defines the reproducible development environment for the project.
-#
-# Development Environment:
-# - Provides all necessary tools for Rust/Wasm development
-# - Includes dependencies for desktop app development
-# - Sets up profiling and debugging tools
-# - Configures mold as the default linker for faster builds
-#
-# Usage:
-# - Development shell: `nix develop .nix` from the project root
-# - Run in dev shell with direnv: add `use flake` to .envrc
-{
- inputs = {
- nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
- rust-overlay = {
- url = "github:oxalica/rust-overlay";
- inputs.nixpkgs.follows = "nixpkgs";
- };
- flake-utils.url = "github:numtide/flake-utils";
- crane.url = "github:ipetkov/crane";
-
- # This is used to provide a identical development shell at `shell.nix` for users that do not use flakes
- flake-compat.url = "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz";
- };
-
- outputs =
- inputs:
- inputs.flake-utils.lib.eachDefaultSystem (
- system:
- let
- info = {
- pname = "graphite";
- version = "unstable";
- src = ./..;
- };
-
- pkgs = import inputs.nixpkgs {
- inherit system;
- overlays = [ (import inputs.rust-overlay) ];
- };
-
- deps = {
- crane = import ./deps/crane.nix { inherit pkgs inputs; };
- cef = import ./deps/cef.nix { inherit pkgs inputs; };
- rustGPU = import ./deps/rust-gpu.nix { inherit pkgs inputs; };
- };
-
- libs = rec {
- desktop = [
- pkgs.wayland
- pkgs.openssl
- pkgs.vulkan-loader
- pkgs.libraw
- pkgs.libGL
- ];
- desktop-x11 = [
- pkgs.libxkbcommon
- pkgs.xorg.libXcursor
- pkgs.xorg.libxcb
- pkgs.xorg.libX11
- ];
- desktop-all = desktop ++ desktop-x11;
- all = desktop-all;
- };
-
- tools = rec {
- desktop = [
- pkgs.pkg-config
- ];
- frontend = [
- pkgs.lld
- pkgs.nodejs
- pkgs.nodePackages.npm
- pkgs.binaryen
- pkgs.wasm-bindgen-cli_0_2_100
- pkgs.wasm-pack
- pkgs.cargo-about
- ];
- dev = [
- pkgs.rustc
- pkgs.cargo
- pkgs.rust-analyzer
- pkgs.clippy
- pkgs.rustfmt
-
- pkgs.git
-
- pkgs.cargo-watch
- pkgs.cargo-nextest
- pkgs.cargo-expand
-
- # Linker
- pkgs.mold
-
- # Profiling tools
- pkgs.gnuplot
- pkgs.samply
- pkgs.cargo-flamegraph
-
- # Plotting tools
- pkgs.graphviz
- ];
- all = desktop ++ frontend ++ dev;
- };
- in
- {
- packages = rec {
- graphiteWithArgs =
- args:
- (import ./pkgs/graphite.nix {
- pkgs = pkgs // {
- inherit raster-nodes-shaders;
- };
- inherit
- info
- inputs
- deps
- libs
- tools
- ;
- })
- args;
- graphite = graphiteWithArgs { };
- graphite-dev = graphiteWithArgs { dev = true; };
- graphite-without-resources = graphiteWithArgs { embeddedResources = false; };
- graphite-without-resources-dev = graphiteWithArgs {
- embeddedResources = false;
- dev = true;
- };
- #TODO: graphene-cli = import ./pkgs/graphene-cli.nix { inherit info pkgs inputs deps libs tools; };
- raster-nodes-shaders = import ./pkgs/raster-nodes-shaders.nix {
- inherit
- info
- pkgs
- inputs
- deps
- libs
- tools
- ;
- };
-
- default = graphite;
- };
-
- devShells.default = import ./dev.nix {
- inherit
- pkgs
- deps
- libs
- tools
- ;
- };
-
- formatter = pkgs.nixfmt-tree;
- }
- );
-}
diff --git a/.nix/pkgs/graphite-branding.nix b/.nix/pkgs/graphite-branding.nix
new file mode 100644
index 0000000000..85b53791f8
--- /dev/null
+++ b/.nix/pkgs/graphite-branding.nix
@@ -0,0 +1,20 @@
+{ info, pkgs, ... }:
+
+let
+ brandingTar = pkgs.fetchurl (
+ let
+ lockContent = builtins.readFile "${info.src}/.branding";
+ lines = builtins.filter (s: s != [ ]) (builtins.split "\n" lockContent);
+ url = builtins.elemAt lines 0;
+ hash = builtins.elemAt lines 1;
+ in
+ {
+ url = url;
+ sha256 = hash;
+ }
+ );
+in
+pkgs.runCommand "${info.pname}-branding" { } ''
+ mkdir -p $out
+ tar -xvf ${brandingTar} -C $out --strip-components 1
+''
diff --git a/.nix/pkgs/graphite-bundle.nix b/.nix/pkgs/graphite-bundle.nix
new file mode 100644
index 0000000000..d50b00fccd
--- /dev/null
+++ b/.nix/pkgs/graphite-bundle.nix
@@ -0,0 +1,92 @@
+{
+ pkgs,
+ self,
+ system,
+ ...
+}:
+let
+ bundle =
+ {
+ archive ? false,
+ compression ? null,
+ passthru ? { },
+ }:
+ (
+ let
+ graphite = self.packages.${system}.graphite;
+ tar = if compression == null then archive else true;
+ nameArchiveSuffix = if tar then ".tar" else "";
+ nameCompressionSuffix = if compression == null then "" else "." + compression;
+ name = "graphite-bundle${nameArchiveSuffix}${nameCompressionSuffix}";
+ build = ''
+ mkdir -p out
+ mkdir -p out/bin
+ cp ${graphite}/bin/graphite out/bin/graphite
+ chmod -v +w out/bin/graphite
+ patchelf \
+ --set-rpath '$ORIGIN/../lib:$ORIGIN/../lib/cef' \
+ --set-interpreter '/lib64/ld-linux-x86-64.so.2' \
+ --remove-needed libGL.so \
+ out/bin/graphite
+ cp -r ${graphite}/share out/share
+ mkdir -p out/lib/cef
+ mkdir -p ./cef
+ tar -xvf ${pkgs.cef-binary.src} -C ./cef --strip-components=1
+ cp -r ./cef/Release/* out/lib/cef/
+ cp -r ./cef/Resources/* out/lib/cef/
+ find "out/lib/cef/locales" -type f ! -name 'en-US*' -delete
+ ${pkgs.bintools}/bin/strip out/lib/cef/*.so*
+ '';
+ install =
+ if tar then
+ ''
+ cd out
+ tar -c \
+ --sort=name \
+ --mtime='@1' --clamp-mtime \
+ --owner=0 --group=0 --numeric-owner \
+ --mode='u=rwX,go=rX' \
+ --format=posix \
+ --pax-option=delete=atime,delete=ctime \
+ --no-acls --no-xattrs --no-selinux \
+ * ${
+ if compression == "xz" then
+ "| xz "
+ else if compression == "gz" then
+ "| gzip -n "
+ else
+ ""
+ }> $out
+ ''
+ else
+ ''
+ mkdir -p $out
+ cp -r out/* $out/
+ '';
+ in
+
+ pkgs.runCommand name
+ {
+ inherit passthru;
+ }
+ ''
+ ${build}
+ ${install}
+ ''
+ );
+in
+bundle {
+ passthru = {
+ tar = bundle {
+ archive = true;
+ passthru = {
+ gz = bundle {
+ compression = "gz";
+ };
+ xz = bundle {
+ compression = "xz";
+ };
+ };
+ };
+ };
+}
diff --git a/.nix/pkgs/graphite-flatpak-manifest.nix b/.nix/pkgs/graphite-flatpak-manifest.nix
new file mode 100644
index 0000000000..fee6603119
--- /dev/null
+++ b/.nix/pkgs/graphite-flatpak-manifest.nix
@@ -0,0 +1,39 @@
+{
+ pkgs,
+ self,
+ system,
+ ...
+}:
+
+(pkgs.formats.json { }).generate "art.graphite.Graphite.json" {
+ app-id = "art.graphite.Graphite";
+ runtime = "org.freedesktop.Platform";
+ runtime-version = "25.08";
+ sdk = "org.freedesktop.Sdk";
+ command = "graphite";
+ finish-args = [
+ "--device=dri"
+ "--share=ipc"
+ "--socket=wayland"
+ "--socket=fallback-x11"
+ "--share=network"
+ ];
+ modules = [
+ {
+ name = "app";
+ buildsystem = "simple";
+ build-commands = [
+ "mkdir -p /app"
+ "cp -r ./* /app/"
+ "chmod +x /app/bin/*"
+ ];
+ sources = [
+ {
+ type = "archive";
+ path = self.packages.${system}.graphite-bundle.tar;
+ strip-components = 0;
+ }
+ ];
+ }
+ ];
+}
diff --git a/.nix/pkgs/raster-nodes-shaders.nix b/.nix/pkgs/graphite-raster-nodes-shaders.nix
similarity index 78%
rename from .nix/pkgs/raster-nodes-shaders.nix
rename to .nix/pkgs/graphite-raster-nodes-shaders.nix
index 46e2f90a29..727e8c9555 100644
--- a/.nix/pkgs/raster-nodes-shaders.nix
+++ b/.nix/pkgs/graphite-raster-nodes-shaders.nix
@@ -1,12 +1,4 @@
-{
- info,
- pkgs,
- inputs,
- deps,
- libs,
- tools,
- ...
-}:
+{ info, deps, ... }:
(deps.crane.lib.overrideToolchain (_: deps.rustGPU.toolchain)).buildPackage {
pname = "raster-nodes-shaders";
@@ -16,7 +8,7 @@
inherit (deps.crane.lib.findCargoFiles (deps.crane.lib.cleanCargoSource info.src)) cargoConfigs;
cargoLockList = [
"${info.src}/Cargo.lock"
- "${deps.rustGPU.toolchain.passthru.availableComponents.rust-src}/lib/rustlib/src/rust/library/Cargo.lock"
+ "${deps.rustGPU.toolchain.availableComponents.rust-src}/lib/rustlib/src/rust/library/Cargo.lock"
];
};
diff --git a/.nix/pkgs/graphite.nix b/.nix/pkgs/graphite.nix
index 31fd507254..bd757add80 100644
--- a/.nix/pkgs/graphite.nix
+++ b/.nix/pkgs/graphite.nix
@@ -1,61 +1,58 @@
{
info,
pkgs,
- inputs,
+ self,
deps,
- libs,
- tools,
+ system,
+ lib,
...
}:
{
- embeddedResources ? true,
dev ? false,
}:
let
- brandingTar = pkgs.fetchurl (
- let
- lockContent = builtins.readFile "${info.src}/.branding";
- lines = builtins.filter (s: s != [ ]) (builtins.split "\n" lockContent);
- url = builtins.elemAt lines 0;
- hash = builtins.elemAt lines 1;
- in
- {
- url = url;
- sha256 = hash;
- }
- );
- branding = pkgs.runCommand "${info.pname}-branding" { } ''
- mkdir -p $out
- tar -xvf ${brandingTar} -C $out --strip-components 1
- '';
+ branding = self.packages.${system}.graphite-branding;
+ cargoVendorDir = deps.crane.lib.vendorCargoDeps { inherit (info) src; };
resourcesCommon = {
pname = "${info.pname}-resources";
inherit (info) version src;
+ inherit cargoVendorDir;
strictDeps = true;
- doCheck = false;
- nativeBuildInputs = tools.frontend;
+ nativeBuildInputs = [
+ pkgs.pkg-config
+ pkgs.lld
+ pkgs.nodejs
+ pkgs.nodePackages.npm
+ pkgs.binaryen
+ pkgs.wasm-bindgen-cli_0_2_100
+ pkgs.wasm-pack
+ pkgs.cargo-about
+ ];
+ buildInputs = [ pkgs.openssl ];
env.CARGO_PROFILE = if dev then "dev" else "release";
cargoExtraArgs = "--target wasm32-unknown-unknown -p graphite-wasm --no-default-features --features native";
+ doCheck = false;
};
resources = deps.crane.lib.buildPackage (
resourcesCommon
// {
cargoArtifacts = deps.crane.lib.buildDepsOnly resourcesCommon;
- # TODO: Remove the need for this hash by using individual package resolutions and hashes from package-lock.json
- npmDeps = pkgs.fetchNpmDeps {
- inherit (info) pname version;
- src = "${info.src}/frontend";
- hash = "sha256-D8VCNK+Ca3gxO+5wriBn8FszG8/x8n/zM6/MPo9E2j4=";
+ npmDeps = pkgs.importNpmLock {
+ npmRoot = "${info.src}/frontend";
};
npmRoot = "frontend";
npmConfigScript = "setup";
makeCacheWritable = true;
- nativeBuildInputs = tools.frontend ++ [ pkgs.npmHooks.npmConfigHook ];
+ nativeBuildInputs = [
+ pkgs.importNpmLock.npmConfigHook
+ pkgs.removeReferencesTo
+ ]
+ ++ resourcesCommon.nativeBuildInputs;
prePatch = ''
mkdir branding
@@ -75,19 +72,39 @@ let
mkdir -p $out
cp -r frontend/dist/* $out/
'';
+
+ postFixup = ''
+ find "$out" -type f -exec remove-references-to -t "${cargoVendorDir}" '{}' +
+ '';
}
);
+ libs = [
+ pkgs.wayland
+ pkgs.vulkan-loader
+ pkgs.libGL
+ pkgs.openssl
+ pkgs.libraw
+
+ # X11 Support
+ pkgs.libxkbcommon
+ pkgs.libXcursor
+ pkgs.libxcb
+ pkgs.libX11
+ ];
common = {
inherit (info) pname version src;
+ inherit cargoVendorDir;
strictDeps = true;
- buildInputs = libs.desktop-all;
- nativeBuildInputs = tools.desktop ++ [ pkgs.makeWrapper ];
+ buildInputs = libs;
+ nativeBuildInputs = [
+ pkgs.pkg-config
+ pkgs.cargo-about
+ pkgs.removeReferencesTo
+ ];
env = deps.cef.env // {
CARGO_PROFILE = if dev then "dev" else "release";
};
- cargoExtraArgs = "-p graphite-desktop${
- if embeddedResources then "" else " --no-default-features --features recommended"
- }";
+ cargoExtraArgs = "-p graphite-desktop";
doCheck = false;
};
in
@@ -97,24 +114,34 @@ deps.crane.lib.buildPackage (
// {
cargoArtifacts = deps.crane.lib.buildDepsOnly common;
- env =
- common.env
- // {
- RASTER_NODES_SHADER_PATH = pkgs.raster-nodes-shaders;
- }
- // (
- if embeddedResources then
- {
- EMBEDDED_RESOURCES = resources;
- }
- else
- { }
- );
+ env = common.env // {
+ RASTER_NODES_SHADER_PATH = self.packages.${system}.graphite-raster-nodes-shaders;
+ EMBEDDED_RESOURCES = resources;
+ GRAPHITE_GIT_COMMIT_HASH = self.rev or "unknown";
+ GRAPHITE_GIT_COMMIT_DATE = self.lastModified or "unknown";
+ };
- postUnpack = ''
- mkdir ./branding
- cp -r ${branding}/* ./branding
- '';
+ npmDeps = pkgs.importNpmLock {
+ npmRoot = "${info.src}/frontend";
+ };
+ npmRoot = "frontend";
+ nativeBuildInputs = [
+ pkgs.importNpmLock.npmConfigHook
+ pkgs.nodePackages.npm
+ ]
+ ++ common.nativeBuildInputs;
+
+ preBuild = ''
+ ${lib.getExe self.packages.${system}.tools.third-party-licenses}
+ ''
+ + (
+ if self ? rev then
+ ''
+ export GRAPHITE_GIT_COMMIT_DATE="$(date -u -d "@$GRAPHITE_GIT_COMMIT_DATE" +"%Y-%m-%dT%H:%M:%SZ")"
+ ''
+ else
+ ""
+ );
installPhase = ''
mkdir -p $out/bin
@@ -124,13 +151,22 @@ deps.crane.lib.buildPackage (
cp $src/desktop/assets/*.desktop $out/share/applications/
mkdir -p $out/share/icons/hicolor/scalable/apps
- cp ${branding}/app-icons/graphite.svg $out/share/icons/hicolor/scalable/apps/
+ cp ${branding}/app-icons/graphite.svg $out/share/icons/hicolor/scalable/apps/art.graphite.Graphite.svg
+ mkdir -p $out/share/icons/hicolor/512x512/apps
+ cp ${branding}/app-icons/graphite-512.png $out/share/icons/hicolor/512x512/apps/art.graphite.Graphite.png
+ mkdir -p $out/share/icons/hicolor/256x256/apps
+ cp ${branding}/app-icons/graphite-256.png $out/share/icons/hicolor/256x256/apps/art.graphite.Graphite.png
+ mkdir -p $out/share/icons/hicolor/128x128/apps
+ cp ${branding}/app-icons/graphite-128.png $out/share/icons/hicolor/128x128/apps/art.graphite.Graphite.png
'';
postFixup = ''
- wrapProgram "$out/bin/graphite" \
- --prefix LD_LIBRARY_PATH : "${pkgs.lib.makeLibraryPath libs.desktop-all}:${deps.cef.env.CEF_PATH}" \
- --set CEF_PATH "${deps.cef.env.CEF_PATH}"
+ remove-references-to -t "${cargoVendorDir}" $out/bin/graphite
+
+ patchelf \
+ --set-rpath "${pkgs.lib.makeLibraryPath libs}:${deps.cef.env.CEF_PATH}" \
+ --add-needed libGL.so \
+ $out/bin/graphite
'';
}
)
diff --git a/.nix/pkgs/tools/third-party-licenses.nix b/.nix/pkgs/tools/third-party-licenses.nix
new file mode 100644
index 0000000000..9559603377
--- /dev/null
+++ b/.nix/pkgs/tools/third-party-licenses.nix
@@ -0,0 +1,31 @@
+{
+ info,
+ deps,
+ pkgs,
+ ...
+}:
+
+let
+ cargoVendorDir = deps.crane.lib.vendorCargoDeps { inherit (info) src; };
+ common = {
+ pname = "third-party-licenses";
+ inherit (info) version src;
+ inherit cargoVendorDir;
+ nativeBuildInputs = [ pkgs.pkg-config ];
+ buildInputs = [ pkgs.openssl ];
+ strictDeps = true;
+ env = deps.cef.env // {
+ CARGO_PROFILE = "dev";
+ };
+ cargoExtraArgs = "-p third-party-licenses --features desktop";
+ doCheck = false;
+ };
+in
+deps.crane.lib.buildPackage (
+ common
+ // {
+ inherit cargoVendorDir;
+ cargoArtifacts = deps.crane.lib.buildDepsOnly common;
+ meta.mainProgram = "third-party-licenses";
+ }
+)
diff --git a/.nix/shell.nix b/.nix/shell.nix
deleted file mode 100644
index 5b13af2e20..0000000000
--- a/.nix/shell.nix
+++ /dev/null
@@ -1,28 +0,0 @@
-# This is a helper file for people using NixOS as their operating system.
-# If you don't know what this file does, you can safely ignore it.
-
-# If you are using Nix as your package manager, you can run 'nix-shell .nix'
-# in the root directory of the project and Nix will open a bash shell
-# with all the packages needed to build and run Graphite installed.
-# A shell.nix file is used in the Nix ecosystem to define a development
-# environment with specific dependencies. When you enter a Nix shell using
-# this file, it ensures that all the specified tools and libraries are
-# available regardless of the host system's configuration. This provides
-# a reproducible development environment across different machines and developers.
-
-# You can enter the Nix shell and run Graphite like normal with:
-# > npm start
-# Or you can run it like this without needing to first enter the Nix shell:
-# > nix-shell .nix --command "npm start"
-
-# Uses flake compat to provide a development shell that is identical to the one defined in the flake
-(import (
- let
- lock = builtins.fromJSON (builtins.readFile ./flake.lock);
- nodeName = lock.nodes.root.inputs.flake-compat;
- in
- fetchTarball {
- url = lock.nodes.${nodeName}.locked.url;
- sha256 = lock.nodes.${nodeName}.locked.narHash;
- }
-) { src = ./.; }).shellNix
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 25148f729c..dd8c135ef9 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -11,9 +11,10 @@
// Code quality
"wayou.vscode-todo-highlight",
"streetsidesoftware.code-spell-checker",
- // Helpful
+ // Git
"mhutchie.git-graph",
"qezhu.gitlink",
+ // Helpful
"wmaurer.change-case"
]
}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index a9ae607985..d1c8a4ae1d 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -26,12 +26,17 @@
// Configured in `.prettierrc`
"editor.defaultFormatter": "esbenp.prettier-vscode"
},
+ // Website: don't format Zola/Tera-templated HTML on save
+ "[html]": {
+ "editor.formatOnSave": false
+ },
// Handlebars: don't save on format
// (`about.hbs` is used by Cargo About to encode license information)
"[handlebars]": {
"editor.formatOnSave": false
},
// Rust Analyzer config
+ "rust-analyzer.check.command": "clippy",
"rust-analyzer.cargo.allTargets": false,
"rust-analyzer.procMacro.ignored": {
"serde_derive": ["Serialize", "Deserialize"],
@@ -47,13 +52,36 @@
"vite-plugin-svelte-css-no-scopable-elements": "ignore", // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
"a11y-no-static-element-interactions": "ignore", // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
"a11y-no-noninteractive-element-interactions": "ignore", // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
- "a11y-click-events-have-key-events": "ignore" // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
+ "a11y-click-events-have-key-events": "ignore", // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
+ "a11y_consider_explicit_label": "ignore", // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
+ "a11y_click_events_have_key_events": "ignore", // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
+ "a11y_no_noninteractive_element_interactions": "ignore", // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
+ "a11y_no_static_element_interactions": "ignore" // NOTICE: Keep this list in sync with the list in `frontend/vite.config.ts`
},
+ // Git Graph config
+ "git-graph.repository.fetchAndPrune": true,
+ "git-graph.repository.showRemoteHeads": false,
+ "git-graph.repository.commits.fetchAvatars": true,
+ // VS Code Git config
+ "git.autofetch": true,
+ "git.enableStatusBarSync": false,
+ "git.showActionButton": {
+ "sync": false
+ },
+ // CSpell config
+ "cSpell.language": "en-US",
+ "cSpell.logLevel": "Information",
+ "cSpell.allowCompoundWords": true,
+ // Other extensions config
+ "evenBetterToml.formatter.alignComments": false,
+ "package-json-upgrade.ignorePatterns": ["source-sans-pro"],
// VS Code config
"html.format.wrapLineLength": 200,
"files.eol": "\n",
"files.insertFinalNewline": true,
"files.associations": {
"*.graphite": "json"
- }
+ },
+ "editor.renderWhitespace": "boundary",
+ "editor.minimap.markSectionHeaderRegex": "// ===+\\n\\s*//\\s*(?