Developer Setup

Project structure, config file paths, and development environment setup for MC-Vector.

Overview

MC-Vector is a Tauri v2 desktop application built with:

LayerTechnology
FrontendReact 19 + Vite + TypeScript
StylingTailwind CSS
BackendRust (Tauri commands)
IPCTauri invoke() — no REST or WebSocket API

All communication between the React frontend and Rust backend goes through Tauri's built-in IPC mechanism, not HTTP.

Prerequisites

Make sure the following are installed before you begin:

ToolVersionPurpose
Node.jsv18+JavaScript runtime
pnpmlatestPackage manager
Rustv1.77.2+Backend compilation
Cargo(bundled with Rust)Rust build tool

Install all prerequisites (Node.js, pnpm, and Rust):

# Install Node.js & pnpm (macOS with Homebrew)
brew install node pnpm

# Or on Linux/macOS without Homebrew, install Node.js from https://nodejs.org/
# Then install pnpm globally:
npm install -g pnpm

# Install Rust via rustup
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Activate Rust environment
source $HOME/.cargo/env

Windows users: Install Node.js from the official installer, then run npm install -g pnpm and rustup-init from https://rustup.rs/

Getting Started

# 1. Clone the repository
git clone https://github.com/tukuyomil032/MC-Vector.git
cd MC-Vector

# 2. Install JS dependencies
pnpm install

# 3. Launch development server (hot-reload for both frontend and backend)
pnpm tauri dev

# 4. Build production binary (when ready to ship)
pnpm tauri build

First run: The Rust crate compilation will take a few minutes. Subsequent runs use the incremental build cache and start faster.

Platform-specific bundles are output to:

src-tauri/target/release/bundle/
 ├── dmg/          ← macOS DMG
 ├── macos/        ← macOS .app
 └── nsis/         ← Windows NSIS installer (.exe)

Project Structure

MC-Vector/
├── src/                              # Frontend (React + Vite)
│   ├── App.tsx                       # Root component & view router
│   ├── main.tsx                      # Vite / React entry point
│   ├── index.css                     # Global styles (Tailwind)
│   ├── vite-env.d.ts                 # Vite type declarations + SVG module
│   ├── assets/
│   │   └── icons/                    # SVG icon files (folder, file, trash
)
│   ├── lib/                          # Tauri IPC command wrappers
│   │   ├── server-commands.ts        # Server start/stop/restart
│   │   ├── backup-commands.ts        # Backup operations
│   │   ├── file-commands.ts          # File system operations
│   │   ├── plugin-commands.ts        # Plugin/mod management
│   │   ├── java-commands.ts          # Java detection & management
│   │   ├── ngrok-commands.ts         # ngrok tunnel control
│   │   ├── proxy-commands.ts         # Proxy server setup
│   │   ├── config-commands.ts        # Config read/write
│   │   └── update-commands.ts        # App auto-update
│   └── renderer/
│       ├── components/               # Feature UI components
│       │   ├── DashboardView.tsx     # CPU/RAM graphs (Recharts)
│       │   ├── ConsoleView.tsx       # Live console + ANSI output
│       │   ├── FilesView.tsx         # File manager (Monaco editor)
│       │   ├── BackupsView.tsx       # Backup creation & restore
│       │   ├── PluginBrowser.tsx     # Modrinth / Hangar browser
│       │   ├── UsersView.tsx         # Whitelist / ban / op management
│       │   ├── ProxySetupView.tsx    # Velocity / Waterfall setup
│       │   ├── ProxyHelpView.tsx     # Proxy configuration guide
│       │   ├── AddServerModal.tsx    # New server wizard modal
│       │   ├── NgrokGuideView.tsx    # ngrok guide view
│       │   ├── SettingsWindow.tsx    # App settings (theme, etc.)
│       │   ├── JavaManagerModal.tsx  # JRE download & management
│       │   ├── Toast.tsx             # Toast notification component
│       │   ├── ToastProvider.tsx     # Toast context provider
│       │   └── properties/
│       │       ├── PropertiesView.tsx           # Quick server.properties editor
│       │       ├── AdvancedSettingsWindow.tsx   # Full 60+ property editor
│       │       └── ServerSettings.tsx           # Server meta settings
│       ├── shared/
│       │   ├── propertiesData.ts     # 60+ server.properties definitions
│       │   └── server declaration.ts # MinecraftServer & AppView types
│       └── constants/
│           └── versionOptions.ts     # Supported Minecraft version list
│
└── src-tauri/                        # Rust backend (Tauri)
    ├── tauri.conf.json               # Tauri app configuration
    ├── Cargo.toml                    # Rust dependencies
    └── src/
        ├── main.rs                   # Entry point
        └── commands/                 # Tauri command handlers
            ├── server.rs             # Server process management
            ├── backup.rs             # Backup / restore
            ├── file_utils.rs         # File operations
            ├── java.rs               # Java runtime detection
            ├── ngrok.rs              # ngrok integration
            ├── download.rs           # Server .jar download
            └── process_stats.rs      # CPU/RAM monitoring

Config & Data File Paths

When MC-Vector creates servers and stores application data, it uses the following OS-specific paths:

PlatformBase Path
macOS~/Library/Application Support/MC-Vector/
WindowsC:\Users\<username>\AppData\Roaming\MC-Vector\

Server data layout

MC-Vector/
└── servers/
    └── <server-name>/
        ├── server.jar          ← Downloaded server software
        ├── server.properties
        ├── eula.txt
        ├── world/              ← World data
        ├── plugins/ or mods/   ← Installed plugins/mods
        └── backups/            ← ZIP backups created via the app
            └── backup-2026-02-26T12-00-00.zip

App config

MC-Vector/
└── config.json    ← Stores server list, ngrok token, theme preference, etc.

Architecture Notes

  • Tauri IPC — The frontend calls invoke("command_name", { args }) to interact with Rust. See src/lib/*.ts for all available commands.
  • No REST API — There is no HTTP server exposed. All communication is local Tauri IPC.
  • No auto-backup — Backups are created manually by the user from the Backups tab.
  • Dashboard — Uses Recharts to display CPU/RAM graphs updated every 2 seconds via Tauri events.
  • Console — ANSI 16-color, auto-scrolls when within 120px of bottom, 2000-line buffer.

Writing a New Tauri Command

1. Define the command in Rust

Add a new file under src-tauri/src/commands/ or append to an existing one:

// src-tauri/src/commands/example.rs
use tauri::State;
use crate::state::AppState;

#[tauri::command]
pub async fn get_server_count(
    state: State<'_, AppState>,
) -> Result<usize, String> {
    let servers = state.servers.lock().await;
    Ok(servers.len())
}

2. Register in main.rs

// src-tauri/src/main.rs
.invoke_handler(tauri::generate_handler![
    // ... existing commands ...
    commands::example::get_server_count,
])

3. Declare the permission (Tauri v2)

Tauri v2 requires explicit capability declarations. Edit src-tauri/capabilities/default.json:

{
  "identifier": "default",
  "description": "Default capabilities",
  "permissions": [
    "core:default",
    "shell:allow-open"
  ]
}

4. Call from the React frontend

Wrap the invoke call in a typed helper in src/lib/:

// src/lib/server-commands.ts
import { invoke } from "@tauri-apps/api/core";

export async function getServerCount(): Promise<number> {
  return invoke<number>("get_server_count");
}

Then use it in any component:

// src/renderer/components/Dashboard.tsx
import { getServerCount } from "@/lib/server-commands";

const count = await getServerCount();
console.log(`Managing ${count} servers`);

Console — Implementation Details

Server stdout/stderr is captured by a tokio task in Rust and emitted as Tauri events:

// src-tauri/src/commands/server.rs
tokio::spawn(async move {
    let reader = BufReader::new(stdout);
    for line in reader.lines() {
        let Ok(line) = line else { break };
        app_handle
            .emit("server-log", LogPayload {
                server_id: id.clone(),
                line: line.trim_end().to_string(),
            })
            .ok();
    }
});

The React console component subscribes and enforces the 2,000-line buffer:

// src/renderer/components/ConsoleView.tsx
import { listen } from "@tauri-apps/api/event";

const unlisten = await listen<LogPayload>("server-log", ({ payload }) => {
  if (payload.server_id !== currentServerId) {
    return;
  }

  setLines((prev) => {
    const next = [...prev, payload.line];
    return next.length > 2000 ? next.slice(-2000) : next;   // buffer cap
  });
});

// cleanup on unmount
return () => unlisten();

Auto-scroll logic (120 px threshold):

const handleScroll = () => {
  if (!containerRef.current) {
    return;
  }
  const { scrollTop, scrollHeight, clientHeight } = containerRef.current;
  isAtBottomRef.current = scrollHeight - scrollTop - clientHeight < 120;
};

useEffect(() => {
  if (isAtBottomRef.current) {
    containerRef.current?.scrollTo({ top: containerRef.current.scrollHeight });
  }
}, [lines]);

Useful Commands

CommandDescription
pnpm tauri devStart dev server with hot-reload
pnpm tauri buildBuild production binary
pnpm lintRun ESLint
pnpm formatPrettier format
cargo testRun Rust unit tests (in src-tauri/)
cargo clippyRust linter
cargo doc --openGenerate and open Rust API docs

Contributing

  1. Fork the repo and create a feature branch:
git checkout -b feat/my-awesome-feature
  1. Implement your change, then verify:
# Frontend checks
pnpm lint && pnpm format --check

# Rust checks
cd src-tauri && cargo clippy -- -D warnings && cargo test
  1. Open a pull request against main with a description of what you changed and why.