SlideStage Lite
CHANGELOG.mdAll notable changes to the SlideStage Lite app and its @slidestage/*
packages live here. Per-package CHANGELOG.md files reference the
relevant sections of this file.
This project follows Semantic Versioning. Until
1.0 the public API of every @slidestage/* package may evolve between
0.x minor releases; we will call out breaking changes explicitly.
0.3.0 — 2026-05-28
Markdown lands in the presenter view, slide-internal Markdown gains GFM
table support, and the reveal.js / impress.js → .stage converter is
now native end-to-end. Existing 0.2.x desktop users will pick this up
through the in-app updater on next launch — same minisign keypair, no
reinstall.
Highlights — Presenter view
- Speaker notes render Markdown. Code blocks, links, lists,
headings, emphasis, blockquotes, and GFM tables all render in the
presenter window's notes panel. The same
renderMarkdownalso powers in-slide Markdown viewers, so deck authors can drop GFM table syntax anywhere instead of falling back to handwritten HTML.
Highlights — Converter
- Native reveal.js / impress.js splitter.
pnpm convertand the in-app Web Converter route.html, zip, and folder inputs through a native splitter instead of string-slicing scripts. New e2e suites cover round-trip, folder ingest, oversized decks, tricky assets, relaxed manifests, and the trust prompt. reveal-basictemplate ships its bundledreveal.js. A.gitignorerule was silently eatingpackages/spec/templates/reveal-basic/dist/reveal.js, so converted decks fell through to a missing-script error. The bundle is now tracked and ships with the template.
Highlights — Architecture
- **
@slidestage/specand@slidestage/brandextracted as standalone workspace packages on npm.** Spec owns the.stageschema, manifest validation, path safety, trust capability, and fixtures. Brand owns marks, wordmarks, the product registry, and the ecosystem README generator. SlideStagePack and SlideStagePro consume both via@slidestage/<pkg>@<semver>— no source-level coupling. - GitHub Releases is reserved for the desktop app. Per-package
@slidestage/<pkg>@<version>Releases no longer auto-create on npm publish (createGithubReleases: falseon the changesets action). npm publishing itself is unchanged; the @slidestage scope on npmjs.com is still the SoT for package consumers.
Downloads
| Platform | File |
|---|---|
| macOS Apple Silicon | SlideStageLite-0.3.0-macOS-AppleSilicon.dmg |
| macOS Intel | SlideStageLite-0.3.0-macOS-Intel.dmg |
| Windows x64 | SlideStageLite-0.3.0-Windows-x64-setup.exe |
Existing 0.2.x desktop users will see the in-app update banner on next launch and can install in place. Fresh installs should grab the DMG / NSIS installer above.
0.2.1 — 2026-05-24
Windows desktop bundle reaches feature parity with macOS: NSIS installer,
in-app auto-updater (sharing the macOS minisign keypair and the same
latest.json manifest), and a Help → Check for Updates… / `Help →
About SlideStage Lite` menu surface. This release also introduces the
macOS application-menu Check for Updates… item; both platforms now
drive the manual update flow through the same runManualUpdateCheck
entry point.
Highlights — Windows
- NSIS installer. Track 2 (MVP) ships an unsigned
currentUser-mode NSIS.exebundle (SlideStageLite-<version>-Windows-x64-setup.exe). No UAC prompt on install or update, Start Menu shortcut by default, WebView2 fetched on-demand via the download bootstrapper (~6 MB installer; Windows 11 already has WebView2 pre-installed; Windows 10 1809+ pulls the runtime on first launch). Code signing is intentionally deferred — Defender SmartScreen "Unrecognized app" guidance lives in the README anddocs/WINDOWS_DISTRIBUTION.mdalong with the Azure Trusted Signing / SignPath upgrade hooks. - Auto-updater is the same plumbing as macOS. The Windows build
reuses the existing
tauri-plugin-updaterflow with the same minisign public key baked intotauri.conf.json > plugins.updater.pubkey, the samelatest.jsonmanifest, and the same dual endpoints (releases/latest/download/latest.json+updates.slidestage.devfallback).scripts/build-update-manifest.mjslearned a--merge-existingflag that lets the Windows pipeline merge awindows-x86_64block into an already-publishedlatest.jsonwithout evictingdarwin-*entries — required because the macOS DMG is built locally while the Windows installer is built on a GitHub Actionswindows-latestrunner. Help → Check for Updates…mirrors the macOS app-menu trigger. Same Rust event (menu:check-update), samerunManualUpdateCheckflow on the front-end, same locale-awareplugin-dialogmodals.set_check_update_menu_statelearned to recurse one level into submenus so the toggle works whether the item lives at the top of the App menu (macOS) or nested under Help (Windows).Help → About SlideStage Liteuses Tauri'sPredefinedMenuItem::aboutwith anAboutMetadatapopulated fromCargo.toml. Windows pops the native About dialog with name, version, copyright, and the slidestage.dev website link — equivalent information to macOS'About SlideStage LiteSparkle entry..stagefile association +stage://deep-links. NSIS auto- registers the file extension at install time; the Rust setup also callsDeepLinkExt::register_all()at runtime as a defensive fallback (writes under HKCU, no admin rights) to dodge Tauri's historic NSIS deep-link registration regressions (#10095).single-instanceis wired with thedeep-linkfeature so an open app handlesstage://URLs without spawning a second process.
Highlights — macOS
- Native menu entry. The macOS app menu now includes a
Check for Updates…item, slotted betweenAbout SlideStage LiteandServicesper the Safari / Xcode / Sparkle convention. Click it to force an immediate manifest probe regardless of whether a deck is open — the silent boot probe +UpdateBannercontinues to handle the passive "new release available" surface on the landing page. - Native dialog feedback. Manual checks surface their result
through
@tauri-apps/plugin-dialog: an info dialog announces "You're up to date" with the running version, a confirm dialog (Install Now / Later) offers to install the new release, and error states report the failure reason without dismissing the menu trigger for next launch. - Visual feedback on the menu itself. The menu item swaps to
Checking for Updates…and goes disabled while the manifest probe is running, and stays disabled through the install pass so a second click cannot accidentally re-fire the flow. The Rust side exposes aset_check_update_menu_statecommand that the front-end uses to drive the toggle from atry/finally. - Locale-aware copy. All dialog text follows the app locale (zh-CN + en); the menu item text is hard-coded English to match macOS convention.
- Boundary preserved. Edit / View / Window / Help submenus on macOS are untouched — only the App submenu is rebuilt — so user expectations for standard macOS shortcuts (Cmd-W, Cmd-M, etc.) stay intact.
@slidestage/lite-preset
- New:
desktop/manualUpdateCheck— exportsrunManualUpdateCheck(labels), the imperative entry point theLiteAppshell wires to themenu:check-updateTauri event. Pure TypeScript, no React dependency, all i18n strings supplied by the caller. Works identically on macOS and Windows. - New peer dependency (optional):
@tauri-apps/plugin-dialogalongside the existingplugin-updater/plugin-process. Marked optional so the web bundle never installs it. - i18n: new keys under
menu.checkUpdate.*(zh-CN + en) covering the up-to-date / available / error / install-error dialog variants and the Install / Later confirm-button labels.
Desktop
src-tauri/src/lib.rs: cross-platform menu setup insetup().- macOS: takes
Menu::default(app), drops item[0] (the OS-generated App submenu) and inserts a hand-built submenu that mirrors the standard layout plus the newCheck for Updates…item. - Windows: attaches a window menu bar with a
Helpsubmenu containingCheck for Updates…, a separator, andAbout SlideStage Lite(native dialog viaPredefinedMenuItem::about). - Both platforms:
on_menu_eventforwardscheck_updatesclicks as themenu:check-updateTauri event. set_check_update_menu_state(checking: bool)toggles the menu item text / enabled state. Recurses one level into submenus so it works on Windows where the item is nested underHelp.- Windows / Linux setup also calls
DeepLinkExt::register_all()as a runtime fallback for thestage://scheme registration.
- macOS: takes
src-tauri/tauri.conf.json:bundle.windows.nsisswitched to the Tauri 2.x schema (installMode: "currentUser", `languages: [English, SimpChinese], etc.) andcreateUpdaterArtifacts: true` so the bundler emits.nsis.zip+.sigfor the updater pipeline.src-tauri/capabilities/default.json:dialog:allow-openupgraded todialog:defaultso the front-end can callconfirmandmessagein addition to the file picker.updater:default/process:default/process:allow-restartwere already in place from 0.2.0.
Release pipeline
- New:
scripts/release-windows.mjs— orchestrates the Windows bundle on a Windows host (refuses to run on non-win32). Same--dry-run/--skip-updater/--uploadflags asrelease-macos.mjs. Invokes `build-update-manifest.mjs --merge-existingso the Windowswindows-x86_64` block joins the existing macOS blocks without overwriting them. - New:
.github/workflows/release-windows.yml— runs on tag push (v*.*.*) andworkflow_dispatch. Uses the sameTAURI_SIGNING_PRIVATE_KEY{,_PASSWORD}repository secrets the macOS release machine consumes locally, runs `pnpm fixtures && pnpm typecheck && pnpm test:unit` as a sanity gate before the bundler (catches Windows-only regressions before release), then attaches artifacts to the matching GitHub Release via `gh release upload --clobber`. scripts/build-update-manifest.mjs: new--merge-existingflag, Windows + Linux Rust triple → platform-key mappings, hyphenated artifact rename (SlideStageLite-<v>-Windows-x64-setup.exe).scripts/desktop-smoke.mjs: new Windows code path usingtasklist/taskkill, with a 60 MB binary size cap (Tauri + WebView2 host is larger than the 25 MB macOS cap).
Docs
docs/WINDOWS_DISTRIBUTION.md— full Windows distribution playbook, including the Track 2 (NSIS unsigned MVP) defaults, the rationale for each decision, and the Azure Trusted Signing / SignPath / MSIX-via-Store upgrade paths.docs/AUTO_UPDATER.mdextended to cover the macOS + Windows dual-runner flow and the--merge-existingmanifest contract.README.md/README_cn.md— added Windows download / SmartScreen guidance to the "Desktop App" section..env.example— documented the sharedTAURI_SIGNING_PRIVATE_KEYcontract for Windows GHA secrets.
Release pipeline hardening (during first publish)
Five latent bugs surfaced while shipping the first cross-platform
release. They are fully written up in .memory/desktop-tauri.md
under "Release Retrospective — v0.2.1"; the short version:
936a0ff—latest.jsoncross-platform merge: mac dual-arch was overwriting its own block; the Windows GHA runner was overwriting the mac block. macOS now passes--merge-existing; Windows seedsdist-desktop/latest.jsonfrom the release before merging.e69ee83—release-windows.ymlNode20→22(pnpm 11 requiresnode:sqlitefrom Node 22.5).0bb7cee—release-*.mjskey validation recognizes the base64 envelope (dW50cnVzdGVkIGNvbW1lbnQ6…) so GHA secrets containing raw keyfile contents aren't mis-classified as missing paths.41986fc—RunEvent::Openedcfg-gated to macOS (the variant doesn't exist in Tauri's enum on Windows/Linux; the closure was rejecting the entire crate at compile time).0af4e96— adopt Tauri 2.x Windows updater format: bundler now ships-setup.exe+-setup.exe.sig(the.nsis.zipwrapper from 1.x is gone). Both release-windows.mjs and build-update-manifest.mjs updated to match.
Known follow-up for v0.2.2: extend the upload regex in
release-windows.mjs to include *.exe.sig (currently the signature
is only inline-embedded in latest.json, not uploaded as a separate
asset). The updater works correctly without it; manual minisign -V
verification of the installer does not.
0.2.0 — 2026-05-22
Native in-app auto-updater on the desktop.
Highlights
- Tauri 2 native auto-updater. The desktop build now uses
@tauri-apps/plugin-updaterto fetch a staticlatest.jsonmanifest, verify the bundled.app.tar.gz.sigagainst a minisign public key baked intotauri.conf.json, download the new build, install it, and relaunch — all inside the running app. No more "click the link, drag the DMG to Applications" two-step. - Dual endpoints. Tauri tries the GitHub Releases manifest first
(
releases/latest/download/latest.json) and falls back to a mirror atupdates.slidestage.dev/latest.jsonif GitHub is unreachable. Both URLs return the same signed manifest. - Per-version dismissal. The banner remembers the version the user dismissed and stays quiet until a strictly newer release appears.
- Five-state UI. The new banner walks the user through
available → downloading → installing → restarting, with a fiftherrorstate that supports retry. Progress is byte-accurate when the server returns Content-Length; a striped indeterminate bar covers the case when it doesn't. - Release pipeline upgrades.
pnpm release:macosnow also emits<app>.app.tar.gz+.sig, runsscripts/build-update-manifest.mjsto writedist-desktop/latest.json, and accepts a new--uploadflag that attaches every artifact to the matching GitHub Release viagh release upload --clobber. - Web build is untouched. All
@tauri-apps/plugin-updaterand@tauri-apps/plugin-processimports are dynamic and gated byisTauri(), so the Vite bundle never ships the updater code to browser users — the chunks split out to ~1.4 KB of lazy-loaded JS that web users will never download.
Breaking changes
packages/lite-preset/src/desktop/updateCheck.tspublic API changed:checkForUpdate(opts)now takes no arguments and returns{ version, currentVersion, notes, publishedAt }instead of{ tag, version, releaseUrl, publishedAt, notes }. NewinstallUpdate(onProgress)API replaces "open the release page in the browser". The semver helpers (compareSemver,fetchLatestRelease) are gone — Tauri's plugin owns the comparison and the network call.update.ctai18n key replaced byupdate.cta.install(andupdate.cta.retry); new keysupdate.progress.body,update.progress.detail,update.progress.detailUnknown,update.installing,update.restarting,update.error.bundle.createUpdaterArtifactsistrueby default. Passpnpm release:macos --skip-updaterfor the legacy DMG-only flow.
Operational notes
- Run
pnpm updater:keygenonce to produce the minisign keypair, paste the public key intotauri.conf.json > plugins.updater.pubkey, and setTAURI_SIGNING_PRIVATE_KEY+TAURI_SIGNING_PRIVATE_KEY_PASSWORDin.env.local. Losing either makes shipping updates the existing fleet accepts impossible — back the keypair up offline. - Full setup walkthrough lives in
docs/AUTO_UPDATER.md; condensed reference in.memory/desktop-tauri.md.
0.1.1 — 2026-05-21
Desktop polish + Mac App Store prep.
Highlights
- macOS app links are clickable again. Footer links (ICP / 公网安备 /
slidestage.dev) now open in the user's default browser via
tauri-plugin-openerinstead of being swallowed by the WKWebView. - Official product name standardized. Display name is now "SlideStage Lite" (and Pro counterpart is "SlideStage Pro") — with a space, per branding decision. Bundle identifier, npm package names, repository name, and DMG filename remain unchanged so existing installs upgrade in place without losing locale, trust, or annotation state.
- Self-distributed builds detect new versions. A passive update
banner polls GitHub Releases on launch; when a newer tag is found,
the user sees a one-click link to the release page. Dismissed
versions are remembered per tag in
localStorage. - Window-scoped keyboard shortcuts. The OS-level
tauri-plugin-global-shortcutplugin was removed. Presentation keys now work via the existingwindow.addEventListener('keydown', …)layer, with focus reclaim triggered on iframe load, container pointerdown, and host-window refocus (Alt/Cmd-Tab back). - Mac App Store feasibility assessment (
docs/MAC_APP_STORE_ASSESSMENT.md) documents the remaining sandbox / library-validation blockers and the planned remediation path. The global-shortcut blocker is now resolved, leaving App Sandbox + library validation as the remaining large items. MAS submission is deferred per current direction.
@slidestage/lite-preset
- New:
desktop/openExternal— opens URLs in the OS browser viatauri-plugin-opener(Tauri-only), with awithDesktopOpener(url)React helper that intercepts anchor clicks in host UI. - New:
desktop/updateCheck— GitHub Releases poller with semver comparison (vprefix, pre-release skip, draft skip) and per-tag dismissal stored inlocalStorage. - New:
app/UpdateBanner— passive banner shown in thedeck-closedshell; callsopenExternalto route to the release page. - Removed:
desktop/globalShortcutsand the@tauri-apps/plugin-global-shortcutpeer dependency. Window-scoped shortcuts handle the same surface (see@slidestage/uinotes below). - i18n:
app.brand.name,viewer.notice.autoElevatedSize,trust.lead.beforeupdated to "SlideStage Lite"; new `update.body / cta / dismiss` keys for the banner (zh-CN + en). audienceWindow.titleupdated to"SlideStage Lite — Audience".
@slidestage/ui
DeckStagegains a third focus-reclaim trigger: when the hostwindowregains focus (Alt/Cmd-Tab back, dismissing a system dialog), focus is pulled back into the deck container so presentation shortcuts are available immediately. Previously this was papered over by global shortcuts; with that plugin gone, the reclaim is needed to keep window-scoped shortcuts feeling responsive.
@slidestage/core
- Cosmetic:
converter/buildManifestsniffer description string uses the new product name.
Desktop
tauri.conf.json > productNameis now"SlideStage Lite". The built bundle moves fromtarget/.../bundle/macos/SlideStageLite.apptotarget/.../bundle/macos/SlideStage Lite.app. Release / smoke / signing scripts probe both paths so older artifacts on disk are still inspectable.- Removed
tauri-plugin-global-shortcutfromCargo.toml,src-tauri/src/lib.rs, andcapabilities/default.json. - DMG filename pattern is unchanged:
SlideStageLite-<version>-macOS-AppleSilicon.dmg. - Bundle identifier unchanged:
dev.slidestage.slidestagelite.
Documentation
README.md/README_cn.mdrebranded.docs/MAC_APP_STORE_ASSESSMENT.mdpublished (feasibility-only, no code changes for MAS yet)..memory/desktop-tauri.mdrecords the naming policy and the window-scoped shortcut decision.
0.1.0
Initial public release. See the v0.1.0 GitHub Release for the introductory notes.