feat: add Tauri desktop builds, improve gameplay UX, and clean repo
Some checks failed
desktop-builds / build-linux (push) Failing after 0s
desktop-builds / build-windows (push) Failing after 0s

This commit is contained in:
2026-03-18 22:46:45 -04:00
parent c04327c380
commit 366fbd7c49
36 changed files with 6236 additions and 170 deletions

View File

@@ -0,0 +1,125 @@
name: desktop-builds
on:
push:
branches:
- main
- master
pull_request:
workflow_dispatch:
jobs:
build-linux:
name: build-linux
runs-on: linux
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
- name: Install Linux dependencies
run: |
if command -v sudo >/dev/null 2>&1; then
SUDO=sudo
else
SUDO=
fi
$SUDO apt-get update
$SUDO apt-get install -y \
libwebkit2gtk-4.1-dev \
libgtk-3-dev \
libayatana-appindicator3-dev \
librsvg2-dev \
patchelf \
rpm
- name: Install toolchain
run: |
if ! command -v rustup >/dev/null 2>&1; then
curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal
fi
if ! command -v bun >/dev/null 2>&1; then
curl -fsSL https://bun.sh/install | bash
fi
- name: Install JavaScript dependencies
run: |
export PATH="$HOME/.cargo/bin:$HOME/.bun/bin:$PATH"
bun install --frozen-lockfile
- name: Build Linux bundles
run: |
export PATH="$HOME/.cargo/bin:$HOME/.bun/bin:$PATH"
bun run tauri:build:linux
- name: Upload Linux bundles
uses: https://gitea.com/actions/upload-artifact@v4
with:
name: endless-sea-linux
if-no-files-found: error
path: |
src-tauri/target/release/bundle/deb/*.deb
src-tauri/target/release/bundle/rpm/*.rpm
build-windows:
name: build-windows
runs-on: linux
steps:
- name: Checkout
uses: https://gitea.com/actions/checkout@v4
- name: Install Windows cross-build dependencies
run: |
if command -v sudo >/dev/null 2>&1; then
SUDO=sudo
else
SUDO=
fi
$SUDO apt-get update
$SUDO apt-get install -y \
nsis \
llvm \
lld \
wget \
unzip \
zip
- name: Install toolchain
run: |
if ! command -v rustup >/dev/null 2>&1; then
curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal
fi
if ! command -v bun >/dev/null 2>&1; then
curl -fsSL https://bun.sh/install | bash
fi
export PATH="$HOME/.cargo/bin:$HOME/.bun/bin:$PATH"
rustup target add x86_64-pc-windows-msvc
- name: Install cargo-xwin
run: |
export PATH="$HOME/.cargo/bin:$HOME/.bun/bin:$PATH"
cargo install --locked cargo-xwin
- name: Install JavaScript dependencies
run: |
export PATH="$HOME/.cargo/bin:$HOME/.bun/bin:$PATH"
bun install --frozen-lockfile
- name: Build Windows installer from Linux
run: |
export PATH="$HOME/.cargo/bin:$HOME/.bun/bin:$PATH"
bun run tauri:build:windows
- name: Upload Windows bundles
uses: https://gitea.com/actions/upload-artifact@v4
with:
name: endless-sea-windows
if-no-files-found: error
path: |
src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis/*.exe

3
.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
node_modules/
dist/
src-tauri/target/

View File

@@ -5,7 +5,6 @@ Endless Sea is a small browser survival game built with HTML5 canvas, jQuery, an
## Play ## Play
- Live demo: https://zbww.github.io/EndlessSea - Live demo: https://zbww.github.io/EndlessSea
- Project report: https://zbww.github.io/EndlessSea/report.pdf
- Original source reference: https://github.com/zbww/EndlessSea/blob/master/js/main.js - Original source reference: https://github.com/zbww/EndlessSea/blob/master/js/main.js
## How To Play ## How To Play
@@ -36,6 +35,31 @@ This project is static and does not require a build step.
If your browser blocks autoplay audio, start the game with a click so music playback can begin normally. If your browser blocks autoplay audio, start the game with a click so music playback can begin normally.
## Desktop Build
The project now includes a Tauri desktop wrapper.
Requirements:
- Rust and Cargo
- Bun
- Linux desktop build dependencies required by Tauri on your distribution
Useful commands:
```bash
bun install
bun run build:web
bun run tauri:build
```
Build artifacts are generated under `src-tauri/target/release/bundle/`.
CI:
- A Gitea Actions workflow now lives in `.gitea/workflows/desktop-builds.yml`.
- Linux runners build native Linux bundles and cross-compile the Windows release target.
## Project Notes ## Project Notes
- Most visible game elements are generated dynamically in JavaScript. - Most visible game elements are generated dynamically in JavaScript.

37
bun.lock Normal file
View File

@@ -0,0 +1,37 @@
{
"lockfileVersion": 1,
"configVersion": 1,
"workspaces": {
"": {
"name": "endless-sea",
"devDependencies": {
"@tauri-apps/cli": "^2.10.1",
},
},
},
"packages": {
"@tauri-apps/cli": ["@tauri-apps/cli@2.10.1", "", { "optionalDependencies": { "@tauri-apps/cli-darwin-arm64": "2.10.1", "@tauri-apps/cli-darwin-x64": "2.10.1", "@tauri-apps/cli-linux-arm-gnueabihf": "2.10.1", "@tauri-apps/cli-linux-arm64-gnu": "2.10.1", "@tauri-apps/cli-linux-arm64-musl": "2.10.1", "@tauri-apps/cli-linux-riscv64-gnu": "2.10.1", "@tauri-apps/cli-linux-x64-gnu": "2.10.1", "@tauri-apps/cli-linux-x64-musl": "2.10.1", "@tauri-apps/cli-win32-arm64-msvc": "2.10.1", "@tauri-apps/cli-win32-ia32-msvc": "2.10.1", "@tauri-apps/cli-win32-x64-msvc": "2.10.1" }, "bin": { "tauri": "tauri.js" } }, "sha512-jQNGF/5quwORdZSSLtTluyKQ+o6SMa/AUICfhf4egCGFdMHqWssApVgYSbg+jmrZoc8e1DscNvjTnXtlHLS11g=="],
"@tauri-apps/cli-darwin-arm64": ["@tauri-apps/cli-darwin-arm64@2.10.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-Z2OjCXiZ+fbYZy7PmP3WRnOpM9+Fy+oonKDEmUE6MwN4IGaYqgceTjwHucc/kEEYZos5GICve35f7ZiizgqEnQ=="],
"@tauri-apps/cli-darwin-x64": ["@tauri-apps/cli-darwin-x64@2.10.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-V/irQVvjPMGOTQqNj55PnQPVuH4VJP8vZCN7ajnj+ZS8Kom1tEM2hR3qbbIRoS3dBKs5mbG8yg1WC+97dq17Pw=="],
"@tauri-apps/cli-linux-arm-gnueabihf": ["@tauri-apps/cli-linux-arm-gnueabihf@2.10.1", "", { "os": "linux", "cpu": "arm" }, "sha512-Hyzwsb4VnCWKGfTw+wSt15Z2pLw2f0JdFBfq2vHBOBhvg7oi6uhKiF87hmbXOBXUZaGkyRDkCHsdzJcIfoJC2w=="],
"@tauri-apps/cli-linux-arm64-gnu": ["@tauri-apps/cli-linux-arm64-gnu@2.10.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-OyOYs2t5GkBIvyWjA1+h4CZxTcdz1OZPCWAPz5DYEfB0cnWHERTnQ/SLayQzncrT0kwRoSfSz9KxenkyJoTelA=="],
"@tauri-apps/cli-linux-arm64-musl": ["@tauri-apps/cli-linux-arm64-musl@2.10.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-MIj78PDDGjkg3NqGptDOGgfXks7SYJwhiMh8SBoZS+vfdz7yP5jN18bNaLnDhsVIPARcAhE1TlsZe/8Yxo2zqg=="],
"@tauri-apps/cli-linux-riscv64-gnu": ["@tauri-apps/cli-linux-riscv64-gnu@2.10.1", "", { "os": "linux", "cpu": "none" }, "sha512-X0lvOVUg8PCVaoEtEAnpxmnkwlE1gcMDTqfhbefICKDnOTJ5Est3qL0SrWxizDackIOKBcvtpejrSiVpuJI1kw=="],
"@tauri-apps/cli-linux-x64-gnu": ["@tauri-apps/cli-linux-x64-gnu@2.10.1", "", { "os": "linux", "cpu": "x64" }, "sha512-2/12bEzsJS9fAKybxgicCDFxYD1WEI9kO+tlDwX5znWG2GwMBaiWcmhGlZ8fi+DMe9CXlcVarMTYc0L3REIRxw=="],
"@tauri-apps/cli-linux-x64-musl": ["@tauri-apps/cli-linux-x64-musl@2.10.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Y8J0ZzswPz50UcGOFuXGEMrxbjwKSPgXftx5qnkuMs2rmwQB5ssvLb6tn54wDSYxe7S6vlLob9vt0VKuNOaCIQ=="],
"@tauri-apps/cli-win32-arm64-msvc": ["@tauri-apps/cli-win32-arm64-msvc@2.10.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-iSt5B86jHYAPJa/IlYw++SXtFPGnWtFJriHn7X0NFBVunF6zu9+/zOn8OgqIWSl8RgzhLGXQEEtGBdR4wzpVgg=="],
"@tauri-apps/cli-win32-ia32-msvc": ["@tauri-apps/cli-win32-ia32-msvc@2.10.1", "", { "os": "win32", "cpu": "ia32" }, "sha512-gXyxgEzsFegmnWywYU5pEBURkcFN/Oo45EAwvZrHMh+zUSEAvO5E8TXsgPADYm31d1u7OQU3O3HsYfVBf2moHw=="],
"@tauri-apps/cli-win32-x64-msvc": ["@tauri-apps/cli-win32-x64-msvc@2.10.1", "", { "os": "win32", "cpu": "x64" }, "sha512-6Cn7YpPFwzChy0ERz6djKEmUehWrYlM+xTaNzGPgZocw3BD7OfwfWHKVWxXzdjEW2KfKkHddfdxK1XXTYqBRLg=="],
}
}

View File

@@ -1,54 +1,59 @@
html, body
{
margin:0;
padding:0;
overflow:hidden;
background:#0d1f38;
}
#die,#startgame,#pause #die,#startgame,#pause
{ {
cursor:default; cursor:default;
position:absolute; position:absolute;
width:400px; width:420px;
height:200px; min-height:260px;
background:#3369cd; padding:14px 0 20px;
opacity:0.7; background:rgba(24,71,153,0.82);
text-align:center; text-align:center;
font-family:'华文细黑', 'STHeiti Light','STXihei','黑体'; font-family:'Segoe UI', 'Trebuchet MS', Arial, sans-serif;
font-size:36px; font-size:34px;
color:#eef; color:#eef;
box-shadow: 7px 7px 10px rgba(255,255,255,0.3); box-shadow:0 16px 40px rgba(6,20,47,0.35);
border:1px solid #fff; border:1px solid rgba(255,255,255,0.65);
border-radius:18px;
backdrop-filter:blur(8px);
} }
#instructions,#about,#score,#ranking,#settingsbutton,#fullscreenbutton,#scorereset
#instructions,#about,#score,#ranking
{ {
font-size:36px; font-size:30px;
margin-top:12px; margin-top:12px;
} }
.title .title
{ {
border-bottom:2px solid #430fc8; border-bottom:2px solid #430fc8;
position:absolute;
position: absolute; height:auto;
height: auto; font-family:'Segoe UI', 'Trebuchet MS', Arial, sans-serif;
font-family:'华文细黑', 'STHeiti Light','STXihei','黑体';
font-size:50px; font-size:50px;
font-weight: bold; font-weight:bold;
color:#430fc8; color:#430fc8;
} }
.moreinfo/*两侧的窗口*/ .moreinfo
{ {
position:absolute; position:absolute;
font-family:'华文细黑', 'STHeiti Light','STXihei','黑体'; font-family:'Segoe UI', 'Trebuchet MS', Arial, sans-serif;
font-size:18px; font-size:18px;
height:200px; min-height:220px;
background:#1954c0; background:rgba(25,84,192,0.78);
opacity:0.7; padding:12px 16px;
padding-left:10px;
text-align:left; text-align:left;
color:#eef; color:#eef;
box-shadow: 7px 7px 10px rgba(255,255,255,0.3); box-shadow:0 16px 40px rgba(6,20,47,0.25);
border:1px solid #fff; border:1px solid rgba(255,255,255,0.65);
border-radius:16px;
display:none; display:none;
} }
@@ -56,7 +61,7 @@
{ {
position:absolute; position:absolute;
text-align:center; text-align:center;
font-family:'华文细黑', 'STHeiti Light','STXihei','黑体'; font-family:'Segoe UI', 'Trebuchet MS', Arial, sans-serif;
font-size:18px; font-size:18px;
width:200px; width:200px;
height:100px; height:100px;
@@ -65,15 +70,118 @@
.button .button
{ {
margin-top:11px; cursor:pointer;
background:#227; width:80%;
margin:11px auto 0;
padding:8px 12px;
background:rgba(34,34,119,0.76);
border:1px solid rgba(255,255,255,0.25);
border-radius:12px;
transition:background 0.2s ease, transform 0.2s ease;
} }
.button:hover
{
background:rgba(53,53,160,0.88);
transform:translateY(-1px);
}
.right2 .right2
{ {
margin-top:5px;
margin-top: 5px; font-size:22px;
font-size: 22px; margin-left:20px;
margin-left: 20px; }
#settingspanel
{
position:absolute;
width:300px;
padding:16px;
background:rgba(12,34,70,0.88);
color:#eef;
border:1px solid rgba(255,255,255,0.65);
border-radius:16px;
box-shadow:0 18px 48px rgba(5,13,33,0.35);
font-family:'Segoe UI', 'Trebuchet MS', Arial, sans-serif;
display:none;
}
} .settings-title
{
font-size:28px;
margin-bottom:10px;
text-align:center;
}
.settings-row
{
margin-top:12px;
}
.settings-label
{
display:flex;
justify-content:space-between;
align-items:center;
font-size:16px;
margin-bottom:6px;
}
.settings-label span:last-child
{
color:#b9d8ff;
font-size:14px;
}
.settings-range
{
width:100%;
}
.settings-toggle
{
display:flex;
justify-content:space-between;
align-items:center;
font-size:16px;
}
.settings-actions
{
display:flex;
flex-direction:column;
gap:8px;
margin-top:14px;
}
.settings-button
{
cursor:pointer;
border:1px solid rgba(255,255,255,0.25);
border-radius:10px;
padding:8px 10px;
background:rgba(53,93,165,0.62);
text-align:center;
font-size:15px;
}
.settings-button:hover
{
background:rgba(75,118,196,0.75);
}
.settings-note
{
margin-top:12px;
font-size:13px;
line-height:1.35;
color:#c5dbff;
}
#pausemessage
{
margin-top:10px;
font-size:16px;
color:#d8e8ff;
}

File diff suppressed because it is too large Load Diff

16
package.json Normal file
View File

@@ -0,0 +1,16 @@
{
"name": "endless-sea",
"private": true,
"version": "0.1.0",
"description": "Endless Sea desktop wrapper built with Tauri",
"scripts": {
"build:web": "bun run ./scripts/build-web.mjs",
"tauri:dev": "bunx tauri dev",
"tauri:build": "bunx tauri build",
"tauri:build:linux": "bunx tauri build",
"tauri:build:windows": "bunx tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc"
},
"devDependencies": {
"@tauri-apps/cli": "^2.10.1"
}
}

Binary file not shown.

Binary file not shown.

25
scripts/build-web.mjs Normal file
View File

@@ -0,0 +1,25 @@
import { cp, mkdir, rm } from "node:fs/promises";
import { dirname, resolve } from "node:path";
import { fileURLToPath } from "node:url";
const scriptDir = dirname(fileURLToPath(import.meta.url));
const rootDir = resolve(scriptDir, "..");
const distDir = resolve(rootDir, "dist");
const copyTargets = [
"index.html",
"css",
"js",
"music"
];
await rm(distDir, { recursive: true, force: true });
await mkdir(distDir, { recursive: true });
for (const target of copyTargets) {
await cp(resolve(rootDir, target), resolve(distDir, target), {
recursive: true
});
}
console.log(`Built static frontend into ${distDir}`);

4
src-tauri/.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
# Generated by Cargo
# will have compiled files and executables
/target/
/gen/schemas

5259
src-tauri/Cargo.lock generated Normal file

File diff suppressed because it is too large Load Diff

25
src-tauri/Cargo.toml Normal file
View File

@@ -0,0 +1,25 @@
[package]
name = "endless-sea"
version = "0.1.0"
description = "Endless Sea desktop wrapper"
authors = ["Endless Sea contributors"]
license = "MIT"
repository = "https://github.com/zbww/EndlessSea"
edition = "2021"
rust-version = "1.77.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib]
name = "endless_sea_lib"
crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies]
tauri-build = { version = "2.5.6", features = [] }
[dependencies]
serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] }
log = "0.4"
tauri = { version = "2.10.3", features = [] }
tauri-plugin-log = "2"

3
src-tauri/build.rs Normal file
View File

@@ -0,0 +1,3 @@
fn main() {
tauri_build::build()
}

View File

@@ -0,0 +1,11 @@
{
"$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default",
"description": "enables the default permissions",
"windows": [
"main"
],
"permissions": [
"core:default"
]
}

BIN
src-tauri/icons/128x128.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src-tauri/icons/32x32.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
src-tauri/icons/icon.icns Normal file

Binary file not shown.

BIN
src-tauri/icons/icon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

BIN
src-tauri/icons/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

16
src-tauri/src/lib.rs Normal file
View File

@@ -0,0 +1,16 @@
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.setup(|app| {
if cfg!(debug_assertions) {
app.handle().plugin(
tauri_plugin_log::Builder::default()
.level(log::LevelFilter::Info)
.build(),
)?;
}
Ok(())
})
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

6
src-tauri/src/main.rs Normal file
View File

@@ -0,0 +1,6 @@
// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
fn main() {
endless_sea_lib::run();
}

38
src-tauri/tauri.conf.json Normal file
View File

@@ -0,0 +1,38 @@
{
"$schema": "https://schema.tauri.app/config/2",
"productName": "Endless Sea",
"version": "0.1.0",
"identifier": "com.endlesssea.desktop",
"build": {
"frontendDist": "../dist",
"beforeDevCommand": "bun run build:web",
"beforeBuildCommand": "bun run build:web"
},
"app": {
"windows": [
{
"title": "Endless Sea",
"width": 1280,
"height": 720,
"minWidth": 800,
"minHeight": 600,
"center": true,
"resizable": true,
"fullscreen": false
}
],
"security": {
"csp": null
}
},
"bundle": {
"active": true,
"icon": [
"icons/32x32.png",
"icons/128x128.png",
"icons/128x128@2x.png",
"icons/icon.icns",
"icons/icon.ico"
]
}
}

View File

@@ -0,0 +1,9 @@
{
"$schema": "https://schema.tauri.app/config/2",
"bundle": {
"targets": [
"deb",
"rpm"
]
}
}

View File

@@ -0,0 +1,16 @@
{
"$schema": "https://schema.tauri.app/config/2",
"bundle": {
"targets": [
"nsis"
],
"windows": {
"webviewInstallMode": {
"type": "downloadBootstrapper"
},
"nsis": {
"displayLanguageSelector": true
}
}
}
}