From 5c7c1044c033e5336c194fec2d19af785b3b234f Mon Sep 17 00:00:00 2001 From: zcourts Date: Fri, 22 May 2026 05:56:41 +0100 Subject: [PATCH 1/3] Specify package icon generation pipeline --- docs/post-build-lifecycle.md | 285 ++++++++++++++++++++++++++++++++--- 1 file changed, 264 insertions(+), 21 deletions(-) diff --git a/docs/post-build-lifecycle.md b/docs/post-build-lifecycle.md index d5c8f7c0..7c2d1f07 100644 --- a/docs/post-build-lifecycle.md +++ b/docs/post-build-lifecycle.md @@ -173,10 +173,35 @@ privacy_url = "https://example.com/privacy" license = "MIT" [package] -icon = "assets/app-icon.png" category = "Productivity" copyright = "Copyright (c) 2026 Example Software Ltd" +[package.icons] +mode = "generate" +source = "assets/app-icon.png" +background_color = "#070C1D" +safe_zone = "platform" +allow_upscale = false +monochrome = "assets/app-icon-monochrome.svg" + +[package.icons.android] +foreground = "assets/android-icon-foreground.svg" +background = "assets/android-icon-background.svg" +monochrome = "assets/android-icon-monochrome.svg" + +[package.icons.ios] +source = "assets/app-icon-ios.png" + +[package.icons.macos] +source = "assets/app-icon-macos.png" + +[package.icons.windows] +source = "assets/app-icon-windows.png" + +[package.icons.web] +favicon = "assets/favicon.svg" +maskable = "assets/app-icon-maskable.png" + [package.linux.run] install_name = "todo" default_scope = "user" @@ -381,7 +406,7 @@ The CLI MUST validate that: - platform bundle/package identifiers match the corresponding store configuration. - `app.version` is semantic for Fission metadata, but platform-specific build numbers follow platform rules. - secrets are referenced by key name or provider account, not embedded as plaintext values. -- icon and store asset paths exist before packaging. +- icon source assets, provided icon outputs, and store asset paths exist before packaging. - `fission.toml` contains the required release root entries for the selected provider, release, and locales. - every file referenced by `[[releases]]` exists, is inside an allowed project path, and validates against the release-content schema. - release-content output roots are inside the project or an explicitly allowed workspace path. @@ -390,6 +415,198 @@ The CLI MUST validate that: - static-site distribution entries match the generated site's base path, custom-domain mode, and provider publishing source. - signing asset references point to keychain/certificate-store/vault entries or CI secret names, not plaintext secrets. +### 5.1 App icon intent, generation, and overrides + +`fission.toml` declares icon intent and source assets; it must not require users to hand-maintain every platform's generated icon output. `fission package` MUST generate platform-specific icon sets from those declared sources before the platform packager runs. `fission readiness package` MUST validate icon configuration before expensive build work starts. + +The authoritative schema is `[package.icons]`. The older shorthand: + +```toml +[package] +icon = "assets/app-icon.png" +``` + +MAY be accepted for compatibility, but it MUST be treated as a desugaring to: + +```toml +[package.icons] +mode = "generate" +source = "assets/app-icon.png" +``` + +The package icon mode MUST be one of: + +- `generate`: Fission generates every required target icon output from declared source assets. +- `provided`: the user provides the complete platform icon set and Fission validates/copies it without regenerating it. +- `mixed`: platform-specific provided outputs win, and Fission generates any missing outputs from the shared/default sources. + +The shared icon declaration is: + +```toml +[package.icons] +mode = "generate" +source = "assets/app-icon.png" +monochrome = "assets/app-icon-monochrome.svg" +background_color = "#070C1D" +safe_zone = "platform" +allow_upscale = false +``` + +`source` is the default full-colour launcher icon source. It SHOULD be SVG or a high-resolution square PNG. `monochrome` is an alpha/silhouette source used by platforms that support monochrome or themed icons. `background_color` is used when a generated target requires a solid backing plate or an adaptive-icon background and no explicit platform background is supplied. `safe_zone` controls padding/cropping and MUST accept at least `platform`, `none`, and a numeric fraction such as `0.72`. `allow_upscale = false` means readiness fails if a raster source is too small for the required target output. + +Platform-specific generation inputs are optional overrides: + +```toml +[package.icons.android] +foreground = "assets/android-icon-foreground.svg" +background = "assets/android-icon-background.svg" +monochrome = "assets/android-icon-monochrome.svg" + +[package.icons.ios] +source = "assets/app-icon-ios.png" +dark = "assets/app-icon-ios-dark.png" +tinted = "assets/app-icon-ios-tinted.png" + +[package.icons.macos] +source = "assets/app-icon-macos.png" + +[package.icons.windows] +source = "assets/app-icon-windows.png" +light = "assets/app-icon-windows-light.png" +dark = "assets/app-icon-windows-dark.png" +unplated = "assets/app-icon-windows-unplated.png" + +[package.icons.linux] +source = "assets/app-icon-linux.png" + +[package.icons.web] +favicon = "assets/favicon.svg" +maskable = "assets/app-icon-maskable.png" +monochrome = "assets/app-icon-monochrome.svg" +``` + +Manual output mode is explicit and must validate completeness: + +```toml +[package.icons] +mode = "provided" + +[package.icons.android.provided] +res_dir = "platforms/android/app/src/main/res" + +[package.icons.ios.provided] +appiconset = "platforms/ios/App/Assets.xcassets/AppIcon.appiconset" + +[package.icons.macos.provided] +icns = "platforms/macos/AppIcon.icns" + +[package.icons.windows.provided] +ico = "platforms/windows/AppIcon.ico" +msix_assets = "platforms/windows/Assets" + +[package.icons.linux.provided] +hicolor_dir = "platforms/linux/icons/hicolor" + +[package.icons.web.provided] +manifest_icons_dir = "platforms/web/icons" +favicon = "platforms/web/favicon.svg" +``` + +In `mixed` mode, any `[package.icons..provided]` block is authoritative for that target. Fission MUST generate only the missing targets from `[package.icons]` and platform-specific source overrides. + +The generated output root MUST be disposable and reproducible: + +```text +target/fission/icons/android/ +target/fission/icons/ios/AppIcon.appiconset/ +target/fission/icons/macos/AppIcon.icns +target/fission/icons/windows/AppIcon.ico +target/fission/icons/windows/msix/ +target/fission/icons/linux/hicolor/ +target/fission/icons/web/ +target/fission/icons/icon-manifest.json +``` + +Packaging stages MUST consume the generated or validated icon manifest rather than re-reading icon configuration independently. The manifest MUST record source paths, source hashes, mode, target, generated output paths, dimensions, roles, and target package paths. Example: + +```json +{ + "mode": "generate", + "target": "android", + "sources": [ + { + "role": "android_foreground", + "path": "assets/android-icon-foreground.svg", + "sha256": "..." + } + ], + "outputs": [ + { + "role": "android_adaptive_icon", + "path": "target/fission/icons/android/mipmap-anydpi-v26/ic_launcher.xml", + "package_path": "res/mipmap-anydpi-v26/ic_launcher.xml" + } + ] +} +``` + +Target generation requirements: + +| Target | Generated outputs | +| --- | --- | +| Android | Adaptive icon XML using foreground/background/monochrome layers where available, legacy density PNGs where required by the minimum SDK/package format, and launcher manifest/resource references. Android adaptive icons are layered and masked by the launcher, so safe-zone validation is mandatory [R68]. | +| iOS | `AppIcon.appiconset` PNGs and `Contents.json` from the selected source, including dark/tinted variants when configured and supported by the selected iOS deployment target. Apple app icons use platform-shaped assets and high-resolution source art [R69]. | +| macOS | `AppIcon.icns`, any required appiconset intermediates, and the bundle `Info.plist` icon key. | +| Windows | Win32 `.ico` plus MSIX/Store visual assets, target-size PNGs, scale variants, and light/dark/unplated variants where configured. Windows selects exact icon sizes first and benefits from multiple target sizes [R70]. | +| Linux | hicolor icon-theme directory outputs at required sizes plus desktop-entry and AppStream references. Freedesktop icon lookup is size/theme based [R35][R36][R72]. | +| Web/static | favicon files, Apple touch icon where configured, web manifest `icons` entries with `sizes`, `type`, and `purpose`, including `any`, `maskable`, and `monochrome` roles where sources exist. The Web App Manifest defines icon purposes and safe zones for maskable icons [R71]. | + +Readiness MUST fail when: + +- configured source files do not exist; +- a raster source is too small and `allow_upscale = false`; +- a required platform output cannot be produced from the available sources; +- `mode = "provided"` omits required platform files; +- platform-provided directories contain inconsistent metadata, missing sizes, or unreadable images; +- a source is not square where the target requires square source art; +- transparent pixels or missing background declarations would produce invalid or low-quality outputs for the selected target; +- generated outputs would overwrite user-authored source files. + +Readiness SHOULD warn when: + +- text-heavy icon art is used for mobile, maskable, monochrome, or small-size outputs; +- the important artwork appears outside the selected safe zone; +- the source is raster-only and cannot produce crisp large outputs; +- platform-specific overrides would materially improve output quality; +- generated Windows, Linux, or web icons will be scaled by the platform because an exact size is unavailable. + +The CLI implementation MUST keep all icon handling in a dedicated Rust module: + +```text +crates/tools/fission-cli/src/icons/ + mod.rs + config.rs + model.rs + validate.rs + generate.rs + manifest.rs + android.rs + ios.rs + macos.rs + windows.rs + linux.rs + web.rs +``` + +Packagers MUST call this module through a small API such as: + +```rust +pub fn prepare_icons(ctx: &ReleaseContext, target: Target) -> anyhow::Result; +pub fn validate_icons(ctx: &ReleaseContext, target: Target) -> Vec; +``` + +No packager implementation may parse `[package.icons]`, discover conventional icon paths, or generate icon files directly. This keeps icon policy, validation, generation, hashing, and diagnostics in one place and prevents platform packagers from drifting apart. + ## 6. Artifact manifest Every successful `fission package` command MUST emit an artifact manifest. Distribution commands consume the manifest instead of rediscovering files by path conventions. @@ -424,6 +641,11 @@ Minimum schema: "mime_type": "application/octet-stream" } ], + "icon_manifest": { + "path": "target/fission/icons/icon-manifest.json", + "sha256": "...", + "outputs": 18 + }, "signing": { "state": "signed", "identity": "android-upload-key:upload", @@ -437,6 +659,8 @@ Minimum schema: } ``` +If the selected target uses application icons, the artifact manifest MUST include the icon manifest path and hash. This connects the signed/package artifact to the exact generated or validated icon set it consumed. + The manifest MUST be immutable once distribution starts. A distribute command that modifies provider state MUST write a separate distribution receipt. ```text @@ -598,6 +822,7 @@ The release tooling should prefer Rust for Fission-owned control flow and data h | Area | Fission/Rust responsibility | Provider/platform tool | Notes | | --- | --- | --- | --- | +| App icon generation | Dedicated `crates/tools/fission-cli/src/icons` module using `usvg`, `resvg`, `tiny-skia`, `image`, `png`, `ico`, `icns`, `plist`, `serde_json`, `quick-xml`, `sha2`, and optional `oxipng` | platform tools only for final platform-owned bundle/package signing or validation | Fission owns deterministic icon generation from `[package.icons]` into target-specific outputs. Platform packagers consume the generated icon manifest and must not implement their own icon parsing or generation [R73][R74][R75][R76][R77][R78][R79][R80][R81][R82][R83][R84]. | | Desktop bundle generation | `cargo-packager` integration where it fits, plus Fission manifest and asset staging | platform-specific packager | `cargo-packager` supports macOS `.app`, Linux AppImage/deb, Windows NSIS/WiX, but not every Fission-required format such as Linux `.run`, macOS `.pkg`, MSIX, AAB, or IPA [R25]. | | macOS `.app` basics | bundle metadata, assets, `Info.plist` inputs, and readiness checks | Xcode command-line tools for signing/notarization | `.app` bundle structure and `Info.plist` requirements are Apple platform rules [R8][R9]. | | macOS `.pkg` | configuration, staging, receipts, and readiness checks | `pkgbuild`, `productbuild`, `productsign` | Apple's package tools create installer component packages and product archives [R13]. | @@ -1848,25 +2073,26 @@ These are implementation milestones, not partial product definitions. The final 2. Add credential vault and `fission auth` commands. 3. Add release-config root schema in `fission.toml`, `[[releases]]` file references, referenced release-file schemas, TUI editing, non-interactive edit/import/diff/validate/push commands, screenshot scenario model, and content manifest. 4. Add readiness engine with JSON output and stable error IDs. -5. Implement Linux `.run` packager and smoke install/uninstall checks. -6. Implement macOS `.app`, `.pkg`, signing, notarization, and readiness checks. -7. Implement Windows `.exe`, `.msi`, `.msix`, signing/provider distinctions, and readiness checks. -8. Implement Android APK/AAB packaging, bundle validation, signing, and Play readiness. -9. Implement iOS IPA packaging, signing/provisioning readiness, and App Store/TestFlight distribution path. -10. Implement web static packaging with MIME/cache metadata. -11. Implement screenshot capture/rendering for web, Android, iOS, macOS, and Windows where device automation is available. -12. Implement store metadata import/diff/validate/push for supported providers using `fission.toml` plus referenced release files as the authoritative inputs. -13. Implement beta group/tester/flight management for supported providers. -14. Implement version-state queries, release recipes, and provider-side status observation. -15. Implement GitHub Pages distribution for Actions and branch-source modes, including custom-domain readiness and DNS health checks. -16. Implement Cloudflare Pages distribution with API-token auth, Wrangler-based prebuilt upload, project/domain readiness, and receipts. -17. Implement Netlify distribution with token auth, API deploys, draft/production deploys, custom-domain readiness, and receipts. -18. Implement S3-compatible distribution and receipts. -19. Implement Google Drive, OneDrive, and Dropbox distribution. -20. Implement store distribution for Google Play, App Store Connect/TestFlight, and Microsoft Store. -21. Implement review/customer-feedback list/reply where provider APIs support it. -22. Add install/upload/screenshot smoke tests and CI coverage for non-secret paths. -23. Document provider setup walkthroughs and first-release manual checklists. +5. Add `[package.icons]`, the dedicated `crates/tools/fission-cli/src/icons` module, icon readiness checks, deterministic platform icon generation, manual/provided icon validation, and icon manifests before platform packagers consume icons. +6. Implement Linux `.run` packager and smoke install/uninstall checks. +7. Implement macOS `.app`, `.pkg`, signing, notarization, and readiness checks. +8. Implement Windows `.exe`, `.msi`, `.msix`, signing/provider distinctions, and readiness checks. +9. Implement Android APK/AAB packaging, bundle validation, signing, and Play readiness. +10. Implement iOS IPA packaging, signing/provisioning readiness, and App Store/TestFlight distribution path. +11. Implement web static packaging with MIME/cache metadata. +12. Implement screenshot capture/rendering for web, Android, iOS, macOS, and Windows where device automation is available. +13. Implement store metadata import/diff/validate/push for supported providers using `fission.toml` plus referenced release files as the authoritative inputs. +14. Implement beta group/tester/flight management for supported providers. +15. Implement version-state queries, release recipes, and provider-side status observation. +16. Implement GitHub Pages distribution for Actions and branch-source modes, including custom-domain readiness and DNS health checks. +17. Implement Cloudflare Pages distribution with API-token auth, Wrangler-based prebuilt upload, project/domain readiness, and receipts. +18. Implement Netlify distribution with token auth, API deploys, draft/production deploys, custom-domain readiness, and receipts. +19. Implement S3-compatible distribution and receipts. +20. Implement Google Drive, OneDrive, and Dropbox distribution. +21. Implement store distribution for Google Play, App Store Connect/TestFlight, and Microsoft Store. +22. Implement review/customer-feedback list/reply where provider APIs support it. +23. Add install/upload/screenshot smoke tests and CI coverage for non-secret paths. +24. Document provider setup walkthroughs and first-release manual checklists. Each milestone MUST land with unit tests for config/readiness logic, integration tests for local packaging where possible, and mocked provider tests for distribution APIs. @@ -1961,3 +2187,20 @@ The post-build lifecycle work is accepted when the following are true: [R65] GitHub CLI manual, `gh release upload`: https://cli.github.com/manual/gh_release_upload [R66] Microsoft Learn, Microsoft Store Developer CLI overview: https://learn.microsoft.com/en-us/windows/apps/publish/msstore-dev-cli/overview [R67] Microsoft Learn, Microsoft Store Developer CLI commands: https://learn.microsoft.com/en-us/windows/apps/publish/msstore-dev-cli/commands +[R68] Android Developers, Adaptive icons: https://developer.android.com/develop/ui/views/launch/icon_design_adaptive +[R69] Apple Developer, App icons: https://developer.apple.com/design/human-interface-guidelines/app-icons/ +[R70] Microsoft Learn, Construct your Windows app's icon: https://learn.microsoft.com/en-us/windows/apps/design/iconography/app-icon-construction +[R71] W3C, Web Application Manifest icon purposes and masks: https://www.w3.org/TR/appmanifest/ +[R72] Freedesktop Icon Theme Specification: https://specifications.freedesktop.org/icon-theme/latest/ +[R73] `usvg` crate documentation: https://docs.rs/usvg/ +[R74] `resvg` crate documentation: https://docs.rs/resvg/ +[R75] `tiny-skia` crate documentation: https://docs.rs/tiny-skia/ +[R76] `image` crate documentation: https://docs.rs/image/ +[R77] `png` crate documentation: https://docs.rs/png/ +[R78] `ico` crate documentation: https://docs.rs/ico/ +[R79] `icns` crate documentation: https://docs.rs/icns/ +[R80] `plist` crate documentation: https://docs.rs/plist/ +[R81] `quick-xml` crate documentation: https://docs.rs/quick-xml/ +[R82] `oxipng` crate documentation: https://docs.rs/oxipng/ +[R83] `serde_json` crate documentation: https://docs.rs/serde_json/ +[R84] `sha2` crate documentation: https://docs.rs/sha2/ From 2c8cecd885bf11fc564307c0f7cda7e9c5e6118f Mon Sep 17 00:00:00 2001 From: zcourts Date: Fri, 22 May 2026 08:11:23 +0100 Subject: [PATCH 2/3] refactor(site): rework docs IA, marketing pages, and homepage --- .../docs/build-and-package/overview.mdx | 40 + .../content/docs/develop/workflow.mdx | 38 + .../platform-shells-cli-and-testing.mdx | 4 +- documentation/content/docs/intro.mdx | 44 +- .../docs/release-and-distribute/overview.mdx | 37 + .../post-build-lifecycle.mdx | 153 +++ .../content/docs/test-and-debug/overview.mdx | 32 + .../content/reference/overview/overview.mdx | 12 +- documentation/fission.toml | 26 +- documentation/site/docs-sidebar.toml | 146 ++- documentation/site/overrides.css | 131 +++ documentation/src/components/footer.rs | 243 ++--- documentation/src/components/home.rs | 5 +- documentation/src/components/home_nav.rs | 10 +- documentation/src/components/home_sections.rs | 221 +++- documentation/src/components/marketing.rs | 961 ++++++++++++++++++ documentation/src/components/mod.rs | 2 + documentation/src/main.rs | 52 +- 18 files changed, 1909 insertions(+), 248 deletions(-) create mode 100644 documentation/content/docs/build-and-package/overview.mdx create mode 100644 documentation/content/docs/develop/workflow.mdx create mode 100644 documentation/content/docs/release-and-distribute/overview.mdx create mode 100644 documentation/content/docs/release-and-distribute/post-build-lifecycle.mdx create mode 100644 documentation/content/docs/test-and-debug/overview.mdx create mode 100644 documentation/src/components/marketing.rs diff --git a/documentation/content/docs/build-and-package/overview.mdx b/documentation/content/docs/build-and-package/overview.mdx new file mode 100644 index 00000000..ab5f81c3 --- /dev/null +++ b/documentation/content/docs/build-and-package/overview.mdx @@ -0,0 +1,40 @@ +--- +title: Build and package +description: Package Fission apps for desktop, mobile, web, terminal, and static site targets with preflight checks and artifact manifests. +--- + +# Build and package + +Packaging turns a built app into an artifact another system can install, upload, host, or verify. Fission treats packaging as a first-class workflow because production releases fail when packaging is handled as a pile of shell scripts nobody understands. + +## Package outputs + +| Target | Package formats | +| --- | --- | +| Linux | `.run` | +| macOS | `.app`, `.pkg` | +| Windows | `.exe`, `.msi`, `.msix` | +| Android | `.apk`, `.aab` | +| iOS | `.ipa` | +| Web/site | static HTML/CSS/JS asset directory or archive | + +Every package flow writes an `artifact-manifest.json` describing the output: project identity, target, format, profile, artifact paths, relative paths, file sizes, hashes, MIME types, and validation checks. + +## Preflight checks + +Run readiness checks before you package or release: + +```bash +fission readiness package --project-dir . --target windows --format msix +fission readiness release --project-dir . --target android --format aab --provider play-store +``` + +Readiness checks are deliberately concrete. They look for SDKs, NDKs, Xcode tools, Windows packaging tools, package scripts, signing tools, credentials, provider config, and artifact shape. The goal is to tell you what is missing before the release is blocked at the end of the process. + +## Signing + +Signing is platform-owned. Fission should orchestrate checks, configuration, and receipts, but it should use the tools provided by the platform owner for the part of the process they own. Signing secrets should come from environment variables, CI secret stores, authenticated platform tooling, or the Fission credential vault, not from plain text committed into `fission.toml`. + +## Where to go next + +Read [Production lifecycle](/product/production-lifecycle/) for the platform view and [Release and distribute](/docs/release-and-distribute/overview/) when you are ready to publish artifacts. diff --git a/documentation/content/docs/develop/workflow.mdx b/documentation/content/docs/develop/workflow.mdx new file mode 100644 index 00000000..fcc9f8e6 --- /dev/null +++ b/documentation/content/docs/develop/workflow.mdx @@ -0,0 +1,38 @@ +--- +title: Develop workflow +description: Use the Fission CLI, targets, shells, devices, logs, and project configuration during day-to-day app development. +--- + +# Develop workflow + +The Fission development workflow starts with one project and grows by adding targets. You do not create a separate product for every platform. You keep product behavior in shared Rust and let Fission generate or run the shell needed for the current target. + +## Daily loop + +1. Create or open a project with `fission.toml` at the root. +2. Add the targets your product needs. +3. Run the fastest target while building shared behavior. +4. Switch to the real host whenever the question depends on browser, mobile, terminal, or static-site behavior. +5. Keep logs attached while the app runs. +6. Use readiness checks before packaging or publishing. + +```bash +fission init my-app +cargo fission add-target web android ios --project-dir my-app +fission devices --project-dir my-app +fission run --project-dir my-app +``` + +## Targets and shells + +A target is the output family you want to run or build. A shell is the host layer that boots the shared app model for that target. Desktop, web, mobile, terminal, and static site targets use different shell code, but the state, reducers, widgets, and design system stay shared. + +That distinction keeps your codebase maintainable. Product modules should not know whether they are inside a native window, browser, phone, terminal, or static page unless the feature itself depends on that host. + +## Configuration belongs in `fission.toml` + +`fission.toml` is the authoritative project root for targets, app metadata, site config, distribution config, release roots, and provider references. Keep long-form release notes, localized listing text, screenshots, and large provider metadata in referenced release-content files so the root manifest stays readable. + +## Where to go next + +Read [Platform shells, CLI, and testing](/docs/guides/platform-shells-cli-and-testing/) for the shell model, [Examples and targets](/docs/learn/examples-and-targets/) for target examples, and [Reference: CLI](/reference/cli/overview/) for command details. diff --git a/documentation/content/docs/guides/platform-shells-cli-and-testing.mdx b/documentation/content/docs/guides/platform-shells-cli-and-testing.mdx index b7086b2a..10337a04 100644 --- a/documentation/content/docs/guides/platform-shells-cli-and-testing.mdx +++ b/documentation/content/docs/guides/platform-shells-cli-and-testing.mdx @@ -5,9 +5,9 @@ description: Learn how Fission's shell wrappers and generated host projects fit # Platform shells, command-line interface, and testing -Fission is suitable for production desktop, web, Android, and iOS apps today. The clearest way to understand that claim is to separate three different questions that often get mixed together. +Fission is suitable for production desktop, web, Android, iOS, terminal, and static site work today. The clearest way to understand that claim is to separate three different questions that often get mixed together. -The first question is whether the shared app model is ready for real product work. In Fission, that answer is yes. Your app state, actions, reducers, widgets, layout rules, semantics, and rendering model live in one shared runtime that is meant to power real desktop, browser, Android, and iOS applications. +The first question is whether the shared app model is ready for real product work. In Fission, that answer is yes. Your app state, actions, reducers, widgets, layout rules, semantics, and rendering model live in one shared runtime that is meant to power real desktop, browser, mobile, terminal, and static site surfaces. The second question is whether every shell wrapper and every testing convenience is equally mature today. That answer is more nuanced. The shells expose slightly different wrapper methods, and the current live-testing hooks are not identical on every target. diff --git a/documentation/content/docs/intro.mdx b/documentation/content/docs/intro.mdx index c557ccc5..586eb9dd 100644 --- a/documentation/content/docs/intro.mdx +++ b/documentation/content/docs/intro.mdx @@ -1,34 +1,36 @@ --- title: Docs -sidebar_position: 1 -description: A gentle introduction to what Fission is, how it is structured, and what to read first. +description: Follow the Fission software development lifecycle from setup through development, testing, packaging, signing, release, and distribution. --- # Docs -If you are new to Fission, start here. Fission is a Rust framework for building user interfaces from one shared app model across desktop, web, Android, and iOS. These docs are written to help readers who may be new to Rust user interface work and even new to state-driven user interface, so the first goal is not to overwhelm you with names. The first goal is to give you a mental model that makes the rest of the framework feel understandable. +Fission is a Rust application platform. It helps you build the app, run it on the targets your users care about, test and debug it, package it, sign it, prepare release content, and distribute it through stores, static hosts, GitHub Releases, object stores, and provider-specific tracks. -Fission is structured around a simple idea: your app should behave predictably. In practice, that means the same app state, the same input, and the same time progression should lead to the same result. That kind of predictability matters because it makes bugs easier to reproduce, tests easier to trust, and cross-platform work easier to carry from one target to another without rewriting the core of the app. +These docs are organized around that lifecycle. You can still learn individual concepts such as widgets, reducers, layout, charts, design systems, commands, jobs, and services, but the main path follows the way real software moves from an empty project to a released product. -At a high level, a Fission app works like this. App state holds the data your product cares about, such as the current screen, the selected item, or the text in an editor. Actions are named messages that describe user intent, such as "increment the counter", "open this message", or "save the file". Reducers are the functions that receive those actions and change the state. Widgets then read the current state and describe the hierarchy of interface elements, sometimes called a widget tree, that should appear on screen right now. Finally, shells are the thin platform-specific runners that host the same shared app on desktop, web, Android, and iOS. +## Recommended path -This structure matters because it keeps each job in a clear place. State changes happen in one predictable path instead of being scattered through callbacks. Widgets focus on describing what to show instead of quietly performing outside work. Shells handle windows, browser surfaces, input, lifecycle, and accessibility, while the shared core still defines what the app means. The result is a framework that is easier to debug, easier to test, and easier to move across platforms. +1. **Start** with [Quickstart](/docs/learn/quickstart/) and [Project structure](/docs/guides/app-structure/) so the repository shape and app model are clear. +2. **Learn Fission** with [Runtime model](/docs/learn/runtime-model/), [Rendering pipeline](/docs/learn/rendering-pipeline/), [Layout and widgets](/docs/guides/layout-and-widgets/), and [Resources and async](/docs/guides/resources-and-async/). +3. **Develop** with [Development workflow](/docs/develop/workflow/), [Platform shells and CLI](/docs/guides/platform-shells-cli-and-testing/), [Terminal user interfaces](/docs/guides/terminal-user-interfaces/), and [Static sites](/docs/guides/static-sites/). +4. **Test and debug** with [Testing lifecycle](/docs/test-and-debug/overview/) and [Testing and diagnostics](/docs/guides/testing-and-diagnostics/). +5. **Build and package** with [Packaging overview](/docs/build-and-package/overview/) and the platform-specific readiness checks. +6. **Release and distribute** with [Release overview](/docs/release-and-distribute/overview/) and [Post-build lifecycle RFC](/docs/release-and-distribute/post-build-lifecycle/). +7. **Look up exact contracts** in the [Reference](/reference/overview/overview/) when you know what subsystem you need. -## Recommended reading path +## How the docs are grouped -If you want the smoothest introduction, read the docs in this order. +| Section | What it answers | +| --- | --- | +| Start | How do I create or open a Fission project and understand its shape? | +| Learn Fission | How do state, reducers, widgets, layout, environment, resources, and rendering fit together? | +| Develop | How do I run the app, add targets, work with shells, and use the CLI every day? | +| Test and debug | How do I prove behavior, inspect output, capture screenshots, and validate target-specific behavior? | +| Build and package | How do I create installable or uploadable artifacts with readiness checks? | +| Release and distribute | How do I ship artifacts, release content, testers, tracks, rollouts, and receipts? | +| Reference | What are the exact API contracts, fields, widgets, chart variants, and CLI commands? | -1. Start with [Learn overview](/docs/learn/overview), because it gives you the big picture of a Fission app before the details start to pile up. -2. Move to [Quickstart](/docs/learn/quickstart), because running an example or scaffolding a small app early makes the architecture feel real instead of theoretical. -3. Read [Runtime model](/docs/learn/runtime-model) next, because it explains what your app owns, what the runtime owns, and why Fission keeps cross-frame behavior out of your product state. -4. Then open [Rendering pipeline](/docs/learn/rendering-pipeline), because it shows how widgets become layout, accessibility information, and painted output, which is the key to understanding debugging and performance. -5. Continue to [Examples and targets](/docs/learn/examples-and-targets), because it connects the ideas to the repository's real desktop, web, Android, and iOS paths. -6. When you are ready to organize your own app, read [App structure](/docs/guides/app-structure), because it turns the mental model into a project shape you can maintain. -7. After that, pick the guide that matches your next question: [Resources and async](/docs/guides/resources-and-async) explains outside work such as background jobs, timers, and host integrations; [Platform shells and command-line interface](/docs/guides/platform-shells-cli-and-testing) explains how the shared app reaches each platform through the command-line interface and shell wrappers; and [Testing and diagnostics](/docs/guides/testing-and-diagnostics) shows how Fission turns predictable behavior into practical tests. -8. Use [Build a counter](/docs/cookbook/build-a-counter) when you want a worked example you can follow end to end, and use [Reference overview](/reference/overview/overview) when you need exact types, fields, and function names after the bigger ideas are already familiar. +## What to remember -## How to use the rest of the docs - -The docs are organized by job, not only by difficulty. The Learn pages teach the model. The Guides explain real subsystems you will use while building an app. The Cookbook gives you practical recipes when you want a known-good pattern. The Reference is there for precise details when you already know what concept you are looking for. - -If you ever feel lost, come back to the core flow: state holds the data, actions describe intent, reducers change state, widgets render from state, and shells run the same app on each platform. That flow is the reason the rest of Fission stays understandable. +The same app model sits underneath the lifecycle. State holds product truth. Actions describe intent. Reducers update state. Widgets render from state. Resources, commands, jobs, services, and capabilities describe outside work explicitly. Shells host that app model on desktop, web, mobile, terminal, and static site targets. The CLI then carries the project through development, packaging, release, and distribution. diff --git a/documentation/content/docs/release-and-distribute/overview.mdx b/documentation/content/docs/release-and-distribute/overview.mdx new file mode 100644 index 00000000..f7c64378 --- /dev/null +++ b/documentation/content/docs/release-and-distribute/overview.mdx @@ -0,0 +1,37 @@ +--- +title: Release and distribute +description: Publish Fission artifacts to app stores, static hosts, object stores, GitHub Releases, testers, tracks, rollouts, and release receipts. +--- + +# Release and distribute + +Release is where package artifacts, store metadata, screenshots, credentials, tracks, testers, and provider-specific workflows meet. Fission makes that a project workflow instead of leaving every app to invent its own release scripts. + +## Provider families + +| Provider family | What Fission manages | +| --- | --- | +| App stores | Google Play APK/AAB upload, App Store Connect IPA upload, Microsoft Store MSI/EXE API path, Microsoft Store MSIX/MSIXUPLOAD Partner Center path through `msstore`. | +| Static hosting | GitHub Pages, Cloudflare Pages, Netlify, custom domain readiness, and generated static site assets. | +| Artifact distribution | GitHub Releases, S3-compatible object stores, Google Drive, OneDrive, Dropbox, and direct artifact upload receipts. | +| Release content | Screenshots, preview videos, feature graphics, logos, trailers, notes, privacy metadata, review attachments, and provider-specific validation. | +| Release management | Testers, beta groups, tracks, package flights, staged rollout, status queries, receipts, and CI JSON output. | + +## Typical release flow + +```bash +fission readiness release --project-dir . --target windows --format msix --provider microsoft-store +fission package --project-dir . --target windows --format msix --release +fission release-content validate --project-dir . --provider microsoft-store +fission distribute --project-dir . --provider microsoft-store --artifact target/fission/release/windows/msix/artifact-manifest.json --track public --yes +``` + +The exact commands vary by provider, but the shape stays consistent: check readiness, build the artifact, validate release content, publish, then keep the receipt. + +## Credentials + +Provider credentials should not be committed to the repository. Fission supports environment variables, CI secrets, authenticated provider tools, and its encrypted release credential vault. The project manifest stores references and provider metadata, while secrets stay outside plain-text project config. + +## Where to go next + +Read [Production lifecycle](/product/production-lifecycle/) for the high-level model, [Build and package](/docs/build-and-package/overview/) for artifacts, and [Post-build lifecycle](/docs/release-and-distribute/post-build-lifecycle/) for the RFC-level detail. diff --git a/documentation/content/docs/release-and-distribute/post-build-lifecycle.mdx b/documentation/content/docs/release-and-distribute/post-build-lifecycle.mdx new file mode 100644 index 00000000..a06e36f9 --- /dev/null +++ b/documentation/content/docs/release-and-distribute/post-build-lifecycle.mdx @@ -0,0 +1,153 @@ +--- +title: Release lifecycle details +description: Learn how Fission moves an app from a built artifact to a signed package, release content, provider upload, rollout, and audit receipt. +--- + +# Release lifecycle details + +A Fission project can produce more than a runnable binary. It can also produce the files, metadata, checks, and receipts you need to ship that binary through a store, a static host, an object store, or a release page. This page explains the release workflow from a developer's point of view. + +You do not need to memorize every provider rule before you start. The important idea is that Fission keeps the release process explicit. Each command does one job, writes inspectable output, and gives you a clear error when something is missing. + +## The release workflow + +Most projects follow the same shape: + +1. Run a readiness check before doing expensive work. +2. Package the app for the target platform. +3. Prepare release content such as notes, screenshots, previews, and review information. +4. Distribute the artifact to the selected provider. +5. Keep the generated receipts in CI logs or build artifacts so the team can audit what happened. + +For example, a Windows Store release might look like this: + +```bash +fission readiness release --project-dir . --target windows --format msix --provider microsoft-store +fission package --project-dir . --target windows --format msix --release +fission release-content validate --project-dir . --provider microsoft-store +fission distribute --project-dir . --provider microsoft-store --artifact target/fission/release/windows/msix/artifact-manifest.json --track public --yes +``` + +The same pattern works for other providers. The target, package format, provider, and track change; the workflow remains recognizable. + +## Keep release metadata reviewable + +`fission.toml` is the root of the release configuration. It should contain the stable facts a reviewer expects to find quickly: app identity, package identifiers, provider IDs, active release, tracks, locales, and paths to the files that contain longer release content. + +Long text should live in referenced files. Full release notes, store descriptions, privacy declarations, review instructions, screenshots, preview videos, trailers, and generated content manifests are too large for the root manifest. Keeping them in `release-content/` makes them easier to review, localize, regenerate, and compare in pull requests. + +A typical release section looks like this: + +```toml +[release] +active_release = "1.2.3+42" +metadata_root = "release-content/metadata" +content_output_dir = "release-content" +default_locales = ["en-US"] + +[[releases]] +id = "1.2.3+42" +version = "1.2.3" +build = 42 +status = "candidate" +tracks = ["play-store:internal", "app-store:testflight", "microsoft-store:private"] +locales = ["en-US"] +metadata = "release-content/metadata/1.2.3+42/release.toml" +release_notes = "release-content/metadata/1.2.3+42/notes" +review = "release-content/metadata/1.2.3+42/review.toml" +privacy = "release-content/metadata/1.2.3+42/privacy.toml" +``` + +The CLI can help create and edit these entries, but the files remain normal project files. They should be committed, reviewed, and changed deliberately. + +## Readiness checks tell you what is missing + +Use readiness checks before packaging or publishing. They check the selected platform and provider instead of giving a vague environment report. + +```bash +fission readiness package --project-dir . --target android --format aab +fission readiness distribute --project-dir . --provider play-store --artifact target/fission/release/android/aab/artifact-manifest.json --track internal +fission readiness release --project-dir . --target ios --format ipa --provider app-store +``` + +A readiness check should answer three questions: + +| Question | What Fission checks | +| --- | --- | +| Can this machine package the target? | SDKs, platform tools, target configuration, package scripts, signing tools, icon inputs, and output paths. | +| Can this artifact be distributed? | Artifact manifest, provider configuration, credentials, release content, track names, and provider-specific constraints. | +| What should I do next? | Stable error IDs, human-readable explanation, and concrete remediation steps. | + +Use `--json` in CI so a workflow can fail with structured diagnostics instead of parsing console text. + +## Package commands produce artifact manifests + +`fission package` creates the platform artifact and writes an `artifact-manifest.json` beside it. Distribution commands consume that manifest instead of guessing file paths. + +```bash +fission package --project-dir . --target site --format static --release +fission package --project-dir . --target linux --format run --release +fission package --project-dir . --target macos --format app --release +fission package --project-dir . --target android --format apk --release +``` + +The manifest records the target, format, profile, artifact paths, hashes, sizes, MIME types, validation checks, and any secondary artifacts such as symbols or crash diagnostics. That gives later release commands an exact input and gives CI something durable to store. + +## Release content is separate from the binary + +Store listings and marketing assets often change without rebuilding the app. Fission treats release content as its own workflow: + +```bash +fission release-content capture --project-dir . --target ios --set app-store +fission release-content render --project-dir . --provider app-store +fission release-content validate --project-dir . --provider app-store +``` + +Capture commands should use the same platform run and test infrastructure as normal Fission testing. Render commands turn raw captures into provider-ready images or videos. Validate commands check required screenshots, previews, metadata files, review attachments, locales, and provider-specific rules before you upload. + +## Distribution writes receipts + +`fission distribute` publishes an artifact or site to a provider and writes a receipt under `target/fission/distribution/`. + +```bash +fission distribute --project-dir . --provider github-releases --artifact target/fission/release/windows/msix/artifact-manifest.json --site production --deploy v1.2.3 +fission distribute --project-dir . --provider github-pages --artifact target/fission/release/site/static/artifact-manifest.json --site production +fission distribute --project-dir . --provider cloudflare-pages --artifact target/fission/release/site/static/artifact-manifest.json --site production +fission distribute --project-dir . --provider microsoft-store --artifact target/fission/release/windows/msix/artifact-manifest.json --track public +``` + +Receipts record provider IDs, URLs, deployment IDs, submitted tracks, uploaded bytes, artifact hashes, provider status, and follow-up steps. They are not source files; they are audit output. + +## Credentials stay out of project files + +Secrets do not belong in `fission.toml`. Store tokens, OAuth refresh tokens, signing passwords, API keys, and private keys should come from CI secrets, environment variables, provider CLIs, platform key stores, or the Fission credential vault. + +Use the auth commands to inspect and manage local provider credentials: + +```bash +fission auth status +fission auth import play-store --from file:service-account.json --yes +fission auth logout microsoft-store --yes +fission auth audit +``` + +The project can reference an account or credential label, but it should not contain the credential material itself. + +## Store releases have tracks and follow-up operations + +Stores are not just upload endpoints. They have test tracks, package flights, phased rollout, review status, provider-side processing, tester groups, and metadata state. Fission models those operations explicitly so the release is visible and repeatable. + +Common operations include: + +```bash +fission beta groups list --project-dir . --provider app-store +fission beta testers import --project-dir . --provider app-store --group external-beta --csv testers.csv +fission beta distribute --project-dir . --provider play-store --artifact target/fission/release/android/aab/artifact-manifest.json --track internal +fission distribute status --project-dir . --provider microsoft-store --site production +``` + +When a provider requires a manual first-time setup step, readiness should say exactly what to do and which values from `fission.toml` to copy into the provider portal. + +## Where to go next + +Start with [Build and package](/docs/build-and-package/overview/) when you need an installable artifact. Use [Release and distribute](/docs/release-and-distribute/overview/) when you are ready to publish. Use [Static sites](/docs/guides/static-sites/) if the output is a documentation or marketing site. diff --git a/documentation/content/docs/test-and-debug/overview.mdx b/documentation/content/docs/test-and-debug/overview.mdx new file mode 100644 index 00000000..d308bd12 --- /dev/null +++ b/documentation/content/docs/test-and-debug/overview.mdx @@ -0,0 +1,32 @@ +--- +title: Test and debug +description: Structure Fission testing and diagnostics around reducers, widgets, shells, screenshots, logs, inspectors, and target-specific validation. +--- + +# Test and debug + +Fission's testing story follows the architecture. Test pure behavior where it is pure, test widget output where the widget tree is the question, and test the live host when the host is part of the behavior. + +## Testing layers + +| Layer | Use it for | +| --- | --- | +| Unit tests | Reducers, selectors, state transitions, parsers, helpers, and deterministic business logic. | +| Widget tests | Rendered widget structure, semantics, layout intent, bindings, and state-derived UI. | +| Runtime smoke tests | Shell startup, route rendering, command/job wiring, capability boundaries, and target compatibility. | +| Screenshot tests | Release screenshots, visual regression checks, docs/gallery captures, and store content validation. | +| Device/browser tests | Mobile safe areas, soft keyboards, browser behavior, accessibility bridges, pointer/touch handling, and packaging validation. | + +## Developer tools direction + +Fission's developer tools are designed around inspection rather than guesswork. The tooling surface should expose widget trees, Core IR, layout boxes, semantics, reducer/action history, logs, resource calls, frame timing, screenshots, and device output. IDE plugins should make those tools discoverable from normal development environments. + +The principle is simple: if the runtime can see a boundary, developers should be able to inspect it. + +## Debug without breaking the model + +Do not add hidden host callbacks just to make debugging easier. Keep reducers explicit, host work named, resources typed, and shell behavior observable. That gives tools a stable surface to inspect and keeps the production app understandable. + +## Where to go next + +Read [Testing and diagnostics](/docs/guides/testing-and-diagnostics/) for current practices, [Developer tools](/product/developer-tools/) for the product view, and [Platform testing reference](/reference/platform/testing/) for target-level details. diff --git a/documentation/content/reference/overview/overview.mdx b/documentation/content/reference/overview/overview.mdx index 0c6b9cf2..5d23fe7a 100644 --- a/documentation/content/reference/overview/overview.mdx +++ b/documentation/content/reference/overview/overview.mdx @@ -1,12 +1,12 @@ --- title: Reference overview -description: The technical map of Fission's runtime, shells, command-line interface, and widget surface. +description: The technical map of Fission's runtime, shells, command-line interface, widgets, charts, targets, and lifecycle tooling. slug: /overview/overview --- # Reference overview -The Learn section teaches the framework in a guided order. The Reference section is the place you come back to when you already know roughly what you are building and need to confirm a contract, a type, a lifecycle rule, or the right subsystem for a problem. +The Learn and Docs sections teach Fission in lifecycle order. The Reference section is the place you come back to when you already know roughly what you are building and need to confirm a contract, a type, a lifecycle rule, or the right subsystem for a problem. That difference matters. @@ -26,7 +26,7 @@ The fastest way to use this reference well is to identify the layer your questio If your question is about app behavior, start in the core runtime pages. That is where the shared contracts live: widgets, state, reducers, effects, resources, environment, input, the rendering pipeline, testing, and diagnostics. -If your question is about how the app reaches desktop, web, Android, or iOS, move to the platform pages. Those pages explain shells, targets, target-level testing, and where platform responsibility begins and ends. +If your question is about how the app reaches desktop, web, Android, iOS, terminal, or static HTML output, move to the platform pages. Those pages explain shells, targets, target-level testing, and where platform responsibility begins and ends. If your question is about scaffolding or day-to-day project setup, go to the command-line interface page. If your question is about authoring user interface, go to the widget catalog and then into the relevant widget family. @@ -34,7 +34,7 @@ In other words, treat the reference as a subsystem map. Do not search for type n ## Core runtime reference -The core runtime is the heart of Fission. These pages describe the shared model that stays consistent across desktop, web, Android, and iOS. +The core runtime is the heart of Fission. These pages describe the shared model that stays consistent across desktop, web, Android, iOS, terminal, and static site targets. Start with [Widget trait](/reference/core/widget-trait) when you need to confirm what a widget is, what `build()` is allowed to do, or how `BuildCtx` and `View` divide responsibility. @@ -50,7 +50,7 @@ Round that out with [Platform runtime](/reference/core/platform-runtime), [Testi The platform pages explain what happens after the shared runtime reaches a real host. -[Targets](/reference/platform/targets) is the page to open when you need to understand generated host output, target folders, and the practical expectations for desktop, web, Android, and iOS. +[Targets](/reference/platform/targets) is the page to open when you need to understand generated host output, target folders, and the practical expectations for desktop, web, Android, iOS, terminal, and static site targets. [Accessibility and internationalization](/reference/platform/accessibility-and-i18n) focuses on how semantic meaning and locale-sensitive behavior connect to platform adapters and testing. @@ -58,7 +58,7 @@ The platform pages explain what happens after the shared runtime reaches a real ## command-line interface reference -The command-line interface is intentionally small, but it is part of the public workflow. +The command-line interface is part of the public workflow, from project setup through run, logs, readiness, package, release content, distribution, and release receipts. Open [command-line interface overview](/reference/cli/overview) when you want the exact scaffold and target-management commands, the meaning of their major flags, and the files they generate. diff --git a/documentation/fission.toml b/documentation/fission.toml index ec780cc7..f30af7a0 100644 --- a/documentation/fission.toml +++ b/documentation/fission.toml @@ -14,7 +14,7 @@ pretty_urls = true generate_sitemap = true generate_robots = true title = "Fission" -description = "Build production desktop, web, Android, and iOS apps with Fission." +description = "Build, test, package, and release production Rust apps across desktop, mobile, web, terminal, and static site targets." logo = "/img/fission-mark.svg" favicon = "/img/fission-mark.svg" asset_dirs = ["static"] @@ -38,28 +38,28 @@ workflow = "publish-website.yml" production_branch = "main" [[site.nav]] -title = "Learn" -href = "/docs/learn/overview/" +title = "Product" +href = "/product/overview/" [[site.nav]] -title = "Guides" -href = "/docs/guides/app-structure/" +title = "Setup" +href = "/docs/learn/quickstart/" [[site.nav]] -title = "Charts" -href = "/reference/charts/overview/" +title = "Learn" +href = "/docs/learn/overview/" [[site.nav]] -title = "Cookbook" -href = "/docs/cookbook/build-a-counter/" +title = "Build" +href = "/docs/build-and-package/overview/" [[site.nav]] -title = "Reference" -href = "/reference/overview/overview/" +title = "Test" +href = "/docs/test-and-debug/overview/" [[site.nav]] -title = "Examples" -href = "/docs/learn/examples-and-targets/" +title = "Publish" +href = "/docs/release-and-distribute/overview/" [[site.routes]] kind = "content" diff --git a/documentation/site/docs-sidebar.toml b/documentation/site/docs-sidebar.toml index 225ad061..3d5b92f2 100644 --- a/documentation/site/docs-sidebar.toml +++ b/documentation/site/docs-sidebar.toml @@ -4,45 +4,50 @@ href = "/docs/intro/" level = 0 [[items]] -title = "Learn" -href = "/docs/learn/overview/" +title = "Start" +href = "/docs/intro/" level = 1 group = true [[items]] -title = "Quickstart" -href = "/docs/learn/quickstart/" +title = "Introduction" +href = "/docs/intro/" level = 2 [[items]] -title = "Runtime model" -href = "/docs/learn/runtime-model/" +title = "Quickstart" +href = "/docs/learn/quickstart/" level = 2 [[items]] -title = "Rendering pipeline" -href = "/docs/learn/rendering-pipeline/" +title = "Project structure" +href = "/docs/guides/app-structure/" level = 2 [[items]] -title = "Examples and targets" -href = "/docs/learn/examples-and-targets/" +title = "Add platform targets" +href = "/docs/cookbook/add-platform-targets/" level = 2 [[items]] -title = "Guides" -href = "/docs/guides/app-structure/" +title = "Learn Fission" +href = "/docs/learn/overview/" level = 1 group = true [[items]] -title = "Resources and async" -href = "/docs/guides/resources-and-async/" +title = "Overview" +href = "/docs/learn/overview/" level = 2 [[items]] -title = "Input, events, text, and environment" -href = "/docs/guides/input-events-text-and-env/" +title = "Runtime model" +href = "/docs/learn/runtime-model/" +level = 2 + +[[items]] +title = "Rendering pipeline" +href = "/docs/learn/rendering-pipeline/" level = 2 [[items]] @@ -50,6 +55,16 @@ title = "Layout and widgets" href = "/docs/guides/layout-and-widgets/" level = 2 +[[items]] +title = "Input, events, text, and environment" +href = "/docs/guides/input-events-text-and-env/" +level = 2 + +[[items]] +title = "State, resources, and async" +href = "/docs/guides/resources-and-async/" +level = 2 + [[items]] title = "Theming and internationalisation" href = "/docs/guides/theming-and-i18n/" @@ -66,18 +81,29 @@ href = "/docs/guides/media-animation-portals-and-3d/" level = 2 [[items]] -title = "Platform shells, CLI, and testing" +title = "Develop" +href = "/docs/develop/workflow/" +level = 1 +group = true + +[[items]] +title = "Development workflow" +href = "/docs/develop/workflow/" +level = 2 + +[[items]] +title = "Platform shells and CLI" href = "/docs/guides/platform-shells-cli-and-testing/" level = 2 [[items]] -title = "Terminal user interfaces" -href = "/docs/guides/terminal-user-interfaces/" +title = "Examples and targets" +href = "/docs/learn/examples-and-targets/" level = 2 [[items]] -title = "Testing and diagnostics" -href = "/docs/guides/testing-and-diagnostics/" +title = "Terminal user interfaces" +href = "/docs/guides/terminal-user-interfaces/" level = 2 [[items]] @@ -91,6 +117,11 @@ href = "/docs/charts/overview/" level = 1 group = true +[[items]] +title = "Charts overview" +href = "/docs/charts/overview/" +level = 2 + [[items]] title = "Catalog" href = "/docs/charts/catalog/" @@ -111,6 +142,54 @@ title = "Three-dimensional and GL" href = "/docs/charts/three-dimensional-and-gl/" level = 2 +[[items]] +title = "Test and debug" +href = "/docs/test-and-debug/overview/" +level = 1 +group = true + +[[items]] +title = "Testing lifecycle" +href = "/docs/test-and-debug/overview/" +level = 2 + +[[items]] +title = "Testing and diagnostics" +href = "/docs/guides/testing-and-diagnostics/" +level = 2 + +[[items]] +title = "Write a live UI test" +href = "/docs/cookbook/write-a-live-ui-test/" +level = 2 + +[[items]] +title = "Build and package" +href = "/docs/build-and-package/overview/" +level = 1 +group = true + +[[items]] +title = "Packaging overview" +href = "/docs/build-and-package/overview/" +level = 2 + +[[items]] +title = "Release and distribute" +href = "/docs/release-and-distribute/overview/" +level = 1 +group = true + +[[items]] +title = "Release overview" +href = "/docs/release-and-distribute/overview/" +level = 2 + +[[items]] +title = "Release lifecycle details" +href = "/docs/release-and-distribute/post-build-lifecycle/" +level = 2 + [[items]] title = "Cookbook" href = "/docs/cookbook/build-a-counter/" @@ -143,16 +222,27 @@ href = "/docs/cookbook/modal-text-flow/" level = 2 [[items]] -title = "Add platform targets" -href = "/docs/cookbook/add-platform-targets/" +title = "Reference" +href = "/reference/overview/overview/" +level = 1 +group = true + +[[items]] +title = "Reference overview" +href = "/reference/overview/overview/" level = 2 [[items]] -title = "Write a live UI test" -href = "/docs/cookbook/write-a-live-ui-test/" +title = "CLI reference" +href = "/reference/cli/overview/" level = 2 [[items]] -title = "Reference overview" -href = "/reference/overview/overview/" -level = 1 +title = "Widget reference" +href = "/reference/widgets/catalog/" +level = 2 + +[[items]] +title = "Chart reference" +href = "/reference/charts/overview/" +level = 2 diff --git a/documentation/site/overrides.css b/documentation/site/overrides.css index 8a3754e0..f048881a 100644 --- a/documentation/site/overrides.css +++ b/documentation/site/overrides.css @@ -68,3 +68,134 @@ height: auto !important; } } + +/* Product landing pages use large fixed desktop art direction; clamp it on narrow screens. */ +.fission-site-product-page, +.fission-site-product-hero, +.fission-site-product-feature-showcase, +.fission-site-product-proof { + box-sizing: border-box; + max-width: 100%; +} + +.fission-site-product-page .fission-site-box, +.fission-site-product-page .fission-site-row, +.fission-site-product-page .fission-site-column { + box-sizing: border-box; +} + +@media (max-width: 760px) { + .fission-site-product-page { + padding-left: 1rem !important; + padding-right: 1rem !important; + width: 100% !important; + } + + .fission-site-product-page > .fission-site-column { + gap: 2.25rem !important; + } + + .fission-site-product-hero { + overflow: hidden; + padding: 1.5rem !important; + width: 100% !important; + } + + .fission-site-product-hero > .fission-site-row { + gap: 1.5rem !important; + } + + .fission-site-product-hero .fission-site-box { + max-width: 100% !important; + } + + .fission-site-product-hero-title .fission-site-text-run { + font-size: clamp(2.75rem, 10vw, 3.35rem) !important; + line-height: 0.98 !important; + } + + .fission-site-product-feature-showcase > .fission-site-row, + .fission-site-product-proof > .fission-site-row { + gap: 1.5rem !important; + } +} + +@media (max-width: 760px) { + .fission-site-product-hero > .fission-site-row { + justify-content: flex-start !important; + } + + .fission-site-product-hero > .fission-site-row > .fission-site-box { + width: 100% !important; + max-width: 100% !important; + } +} + +@media (max-width: 760px) { + .fission-site-product-hero { + width: calc(100vw - 2rem) !important; + max-width: calc(100vw - 2rem) !important; + } +} + +@media (max-width: 760px) { + .fission-site-product-hero-title, + .fission-site-product-hero-body, + .fission-site-product-hero-ctas, + .fission-site-product-hero-title > .fission-site-box, + .fission-site-product-hero-body > .fission-site-box { + width: 100% !important; + max-width: 100% !important; + } + + .fission-site-product-hero-title .fission-site-text-run, + .fission-site-product-hero-body .fission-site-text-run { + overflow-wrap: break-word; + } +} + +@media (max-width: 760px) { + .fission-site-product-hero-title .fission-site-text-run { + font-size: clamp(2.2rem, 9vw, 2.85rem) !important; + } + + .fission-site-product-hero-body .fission-site-text-run { + font-size: 1rem !important; + line-height: 1.6 !important; + } + + .fission-site-product-hero-ctas .fission-site-row { + flex-direction: column !important; + align-items: flex-start !important; + } +} + +@media (max-width: 760px) { + .fission-site-box:has(> .fission-site-product-page) { + width: 100% !important; + max-width: 100% !important; + padding-left: 1rem !important; + padding-right: 1rem !important; + } + + .fission-site-box:has(> .fission-site-product-hero), + .fission-site-box:has(> .fission-site-product-feature-showcase), + .fission-site-box:has(> .fission-site-product-proof) { + width: 100% !important; + max-width: 100% !important; + box-sizing: border-box; + overflow: hidden; + } +} + +@media (max-width: 760px) { + .fission-site-row:has(> .fission-site-box > .fission-site-product-page) { + width: 100% !important; + justify-content: flex-start !important; + } + + .fission-site-box:has(> .fission-site-product-page) { + width: calc(100vw - 2rem) !important; + max-width: calc(100vw - 2rem) !important; + } +} diff --git a/documentation/src/components/footer.rs b/documentation/src/components/footer.rs index 2de0b0fe..d7742ab3 100644 --- a/documentation/src/components/footer.rs +++ b/documentation/src/components/footer.rs @@ -1,6 +1,6 @@ use super::home_widgets::semantic_row; use super::state::DocsState; -use fission::op::{AlignItems, Fill, FlexWrap, JustifyContent}; +use fission::op::{AlignItems, Fill, FlexWrap, JustifyContent, TextAlign}; use fission::prelude::*; #[derive(Clone, Debug)] @@ -14,65 +14,58 @@ impl Widget for DocsFooter { children: vec![ Row { children: vec![ - footer_brand(ctx, view), + FooterColumn::new( + "Setup", + &[ + ("Quickstart", "/docs/learn/quickstart/"), + ("Add targets", "/docs/cookbook/add-platform-targets/"), + ("Project structure", "/docs/guides/app-structure/"), + ], + ) + .build(ctx, view), FooterColumn::new( "Learn", &[ ("Overview", "/docs/learn/overview/"), - ("Quickstart", "/docs/learn/quickstart/"), ("Runtime model", "/docs/learn/runtime-model/"), + ("Widgets", "/docs/guides/layout-and-widgets/"), + ("Design systems", "/docs/guides/design-system/"), + ("Charts", "/docs/charts/overview/"), ], ) .build(ctx, view), FooterColumn::new( - "Guides", + "Build", &[ - ("App structure", "/docs/guides/app-structure/"), - ("Resources and async", "/docs/guides/resources-and-async/"), - ( - "Testing and diagnostics", - "/docs/guides/testing-and-diagnostics/", - ), - ("Theming and i18n", "/docs/guides/theming-and-i18n/"), ( "Platform shells", "/docs/guides/platform-shells-cli-and-testing/", ), - ( - "Terminal interfaces", - "/docs/guides/terminal-user-interfaces/", - ), + ("Terminal UI", "/docs/guides/terminal-user-interfaces/"), + ("Static sites", "/docs/guides/static-sites/"), + ("Packaging", "/docs/build-and-package/overview/"), ], ) .build(ctx, view), FooterColumn::new( - "Charts", + "Test", &[ - ("Overview", "/reference/charts/overview/"), - ("Catalog", "/docs/charts/catalog/"), - ("Data and interaction", "/docs/charts/data-and-interaction/"), - ("3D and GL", "/docs/charts/three-dimensional-and-gl/"), + ("Testing lifecycle", "/docs/test-and-debug/overview/"), + ("Diagnostics", "/docs/guides/testing-and-diagnostics/"), + ("Live UI test", "/docs/cookbook/write-a-live-ui-test/"), ], ) .build(ctx, view), FooterColumn::new( - "Cookbook", + "Publish", &[ - ("Build a counter", "/docs/cookbook/build-a-counter/"), - ("Add platform targets", "/docs/cookbook/add-platform-targets/"), + ("Release overview", "/docs/release-and-distribute/overview/"), ( - "Write a live interface test", - "/docs/cookbook/write-a-live-ui-test/", + "Lifecycle details", + "/docs/release-and-distribute/post-build-lifecycle/", ), - ], - ) - .build(ctx, view), - FooterColumn::new( - "Explore", - &[ - ("Reference", "/reference/overview/overview/"), + ("CLI reference", "/reference/cli/overview/"), ("Examples", "/docs/learn/examples-and-targets/"), - ("GitHub", "https://github.com/worka-ai/fission"), ], ) .build(ctx, view), @@ -80,34 +73,14 @@ impl Widget for DocsFooter { gap: Some(tokens.spacing.xxl), wrap: FlexWrap::Wrap, align_items: AlignItems::Start, - justify_content: JustifyContent::SpaceBetween, + justify_content: JustifyContent::Center, ..Default::default() } .into_node(), - Container::new( - Row { - children: vec![ - Text::new("Copyright (c) 2026 Fission - MIT License") - .size(tokens.typography.font_size_sm) - .color(tokens.colors.text_muted) - .into_node(), - Text::new("The Fission framework is ready to use today, but some areas are actively under development. Widget APIs are expected to remain stable; some runtime or shell APIs may get breaking changes before 1.0.0.") - .size(tokens.typography.font_size_sm) - .color(tokens.colors.text_muted) - .into_node(), - ], - gap: Some(tokens.spacing.l), - wrap: FlexWrap::Wrap, - justify_content: JustifyContent::SpaceBetween, - ..Default::default() - } - .into_node(), - ) - .padding([0.0, 0.0, tokens.spacing.l, 0.0]) - .border(tokens.colors.border, 1.0) - .into_node(), + footer_identity(ctx, view), ], gap: Some(tokens.spacing.xxl), + align_items: AlignItems::Center, ..Default::default() } .into_node(), @@ -119,56 +92,81 @@ impl Widget for DocsFooter { } } -fn footer_brand(ctx: &mut BuildCtx, view: &View) -> Node { +fn footer_identity(ctx: &mut BuildCtx, view: &View) -> Node { let tokens = &view.env.theme.tokens; - Column { - children: vec![ - semantic_row( - "site-route:/", - vec![ - Image { - source: "/img/fission-mark.svg".to_string(), - width: Some(tokens.spacing.l), - height: Some(tokens.spacing.l), - ..Default::default() - } - .into_node(), - Text::new("Fission") - .size(tokens.typography.font_size_lg) - .weight(tokens.typography.font_weight_bold) - .color(tokens.colors.heading) + Container::new( + Column { + children: vec![ + semantic_row( + "site-route:/", + vec![ + Image { + source: "/img/fission-mark.svg".to_string(), + width: Some(tokens.spacing.l), + height: Some(tokens.spacing.l), + ..Default::default() + } .into_node(), - ], - Some(tokens.spacing.s), - FlexWrap::NoWrap, - AlignItems::Center, - JustifyContent::Start, - ), - Text::new("A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.") - .size(tokens.typography.body_medium_size) - .line_height(tokens.typography.body_medium_size * tokens.typography.line_height_normal) - .color(tokens.colors.text_secondary) - .into_node(), - Row { - children: vec![ - FooterLink::new("GitHub", "https://github.com/worka-ai/fission").build(ctx, view), - FooterLink::new("Quickstart", "/docs/learn/quickstart/").build(ctx, view), - ], - gap: Some(tokens.spacing.m), - wrap: FlexWrap::Wrap, - ..Default::default() - } - .into_node(), - Text::new("main - v0.1.0 alpha") - .size(tokens.typography.font_size_sm) - .family(tokens.typography.font_family_mono.clone()) - .color(tokens.colors.text_muted) + Text::new("Fission") + .size(tokens.typography.font_size_lg) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + ], + Some(tokens.spacing.s), + FlexWrap::NoWrap, + AlignItems::Center, + JustifyContent::Center, + ), + Text::new("A cross-platform, GPU-accelerated user interface framework for Rust. MIT licensed.") + .size(tokens.typography.body_medium_size) + .line_height(tokens.typography.body_medium_size * tokens.typography.line_height_normal) + .color(tokens.colors.text_secondary) + .max_width(tokens.spacing.xxxxl * 7.0) + .text_align(TextAlign::Center) + .flex_shrink(1.0) + .into_node(), + Text::new("Copyright (c) 2026 Fission") + .size(tokens.typography.font_size_sm) + .color(tokens.colors.text_muted) + .text_align(TextAlign::Center) + .into_node(), + Text::new("Ready to use today. Widget APIs are expected to remain stable; some runtime and shell APIs may change before 1.0.0.") + .size(tokens.typography.font_size_sm) + .line_height(tokens.typography.font_size_sm * tokens.typography.line_height_normal) + .color(tokens.colors.text_muted) + .max_width(tokens.spacing.xxxxl * 8.0) + .text_align(TextAlign::Center) + .flex_shrink(1.0) + .into_node(), + Row { + children: vec![ + FooterLink::new("GitHub", "https://github.com/worka-ai/fission") + .build(ctx, view), + FooterLink::new("Quickstart", "/docs/learn/quickstart/").build(ctx, view), + FooterLink::new("Reference", "/reference/overview/overview/") + .build(ctx, view), + ], + gap: Some(tokens.spacing.m), + wrap: FlexWrap::Wrap, + justify_content: JustifyContent::Center, + ..Default::default() + } .into_node(), - ], - gap: Some(tokens.spacing.m), - flex_shrink: 1.0, - ..Default::default() - } + Text::new("main - v0.1.0 alpha") + .size(tokens.typography.font_size_sm) + .family(tokens.typography.font_family_mono.clone()) + .color(tokens.colors.text_muted) + .text_align(TextAlign::Center) + .into_node(), + ], + gap: Some(tokens.spacing.m), + align_items: AlignItems::Center, + ..Default::default() + } + .into_node(), + ) + .padding([0.0, 0.0, tokens.spacing.l, 0.0]) .into_node() } @@ -187,23 +185,28 @@ impl FooterColumn { impl Widget for FooterColumn { fn build(&self, ctx: &mut BuildCtx, view: &View) -> Node { let tokens = &view.env.theme.tokens; - Column { - children: std::iter::once( - Text::new(self.title) - .size(tokens.typography.font_size_sm) - .weight(tokens.typography.font_weight_bold) - .color(tokens.colors.heading) - .into_node(), - ) - .chain( - self.links - .iter() - .map(|(label, href)| FooterLink::new(label, href).build(ctx, view)), - ) - .collect(), - gap: Some(tokens.spacing.s), - ..Default::default() - } + Container::new( + Column { + children: std::iter::once( + Text::new(self.title) + .size(tokens.typography.font_size_sm) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + ) + .chain( + self.links + .iter() + .map(|(label, href)| FooterLink::new(label, href).build(ctx, view)), + ) + .collect(), + gap: Some(tokens.spacing.s), + ..Default::default() + } + .into_node(), + ) + .width(tokens.spacing.xxxxl * 1.75) + .flex_shrink(1.0) .into_node() } } diff --git a/documentation/src/components/home.rs b/documentation/src/components/home.rs index 3f7b9b4c..befd1b94 100644 --- a/documentation/src/components/home.rs +++ b/documentation/src/components/home.rs @@ -1,7 +1,7 @@ use super::home_nav::HomePageNav; use super::home_sections::{ - ArchitectureSection, ChartsSection, ExamplesSection, FinalCta, HomePageHero, ModelSection, - ProofStrip, TargetsSection, + ArchitectureSection, ChartsSection, ExamplesSection, FinalCta, HomePageHero, LifecycleSection, + ModelSection, ProofStrip, TargetsSection, }; use super::home_widgets::{content_width, page_fill}; use super::state::DocsState; @@ -52,6 +52,7 @@ impl Widget for HomePage { children: vec![ HomePageHero.build(ctx, view), ProofStrip.build(ctx, view), + LifecycleSection.build(ctx, view), ArchitectureSection.build(ctx, view), ChartsSection.build(ctx, view), ModelSection.build(ctx, view), diff --git a/documentation/src/components/home_nav.rs b/documentation/src/components/home_nav.rs index b610acb1..59b3c5c6 100644 --- a/documentation/src/components/home_nav.rs +++ b/documentation/src/components/home_nav.rs @@ -6,12 +6,12 @@ use fission::op::{AlignItems, Fill, FlexWrap, JustifyContent}; use fission::prelude::*; const NAV_ITEMS: &[(&str, &str)] = &[ + ("Product", "/product/overview/"), + ("Setup", "/docs/learn/quickstart/"), ("Learn", "/docs/learn/overview/"), - ("Guides", "/docs/guides/app-structure/"), - ("Charts", "/reference/charts/overview/"), - ("Cookbook", "/docs/cookbook/build-a-counter/"), - ("Reference", "/reference/overview/overview/"), - ("Examples", "/docs/learn/examples-and-targets/"), + ("Build", "/docs/build-and-package/overview/"), + ("Test", "/docs/test-and-debug/overview/"), + ("Publish", "/docs/release-and-distribute/overview/"), ]; #[derive(Clone, Debug)] diff --git a/documentation/src/components/home_sections.rs b/documentation/src/components/home_sections.rs index 87855a14..2c0867c2 100644 --- a/documentation/src/components/home_sections.rs +++ b/documentation/src/components/home_sections.rs @@ -16,8 +16,8 @@ impl Widget for HomePageHero { semantic_column( "site-home-hero", vec![ - Pill::new("Production-ready Rust user interface").build(ctx, view), - Text::new("Build desktop, web, Android, and iOS apps in Rust.") + Pill::new("Rust application platform").build(ctx, view), + Text::new("Build, test, package, and release production apps in Rust.") .size(tokens.typography.display_md_size) .family(tokens.typography.font_family_serif.clone()) .line_height( @@ -31,7 +31,7 @@ impl Widget for HomePageHero { .semantics_identifier("site-home-hero-title") .flex_shrink(1.0) .into_node(), - Text::new("Fission is a cross-platform user interface framework with one shared runtime, explicit state, explicit side effects, and a GPU-backed rendering pipeline.") + Text::new("Fission is a full application platform for desktop, mobile, web, terminal, and static site targets, with one shared app model and lifecycle tooling around it.") .size(tokens.typography.font_size_lg) .line_height(tokens.typography.font_size_lg * tokens.typography.line_height_relaxed) .color(tokens.colors.text_secondary) @@ -40,7 +40,7 @@ impl Widget for HomePageHero { .text_align(TextAlign::Center) .flex_shrink(1.0) .into_node(), - Text::new("You write app state as plain Rust data, update it with reducers, and let Fission keep layout, input, time, rendering, and platform boundaries consistent across every target.") + Text::new("Write product state as plain Rust data, render with widgets, run through target shells, then use the CLI for devices, tests, preflight checks, packages, signing, release content, and distribution.") .size(tokens.typography.body_large_size) .line_height(tokens.typography.body_large_size * tokens.typography.line_height_relaxed) .color(tokens.colors.text_muted) @@ -51,11 +51,11 @@ impl Widget for HomePageHero { .into_node(), Row { children: vec![ - Cta::new("Start with Quickstart ->", "/docs/learn/quickstart/", true) + Cta::new("Start building ->", "/docs/learn/quickstart/", true) .build(ctx, view), - Cta::new("Read Learn overview", "/docs/learn/overview/", false) + Cta::new("Explore platform", "/product/overview/", false) .build(ctx, view), - NavLink::new("Browse Reference ->", "/reference/overview/overview/") + NavLink::new("Release workflow ->", "/docs/release-and-distribute/overview/") .build(ctx, view), ], gap: Some(tokens.spacing.m), @@ -66,9 +66,10 @@ impl Widget for HomePageHero { .into_node(), Row { children: vec![ - CodeCard::new("Run a real app", "cargo run -p counter").build(ctx, view), - CodeCard::new("Create your own project", "fission init my-app") + CodeCard::new("Create an app", "fission init my-app").build(ctx, view), + CodeCard::new("Run on a target", "fission run --project-dir my-app") .build(ctx, view), + CodeCard::new("Check release readiness", "fission readiness release --target windows --format msix --provider microsoft-store").build(ctx, view), ], gap: Some(tokens.spacing.m), wrap: FlexWrap::Wrap, @@ -78,10 +79,11 @@ impl Widget for HomePageHero { .into_node(), Row { children: vec![ - StatusText::new("Rust 1.77+").build(ctx, view), - StatusText::new("MIT licensed").build(ctx, view), - StatusText::new("v0.1.0 alpha").build(ctx, view), - StatusText::new("Renders on Vello + wgpu").build(ctx, view), + StatusText::new("Desktop").build(ctx, view), + StatusText::new("Web/WASM").build(ctx, view), + StatusText::new("Android + iOS").build(ctx, view), + StatusText::new("Terminal UI").build(ctx, view), + StatusText::new("Static HTML").build(ctx, view), ], gap: Some(tokens.spacing.l), wrap: FlexWrap::Wrap, @@ -107,42 +109,42 @@ impl Widget for ProofStrip { vec![ SectionHeader::new( "What Fission is", - "A cross-platform Rust framework built for real products.", - "Fission keeps state flow, layout, semantics, input routing, and rendering in one runtime, while platform shells handle packaging, windows, browser surfaces, lifecycle, and operating-system integration.", + "One platform for the whole application lifecycle.", + "Fission combines a Rust UI runtime, target shells, developer workflow, package readiness, release content, and distribution tooling so teams do not have to invent a platform around the framework.", ) .build(ctx, view), Row { children: vec![ LinkCard::new( - "Runtime", - "One shared runtime", - "State, reducers, layout, semantics, and rendering stay in one app model.", - "See the model ->", - "/docs/learn/runtime-model/", + "Build", + "Shared product model", + "State, reducers, selectors, widgets, design systems, charts, commands, jobs, and services stay in Rust.", + "Learn the model ->", + "/docs/learn/overview/", ) .build(ctx, view), LinkCard::new( - "Targets", - "Four real target families", - "Desktop, web, Android, and iOS hosts already exist around the same app code.", + "Run", + "Real target shells", + "Desktop, web, mobile, terminal, and static site shells host the same app model.", "See targets ->", - "/docs/learn/examples-and-targets/", + "/product/cross-platform-apps/", ) .build(ctx, view), LinkCard::new( - "Testing", - "Built for verification", - "Live tests, diagnostics, semantics, and layout inspection are part of the runtime story.", - "See testing ->", - "/docs/guides/testing-and-diagnostics/", + "Verify", + "Tests and diagnostics", + "Unit, widget, shell, screenshot, device, readiness, and future inspector tools are part of the platform story.", + "Debug path ->", + "/docs/test-and-debug/overview/", ) .build(ctx, view), LinkCard::new( - "CLI", - "Target scaffolding included", - "Project setup and host generation are already part of the command-line workflow.", - "See host setup ->", - "/docs/guides/platform-shells-cli-and-testing/", + "Ship", + "Post-build lifecycle", + "Package, sign, publish, manage testers, rollouts, tracks, static hosts, app stores, and release receipts.", + "Release path ->", + "/product/production-lifecycle/", ) .build(ctx, view), ], @@ -159,6 +161,84 @@ impl Widget for ProofStrip { } } +#[derive(Clone, Debug)] +pub(super) struct LifecycleSection; + +impl Widget for LifecycleSection { + fn build(&self, ctx: &mut BuildCtx, view: &View) -> Node { + let tokens = &view.env.theme.tokens; + ShellSection::new( + Column { + children: vec![ + Row { + children: vec![ + Column { + children: vec![ + Text::new("Application lifecycle") + .size(tokens.typography.font_size_sm) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.secondary) + .into_node(), + Text::new("From first run to store rollout.") + .size(tokens.typography.heading2_size) + .family(tokens.typography.font_family_serif.clone()) + .line_height(tokens.typography.heading2_size * tokens.typography.line_height_heading) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + ], + gap: Some(tokens.spacing.m), + flex_grow: 1.0, + ..Default::default() + } + .into_node(), + Text::new("The docs now follow the path teams actually take: setup, develop, test, debug, package, sign, release, distribute, and keep receipts for automation.") + .size(tokens.typography.body_large_size) + .line_height(tokens.typography.body_large_size * tokens.typography.line_height_relaxed) + .color(tokens.colors.text_secondary) + .flex_grow(1.0) + .into_node(), + ], + gap: Some(tokens.spacing.xl), + wrap: FlexWrap::Wrap, + align_items: AlignItems::Start, + ..Default::default() + } + .into_node(), + Row { + children: vec![ + lifecycle_step(tokens, "01", "Start", "init, project shape, targets"), + lifecycle_step(tokens, "02", "Develop", "run, devices, logs, shells"), + lifecycle_step(tokens, "03", "Debug", "tests, screenshots, inspectors"), + lifecycle_step(tokens, "04", "Package", "artifacts, signing, preflight"), + lifecycle_step(tokens, "05", "Release", "stores, hosts, rollouts, receipts"), + ], + gap: Some(tokens.spacing.s), + wrap: FlexWrap::Wrap, + justify_content: JustifyContent::SpaceBetween, + ..Default::default() + } + .into_node(), + Row { + children: vec![ + Cta::new("Open lifecycle docs", "/docs/release-and-distribute/overview/", true).build(ctx, view), + Cta::new("Read product page", "/product/production-lifecycle/", false).build(ctx, view), + ], + gap: Some(tokens.spacing.s), + wrap: FlexWrap::Wrap, + ..Default::default() + } + .into_node(), + ], + gap: Some(tokens.spacing.l), + ..Default::default() + } + .into_node(), + ) + .build(ctx, view) + } +} + #[derive(Clone, Debug)] pub(super) struct ArchitectureSection; @@ -307,16 +387,17 @@ impl Widget for TargetsSection { vec![ SectionHeader::new( "Targets", - "Desktop, web, Android, and iOS stay in the same orbit.", - "Start on the host that answers your next product question fastest, then keep the shared model intact.", + "Desktop, mobile, web, terminal, and static HTML are first-class outputs.", + "Start on the host that answers your next product question fastest, then validate on every real target your users will touch.", ) .build(ctx, view), Column { children: vec![ - TargetRowCard::new("Desktop", "Supported", "macOS - Linux - Windows", "cargo run -p counter", "Fast local loop for reducers, overlays, layout, and diagnostics.", "/docs/learn/examples-and-targets/", "Desktop path ->").build(ctx, view), - TargetRowCard::new("Web", "Smoke path", "WASM", "./examples/web-smoke/platforms/web/run-browser.sh", "Browser host path and generated launcher folder around the same app model.", "/docs/guides/platform-shells-cli-and-testing/", "Web path ->").build(ctx, view), - TargetRowCard::new("Android", "Smoke path", "Emulator", "./examples/mobile-smoke/platforms/android/run-emulator.sh", "Checked-in emulator path and generated Android host folder.", "/docs/guides/platform-shells-cli-and-testing/", "Android path ->").build(ctx, view), - TargetRowCard::new("iOS", "Smoke path", "Simulator", "./examples/mobile-smoke/platforms/ios/run-sim.sh", "Checked-in simulator path and generated iOS host folder.", "/docs/guides/platform-shells-cli-and-testing/", "iOS path ->").build(ctx, view), + TargetRowCard::new("Desktop", "First-class", "macOS - Linux - Windows", "fission run --target desktop", "Native windows, rendering, input, diagnostics, package readiness, and desktop release paths.", "/product/cross-platform-apps/", "Desktop path ->").build(ctx, view), + TargetRowCard::new("Web", "First-class", "WASM", "fission run --target web", "Browser delivery with the same shared app model and web/static packaging workflow.", "/product/cross-platform-apps/", "Web path ->").build(ctx, view), + TargetRowCard::new("Mobile", "First-class", "Android - iOS", "fission devices", "Generated mobile hosts, emulator/simulator workflow, APK/AAB/IPA readiness, and store publishing.", "/product/cross-platform-apps/", "Mobile path ->").build(ctx, view), + TargetRowCard::new("Terminal UI", "First-class", "Windows - macOS - Linux", "fission ui", "Interactive terminal apps built from normal Fission widgets, reducers, screens, and routes.", "/product/terminal-apps/", "Terminal path ->").build(ctx, view), + TargetRowCard::new("Static HTML", "First-class", "Sites - Docs - Marketing", "fission site build", "SEO-friendly static HTML from Fission widgets, Markdown content, search, metadata, and assets.", "/product/static-sites/", "Site path ->").build(ctx, view), ], gap: Some(tokens.spacing.s), ..Default::default() @@ -432,12 +513,12 @@ impl Widget for ExamplesSection { fn build(&self, ctx: &mut BuildCtx, view: &View) -> Node { CenteredSection::new( "Examples", - "Small loop, real app shell, large custom tool surface.", - "Start where your evaluation needs the most signal.", + "Examples across the platform, not only the widget layer.", + "Start with the smallest app, then inspect the examples that prove targets, charts, static sites, terminal tooling, and release workflow.", vec![ ExampleCard::new("Starter", "Counter", "cargo run -p counter", "The smallest complete Fission app loop: plain state, two reducers, a widget tree, and buttons bound with the public prelude macros.", "typed actions and reducers", "single-file starter app", "/docs/cookbook/build-a-counter/", "/reference/core/state-system/").build(ctx, view), - ExampleCard::new("Product shell", "Inbox", "cargo run -p inbox", "A product-like mail app that exercises portals, theme switching, locale switching, routing, and host capabilities in one shell.", "translation bundles and locale sync", "OPEN_URL host capability flow", "/docs/guides/theming-and-i18n/", "/reference/core/environment-input-and-ime/").build(ctx, view), - ExampleCard::new("Custom surface", "Fission Editor", "cargo run -p fission-editor -- .", "The deepest example in the repo: custom editing surface, jobs, timers, portals, terminal panel, and extensive live tests.", "custom render node path", "resource-driven jobs and timers", "/docs/guides/resources-and-async/", "/reference/widgets/media/").build(ctx, view), + ExampleCard::new("Site", "Documentation", "fission site build --project-dir documentation", "This website is a Fission static site: custom homepage widgets, Markdown content routes, generated search, metadata, sidebars, and GitHub Pages output.", "static HTML shell", "content routes and custom widgets", "/docs/guides/static-sites/", "/product/static-sites/").build(ctx, view), + ExampleCard::new("Terminal", "Fission CLI UI", "fission ui --project-dir .", "The CLI includes a terminal Fission app with screens, routes, reducers, dialogs, command sessions, logs, settings, density, and theme switching.", "terminal shell", "non-blocking command workflow", "/docs/guides/terminal-user-interfaces/", "/product/terminal-apps/").build(ctx, view), ], ) .build(ctx, view) @@ -454,7 +535,7 @@ impl Widget for FinalCta { Column { children: vec![ Pill::new("Next").build(ctx, view), - Text::new("Run an app, inspect a host, then go deeper where you need detail.") + Text::new("Pick a lifecycle stage and keep moving.") .size(tokens.typography.heading1_size) .family(tokens.typography.font_family_serif.clone()) .line_height( @@ -464,7 +545,7 @@ impl Widget for FinalCta { .color(tokens.colors.heading) .text_align(TextAlign::Center) .into_node(), - Text::new("The shared runtime is sitting right there. The next product question is one cargo command away.") + Text::new("Start with the app model, add the targets you need, then use Fission's tooling to verify, package, and release the product.") .size(tokens.typography.body_large_size) .line_height(tokens.typography.body_large_size * tokens.typography.line_height_relaxed) .color(tokens.colors.text_secondary) @@ -472,9 +553,9 @@ impl Widget for FinalCta { .into_node(), Row { children: vec![ - Cta::new("Run examples", "/docs/learn/examples-and-targets/", true).build(ctx, view), - Cta::new("Inspect hosts", "/docs/guides/platform-shells-cli-and-testing/", false).build(ctx, view), - NavLink::new("Review testing ->", "/docs/guides/testing-and-diagnostics/").build(ctx, view), + Cta::new("Start docs", "/docs/intro/", true).build(ctx, view), + Cta::new("Product overview", "/product/overview/", false).build(ctx, view), + NavLink::new("Reference ->", "/reference/overview/overview/").build(ctx, view), ], gap: Some(tokens.spacing.m), wrap: FlexWrap::Wrap, @@ -556,6 +637,48 @@ fn boundary_panel( .into_node() } +fn lifecycle_step( + tokens: &Tokens, + number: &'static str, + title: &'static str, + body: &'static str, +) -> Node { + Container::new( + Column { + children: vec![ + Text::new(number) + .size(tokens.typography.font_size_xs) + .family(tokens.typography.font_family_mono.clone()) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.primary) + .into_node(), + Text::new(title) + .size(tokens.typography.font_size_lg) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + Text::new(body) + .size(tokens.typography.font_size_sm) + .line_height( + tokens.typography.font_size_sm * tokens.typography.line_height_normal, + ) + .color(tokens.colors.text_secondary) + .into_node(), + ], + gap: Some(tokens.spacing.s), + ..Default::default() + } + .into_node(), + ) + .padding_all(tokens.spacing.m) + .bg_fill(Fill::Solid(tokens.colors.surface_raised)) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.large) + .width(tokens.spacing.xxxxl * 1.85) + .flex_shrink(1.0) + .into_node() +} + fn reducer_card(tokens: &Tokens) -> Node { Container::new( Text::new("fn reduce(state: &mut AppState, action: Action) {\n match action {\n Action::Inc => state.count += 1,\n Action::Reset => state.count = 0,\n }\n}") diff --git a/documentation/src/components/marketing.rs b/documentation/src/components/marketing.rs new file mode 100644 index 00000000..dfb54713 --- /dev/null +++ b/documentation/src/components/marketing.rs @@ -0,0 +1,961 @@ +use super::home_nav::HomePageNav; +use super::home_widgets::{ + content_width, page_fill, semantic_column, semantic_row, Cta, NavLink, Pill, +}; +use super::state::DocsState; +use fission::op::{AlignItems, Fill, FlexWrap, JustifyContent}; +use fission::prelude::*; + +#[derive(Clone, Copy, Debug)] +pub(crate) enum MarketingPageKind { + Overview, + CrossPlatformApps, + TerminalApps, + StaticSites, + ProductionLifecycle, + DeveloperTools, + DesignSystems, + Charts, +} + +#[derive(Clone, Debug)] +pub(crate) struct ProductMarketingPage { + kind: MarketingPageKind, +} + +impl ProductMarketingPage { + pub(crate) fn new(kind: MarketingPageKind) -> Self { + Self { kind } + } +} + +#[derive(Clone, Copy)] +struct PageCopy { + eyebrow: &'static str, + title: &'static str, + body: &'static str, + primary_label: &'static str, + primary_href: &'static str, + secondary_label: &'static str, + secondary_href: &'static str, + proof_label: &'static str, + proof_body: &'static str, + features: &'static [FeatureCopy], + workflow: &'static [StepCopy], +} + +#[derive(Clone, Copy)] +struct FeatureCopy { + label: &'static str, + title: &'static str, + body: &'static str, +} + +#[derive(Clone, Copy)] +struct StepCopy { + label: &'static str, + body: &'static str, +} + +const OVERVIEW_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "Runtime", title: "One app model", body: "State, actions, reducers, selectors, widgets, resources, jobs, services, capabilities, and design systems stay in shared Rust." }, + FeatureCopy { label: "Targets", title: "Every major surface", body: "Desktop, web, Android, iOS, terminal UI, and static HTML site targets are treated as product outputs, not side projects." }, + FeatureCopy { label: "Lifecycle", title: "Tooling after build", body: "Readiness checks, packages, signing, release content, app stores, static hosting, GitHub Releases, rollouts, and receipts are part of the platform." }, +]; + +const OVERVIEW_STEPS: &[StepCopy] = &[ + StepCopy { + label: "Start", + body: "Create a project, understand the app shape, and add the targets you need.", + }, + StepCopy { + label: "Develop", + body: "Run on devices, attach logs, use the right shell, and keep product behavior shared.", + }, + StepCopy { + label: "Ship", + body: "Check readiness, package, sign, publish, manage tracks, and keep receipts for CI.", + }, +]; + +const CROSS_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "Desktop", title: "Native app loop", body: "Windows, macOS, and Linux provide the fast local loop for product UI, diagnostics, and desktop packaging paths." }, + FeatureCopy { label: "Mobile", title: "Real host projects", body: "Android and iOS hosts keep the shared model intact while validating touch, lifecycle, safe areas, keyboards, package outputs, and stores." }, + FeatureCopy { label: "Web", title: "Browser delivery", body: "The web shell compiles the app for browser delivery without moving product behavior into a separate JavaScript application." }, +]; + +const CROSS_STEPS: &[StepCopy] = &[ + StepCopy { label: "Choose the fastest loop", body: "Use desktop when it answers the current product question fastest." }, + StepCopy { label: "Switch to the host", body: "Use browser, emulator, simulator, or device runs when the host is part of the behavior." }, + StepCopy { label: "Package intentionally", body: "Move from target run to target package without losing the app model." }, +]; + +const TERMINAL_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "Real Fission app", title: "Screens and reducers", body: "Terminal apps use the same state, route, reducer, screen, and component structure as graphical Fission apps." }, + FeatureCopy { label: "Command workflows", title: "Non-blocking tools", body: "Long-running checks, builds, logs, and release commands can run without freezing the interface." }, + FeatureCopy { label: "Verification", title: "Terminal-compatible output", body: "The terminal shell verifies lowered output against terminal capabilities instead of pretending every graphical widget works in cells." }, +]; + +const TERMINAL_STEPS: &[StepCopy] = &[ + StepCopy { label: "Navigate", body: "Use keyboard and supported pointer input for screens, dialogs, settings, and command flows." }, + StepCopy { label: "Observe", body: "Keep bounded scrollback, command sessions, logs, and status visible." }, + StepCopy { label: "Automate", body: "Use the same CLI workflows behind a friendlier interactive shell." }, +]; + +const STATIC_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "Custom pages", title: "Designed landing pages", body: "Homepages and product pages are normal Fission widgets rendered to static HTML at build time." }, + FeatureCopy { label: "Content routes", title: "Markdown at scale", body: "Documentation and reference pages come from content folders, front matter, explicit sidebars, generated headings, and templates." }, + FeatureCopy { label: "SEO", title: "Static output", body: "The site shell emits ordinary HTML, CSS, metadata, search indexes, assets, favicon links, and structured data support." }, +]; + +const STATIC_STEPS: &[StepCopy] = &[ + StepCopy { + label: "Design", + body: "Build bespoke landing pages with Fission widget components.", + }, + StepCopy { + label: "Author", + body: "Write docs and reference content in Markdown or MDX under content folders.", + }, + StepCopy { + label: "Publish", + body: "Generate static output for GitHub Pages or another static host.", + }, +]; + +const LIFECYCLE_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "Readiness", title: "Know what is missing", body: "Preflight checks report SDKs, package tools, signing inputs, credentials, store metadata, and artifact shape before release day." }, + FeatureCopy { label: "Artifacts", title: "Manifests and receipts", body: "Package outputs carry hashes, sizes, MIME types, targets, formats, validation state, and distribution receipts." }, + FeatureCopy { label: "Distribution", title: "Stores and hosts", body: "GitHub Releases, static hosting, object storage, Google Play, App Store Connect, and Microsoft Store paths fit one workflow." }, +]; + +const LIFECYCLE_STEPS: &[StepCopy] = &[ + StepCopy { label: "Package", body: "Produce installable or uploadable artifacts for the selected target." }, + StepCopy { label: "Validate", body: "Check release metadata, screenshots, signing, credentials, and provider requirements." }, + StepCopy { label: "Distribute", body: "Publish to stores, static hosts, package flights, testers, tracks, and rollout channels." }, +]; + +const DEVTOOLS_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "Inspector", title: "See the app model", body: "Inspect widget output, Core IR, layout boxes, semantics, focus, hit testing, and paint order." }, + FeatureCopy { label: "Diagnostics", title: "Follow behavior", body: "Trace actions, reducers, state snapshots, logs, resource calls, command output, and target diagnostics." }, + FeatureCopy { label: "IDE workflow", title: "Bring tools to the editor", body: "Plugins should expose targets, tasks, diagnostics, inspector links, docs, and release checks where developers already work." }, +]; + +const DEVTOOLS_STEPS: &[StepCopy] = &[ + StepCopy { + label: "Inspect", + body: "Understand what widgets produced and how layout resolved.", + }, + StepCopy { + label: "Diagnose", + body: "Correlate actions, resources, logs, device output, and frame timing.", + }, + StepCopy { + label: "Improve", + body: + "Use profiler and test output to fix performance and correctness issues before release.", + }, +]; + +const DESIGN_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "DSP JSON", title: "Bring your system", body: "Read design system package JSON at build time and generate typed Rust theme structures." }, + FeatureCopy { label: "Components", title: "Variants and states", body: "Apply sizes, variants, hover, active, focus, disabled, error, shadows, borders, typography, icon sizing, and dark/light behavior." }, + FeatureCopy { label: "Charts", title: "Visualization palette", body: "Use generated data-visualization palettes so charts match the product design system." }, +]; + +const DESIGN_STEPS: &[StepCopy] = &[ + StepCopy { + label: "Generate", + body: "Convert design system JSON into typed theme code during the build.", + }, + StepCopy { + label: "Select", + body: "Set the active theme through Env from user or platform preference.", + }, + StepCopy { + label: "Apply", + body: "Let widgets, charts, shells, and product surfaces consume the same tokens.", + }, +]; + +const CHART_FEATURES: &[FeatureCopy] = &[ + FeatureCopy { label: "Breadth", title: "Large chart catalog", body: "Line, bar, area, pie, scatter, heatmap, financial, relationship, map, component, dynamic, and 3D-oriented families." }, + FeatureCopy { label: "Product fit", title: "Dashboards and analytics", body: "Build monitoring, finance, operations, reporting, planning, and decision-support surfaces without leaving Fission." }, + FeatureCopy { label: "Design", title: "Theme-aware visuals", body: "Charts consume the design system palette, typography, backgrounds, dark mode, and interaction rules." }, +]; + +const CHART_STEPS: &[StepCopy] = &[ + StepCopy { + label: "Browse", + body: "Use the catalog to choose a family and variant.", + }, + StepCopy { + label: "Configure", + body: + "Bind series, datasets, axes, legends, tooltips, interaction, and animation settings.", + }, + StepCopy { + label: "Ship", + body: "Document and test charts with generated screenshots and gallery examples.", + }, +]; + +impl MarketingPageKind { + fn copy(self) -> PageCopy { + match self { + MarketingPageKind::Overview => PageCopy { + eyebrow: "Fission platform", + title: "A Rust application platform for the full product lifecycle.", + body: "Build the interface, run it on real targets, test and debug it, package artifacts, prepare release content, publish through stores and hosts, and keep receipts for automation.", + primary_label: "Start docs", + primary_href: "/docs/intro/", + secondary_label: "See release workflow", + secondary_href: "/docs/release-and-distribute/overview/", + proof_label: "One product model", + proof_body: "Fission keeps product behavior in shared Rust while shells and tooling handle the host and lifecycle edges.", + features: OVERVIEW_FEATURES, + workflow: OVERVIEW_STEPS, + }, + MarketingPageKind::CrossPlatformApps => PageCopy { + eyebrow: "Cross-platform apps", + title: "One Rust app model across desktop, mobile, and web.", + body: "Fission keeps state, reducers, widgets, resources, jobs, services, design systems, and charts shared while shells host the product on each platform.", + primary_label: "Read shell guide", + primary_href: "/docs/guides/platform-shells-cli-and-testing/", + secondary_label: "Browse targets", + secondary_href: "/docs/learn/examples-and-targets/", + proof_label: "Real targets", + proof_body: "Desktop, web, Android, and iOS are positioned as production targets with host-specific validation where the platform boundary matters.", + features: CROSS_FEATURES, + workflow: CROSS_STEPS, + }, + MarketingPageKind::TerminalApps => PageCopy { + eyebrow: "Terminal UI", + title: "Build terminal apps without leaving Fission.", + body: "Terminal UI is for production command tools, setup flows, diagnostics, admin panels, and developer workflows that need an interactive shell surface.", + primary_label: "Build a terminal app", + primary_href: "/docs/guides/terminal-user-interfaces/", + secondary_label: "Try fission ui", + secondary_href: "/reference/cli/overview/", + proof_label: "Built into the CLI", + proof_body: "The Fission CLI UI is implemented as a Fission terminal app with routes, screens, reducers, dialogs, settings, and command sessions.", + features: TERMINAL_FEATURES, + workflow: TERMINAL_STEPS, + }, + MarketingPageKind::StaticSites => PageCopy { + eyebrow: "Static sites", + title: "Generate SEO-friendly static sites from Fission widgets and content.", + body: "Use custom widget routes for marketing pages and Markdown content routes for documentation, reference, blogs, and changelogs.", + primary_label: "Read static site guide", + primary_href: "/docs/guides/static-sites/", + secondary_label: "View this site structure", + secondary_href: "/docs/release-and-distribute/overview/", + proof_label: "This site is the example", + proof_body: "The Fission documentation site is generated by the Fission static site shell, including custom pages, content routes, sidebars, search, and metadata.", + features: STATIC_FEATURES, + workflow: STATIC_STEPS, + }, + MarketingPageKind::ProductionLifecycle => PageCopy { + eyebrow: "Production lifecycle", + title: "Package, sign, release, distribute, and track the output.", + body: "Fission treats post-build work as a platform feature: readiness checks, artifact manifests, release content, credentials, stores, static hosts, tracks, rollouts, and receipts.", + primary_label: "Open release docs", + primary_href: "/docs/release-and-distribute/overview/", + secondary_label: "Lifecycle details", + secondary_href: "/docs/release-and-distribute/post-build-lifecycle/", + proof_label: "Release work is product work", + proof_body: "The CLI gives packaging and distribution the same project model as development instead of leaving each app to invent release scripts.", + features: LIFECYCLE_FEATURES, + workflow: LIFECYCLE_STEPS, + }, + MarketingPageKind::DeveloperTools => PageCopy { + eyebrow: "Developer tools", + title: "Make the Fission runtime observable while you build.", + body: "The developer tools direction is inspection, diagnostics, profiling, screenshots, device workflow, and IDE integration around the same explicit app model.", + primary_label: "Read testing docs", + primary_href: "/docs/test-and-debug/overview/", + secondary_label: "Open reference", + secondary_href: "/reference/core/testing-and-diagnostics/", + proof_label: "Debug the architecture you ship", + proof_body: "Tools should expose state, actions, reducers, layout, semantics, resources, logs, and target output without adding hidden behavior paths.", + features: DEVTOOLS_FEATURES, + workflow: DEVTOOLS_STEPS, + }, + MarketingPageKind::DesignSystems => PageCopy { + eyebrow: "Design systems", + title: "Bring a real design system into Rust UI code.", + body: "Fission reads design system package JSON at build time and generates typed theme code for widgets, charts, shells, and product surfaces.", + primary_label: "Read design guide", + primary_href: "/docs/guides/design-system/", + secondary_label: "Theme docs", + secondary_href: "/docs/guides/theming-and-i18n/", + proof_label: "No JSON hot path", + proof_body: "Design system JSON is converted during the build, then app code selects typed themes through Env at runtime.", + features: DESIGN_FEATURES, + workflow: DESIGN_STEPS, + }, + MarketingPageKind::Charts => PageCopy { + eyebrow: "Charts", + title: "Beautiful data visualization as a first-class product surface.", + body: "Fission Charts is the native charting layer for dashboards, analytics, finance, maps, networks, dynamic data, and 3D-ready visuals.", + primary_label: "Browse catalog", + primary_href: "/docs/charts/catalog/", + secondary_label: "Chart reference", + secondary_href: "/reference/charts/overview/", + proof_label: "Built for dashboards", + proof_body: "The chart catalog is broad because production apps need reporting, monitoring, planning, financial, and decision-support surfaces.", + features: CHART_FEATURES, + workflow: CHART_STEPS, + }, + } + } +} + +impl Widget for ProductMarketingPage { + fn build(&self, ctx: &mut BuildCtx, view: &View) -> Node { + let tokens = &view.env.theme.tokens; + let copy = self.kind.copy(); + Container::new( + Column { + children: vec![ + HomePageNav.build(ctx, view), + Row { + children: vec![Container::new(semantic_column( + "site-product-page", + vec![ + marketing_hero(ctx, view, self.kind, copy), + product_nav_strip(ctx, view), + feature_showcase(view, copy), + workflow_showcase(view, copy), + proof_band(ctx, view, copy), + ], + Some(tokens.spacing.xxxl), + AlignItems::Stretch, + )) + .max_width(content_width(tokens)) + .flex_grow(1.0) + .flex_shrink(1.0) + .padding([0.0, 0.0, tokens.spacing.xxl, tokens.spacing.xxxxl]) + .into_node()], + justify_content: JustifyContent::Center, + ..Default::default() + } + .into_node(), + ], + gap: Some(0.0), + flex_grow: 1.0, + ..Default::default() + } + .into_node(), + ) + .min_height(tokens.spacing.xxxxl * 9.0) + .bg_fill(page_fill(tokens)) + .into_node() + } +} + +fn marketing_hero( + ctx: &mut BuildCtx, + view: &View, + kind: MarketingPageKind, + copy: PageCopy, +) -> Node { + let tokens = &view.env.theme.tokens; + Container::new(semantic_row( + "site-product-hero", + vec![ + Container::new( + Column { + children: vec![ + Pill::new(copy.eyebrow).build(ctx, view), + Text::new(copy.title) + .size(tokens.typography.display_md_size) + .family(tokens.typography.font_family_serif.clone()) + .line_height( + tokens.typography.display_md_size + * tokens.typography.line_height_display, + ) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .max_width(tokens.spacing.xxxxl * 5.4) + .flex_shrink(1.0) + .semantics_identifier("site-product-hero-title") + .into_node(), + Text::new(copy.body) + .size(tokens.typography.font_size_lg) + .line_height( + tokens.typography.font_size_lg + * tokens.typography.line_height_relaxed, + ) + .color(tokens.colors.text_secondary) + .max_width(tokens.spacing.xxxxl * 5.2) + .flex_shrink(1.0) + .semantics_identifier("site-product-hero-body") + .into_node(), + semantic_row( + "site-product-hero-ctas", + vec![ + Cta::new(copy.primary_label, copy.primary_href, true) + .build(ctx, view), + Cta::new(copy.secondary_label, copy.secondary_href, false) + .build(ctx, view), + ], + Some(tokens.spacing.m), + FlexWrap::Wrap, + AlignItems::Center, + JustifyContent::Start, + ), + ], + gap: Some(tokens.spacing.l), + ..Default::default() + } + .into_node(), + ) + .width(tokens.spacing.xxxxl * 5.45) + .flex_shrink(1.0) + .into_node(), + product_visual(view, kind), + ], + Some(tokens.spacing.xxl), + FlexWrap::Wrap, + AlignItems::Center, + JustifyContent::SpaceBetween, + )) + .padding_all(tokens.spacing.xxl) + .bg_fill(Fill::LinearGradient { + start: (0.0, 0.0), + end: (1.0, 1.0), + stops: vec![ + (0.0, tokens.colors.surface.with_alpha(245)), + (0.52, tokens.colors.surface_sunken.with_alpha(238)), + (1.0, tokens.colors.primary_subtle.with_alpha(180)), + ], + }) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.xxl) + .into_node() +} + +fn product_nav_strip(ctx: &mut BuildCtx, view: &View) -> Node { + let tokens = &view.env.theme.tokens; + Container::new( + Row { + children: vec![ + strip_link(ctx, view, "Platform", "/product/overview/"), + strip_link(ctx, view, "Apps", "/product/cross-platform-apps/"), + strip_link(ctx, view, "Terminal", "/product/terminal-apps/"), + strip_link(ctx, view, "Static sites", "/product/static-sites/"), + strip_link(ctx, view, "Lifecycle", "/product/production-lifecycle/"), + strip_link(ctx, view, "Dev tools", "/product/developer-tools/"), + strip_link(ctx, view, "Design", "/product/design-systems/"), + strip_link(ctx, view, "Charts", "/product/charts/"), + ], + gap: Some(tokens.spacing.s), + wrap: FlexWrap::Wrap, + justify_content: JustifyContent::Center, + align_items: AlignItems::Center, + ..Default::default() + } + .into_node(), + ) + .padding_all(tokens.spacing.m) + .bg_fill(Fill::Solid(tokens.colors.surface.with_alpha(232))) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.full) + .into_node() +} + +fn strip_link( + ctx: &mut BuildCtx, + view: &View, + label: &'static str, + href: &'static str, +) -> Node { + let tokens = &view.env.theme.tokens; + Container::new(NavLink::new(label, href).build(ctx, view)) + .padding([ + tokens.spacing.m, + tokens.spacing.m, + tokens.spacing.s, + tokens.spacing.s, + ]) + .bg_fill(Fill::Solid(tokens.colors.surface_raised)) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.full) + .into_node() +} + +fn feature_showcase(view: &View, copy: PageCopy) -> Node { + let tokens = &view.env.theme.tokens; + semantic_row( + "site-product-feature-showcase", + vec![ + Column { + children: vec![ + Text::new("What teams get") + .size(tokens.typography.font_size_sm) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.secondary) + .into_node(), + Text::new("A product surface, not a loose collection of pages.") + .size(tokens.typography.heading2_size) + .family(tokens.typography.font_family_serif.clone()) + .line_height( + tokens.typography.heading2_size * tokens.typography.line_height_heading, + ) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + Text::new("Each part of the platform has a clear job, and each job links back to the same Rust app model.") + .size(tokens.typography.body_large_size) + .line_height( + tokens.typography.body_large_size + * tokens.typography.line_height_relaxed, + ) + .color(tokens.colors.text_secondary) + .into_node(), + ], + gap: Some(tokens.spacing.m), + flex_grow: 1.0, + ..Default::default() + } + .into_node(), + Row { + children: copy + .features + .iter() + .map(|feature| feature_card(view, *feature)) + .collect(), + gap: Some(tokens.spacing.m), + wrap: FlexWrap::Wrap, + align_items: AlignItems::Stretch, + justify_content: JustifyContent::End, + flex_grow: 1.0, + ..Default::default() + } + .into_node(), + ], + Some(tokens.spacing.xxl), + FlexWrap::Wrap, + AlignItems::Stretch, + JustifyContent::SpaceBetween, + ) +} + +fn feature_card(view: &View, feature: FeatureCopy) -> Node { + let tokens = &view.env.theme.tokens; + Container::new( + Column { + children: vec![ + Text::new(feature.label) + .size(tokens.typography.font_size_xs) + .family(tokens.typography.font_family_mono.clone()) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.primary) + .into_node(), + Text::new(feature.title) + .size(tokens.typography.heading_size) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + Text::new(feature.body) + .size(tokens.typography.body_medium_size) + .line_height( + tokens.typography.body_medium_size * tokens.typography.line_height_relaxed, + ) + .color(tokens.colors.text_secondary) + .flex_shrink(1.0) + .into_node(), + ], + gap: Some(tokens.spacing.m), + ..Default::default() + } + .into_node(), + ) + .width(tokens.spacing.xxxxl * 3.1) + .min_height(tokens.spacing.xxxxl * 2.05) + .flex_shrink(1.0) + .padding_all(tokens.spacing.l) + .bg_fill(Fill::Solid(tokens.colors.surface_raised)) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.xl) + .into_node() +} + +fn workflow_showcase(view: &View, copy: PageCopy) -> Node { + let tokens = &view.env.theme.tokens; + Container::new( + Column { + children: vec![ + Row { + children: vec![ + Text::new("Workflow") + .size(tokens.typography.font_size_sm) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.primary) + .into_node(), + Text::new("The path stays explicit from first run to release.") + .size(tokens.typography.heading_size) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + ], + gap: Some(tokens.spacing.l), + wrap: FlexWrap::Wrap, + align_items: AlignItems::Center, + ..Default::default() + } + .into_node(), + Row { + children: copy + .workflow + .iter() + .enumerate() + .map(|(index, step)| workflow_step(view, index + 1, *step)) + .collect(), + gap: Some(tokens.spacing.m), + wrap: FlexWrap::Wrap, + align_items: AlignItems::Stretch, + justify_content: JustifyContent::SpaceBetween, + ..Default::default() + } + .into_node(), + ], + gap: Some(tokens.spacing.l), + ..Default::default() + } + .into_node(), + ) + .padding_all(tokens.spacing.xl) + .bg_fill(Fill::Solid(tokens.colors.surface)) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.xxl) + .into_node() +} + +fn workflow_step(view: &View, index: usize, step: StepCopy) -> Node { + let tokens = &view.env.theme.tokens; + Container::new( + Column { + children: vec![ + Text::new(format!("{:02}", index)) + .size(tokens.typography.font_size_xs) + .family(tokens.typography.font_family_mono.clone()) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.primary) + .into_node(), + Text::new(step.label) + .size(tokens.typography.font_size_lg) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + Text::new(step.body) + .size(tokens.typography.font_size_sm) + .line_height( + tokens.typography.font_size_sm * tokens.typography.line_height_normal, + ) + .color(tokens.colors.text_secondary) + .into_node(), + ], + gap: Some(tokens.spacing.s), + ..Default::default() + } + .into_node(), + ) + .width(tokens.spacing.xxxxl * 3.05) + .min_height(tokens.spacing.xxxxl * 1.35) + .flex_shrink(1.0) + .padding_all(tokens.spacing.l) + .bg_fill(Fill::Solid(tokens.colors.surface_raised)) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.large) + .into_node() +} + +fn proof_band(ctx: &mut BuildCtx, view: &View, copy: PageCopy) -> Node { + let tokens = &view.env.theme.tokens; + Container::new(semantic_row( + "site-product-proof", + vec![ + Column { + children: vec![ + Text::new(copy.proof_label) + .size(tokens.typography.heading1_size) + .family(tokens.typography.font_family_serif.clone()) + .line_height( + tokens.typography.heading1_size * tokens.typography.line_height_heading, + ) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + Text::new(copy.proof_body) + .size(tokens.typography.body_large_size) + .line_height( + tokens.typography.body_large_size + * tokens.typography.line_height_relaxed, + ) + .color(tokens.colors.text_secondary) + .into_node(), + ], + gap: Some(tokens.spacing.m), + flex_grow: 1.0, + ..Default::default() + } + .into_node(), + Cta::new("Open documentation", "/docs/intro/", true).build(ctx, view), + ], + Some(tokens.spacing.xl), + FlexWrap::Wrap, + AlignItems::Center, + JustifyContent::SpaceBetween, + )) + .padding_all(tokens.spacing.xl) + .bg_fill(Fill::LinearGradient { + start: (0.0, 0.0), + end: (1.0, 1.0), + stops: vec![ + (0.0, tokens.colors.primary_subtle.with_alpha(200)), + (1.0, tokens.colors.surface_sunken), + ], + }) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.xxl) + .into_node() +} + +fn product_visual(view: &View, kind: MarketingPageKind) -> Node { + let tokens = &view.env.theme.tokens; + let children = match kind { + MarketingPageKind::Charts => chart_visual(view), + MarketingPageKind::TerminalApps => terminal_visual(view), + MarketingPageKind::StaticSites => site_visual(view), + MarketingPageKind::ProductionLifecycle => lifecycle_visual(view), + MarketingPageKind::DeveloperTools => devtools_visual(view), + MarketingPageKind::DesignSystems => design_visual(view), + MarketingPageKind::CrossPlatformApps => target_visual(view), + MarketingPageKind::Overview => platform_visual(view), + }; + Container::new(children) + .width(tokens.spacing.xxxxl * 4.35) + .flex_shrink(1.0) + .padding_all(tokens.spacing.l) + .bg_fill(Fill::Solid(tokens.colors.surface_raised.with_alpha(246))) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.xxl) + .into_node() +} + +fn platform_visual(view: &View) -> Node { + visual_stack( + view, + "Platform map", + &[ + ("App model", "State / reducers / widgets"), + ("Targets", "Desktop / Web / Mobile / TUI / Static"), + ("Lifecycle", "Package / sign / release / receipts"), + ], + ) +} + +fn target_visual(view: &View) -> Node { + visual_stack( + view, + "Target matrix", + &[ + ("Desktop", "Windows macOS Linux"), + ("Mobile", "Android iOS"), + ("Web", "WASM browser shell"), + ("Specialized", "Terminal UI Static HTML"), + ], + ) +} + +fn terminal_visual(view: &View) -> Node { + visual_stack( + view, + "fission ui", + &[ + ("Dashboard", "doctor running..."), + ("Logs", "47 checks passed"), + ("Settings", "theme: dark density: compact"), + ("Command", "non-blocking session attached"), + ], + ) +} + +fn site_visual(view: &View) -> Node { + visual_stack( + view, + "Static site build", + &[ + ("Custom route", "/product/overview/"), + ("Content route", "/docs/learn/quickstart/"), + ("Generated", "HTML CSS search sitemap"), + ], + ) +} + +fn lifecycle_visual(view: &View) -> Node { + visual_stack( + view, + "Release pipeline", + &[ + ("Preflight", "SDKs signing credentials"), + ("Package", "artifact-manifest.json"), + ("Publish", "stores hosts releases"), + ("Receipt", "CI-readable output"), + ], + ) +} + +fn devtools_visual(view: &View) -> Node { + visual_stack( + view, + "Inspector surface", + &[ + ("Widget tree", "routes / screens / components"), + ("Core IR", "layout / semantics / paint"), + ("Runtime", "actions / reducers / resources"), + ], + ) +} + +fn design_visual(view: &View) -> Node { + visual_stack( + view, + "Design system", + &[ + ("DSP JSON", "tokens and components"), + ("Codegen", "typed Rust theme"), + ("Runtime", "Env selects active theme"), + ("Surfaces", "widgets and charts"), + ], + ) +} + +fn chart_visual(view: &View) -> Node { + let tokens = &view.env.theme.tokens; + Column { + children: vec![ + visual_header(view, "Chart surfaces"), + Row { + children: vec![ + chart_thumb(view, "/img/charts/line-gradient-area.png"), + chart_thumb(view, "/img/charts/bar-horizontal.png"), + ], + gap: Some(tokens.spacing.s), + wrap: FlexWrap::Wrap, + ..Default::default() + } + .into_node(), + Row { + children: vec![ + chart_thumb(view, "/img/charts/sankey-energy.png"), + chart_thumb(view, "/img/charts/surface3d-wave.png"), + ], + gap: Some(tokens.spacing.s), + wrap: FlexWrap::Wrap, + ..Default::default() + } + .into_node(), + ], + gap: Some(tokens.spacing.m), + ..Default::default() + } + .into_node() +} + +fn visual_stack( + view: &View, + title: &'static str, + rows: &[(&'static str, &'static str)], +) -> Node { + let tokens = &view.env.theme.tokens; + Column { + children: std::iter::once(visual_header(view, title)) + .chain( + rows.iter() + .map(|(label, body)| visual_row(view, label, body)), + ) + .collect(), + gap: Some(tokens.spacing.m), + ..Default::default() + } + .into_node() +} + +fn visual_header(view: &View, title: &'static str) -> Node { + let tokens = &view.env.theme.tokens; + Row { + children: vec![ + dot(tokens.colors.error), + dot(tokens.colors.warning), + dot(tokens.colors.success), + Text::new(title) + .size(tokens.typography.font_size_sm) + .family(tokens.typography.font_family_mono.clone()) + .color(tokens.colors.text_secondary) + .into_node(), + ], + gap: Some(tokens.spacing.s), + align_items: AlignItems::Center, + ..Default::default() + } + .into_node() +} + +fn visual_row(view: &View, label: &'static str, body: &'static str) -> Node { + let tokens = &view.env.theme.tokens; + Container::new( + Row { + children: vec![ + Text::new(label) + .size(tokens.typography.font_size_sm) + .weight(tokens.typography.font_weight_bold) + .color(tokens.colors.heading) + .into_node(), + Text::new(body) + .size(tokens.typography.font_size_sm) + .family(tokens.typography.font_family_mono.clone()) + .color(tokens.colors.text_secondary) + .into_node(), + ], + gap: Some(tokens.spacing.m), + wrap: FlexWrap::Wrap, + justify_content: JustifyContent::SpaceBetween, + ..Default::default() + } + .into_node(), + ) + .padding_all(tokens.spacing.m) + .bg_fill(Fill::Solid(tokens.colors.surface)) + .border(tokens.colors.border, 1.0) + .border_radius(tokens.radii.large) + .into_node() +} + +fn chart_thumb(view: &View, src: &'static str) -> Node { + let tokens = &view.env.theme.tokens; + Container::new( + Image { + source: src.to_string(), + width: Some(tokens.spacing.xxxxl * 1.85), + height: Some(tokens.spacing.xxxxl * 1.05), + ..Default::default() + } + .into_node(), + ) + .padding_all(tokens.spacing.xs) + .bg_fill(Fill::Solid(tokens.colors.on_surface.with_alpha(245))) + .border_radius(tokens.radii.large) + .into_node() +} + +fn dot(color: Color) -> Node { + Container::new(Text::new(" ").into_node()) + .width(9.0) + .height(9.0) + .bg_fill(Fill::Solid(color)) + .border_radius(99.0) + .into_node() +} diff --git a/documentation/src/components/mod.rs b/documentation/src/components/mod.rs index 7c596187..d41d428e 100644 --- a/documentation/src/components/mod.rs +++ b/documentation/src/components/mod.rs @@ -3,8 +3,10 @@ mod home; mod home_nav; mod home_sections; mod home_widgets; +mod marketing; mod state; pub(crate) use footer::DocsFooter; pub(crate) use home::RoutedHomePage; +pub(crate) use marketing::{MarketingPageKind, ProductMarketingPage}; pub(crate) use state::DocsState; diff --git a/documentation/src/main.rs b/documentation/src/main.rs index 0505ca29..9affc682 100644 --- a/documentation/src/main.rs +++ b/documentation/src/main.rs @@ -2,7 +2,7 @@ mod charts; mod components; use anyhow::Result; -use components::{DocsFooter, DocsState, RoutedHomePage}; +use components::{DocsFooter, DocsState, MarketingPageKind, ProductMarketingPage, RoutedHomePage}; use fission::prelude::*; use fission::site::{build_from_cli, FissionSite}; @@ -17,11 +17,59 @@ fn site_app() -> FissionSite { "/", "Fission", Some( - "Build production desktop, web, Android, and iOS apps with one Rust UI framework." + "Build, test, package, and release production Rust apps across desktop, mobile, web, terminal, and static site targets." .to_string(), ), RoutedHomePage::new("/"), ) + .route_widget::( + "/product/overview/", + "Fission platform", + Some("A Rust application platform for the full product lifecycle.".to_string()), + ProductMarketingPage::new(MarketingPageKind::Overview), + ) + .route_widget::( + "/product/cross-platform-apps/", + "Cross-platform apps", + Some("Build desktop, mobile, and web apps from one shared Rust application model.".to_string()), + ProductMarketingPage::new(MarketingPageKind::CrossPlatformApps), + ) + .route_widget::( + "/product/terminal-apps/", + "Terminal apps", + Some("Build terminal user interfaces with the same Fission app model used for graphical apps.".to_string()), + ProductMarketingPage::new(MarketingPageKind::TerminalApps), + ) + .route_widget::( + "/product/static-sites/", + "Static sites", + Some("Generate SEO-friendly static HTML sites from Fission widgets, Markdown content, and explicit site routing.".to_string()), + ProductMarketingPage::new(MarketingPageKind::StaticSites), + ) + .route_widget::( + "/product/production-lifecycle/", + "Production lifecycle", + Some("Package, sign, release, distribute, and track production Fission apps.".to_string()), + ProductMarketingPage::new(MarketingPageKind::ProductionLifecycle), + ) + .route_widget::( + "/product/developer-tools/", + "Developer tools", + Some("Developer tools for inspection, diagnostics, profiling, screenshots, device workflow, and IDE integration.".to_string()), + ProductMarketingPage::new(MarketingPageKind::DeveloperTools), + ) + .route_widget::( + "/product/design-systems/", + "Design systems", + Some("Use design system package JSON to generate typed Fission theme code.".to_string()), + ProductMarketingPage::new(MarketingPageKind::DesignSystems), + ) + .route_widget::( + "/product/charts/", + "Charts and data visualization", + Some("Native Fission charts for dashboards, analytics, finance, maps, networks, dynamic data, and 3D-ready visuals.".to_string()), + ProductMarketingPage::new(MarketingPageKind::Charts), + ) .footer_widget::(DocsFooter) .user_css(include_str!("../site/overrides.css")) .content_transform(charts::expand_documentation_mdx) From 7faf398932e36680bdea765467a0abdd515611f4 Mon Sep 17 00:00:00 2001 From: zcourts Date: Fri, 22 May 2026 08:32:08 +0100 Subject: [PATCH 3/3] ci: install dbus dev library for platform checks --- .github/workflows/platform-checks.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/platform-checks.yml b/.github/workflows/platform-checks.yml index ffafaa6c..ece83f79 100644 --- a/.github/workflows/platform-checks.yml +++ b/.github/workflows/platform-checks.yml @@ -24,6 +24,11 @@ jobs: - name: Set up Rust uses: dtolnay/rust-toolchain@stable + - name: Install Linux DBus development package + run: | + sudo apt-get update + sudo apt-get install -y pkg-config libdbus-1-dev + - name: Test generated platform scripts run: cargo test -p fission-cli @@ -41,6 +46,11 @@ jobs: with: targets: wasm32-unknown-unknown + - name: Install Linux DBus development package + run: | + sudo apt-get update + sudo apt-get install -y pkg-config libdbus-1-dev + - name: Check wasm core crates run: | cargo check -p fission-core --target wasm32-unknown-unknown @@ -76,6 +86,11 @@ jobs: with: targets: aarch64-linux-android + - name: Install Linux DBus development package + run: | + sudo apt-get update + sudo apt-get install -y pkg-config libdbus-1-dev + - name: Set up Android SDK uses: android-actions/setup-android@v3