📦tarwin / tinyjsapp
← 返回首页
Build native apps in JS. Backend, frontend. ~5Mb.
⚖️ MIT📅 创建于 2026-07-12🔄 更新于 2026-10-28

📄 仓库 README

在 GitHub 查看 ↗
来自 GitHub 仓库自述文件 · 版权归原作者所有

tinyjs

tinyjs — desktop apps ~6mb

Tiny desktop apps for macOS, Windows and Linux: a txiki.js backend + a native webview window.

  • ~6 MB shipped, two real files — no Electron, no Node, no bundled Chromium
  • No HTTP server, no ports — the page and the backend talk over a Unix domain socket in a private temp directory
  • Backend is plain JavaScript with full system access (files, sockets, processes, FFI) via txiki.js
  • Frontend is plain HTML/CSS/JS (multi-file, WebGPU included) rendered by the system WebKit
  • Native menus, dialogs, tray/menu-bar apps, notifications, drag & drop with real file paths, window control
  • Hot reload in dev, signed .app bundles out of build, auto-update out of publish

Questions, help, or something you built: come say hi on Discord.

Install

curl -fsSL https://tinyjs.app/install | sh

The same script now handles Linux too (it detects the OS). Installs to ~/.tinyjs and symlinks tinyjs onto your PATH. Pin a version with TINYJS_VERSION=vX.Y.Z. Later, tinyjs update runs the copy of the installer that came with your install if a newer release exists (--check only reports, --dry-run shows what it would run); tinyjs dev also mentions new releases, checking at most once a day. After updating, run tinyjs update-project in each project to refresh its types and coding-agent skill (see below). Linux needs the system WebKitGTK runtime: sudo apt install libwebkit2gtk-4.1-0 on Debian/Ubuntu, sudo zypper install libwebkit2gtk-4_1-0 on openSUSE. Prebuilt binaries ship for Linux x86_64 and arm64 with the first tagged release after Linux support merged — the installer says so plainly against older releases. To install from source instead:

git clone https://github.com/tarwin/tinyjsapp && cd tinyjsapp
./setup.sh    # downloads the txiki.js runtime, compiles the launcher
ln -s "$(pwd)/tinyjs" /usr/local/bin/tinyjs

On Linux, setup.sh needs the system dev packages first. Debian/Ubuntu: sudo apt install build-essential pkg-config libgtk-3-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev. openSUSE: sudo zypper install gcc-c++ make pkgconf-pkg-config gtk3-devel webkitgtk3-devel libayatana-appindicator3-devel (WebKitGTK 4.1's dev package is webkitgtk3-devel there — the "3" says GTK3, not an older WebKit). It downloads a prebuilt tjs from the tinyjsapp releases, or builds txiki.js from source (TJS_BUILD=1 ./setup.sh, needs cmake + ninja).

Windows:

irm https://tinyjs.app/install.ps1 | iex

Installs prebuilt binaries to %LOCALAPPDATA%\tinyjs (override with TINYJS_HOME; pin with TINYJS_VERSION), x86_64 or native arm64 to match the machine (Windows on ARM gets the x86_64 build, which runs emulated, from releases before 0.62.0), and adds it to your user PATH — open a new terminal afterwards. Needs only the WebView2 runtime (preinstalled on Windows 11). tinyjs update runs the installer's bundled copy. (Requires a release that ships Windows assets — the first one after Windows support merged; the installer says so plainly against older releases.)

To develop tinyjs itself from source (needs MinGW-w64: winget install BrechtSanders.WinLibs.POSIX.UCRT; on Windows on ARM, winget install MartinStorsjo.LLVM-MinGW.UCRT for a native launcher — setup.ps1 fetches an arm64 tjs.exe from the latest release):

git clone https://github.com/tarwin/tinyjsapp; cd tinyjsapp
powershell -ExecutionPolicy Bypass -File setup.ps1
# adds the checkout to your user PATH (-SkipPath to opt out); after that,
# `tinyjs dev` auto-rebuilds the launcher whenever the native sources change

Linux:

Runs on X11 and Wayland sessions — Ubuntu 24.04+ and current distros with webkit2gtk-4.1. Use the same install command above (it detects Linux) or build from source with ./setup.sh (see the distro deps above). Needs the WebKitGTK 4.1 runtime — libwebkit2gtk-4.1-0 on Debian/Ubuntu, libwebkit2gtk-4_1-0 on openSUSE.

Playing media? WebKitGTK decodes through GStreamer, and a stock desktop install carries only some of it. Without the rest, <audio>/<video> play MP3, Ogg/Vorbis, Opus, WAV and FLAC, but AAC/M4A won't play at all (canPlayType('audio/mp4; codecs="mp4a.40.2"') returns "") and Media Source Extensions report every type unsupported — which covers most podcasts, most internet radio, and most adaptive streaming. Add:

# Debian/Ubuntu
sudo apt install gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly gstreamer1.0-libav
# openSUSE
sudo zypper install gstreamer-plugins-bad gstreamer-plugins-ugly gstreamer-plugins-libav

WebKit hints at this itself, logging "WebKit wasn't able to find a WebVTT encoder … unless gst-plugins-bad is installed" on startup.

Don't play audio through Web Audio on Linux. WebKitGTK renders the Web Audio graph on a normal-priority (SCHED_OTHER) thread while its media threads get real-time priority, so anything reaching ctx.destination misses its deadline and crunches — on an idle machine, at any latencyHint, whether the source is an element or a decoded buffer. A plain <audio> element goes through GStreamer instead and is flawless. There is no graph-side fix; buffering only softens it, and rtkit won't promote the thread.

So on Linux, play the element directly and get analysis from tiny.audioTap:

if (tiny.system.isLinux()) {
  audio.volume = volume;          // straight to the speakers, no graph
  await tiny.audioTap.start({ scope: 'app' });   // PCM for your visualiser
} else {
  const src = ctx.createMediaElementSource(audio);
  src.connect(gain); gain.connect(ctx.destination);
}

scope: 'app' captures only your own output (a private PipeWire null sink fed by your app's ports), so playback is unaffected and you don't hear the rest of the desktop. What you lose is anything that was a graph node — an equalizer, a StereoPanner — so tell the user rather than leaving dead controls on screen.

For sound effects none of this applies: tiny.audio.sampler mixes decoded samples with per-voice volume/pan/pitch natively in the launcher on Linux (PipeWire's real-time data path — clean under any page load) and via Web Audio on macOS/Windows, same API, same equal-power pan numbers. Use it instead of createBufferSource graphs. See examples/amp for the whole pattern, visualisers included.

Analysis-only graphs are fine: a MediaElementSource feeding nothing but an AnalyserNode never reaches destination, so a missed deadline costs a dropped frame rather than audible crackle. Keep such elements at volume = 0, since WebKitGTK also plays a graph-routed element's own output straight to the speakers (macOS/Windows mute it).

See Portability below for what's supported on Windows and Linux.

If something doesn't work, run tinyjs doctor (from your project folder, if you have one). It checks the install, which tinyjs your PATH runs, the system webview, Node tooling and the project's tinyjs.json, and says how to fix what it finds. It only reads files: see docs/docs/doctor.md.

Full docs: tinyjs.app/docs · release history: tinyjs.app/changelog.

Create and run an app

tinyjs new myapp
cd myapp
tinyjs dev

A window opens. dev hot-reloads: edit anything in src/frontend/ and the page re-renders in place, caches bypassed (no restart, backend state survives); edit backend sources (the backend entry's folder) and the process restarts automatically. With a dev server (devUrl) the server's own HMR does the frontend instead; a watch-mode tool that writes into the frontend folder and reloads the page itself sets "frontend": { "reload": false } so the page doesn't reload twice. TINYJS_DEBUG=1 tinyjs dev traces every message crossing the bridge.

Frameworks welcome: tinyjs new myapp --template react-ts (or vue-ts, svelte-ts, solid-ts, preact-ts, lit-ts, alpine-ts, vanilla-ts, …) scaffolds a Vite app wired to tinyjs — tinyjs dev runs Vite's dev server with HMR inside the native window, and tinyjs build ships the built assets as usual. Plain --template asks which framework and language; --pm npm|pnpm|yarn|bun|vp picks the package manager (otherwise you choose from the ones that work on your machine, or get npm when there's no terminal to ask on), and dependencies install straight away unless --no-install. The chosen manager runs the project's dev and build scripts ("dev": "pnpm run dev" in tinyjs.json). --pm vp uses Vite+ 1.0 or newer over another manager (vp:pnpm, vp:bun, …; asked if left out); an older vp is refused, since its projects can't build against current Vite+ packages (vp upgrade). alpine is Vite's vanilla template with Alpine.js and a small component that calls the backend. TypeScript backends are bundled with esbuild automatically (which also makes npm packages usable in the backend). The zero-dependency default scaffold is unchanged.

The tiny global is injected into every page by the launcher — no script tag needed — and ships with full TypeScript definitions (types/tiny.d.ts). New projects also get a tinyjs reference skill for coding agents (.claude/skills/tinyjs/ and .agents/skills/tinyjs/). Both are copied in when the project is made, so after updating tinyjs, run tinyjs update-project in the project to bring them up to date (tinyjs doctor says when they're behind). It overwrites edits to those files, and adds the skill to a project that doesn't have one. For any other AI tool, the docs are at https://tinyjs.app/llms.txt (an index of markdown pages) and https://tinyjs.app/llms-full.txt (all in one file).

A project is just:

`` myapp/ tinyjs.json # { name, title, size, id, version, icon?, signIdentity?, # urlScheme? (string or array), fileExtensions?, chrome?, update?, notarize?, # permissions? ({ microphone, camera, speechRecognition, location: "why" }), # audioTap? ("app" | "system"), audioTapReason? (macOS prompt text), # contextMenu? (false suppresses WebKit's default right-click menu), # debug? (true = F12 opens devtools (⌥⌘I also works on macOS), # "open" = every window auto-opens them; default off —tinyjs dev` always has F12), # browserAccelerators? (true re-enables the engine's own keys — # Ctrl+F find, Ctrl+R reload…; default suppressed, Windows only),

📈 近 7 天 Star 趋势

每日新增 Star(柱)与累计 Star(线)· 数据来自 GitHub

🏆 排名变化趋势

在各榜单中的排名历史(数字越小越靠前)

📋 历史上榜记录

每次快照的详细数据
日期 榜单 排名 周期新增 总 STAR