Crock UI
A polished Electron + React desktop companion for croc that makes peer-to-peer file and text transfers friendly, observable, and configurable without touching the CLI.
Table of contents
- Crock UI
Overview
Crock UI wraps the battle-tested croc CLI in a modern desktop experience. It bundles croc binaries for the current platform, keeps them up to date, and exposes common workflows through a visual interface. Beneath the surface it uses a hardened Electron main process, a React + Vite renderer, Zustand for state, Tailwind/shadcn components for styling, and a dedicated IPC layer that mirrors the behaviours of the CLI.
Key features
- Instant send & receive — Queue files or plain text, choose a relay, and kick off croc transfers with a single click.
- Code phrase ergonomics — Generate, copy, paste, or scan QR codes for session codes; the UI keeps clipboard and form state in sync.
- Transfer observability — Track real-time progress, inspect structured logs, and revisit prior sessions via the built-in history viewer.
- Configurable defaults — Adjust send/receive flags, destinations, and automation toggles across General, Advanced, Misc, and About tabs.
- Relay & proxy health checks — Test the configured relay, proxy, and croc binary; receive live relay status events streamed from the main process.
- Binary lifecycle management — Download, install, or pin croc releases directly from GitHub without leaving the app.
- Theming & localisation — Light, dark, and system themes plus English, Vietnamese, and Japanese translations out of the box.
- Browser-friendly mock API — In non-Electron contexts a safe mock
window.apikeeps the renderer functional for design previews.
Screenshots
| Send | Receive | History | Settings |
|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Additional previews reside in ./screenshots.
Architecture
The application is split across three collaborating layers:
Renderer (React + Vite)
- Bootstrapped by
src/main.tsx, renderingApp.tsxinto the DOM. - Uses Zustand stores (
src/stores) to model UI, settings, history, and transfer state. - Interfaces with Electron via a typed
window.apibridge (src/lib/window-api.ts). - Tailwind CSS and shadcn-inspired primitives (
src/components/ui) drive design consistency. - Internationalisation is powered by
react-i18nextwith JSON resource bundles insrc/locales.
Preload bridge
electron/preload.tsexposes a whitelisted, type-safe API to the renderer.- Bridges file dialogs, clipboard, window controls, croc lifecycle commands, history access, and settings mutations.
- Provides an event bus (
events.on) for streaming relay status and progress updates to the UI.
Main process
electron/main.tsconfigures the BrowserWindow, single-instance lock, external link handling, and lifecycle integration.- Services in
electron/servicesmanage croc binaries, build commands, spawn processes, monitor relays, and persist history/settings viaelectron-store. - IPC handlers in
electron/ipc/moduleswrap those services into cohesive request/response channels. vite-plugin-electronbuilds and hot-reloads the main/preload code alongside the renderer during development.
Project structure
crock/
├─ electron/ # Main-process code, preload bridge, IPC modules, services
├─ public/ # Static assets bundled at runtime (logo, icons)
├─ src/ # React renderer (components, stores, hooks, contexts)
│ ├─ components/ # UI elements grouped by feature (transfer, settings, history)
│ ├─ lib/ # Utilities (i18n, window API, helpers)
│ ├─ locales/ # i18next resource bundles (en, ja, vi)
│ ├─ providers/ # Theme provider & shared contexts
│ └─ stores/ # Zustand stores synchronised via IPC
├─ dist/ # Renderer production build output (generated)
├─ dist-electron/ # Compiled main & preload bundles (generated)
├─ electron-builder.json5 # Packaging configuration for installers
├─ package.json # Scripts, dependencies, electron-builder metadata
└─ pnpm-lock.yaml # Deterministic dependency lockfile
Getting started
Prerequisites
- Node.js ≥ 18.17 (Electron 30 runtime)
- pnpm ≥ 9 (matching the checked-in
pnpm-lock.yaml) - macOS, Windows, or Linux desktop environment
Install dependencies
Run the app
The Vite dev server and Electron process will launch together. Changes to renderer, main, or preload code hot-reload automatically.
Available scripts
| Script | Purpose |
|---|---|
pnpm dev |
Launch Vite + Electron in development mode with hot reload. |
pnpm build |
Type-check, build renderer bundles, and package Electron via electron-builder. |
pnpm lint |
Run ESLint across .ts and .tsx sources. |
pnpm preview |
Serve the built renderer for inspection without Electron. |
pnpm format |
Format project sources with Prettier using the configured glob. |
Building & packaging
The build pipeline performs the following:
tscvalidates TypeScript types for both renderer and Electron code.- Vite emits production bundles under
dist/. electron-builderpackages the application usingelectron-builder.json5, producing platform-specific installers in thedist/directory.
Adjust icons, app identifiers, update channels, and signing options inside electron-builder.json5 to fit your distribution strategy.
Configuration & data storage
- Settings and history are persisted with
electron-storein the user-specificapp.getPath('userData')directory (varies by OS). - Croc binaries are cached under
<userData>/binwith an accompanying manifest to track versions. - Transfer logs and relay health are streamed from the main process; background monitors stop automatically when the window closes.
- Relay status updates originate from
RelayStatusMonitorand arrive via therelay:statusevent channel.
Internationalisation
- Default language is Vietnamese (
vi), with English (en) and Japanese (ja) translations bundled. - Translation resources live in
src/locales/<lang>/translation.jsonand are loaded bysrc/lib/i18n.ts. - To add a new language, duplicate an existing locale file, add the language code to
supportedLanguages, and update UI copy as needed.
Deeplink
croc://receive?code=<code-phrase>[&relay=<relay-host>][&password=<relay-password>]
Parameters:
code(required): The croc code phrase to receive filesrelay(optional): Custom relay server (host:port format)password(optional): Relay server password
Examples:
-
Basic receive:
croc://receive?code=7243-aurora-ceiling-collect
-
With custom relay:
croc://receive?code=7243-aurora-ceiling-collect&relay=custom.relay.com:9009
-
With relay and password:
croc://receive?code=7243-aurora-ceiling-collect&relay=custom.relay.com:9009&password=secret
Roadmap
- Keyboard shortcuts – Wire global accelerator handling for opening history (
Ctrl+H) and settings (Ctrl+,) from both renderer and main process. - Settings redesign – Simplify copy and grouping across the Settings dialog tabs, removing redundant controls and tightening spacing.
- Type cleanup – Prune duplicate or unused TypeScript definitions in
src/typesandelectron/typesto reduce maintenance overhead.
Known issues & limitations
- Proxy diagnostics are shallow –
ConnectionDiagnostics(electron/services/ConnectionDiagnostics.ts) only reports whether proxy URLs are configured; it does not attempt any connectivity checks, so proxy misconfiguration goes unnoticed. - No SOCKS5 proxy UI – The backend understands SOCKS5 (
electron/services/CrocCommandBuilder.ts,electron/services/SettingsStore.ts), but the settings dialog only exposes HTTP/HTTPS fields. Users cannot currently edit SOCKS5 relay defaults from the UI. - Renderer requires Electron bridge –
getWindowApi()(src/lib/window-api.ts) throws whenwindow.apiis absent. Serving the renderer with plain Vite (without the preload script) will break as soon as settings or transfer actions touch the bridge. A lightweight browser mock is not yet implemented. - Drag-n-Drop: Due to Electron's security limits, drag-n-drop action from renderer side couldn't get the absolute path on the disk. I will try to find a workaround but not promised.
Troubleshooting
- TypeScript warnings about unsupported versions come from
@typescript-eslintif you use a newer compiler; either align the TypeScript version or pin a supported range. - When running outside Electron (e.g.,
pnpm preview), certain bridge features are mocked. Use the full Electron runtime for transfer tests. - If relay checks fail, confirm network access to your chosen relay, or update the relay settings under Settings → Advanced.
Contributing
Contributions are welcome! Please open an issue or pull request on GitHub describing the enhancement or fix. When submitting changes:
- Install dependencies with
pnpm install. - Ensure linting passes (
pnpm lint). - Describe testing steps and screenshots when UI changes are involved.
Acknowledgements
- croc — peer-to-peer transfer utility that powers the underlying protocol.
- Electron, Vite, and React for the developer experience.
- UI primitives influenced by shadcn/ui.
License
This project is distributed under the MIT License. See the license file for full terms and attribution requirements.



