fyne-io/fyne
Cross platform GUI toolkit in Go inspired by Material Design
Healthy across the board
worst of 4 axesnon-standard license (Other)
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 1d ago
- ✓14 active contributors
- ✓Distributed ownership (top contributor 46% of recent commits)
Show 4 more →Show less
- ✓Other licensed
- ✓CI configured
- ✓Tests present
- ⚠Non-standard license (Other) — review terms
What would change the summary?
- →Use as dependency Concerns → Mixed if: clarify license terms
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/fyne-io/fyne)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/fyne-io/fyne on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: fyne-io/fyne
Generated by RepoPilot · 2026-05-09 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/fyne-io/fyne shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across the board
- Last commit 1d ago
- 14 active contributors
- Distributed ownership (top contributor 46% of recent commits)
- Other licensed
- CI configured
- Tests present
- ⚠ Non-standard license (Other) — review terms
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live fyne-io/fyne
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/fyne-io/fyne.
What it runs against: a local clone of fyne-io/fyne — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in fyne-io/fyne | Confirms the artifact applies here, not a fork |
| 2 | License is still Other | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code |
| 5 | Last commit ≤ 31 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of fyne-io/fyne. If you don't
# have one yet, run these first:
#
# git clone https://github.com/fyne-io/fyne.git
# cd fyne
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of fyne-io/fyne and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "fyne-io/fyne(\\.git)?\\b" \\
&& ok "origin remote is fyne-io/fyne" \\
|| miss "origin remote is not fyne-io/fyne (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
&& ok "license is Other" \\
|| miss "license drift — was Other at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 4. Critical files exist
test -f "app/app.go" \\
&& ok "app/app.go" \\
|| miss "missing critical file: app/app.go"
test -f "canvas/canvas.go" \\
&& ok "canvas/canvas.go" \\
|| miss "missing critical file: canvas/canvas.go"
test -f "animation.go" \\
&& ok "animation.go" \\
|| miss "missing critical file: animation.go"
test -f "app/preferences.go" \\
&& ok "app/preferences.go" \\
|| miss "missing critical file: app/preferences.go"
test -f "app/storage.go" \\
&& ok "app/storage.go" \\
|| miss "missing critical file: app/storage.go"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 31 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~1d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/fyne-io/fyne"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Fyne is a cross-platform GUI toolkit written in Go that lets developers build desktop and mobile applications from a single codebase using Material Design principles. It provides native-looking widgets and handles platform-specific rendering through OpenGL, software rasterization, and web backends, eliminating the need to write separate UI code for Windows, macOS, Linux, iOS, and Android. Single-package monorepo structure: core GUI logic in root-level files (animation.go, app.go) with platform-specific implementations under app/ directory (app_darwin.go for macOS, app_mobile_and.go for Android, app_wasm.go for web). Native backend code in Objective-C (.m files) and Java, wrapped by Go interfaces. Widget definitions, theming, and canvas rendering split into separate logical modules, all under the main fyne.io/fyne/v2 import path.
👥Who it's for
Go developers building desktop and mobile applications who want to avoid platform-specific UI code, Qt/wxWidgets complexity, or Electron's resource overhead. Teams needing Material Design-compliant interfaces that run identically on Linux, macOS, Windows, iOS, and Android with minimal platform knowledge.
🌱Maturity & risk
Production-ready with active development. The project has ~6.5k Go files, established CI/CD (platform_tests.yml, mobile_tests.yml, web_tests.yml workflows), comprehensive test coverage (_test.go files throughout), and documented getting-started guides. Requires Go 1.17+, indicating stability focus, though ongoing development suggests regular feature additions and refinements.
Standard open source risks apply.
Active areas of work
Active maintenance on cross-platform compatibility and performance. Recent work visible in mobile test workflows (mobile_tests.yml with iOS/Android targets), web assembly support (app_openurl_wasm.go, app_wasm.go), and platform-specific optimizations (app_desktop_darwin.go). CI runs static analysis and platform-specific tests, indicating focus on code quality and preventing regressions.
🚀Get running
git clone https://github.com/fyne-io/fyne.git && cd fyne && go mod tidy && go get fyne.io/demo@latest && demo
Daily commands: For development: go run ./cmd/demo/main.go (assuming demo exists in cmd/). For library use: import fyne.io/fyne/v2/app and call app.NewApp().ShowAndRun(). Requires C compiler in PATH and platform SDKs for mobile targets.
🗺️Map of the codebase
app/app.go— Core application initialization and lifecycle management—the primary entry point for all Fyne applications.canvas/canvas.go— Central rendering and drawing canvas abstraction that handles all visual output across platforms.animation.go— Animation framework enabling smooth transitions and dynamic UI updates—foundational for Material Design feel.app/preferences.go— Cross-platform preferences and settings persistence layer used throughout the framework.app/storage.go— Abstract storage interface enabling platform-agnostic file and data access patterns.canvas/gradient.go— Gradient rendering system used by Material Design theming and visual styling primitives.app/settings.go— Theme, appearance, and global application settings—drives Material Design compliance across UI.
🛠️How to make changes
Add a new shape primitive to the canvas system
- Create a new file in canvas/ (e.g., canvas/triangle.go) implementing the canvas.Object interface with Refresh(), Hide(), Show(), and Move() methods. (
canvas/triangle.go) - Define the shape struct with position, size, and styling fields (Fill, Stroke, StrokeWidth). (
canvas/triangle.go) - Implement platform-specific rendering by following the pattern in canvas/rectangle.go—delegation to driver.DrawObject(). (
canvas/rectangle.go) - Add unit tests in canvas/triangle_test.go covering bounds calculation, rendering, and visibility toggles. (
canvas/triangle_test.go) - Export the constructor function in the canvas package and document Material Design compliance. (
canvas/canvas.go)
Implement a new theme variant for Material Design
- Add a new theme struct in app/settings.go that implements the fyne.Theme interface with methods for colors, fonts, icons, and sizing. (
app/settings.go) - Define Material Design color palette and typography constants following the existing light/dark theme patterns. (
app/settings.go) - Store theme as JSON in app/testdata/ and add a loader in app/settings_file.go to deserialize and apply it. (
app/settings_file.go) - Add integration tests in app/settings_desktop_test.go to validate theme application across all widgets. (
app/settings_desktop_test.go)
Add platform-specific app initialization logic
- Create app/app_<platform>.go (e.g., app/app_linux.go) following the pattern of app/app_windows.go or app/app_darwin.go. (
app/app_linux.go) - Implement platform-specific setup in the New() constructor and lifecycle hooks (setup preferences, storage paths, native integrations). (
app/app_linux.go) - Add platform detection in app/app.go using build tags (//go:build linux) to conditionally include your implementation. (
app/app.go) - Write integration tests in app/app_<platform>_test.go to validate app lifecycle, preferences persistence, and native notifications. (
app/app_linux_test.go)
Extend animation system with custom easing function
- Add easing function definition to animation.go following the existing Ease() callback pattern. (
animation.go) - Create a struct embedding canvas.Animation and override the callback to apply your custom easing to progress (0.0–1.0). (
canvas/animation.go) - Register the animation with the canvas loop via canvas.Animate() and trigger Refresh() on frame updates. (
canvas/animation.go) - Add test cases in animation_test.go validating easing curves and frame-by-frame progress increments. (
animation_test.go)
🔧Why these technologies
- Go 1.13+ — Cross-platform compilation without runtime dependencies; single binary for Desktop, Mobile, and Web (WASM).
- Material Design inspiration — Provides consistent, recognizable UI patterns across all platforms (Android, iOS, Windows, macOS, Linux, Web).
- Canvas-based rendering — Decouples UI logic from platform-specific rendering drivers, enabling single codebase for all targets.
- Platform abstraction layers (app_.go, preferences_.go) — Isolates native APIs (Cocoa, Win32, Android JNI, iOS Objective-C) into separate build-gated files, reducing complexity.
- File-based preferences & settings — Simple, durable cross-platform persistence without database dependency; theme and config JSON serializable.
⚖️Trade-offs already made
-
Single codebase with platform-specific conditionals (build tags, _darwin.go, _windows.go files) instead of separate repos
- Why: Enables shared widget logic, common animations, and unified testing while allowing native integrations.
- Consequence: Increased file count and conditional compilation complexity, but eliminates code duplication and ensures version coherence.
-
Canvas abstraction over native widgets
- Why: Maximum UI consistency and custom Material Design styling across all platforms.
- Consequence: Slightly higher memory/CPU overhead vs. native widgets; all rendering responsibility on Fyne framework.
-
Preferences stored as JSON files (no database)
- Why: Zero external dependencies, instant I/O, human-readable config, easy testing.
- Consequence: Not suitable for large datasets or frequent writes; no ACID guarantees or concurrent access protection.
-
Synchronous animation loop with canvas.Animate() vs. async event-driven model
- Why: Predictable 60fps rendering; simpler mental model for developers.
- Consequence: Higher baseline CPU usage; jank if frame time exceeds 16ms; less responsive to true event-driven UIs.
🪤Traps & gotchas
C compiler required but errors are cryptic on first build (ensure gcc/clang in PATH). Platform SDKs must match Go cgo expectations—mismatched Xcode/Android NDK versions break builds silently. app/app_darwin.go uses build tags to conditionally import legacy vs. non-legacy code paths; breaking both paths breaks macOS support entirely. Mobile backends require platform-specific toolchains (xcode-select for iOS, Android SDK for Android); these aren't documented in the README. Preferences are loaded asynchronously; accessing preferences immediately after app startup may return stale values.
🏗️Architecture
🔗Related repos
gotk3/gotk3— Alternative Go GUI toolkit wrapping GTK3; similar cross-platform goal but uses C bindings instead of native renderinggo-echarts/go-echarts— Lightweight charting library for Go; often paired with Fyne for data visualization dashboardsfyne-io/fyne-demo— Official Fyne demo application showcasing all widgets and patterns; reference implementation for new Fyne usersfyne-io/tools— Companion tooling (fyne package, fyne-doc) for building, packaging, and documenting Fyne applicationsgoogle/material-design-icons— Official Material Design icon library used by Fyne's theming system for consistent iconography
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add comprehensive test coverage for platform-specific app initialization (app/app_*.go files)
The repo has multiple platform-specific implementations (Darwin, Windows, Android, iOS, WASM, XDG, etc.) but many lack corresponding _test.go files. Only app_darwin_test.go, app_mobile_and_test.go, app_windows_test.go, and app_test.go exist. Platform-specific code paths for app initialization, preferences, and settings are untested, creating maintenance blind spots.
- [ ] Create app/app_xdg_test.go with tests for XDG-specific storage and preferences paths
- [ ] Create app/app_wasm_test.go testing WASM-specific app lifecycle and preferences handling
- [ ] Create app/app_mobile_ios_test.go mirroring coverage from app_mobile_and_test.go
- [ ] Add tests to app/preferences_nonweb.go variants to verify platform-specific preference storage
- [ ] Ensure CI runs these new tests in mobile_tests.yml and platform_tests.yml workflows
Add GitHub Actions workflow for cross-platform cloud storage integration testing
The codebase has app/cloud.go and app/cloud_test.go, indicating cloud storage features exist. However, there's no dedicated CI workflow to test cloud integration across platforms. The existing workflows (mobile_tests.yml, platform_tests.yml, web_tests.yml) don't mention cloud storage testing, leaving potential cloud sync bugs undiscovered.
- [ ] Create .github/workflows/cloud_integration_tests.yml to test app/cloud.go functionality
- [ ] Add matrix strategy to test against mock cloud providers on Linux, macOS, and Windows
- [ ] Configure the workflow to run on pull requests targeting cloud-related files
- [ ] Document expected environment variables for cloud storage in CONTRIBUTING.md
- [ ] Add test fixtures in app/testdata for cloud storage scenarios (e.g., offline sync, conflict resolution)
Refactor and expand animation.go test coverage with scenario-based tests
animation.go and animation_test.go exist at the root level, but the test file is likely minimal given the complexity of animation timing, curves, and lifecycle management. Material Design animations are core to Fyne's identity, yet animation edge cases (concurrent animations, cancellation, completion callbacks) may lack coverage.
- [ ] Review animation_test.go and identify uncovered animation scenarios (timing curves, easing functions, animation groups)
- [ ] Add tests for concurrent animation handling and animation cancellation
- [ ] Add tests for animation lifecycle (start, pause, resume, stop callbacks)
- [ ] Add property-based tests using rapid or quickcheck to verify animation state consistency
- [ ] Document animation testing patterns in CONTRIBUTING.md with examples from animation_test.go
🌿Good first issues
- Add comprehensive unit tests for app/preferences.go non-mobile code paths—currently only Android variant has dedicated test file (app/preferences_android.go exists but no app/preferences_test.go visible), leaving desktop preferences untested.
- Implement missing docstrings for exported functions in animation.go and app.go—Go convention requires documentation comments on public APIs; many core functions lack these, breaking godoc generation.
- Create a comparison matrix or decision guide in CONTRIBUTING.md explaining when to use app_gl.go vs. app_software.go vs. app_wasm.go backends—currently no guidance exists for contributors choosing rendering paths for new features.
⭐Top contributors
Click to expand
Top contributors
- @andydotxyz — 46 commits
- @Jacalz — 22 commits
- @Vinci10 — 7 commits
- @redawl — 6 commits
- @dweymouth — 4 commits
📝Recent commits
Click to expand
Recent commits
963f0f8— Fix demo location (andydotxyz)3f52c5d— Add document to clarify OnSubmitted (andydotxyz)0557a0f— Preparing v2.7.3 (andydotxyz)aa1a7b5— Fix counting for nested ordered lists (MaxGyver83)7ecc835— Handle nested lists in Markdown renderer (MaxGyver83)35df60e— add minsize caches (#6112) (dweymouth)d93b16b— Fix text encoding of entities when parsing markdown (andydotxyz)41bf61c— Fix text blurring by using explicit size rounding instead of position-derived bounds (alexballas)1a6e669— Fixing icon failure whencurrentColoris at the root node (i.e. no current color) (andydotxyz)5cdfaab— [text] bump go-text/typesetting to v0.3.3 and fix deprecated fields. (benoitkugler)
🔒Security observations
The Fyne GUI toolkit codebase shows reasonable security practices with a defined security policy and multi-platform support. However, there are moderate concerns around the outdated Go version requirement (1.13), potential path traversal risks in file operations (particularly in icon caching), and varying security implementations across different platform-specific modules. The codebase lacks visible evidence of hardcoded secrets or obvious injection vulnerabilities in the file structure provided. Recommendations include updating the minimum Go version, implementing secure file path handling, encrypting sensitive data in preferences, and extending the security update support window. The static analysis is limited by the lack of actual source code review; dynamic analysis and code inspection of critical components would provide more definitive findings.
- Medium · Outdated Go Version Requirement —
go.mod. The module specifies go 1.13 as the minimum version, which was released in September 2019 and is now significantly outdated. Go 1.13 has known security vulnerabilities and lacks important security patches available in newer versions. Fix: Update the minimum Go version to at least 1.21 or the latest stable release. Run 'go mod tidy' and test thoroughly after updating. - Medium · Potential Path Traversal in Icon Cache —
app/icon_cache_file.go, app/icon_cache_other.go. The presence of icon_cache_file.go and icon_cache related files suggest file system operations. Without reviewing the actual implementation, icon caching mechanisms could be vulnerable to path traversal attacks if user input or external data isn't properly validated when constructing file paths. Fix: Ensure all file path operations use path.Clean() or filepath.Join() with whitelisted base directories. Validate and sanitize all inputs used in file path construction. Avoid accepting absolute paths or paths with '..' sequences. - Medium · Potential Security Issue with Preferences Storage —
app/preferences*.go files. Multiple preferences files across different platforms (preferences_android.go, preferences_ios.go, preferences_mobile.go, preferences_other.go, preferences_wasm.go) handle user preferences which may include sensitive data. Platform-specific implementations could have varying security levels. Fix: Encrypt sensitive preference data at rest. Use platform-specific secure storage APIs (Keychain on iOS, KeyStore on Android). Implement proper access controls and validate preference data before deserialization. - Low · Missing HTTPS in Documentation Links —
README.md, .godocdown.import. While not a critical vulnerability, some documentation references use non-HTTPS links which could expose users to MITM attacks if they follow these links. Fix: Ensure all documentation and README links use HTTPS protocol. Update any non-HTTPS URLs to their HTTPS equivalents. - Low · Limited Security Update Policy —
SECURITY.md. The SECURITY.md indicates that only version 2.6.x receives security updates, with all earlier versions unsupported. This is a relatively short support window for a GUI toolkit that may be used in production applications. Fix: Consider extending the security update window to cover at least the last 2-3 minor versions. Clearly communicate end-of-life dates to users well in advance.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.