Skip to content

Add macOS onboarding Figma sync pipeline#6346

Merged
kodjima33 merged 1 commit into
mainfrom
feat/onboarding-figma-sync
Apr 5, 2026
Merged

Add macOS onboarding Figma sync pipeline#6346
kodjima33 merged 1 commit into
mainfrom
feat/onboarding-figma-sync

Conversation

@kodjima33
Copy link
Copy Markdown
Collaborator

Summary

  • export onboarding steps directly from the macOS SwiftUI codepath
  • publish the latest onboarding bundle to the figma-onboarding-sync branch on GitHub
  • add a Figma-side auto-sync plugin scaffold for consuming that bundle

Verification

  • generated and published a test onboarding bundle from the existing exported screenshots
  • confirmed the published manifest and assets are reachable on raw.githubusercontent.com

@kodjima33 kodjima33 merged commit eaa05f5 into main Apr 5, 2026
3 checks passed
@kodjima33 kodjima33 deleted the feat/onboarding-figma-sync branch April 5, 2026 23:53
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 5, 2026

Greptile Summary

This PR adds an end-to-end pipeline that compiles the macOS Swift app in headless mode, renders each onboarding step via OnboardingView(isExportPreview: true), bundles the PNGs with a JSON manifest, and force-pushes to a figma-onboarding-sync branch so a companion Figma plugin can poll and auto-render the frames.

  • P1 – dedup key mismatch in code.js: manifestSignature() falls back to JSON.stringify(assets) but applyManifest stores \"\" for the same absent-fields case, so syncOnce never skips re-sync after the first run without sourceCommit/generatedAt.

Confidence Score: 4/5

Safe to merge after fixing the deduplication key mismatch in the Figma plugin; remaining findings are style-level.

One P1 logic bug in code.js means the plugin re-syncs on every poll tick when sourceCommit/generatedAt are absent. The scripts always populate sourceCommit (defaulting to 'local'), so the bug won't trigger on main CI runs, but the plugin code itself has a latent correctness defect worth fixing before shipping to Figma users. All other findings are P2.

figma/onboarding-auto-sync/code.js — dedup key mismatch (P1) and sequential asset fetching (P2)

Important Files Changed

Filename Overview
.github/workflows/onboarding_figma_sync.yml New CI workflow; path filters, concurrency guard, and artifact upload all look correct
desktop/Desktop/Sources/OnboardingView.swift Adds isExportPreview and exportStepOverride props; warmup and completion-check guards correctly skipped in export mode
desktop/Desktop/Sources/ViewExporter.swift Onboarding export registry and --export-onboarding batch mode; subprocess isolation pattern matches existing export modes
figma/onboarding-auto-sync/code.js Polling logic works end-to-end but has a P1 dedup key mismatch and sequential asset fetching that serialises 18 network round-trips
scripts/export_onboarding_sync_bundle.sh Entry-point script; PATH ordering to prefer Apple tools on CI hosts is appropriate
scripts/prepare_onboarding_sync_bundle.sh Copies assets, calls sips for dimensions, generates manifest.json and index.html; filenames are codebase-controlled so HTML interpolation is safe
scripts/publish_onboarding_sync_branch.sh Orphan-style force-push to figma-onboarding-sync is intentional; GITHUB_TOKEN in remote URL could be leaked in git error output

Sequence Diagram

sequenceDiagram
    participant GH as GitHub Actions
    participant Swift as Swift App (headless)
    participant Bundle as Bundle Scripts
    participant Branch as figma-onboarding-sync
    participant Figma as Figma Plugin

    GH->>Swift: swift run --export-onboarding $ASSETS_DIR
    loop subprocess per step (18 total)
        Swift->>Swift: render OnboardingView(isExportPreview=true, step=N)
        Swift-->>GH: stepN.png + stepN.pdf
    end
    GH->>Bundle: prepare_onboarding_sync_bundle.sh
    Bundle->>Bundle: sips dimensions → manifest.json + index.html
    GH->>Branch: force-push onboarding/latest/
    Note over Branch: served via raw.githubusercontent.com
    loop every 15 s
        Figma->>Branch: GET manifest.json
        alt new sourceCommit
            loop sequential fetch (current)
                Figma->>Branch: GET asset.png
            end
            Figma->>Figma: place frames in Onboarding Sync section
        end
    end
Loading

Reviews (1): Last reviewed commit: "Add onboarding sync export pipeline" | Re-trigger Greptile

Comment on lines +62 to +64
function manifestSignature(manifest) {
return manifest.sourceCommit || manifest.generatedAt || JSON.stringify(manifest.assets || []);
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Deduplication key mismatch causes repeated re-sync

manifestSignature() falls back to JSON.stringify(manifest.assets) when both sourceCommit and generatedAt are absent, but applyManifest (line 174) stores "" in config.lastAppliedSourceCommit for the same condition. After the first sync run without those fields, syncOnce compares JSON.stringify(assets) === "", which is always false, so every poll tick re-fetches and re-applies all 18 assets unnecessarily.

Fix by using the same fallback in both places:

Suggested change
function manifestSignature(manifest) {
return manifest.sourceCommit || manifest.generatedAt || JSON.stringify(manifest.assets || []);
}
function manifestSignature(manifest) {
return manifest.sourceCommit || manifest.generatedAt || JSON.stringify(manifest.assets || []);
}

And in applyManifest (line 174):

config.lastAppliedSourceCommit = manifest.sourceCommit || manifest.generatedAt || JSON.stringify(manifest.assets || []);

Comment on lines +143 to +147
for (const asset of manifest.assets || []) {
const assetUrl = new URL(asset.png, config.sourceUrl).toString();
const bytes = await fetchAssetBytes(assetUrl);
assets.push({ asset, bytes });
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Sequential asset fetching adds unnecessary latency

All 18 onboarding PNGs are fetched one-at-a-time in a for/await loop. On a typical network connection this serialises 18 round-trips before any frame is rendered in Figma. Promise.all would reduce wall-clock time to roughly the slowest single request.

Suggested change
for (const asset of manifest.assets || []) {
const assetUrl = new URL(asset.png, config.sourceUrl).toString();
const bytes = await fetchAssetBytes(assetUrl);
assets.push({ asset, bytes });
}
const assets = await Promise.all(
(manifest.assets || []).map(async (asset) => {
const assetUrl = new URL(asset.png, config.sourceUrl).toString();
const bytes = await fetchAssetBytes(assetUrl);
return { asset, bytes };
})
);

Comment on lines +222 to +226
saveConfig(loadConfig());
figma.ui.postMessage({
type: "start",
config: loadConfig(),
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Double loadConfig() call at startup

saveConfig(loadConfig()) parses and immediately re-serialises the stored config (a no-op round-trip), then loadConfig() is called again to build the start message — three JSON operations where one suffices.

Suggested change
saveConfig(loadConfig());
figma.ui.postMessage({
type: "start",
config: loadConfig(),
});
const initialConfig = loadConfig();
saveConfig(initialConfig);
figma.ui.postMessage({
type: "start",
config: initialConfig,
});

Comment on lines +48 to +49
git remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git push --force origin "HEAD:${TARGET_BRANCH}"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Token embedded in remote URL may leak on push failure

git push failure messages can include the remote URL, which would expose GITHUB_TOKEN in workflow logs. Using a credential helper keeps the token out of any printed output.

Suggested change
git remote add origin "https://x-access-token:${GITHUB_TOKEN}@github.com/${GITHUB_REPOSITORY}.git"
git push --force origin "HEAD:${TARGET_BRANCH}"
git remote add origin "https://github.com/${GITHUB_REPOSITORY}.git"
git -c credential.helper= \
-c "url.https://x-access-token:${GITHUB_TOKEN}@github.com.insteadOf=https://github.com" \
push --force origin "HEAD:${TARGET_BRANCH}"

Glucksberg pushed a commit to Glucksberg/omi-local that referenced this pull request Apr 28, 2026
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.

1 participant