init project release
This commit is contained in:
5
World-SEPPJM-Client/frontend/.vscode/extensions.json
vendored
Normal file
5
World-SEPPJM-Client/frontend/.vscode/extensions.json
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"svelte.svelte-vscode"
|
||||
]
|
||||
}
|
63
World-SEPPJM-Client/frontend/README.md
Normal file
63
World-SEPPJM-Client/frontend/README.md
Normal file
@@ -0,0 +1,63 @@
|
||||
# Svelte + Vite
|
||||
|
||||
This template should help get you started developing with Svelte in Vite.
|
||||
|
||||
## Recommended IDE Setup
|
||||
|
||||
[VS Code](https://code.visualstudio.com/)
|
||||
|
||||
+ [Svelte](https://marketplace.visualstudio.com/items?itemName=svelte.svelte-vscode).
|
||||
|
||||
## Need an official Svelte framework?
|
||||
|
||||
Check out [SvelteKit](https://github.com/sveltejs/kit#readme), which is also powered by Vite. Deploy anywhere with its
|
||||
serverless-first approach and adapt to various platforms, with out of the box support for TypeScript, SCSS, and Less,
|
||||
and easily-added support for mdsvex, GraphQL, PostCSS, Tailwind CSS, and more.
|
||||
|
||||
## Technical considerations
|
||||
|
||||
**Why use this over SvelteKit?**
|
||||
|
||||
- It brings its own routing solution which might not be preferable for some users.
|
||||
- It is first and foremost a framework that just happens to use Vite under the hood, not a Vite app.
|
||||
`vite dev` and `vite build` wouldn't work in a SvelteKit environment, for example.
|
||||
|
||||
This template contains as little as possible to get started with Vite + Svelte, while taking into account the developer
|
||||
experience with regards to HMR and intellisense. It demonstrates capabilities on par with the other `create-vite`
|
||||
templates and is a good starting point for beginners dipping their toes into a Vite + Svelte project.
|
||||
|
||||
Should you later need the extended capabilities and extensibility provided by SvelteKit, the template has been
|
||||
structured similarly to SvelteKit so that it is easy to migrate.
|
||||
|
||||
**Why `global.d.ts` instead of `compilerOptions.types` inside `jsconfig.json` or `tsconfig.json`?**
|
||||
|
||||
Setting `compilerOptions.types` shuts out all other types not explicitly listed in the configuration. Using triple-slash
|
||||
references keeps the default TypeScript setting of accepting type information from the entire workspace, while also
|
||||
adding `svelte` and `vite/client` type information.
|
||||
|
||||
**Why include `.vscode/extensions.json`?**
|
||||
|
||||
Other templates indirectly recommend extensions via the README, but this file allows VS Code to prompt the user to
|
||||
install the recommended extension upon opening the project.
|
||||
|
||||
**Why enable `checkJs` in the JS template?**
|
||||
|
||||
It is likely that most cases of changing variable types in runtime are likely to be accidental, rather than deliberate.
|
||||
This provides advanced typechecking out of the box. Should you like to take advantage of the dynamically-typed nature of
|
||||
JavaScript, it is trivial to change the configuration.
|
||||
|
||||
**Why is HMR not preserving my local component state?**
|
||||
|
||||
HMR state preservation comes with a number of gotchas! It has been disabled by default in both `svelte-hmr`
|
||||
and `@sveltejs/vite-plugin-svelte` due to its often surprising behavior. You can read the
|
||||
details [here](https://github.com/rixo/svelte-hmr#svelte-hmr).
|
||||
|
||||
If you have state that's important to retain within a component, consider creating an external store which would not be
|
||||
replaced by HMR.
|
||||
|
||||
```js
|
||||
// store.js
|
||||
// An extremely simple external store
|
||||
import { writable } from 'svelte/store'
|
||||
export default writable(0)
|
||||
```
|
12
World-SEPPJM-Client/frontend/index.html
Normal file
12
World-SEPPJM-Client/frontend/index.html
Normal file
@@ -0,0 +1,12 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8"/>
|
||||
<meta content="width=device-width, initial-scale=1.0" name="viewport"/>
|
||||
<title>World-SEPPJM-Client</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="app"></div>
|
||||
<script src="./src/main.js" type="module"></script>
|
||||
</body>
|
||||
</html>
|
38
World-SEPPJM-Client/frontend/jsconfig.json
Normal file
38
World-SEPPJM-Client/frontend/jsconfig.json
Normal file
@@ -0,0 +1,38 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"moduleResolution": "Node",
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
/**
|
||||
* svelte-preprocess cannot figure out whether you have
|
||||
* a value or a type, so tell TypeScript to enforce using
|
||||
* `import type` instead of `import` for Types.
|
||||
*/
|
||||
"importsNotUsedAsValues": "error",
|
||||
"isolatedModules": true,
|
||||
"resolveJsonModule": true,
|
||||
/**
|
||||
* To have warnings / errors of the Svelte compiler at the
|
||||
* correct position, enable source maps by default.
|
||||
*/
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"baseUrl": ".",
|
||||
/**
|
||||
* Typecheck JS in `.svelte` and `.js` files by default.
|
||||
* Disable this if you'd like to use dynamic types.
|
||||
*/
|
||||
"checkJs": true
|
||||
},
|
||||
/**
|
||||
* Use global.d.ts instead of compilerOptions.types
|
||||
* to avoid limiting type declarations.
|
||||
*/
|
||||
"include": [
|
||||
"src/**/*.d.ts",
|
||||
"src/**/*.js",
|
||||
"src/**/*.svelte"
|
||||
]
|
||||
}
|
781
World-SEPPJM-Client/frontend/package-lock.json
generated
Normal file
781
World-SEPPJM-Client/frontend/package-lock.json
generated
Normal file
@@ -0,0 +1,781 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"version": "0.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "frontend",
|
||||
"version": "0.0.0",
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"svelte": "^3.49.0",
|
||||
"vite": "^3.0.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.15.18.tgz",
|
||||
"integrity": "sha512-5GT+kcs2WVGjVs7+boataCkO5Fg0y4kCjzkB5bAip7H4jfnOS3dA6KPiww9W1OEKTKeAcUVhdZGvgI65OXmUnw==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.15.18.tgz",
|
||||
"integrity": "sha512-L4jVKS82XVhw2nvzLg/19ClLWg0y27ulRwuP7lcyL6AbUWB5aPglXY3M21mauDQMDfRLs8cQmeT03r/+X3cZYQ==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/@sveltejs/vite-plugin-svelte": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-1.4.0.tgz",
|
||||
"integrity": "sha512-6QupI/jemMfK+yI2pMtJcu5iO2gtgTfcBdGwMZZt+lgbFELhszbDl6Qjh000HgAV8+XUA+8EY8DusOFk8WhOIg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "^4.3.4",
|
||||
"deepmerge": "^4.2.2",
|
||||
"kleur": "^4.1.5",
|
||||
"magic-string": "^0.26.7",
|
||||
"svelte-hmr": "^0.15.1",
|
||||
"vitefu": "^0.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >= 16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.44.0",
|
||||
"vite": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/deepmerge": {
|
||||
"version": "4.3.1",
|
||||
"resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
|
||||
"integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.15.18.tgz",
|
||||
"integrity": "sha512-x/R72SmW3sSFRm5zrrIjAhCeQSAWoni3CmHEqfQrZIQTM3lVCdehdwuIqaOtfC2slvpdlLa62GYoN8SxT23m6Q==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/android-arm": "0.15.18",
|
||||
"@esbuild/linux-loong64": "0.15.18",
|
||||
"esbuild-android-64": "0.15.18",
|
||||
"esbuild-android-arm64": "0.15.18",
|
||||
"esbuild-darwin-64": "0.15.18",
|
||||
"esbuild-darwin-arm64": "0.15.18",
|
||||
"esbuild-freebsd-64": "0.15.18",
|
||||
"esbuild-freebsd-arm64": "0.15.18",
|
||||
"esbuild-linux-32": "0.15.18",
|
||||
"esbuild-linux-64": "0.15.18",
|
||||
"esbuild-linux-arm": "0.15.18",
|
||||
"esbuild-linux-arm64": "0.15.18",
|
||||
"esbuild-linux-mips64le": "0.15.18",
|
||||
"esbuild-linux-ppc64le": "0.15.18",
|
||||
"esbuild-linux-riscv64": "0.15.18",
|
||||
"esbuild-linux-s390x": "0.15.18",
|
||||
"esbuild-netbsd-64": "0.15.18",
|
||||
"esbuild-openbsd-64": "0.15.18",
|
||||
"esbuild-sunos-64": "0.15.18",
|
||||
"esbuild-windows-32": "0.15.18",
|
||||
"esbuild-windows-64": "0.15.18",
|
||||
"esbuild-windows-arm64": "0.15.18"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-64/-/esbuild-android-64-0.15.18.tgz",
|
||||
"integrity": "sha512-wnpt3OXRhcjfIDSZu9bnzT4/TNTDsOUvip0foZOUBG7QbSt//w3QV4FInVJxNhKc/ErhUxc5z4QjHtMi7/TbgA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-android-arm64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-android-arm64/-/esbuild-android-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-G4xu89B8FCzav9XU8EjsXacCKSG2FT7wW9J6hOc18soEHJdtWu03L3TQDGf0geNxfLTtxENKBzMSq9LlbjS8OQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"android"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-64/-/esbuild-darwin-64-0.15.18.tgz",
|
||||
"integrity": "sha512-2WAvs95uPnVJPuYKP0Eqx+Dl/jaYseZEUUT1sjg97TJa4oBtbAKnPnl3b5M9l51/nbx7+QAEtuummJZW0sBEmg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-darwin-arm64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-tKPSxcTJ5OmNb1btVikATJ8NftlyNlc8BVNtyT/UAr62JFOhwHlnoPrhYWz09akBLHI9nElFVfWSTSRsrZiDUA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-64/-/esbuild-freebsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-TT3uBUxkteAjR1QbsmvSsjpKjOX6UkCstr8nMr+q7zi3NuZ1oIpa8U41Y8I8dJH2fJgdC3Dj3CXO5biLQpfdZA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-freebsd-arm64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-R/oVr+X3Tkh+S0+tL41wRMbdWtpWB8hEAMsOXDumSSa6qJR89U0S/PpLXrGF7Wk/JykfpWNokERUpCeHDl47wA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-32": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-32/-/esbuild-linux-32-0.15.18.tgz",
|
||||
"integrity": "sha512-lphF3HiCSYtaa9p1DtXndiQEeQDKPl9eN/XNoBf2amEghugNuqXNZA/ZovthNE2aa4EN43WroO0B85xVSjYkbg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-64/-/esbuild-linux-64-0.15.18.tgz",
|
||||
"integrity": "sha512-hNSeP97IviD7oxLKFuii5sDPJ+QHeiFTFLoLm7NZQligur8poNOWGIgpQ7Qf8Balb69hptMZzyOBIPtY09GZYw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm/-/esbuild-linux-arm-0.15.18.tgz",
|
||||
"integrity": "sha512-UH779gstRblS4aoS2qpMl3wjg7U0j+ygu3GjIeTonCcN79ZvpPee12Qun3vcdxX+37O5LFxz39XeW2I9bybMVA==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-arm64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-arm64/-/esbuild-linux-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-54qr8kg/6ilcxd+0V3h9rjT4qmjc0CccMVWrjOEM/pEcUzt8X62HfBSeZfT2ECpM7104mk4yfQXkosY8Quptug==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-mips64le": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.15.18.tgz",
|
||||
"integrity": "sha512-Mk6Ppwzzz3YbMl/ZZL2P0q1tnYqh/trYZ1VfNP47C31yT0K8t9s7Z077QrDA/guU60tGNp2GOwCQnp+DYv7bxQ==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-ppc64le": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.15.18.tgz",
|
||||
"integrity": "sha512-b0XkN4pL9WUulPTa/VKHx2wLCgvIAbgwABGnKMY19WhKZPT+8BxhZdqz6EgkqCLld7X5qiCY2F/bfpUUlnFZ9w==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-riscv64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.15.18.tgz",
|
||||
"integrity": "sha512-ba2COaoF5wL6VLZWn04k+ACZjZ6NYniMSQStodFKH/Pu6RxzQqzsmjR1t9QC89VYJxBeyVPTaHuBMCejl3O/xg==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-linux-s390x": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-linux-s390x/-/esbuild-linux-s390x-0.15.18.tgz",
|
||||
"integrity": "sha512-VbpGuXEl5FCs1wDVp93O8UIzl3ZrglgnSQ+Hu79g7hZu6te6/YHgVJxCM2SqfIila0J3k0csfnf8VD2W7u2kzQ==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-netbsd-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-netbsd-64/-/esbuild-netbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-98ukeCdvdX7wr1vUYQzKo4kQ0N2p27H7I11maINv73fVEXt2kyh4K4m9f35U1K43Xc2QGXlzAw0K9yoU7JUjOg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"netbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-openbsd-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-openbsd-64/-/esbuild-openbsd-64-0.15.18.tgz",
|
||||
"integrity": "sha512-yK5NCcH31Uae076AyQAXeJzt/vxIo9+omZRKj1pauhk3ITuADzuOx5N2fdHrAKPxN+zH3w96uFKlY7yIn490xQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sunos-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-sunos-64/-/esbuild-sunos-64-0.15.18.tgz",
|
||||
"integrity": "sha512-On22LLFlBeLNj/YF3FT+cXcyKPEI263nflYlAhz5crxtp3yRG1Ugfr7ITyxmCmjm4vbN/dGrb/B7w7U8yJR9yw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"sunos"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-32": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-32/-/esbuild-windows-32-0.15.18.tgz",
|
||||
"integrity": "sha512-o+eyLu2MjVny/nt+E0uPnBxYuJHBvho8vWsC2lV61A7wwTWC3jkN2w36jtA+yv1UgYkHRihPuQsL23hsCYGcOQ==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-64/-/esbuild-windows-64-0.15.18.tgz",
|
||||
"integrity": "sha512-qinug1iTTaIIrCorAUjR0fcBk24fjzEedFYhhispP8Oc7SFvs+XeW3YpAKiKp8dRpizl4YYAhxMjlftAMJiaUw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-windows-arm64": {
|
||||
"version": "0.15.18",
|
||||
"resolved": "https://registry.npmjs.org/esbuild-windows-arm64/-/esbuild-windows-arm64-0.15.18.tgz",
|
||||
"integrity": "sha512-q9bsYzegpZcLziq0zgUi5KqGVtfhjxGbnksaBFYmWLxeV/S1fK4OLdq2DFYnXcLMjlZw2L0jLsk1eGoB522WXQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/is-core-module": {
|
||||
"version": "2.16.1",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
|
||||
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hasown": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/kleur": {
|
||||
"version": "4.1.5",
|
||||
"resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
|
||||
"integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/magic-string": {
|
||||
"version": "0.26.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz",
|
||||
"integrity": "sha512-hX9XH3ziStPoPhJxLq1syWuZMxbDvGNbVchfrdCtanC7D13888bMFow61x8axrx+GfHLtVeAx2kxL7tTGRl+Ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"sourcemap-codec": "^1.4.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-parse": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
|
||||
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.10",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
|
||||
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.16.0",
|
||||
"path-parse": "^1.0.7",
|
||||
"supports-preserve-symlinks-flag": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"resolve": "bin/resolve"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "2.79.2",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-2.79.2.tgz",
|
||||
"integrity": "sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sourcemap-codec": {
|
||||
"version": "1.4.8",
|
||||
"resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
|
||||
"integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
|
||||
"deprecated": "Please use @jridgewell/sourcemap-codec instead",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/supports-preserve-symlinks-flag": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
|
||||
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte": {
|
||||
"version": "3.59.2",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-3.59.2.tgz",
|
||||
"integrity": "sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-hmr": {
|
||||
"version": "0.15.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
|
||||
"integrity": "sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "^12.20 || ^14.13.1 || >= 16"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.19.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "3.2.11",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-3.2.11.tgz",
|
||||
"integrity": "sha512-K/jGKL/PgbIgKCiJo5QbASQhFiV02X9Jh+Qq0AKCRCRKZtOTVi4t6wh75FDpGf2N9rYOnzH87OEFQNaFy6pdxQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.15.9",
|
||||
"postcss": "^8.4.18",
|
||||
"resolve": "^1.22.1",
|
||||
"rollup": "^2.79.1"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": ">= 14",
|
||||
"less": "*",
|
||||
"sass": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vitefu": {
|
||||
"version": "0.2.5",
|
||||
"resolved": "https://registry.npmjs.org/vitefu/-/vitefu-0.2.5.tgz",
|
||||
"integrity": "sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"vite": "^3.0.0 || ^4.0.0 || ^5.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"vite": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
16
World-SEPPJM-Client/frontend/package.json
Normal file
16
World-SEPPJM-Client/frontend/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "frontend",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/vite-plugin-svelte": "^1.0.1",
|
||||
"svelte": "^3.49.0",
|
||||
"vite": "^3.0.7"
|
||||
}
|
||||
}
|
1
World-SEPPJM-Client/frontend/package.json.md5
Normal file
1
World-SEPPJM-Client/frontend/package.json.md5
Normal file
@@ -0,0 +1 @@
|
||||
d9dc84f0d17ed164f36dd584057aae68
|
109
World-SEPPJM-Client/frontend/src/App.svelte
Normal file
109
World-SEPPJM-Client/frontend/src/App.svelte
Normal file
@@ -0,0 +1,109 @@
|
||||
<!-- frontend/src/App.svelte -->
|
||||
<script>
|
||||
import { Quit } from '../wailsjs/runtime/runtime';
|
||||
|
||||
let view = 'menu'; // 'menu' | 'offline'
|
||||
|
||||
function goOffline(e) {
|
||||
e.preventDefault();
|
||||
view = 'offline';
|
||||
}
|
||||
function backToMenu(e) {
|
||||
e?.preventDefault();
|
||||
view = 'menu';
|
||||
}
|
||||
function exitApp(e) {
|
||||
e.preventDefault();
|
||||
Quit();
|
||||
}
|
||||
|
||||
function onKeydown(e) {
|
||||
if (e.key === 'Escape' && view !== 'menu') view = 'menu';
|
||||
}
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<link href="//sjm.cdn.prutzel.com/fonts/crn/font.css" rel="stylesheet" type="text/css" />
|
||||
</svelte:head>
|
||||
|
||||
<svelte:window on:keydown={onKeydown} />
|
||||
|
||||
{#if view === 'menu'}
|
||||
<main
|
||||
class="container"
|
||||
style="min-height: 100vh; display: flex; align-items: center; justify-content: center;"
|
||||
>
|
||||
<section class="row" style="width: 100%;">
|
||||
<div class="column" style="text-align: center;">
|
||||
<h3>World.SEPPJM Client</h3>
|
||||
<p>Join the online world or play offline</p>
|
||||
|
||||
<div style="margin: 1rem 0;">
|
||||
<a class="button" href="https://world.seppjm.com">Online</a>
|
||||
<a class="button" href="#" on:click={goOffline}>Offline</a>
|
||||
<a class="button" href="https://seppjm.com">My Website</a>
|
||||
<a class="button" href="#" on:click={exitApp}>Exit (Alt+F4)</a>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
{:else if view === 'offline'}
|
||||
<main
|
||||
class="container"
|
||||
style="min-height: 100vh; display: flex; align-items: center; justify-content: center;"
|
||||
>
|
||||
<section class="row" style="width: 100%;">
|
||||
<div class="column" style="text-align: center;">
|
||||
<h3>Offline Mode not available</h3>
|
||||
<p>Offline mode not implemented yet. Press <kbd>Esc</kbd> or use the button in the top-right to return.</p>
|
||||
|
||||
<!-- TODO: offline 3js scene here -->
|
||||
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
{/if}
|
||||
|
||||
{#if view !== 'menu'}
|
||||
<button class="overlay-back" on:click={backToMenu} aria-label="Return to menu" title="Return">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true">
|
||||
<path d="M15 18l-6-6 6-6" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</svg>
|
||||
<span class="label">Return</span>
|
||||
</button>
|
||||
{/if}
|
||||
|
||||
<style>
|
||||
.overlay-back {
|
||||
position: fixed;
|
||||
top: 12px;
|
||||
right: 12px;
|
||||
z-index: 1000;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
padding: 8px 12px;
|
||||
border-radius: 9999px;
|
||||
border: 1px solid rgba(255,255,255,0.2);
|
||||
background: rgba(0,0,0,0.45);
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
opacity: 0.65;
|
||||
transition: opacity 120ms ease, transform 120ms ease, box-shadow 120ms ease;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.25);
|
||||
backdrop-filter: blur(6px);
|
||||
-webkit-backdrop-filter: blur(6px);
|
||||
}
|
||||
.overlay-back:hover,
|
||||
.overlay-back:focus-visible {
|
||||
opacity: 1;
|
||||
transform: translateY(-1px);
|
||||
box-shadow: 0 6px 18px rgba(0,0,0,0.3);
|
||||
outline: none;
|
||||
}
|
||||
.overlay-back .label {
|
||||
font-size: 0.9rem;
|
||||
line-height: 1;
|
||||
}
|
||||
</style>
|
93
World-SEPPJM-Client/frontend/src/assets/fonts/OFL.txt
Normal file
93
World-SEPPJM-Client/frontend/src/assets/fonts/OFL.txt
Normal file
@@ -0,0 +1,93 @@
|
||||
Copyright 2016 The Nunito Project Authors (contact@sansoxygen.com),
|
||||
|
||||
This Font Software is licensed under the SIL Open Font License, Version 1.1.
|
||||
This license is copied below, and is also available with a FAQ at:
|
||||
http://scripts.sil.org/OFL
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
|
||||
-----------------------------------------------------------
|
||||
|
||||
PREAMBLE
|
||||
The goals of the Open Font License (OFL) are to stimulate worldwide
|
||||
development of collaborative font projects, to support the font creation
|
||||
efforts of academic and linguistic communities, and to provide a free and
|
||||
open framework in which fonts may be shared and improved in partnership
|
||||
with others.
|
||||
|
||||
The OFL allows the licensed fonts to be used, studied, modified and
|
||||
redistributed freely as long as they are not sold by themselves. The
|
||||
fonts, including any derivative works, can be bundled, embedded,
|
||||
redistributed and/or sold with any software provided that any reserved
|
||||
names are not used by derivative works. The fonts and derivatives,
|
||||
however, cannot be released under any other type of license. The
|
||||
requirement for fonts to remain under this license does not apply
|
||||
to any document created using the fonts or their derivatives.
|
||||
|
||||
DEFINITIONS
|
||||
"Font Software" refers to the set of files released by the Copyright
|
||||
Holder(s) under this license and clearly marked as such. This may
|
||||
include source files, build scripts and documentation.
|
||||
|
||||
"Reserved Font Name" refers to any names specified as such after the
|
||||
copyright statement(s).
|
||||
|
||||
"Original Version" refers to the collection of Font Software components as
|
||||
distributed by the Copyright Holder(s).
|
||||
|
||||
"Modified Version" refers to any derivative made by adding to, deleting,
|
||||
or substituting -- in part or in whole -- any of the components of the
|
||||
Original Version, by changing formats or by porting the Font Software to a
|
||||
new environment.
|
||||
|
||||
"Author" refers to any designer, engineer, programmer, technical
|
||||
writer or other person who contributed to the Font Software.
|
||||
|
||||
PERMISSION & CONDITIONS
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the Font Software, to use, study, copy, merge, embed, modify,
|
||||
redistribute, and sell modified and unmodified copies of the Font
|
||||
Software, subject to the following conditions:
|
||||
|
||||
1) Neither the Font Software nor any of its individual components,
|
||||
in Original or Modified Versions, may be sold by itself.
|
||||
|
||||
2) Original or Modified Versions of the Font Software may be bundled,
|
||||
redistributed and/or sold with any software, provided that each copy
|
||||
contains the above copyright notice and this license. These can be
|
||||
included either as stand-alone text files, human-readable headers or
|
||||
in the appropriate machine-readable metadata fields within text or
|
||||
binary files as long as those fields can be easily viewed by the user.
|
||||
|
||||
3) No Modified Version of the Font Software may use the Reserved Font
|
||||
Name(s) unless explicit written permission is granted by the corresponding
|
||||
Copyright Holder. This restriction only applies to the primary font name as
|
||||
presented to the users.
|
||||
|
||||
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
|
||||
Software shall not be used to promote, endorse or advertise any
|
||||
Modified Version, except to acknowledge the contribution(s) of the
|
||||
Copyright Holder(s) and the Author(s) or with their explicit written
|
||||
permission.
|
||||
|
||||
5) The Font Software, modified or unmodified, in part or in whole,
|
||||
must be distributed entirely under this license, and must not be
|
||||
distributed under any other license. The requirement for fonts to
|
||||
remain under this license does not apply to any document created
|
||||
using the Font Software.
|
||||
|
||||
TERMINATION
|
||||
This license becomes null and void if any of the above conditions are
|
||||
not met.
|
||||
|
||||
DISCLAIMER
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
|
||||
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
Binary file not shown.
682
World-SEPPJM-Client/frontend/src/assets/js/world.js
Normal file
682
World-SEPPJM-Client/frontend/src/assets/js/world.js
Normal file
@@ -0,0 +1,682 @@
|
||||
import * as THREE from "three";
|
||||
import { FBXLoader } from "three/addons/loaders/FBXLoader.js";
|
||||
import { TGALoader } from "three/addons/loaders/TGALoader.js";
|
||||
import { PointerLockControls } from "three/addons/controls/PointerLockControls.js";
|
||||
import * as BufferGeometryUtils from "three/addons/utils/BufferGeometryUtils.js";
|
||||
import { MeshBVH, acceleratedRaycast } from "https://esm.sh/three-mesh-bvh@0.7.6?deps=three@0.160.0";
|
||||
import { encode, decode } from "https://esm.sh/@msgpack/msgpack@3.1.2?bundle";
|
||||
|
||||
/* status overlay */
|
||||
const statusEl = document.createElement("div");
|
||||
Object.assign(statusEl.style, { position:"fixed", left:"12px", top:"12px", zIndex:"99999", padding:"6px 10px", borderRadius:"8px", background:"rgba(0,0,0,.55)", color:"#fff", font:"12px/1.2 system-ui,-apple-system,Segoe UI,Roboto,Inter,sans-serif", whiteSpace:"pre", pointerEvents:"none", maxWidth:"45vw" });
|
||||
statusEl.textContent = "booting…";
|
||||
document.body.appendChild(statusEl);
|
||||
const setStatus = (t)=> (statusEl.textContent = t);
|
||||
|
||||
/* config */
|
||||
const MODEL_URL = "https://world.seppjm.com/3js/models/scene.fbx";
|
||||
const USE_FOG = true;
|
||||
let RENDER_SCALE = 3;
|
||||
const COLOR_LEVELS = 32, USE_DITHER = true, VERTEX_SNAP_PIXELS = 0.75;
|
||||
const FIRE_POS = new THREE.Vector3(2885.090654499771, 5.937671631541306, -2843.489246932181);
|
||||
const CAM_POS = new THREE.Vector3(3280.98691276581, 386.84586301208896, -2012.4527013816644);
|
||||
const CAM_ROT_DEG = { yaw: 395.51276597880525, pitch: 2.7272791048226543 };
|
||||
const CAM_FOV = 90;
|
||||
|
||||
/* fire */
|
||||
const FIRE_SPRITE_SIZE = 150.0, FIRE_HEIGHT_OFFSET = 0.25;
|
||||
const FIRE_MAIN_INTENSITY = 2.2, FIRE_SUB_INTENSITY = 1.0, FIRE_MAIN_DISTANCE = 12000, FIRE_SUB_DISTANCE = 6000, FIRE_DECAY = 1.2;
|
||||
|
||||
/* networking */
|
||||
const WS_URL = "wss://ws.world.seppjm.com/ws";
|
||||
|
||||
/* scale / movement */
|
||||
const SCALE = 50;
|
||||
const WALK_SPEED = 4.6 * SCALE, ACCEL = 30.0, AIR_ACCEL = 7.0, FRICTION = 9.0, GRAVITY = 27.0 * SCALE;
|
||||
const JUMP_STRENGTH = 11.0 * SCALE, COYOTE_TIME = 0.12;
|
||||
|
||||
/* spectator freecam */
|
||||
const FREECAM_SPEED = 6.0 * SCALE;
|
||||
|
||||
/* slopes / capsule */
|
||||
const WALL_NORMAL_Y = 0.58;
|
||||
const CAPSULE_RADIUS = 0.5 * SCALE, CAPSULE_HEIGHT = 1.2 * SCALE, PLAYER_EYE_HEIGHT = CAPSULE_HEIGHT * 0.9 + CAPSULE_RADIUS;
|
||||
|
||||
/* spawn */
|
||||
const SPAWN_OFFSET = new THREE.Vector3(2.8 * SCALE, 0, 2.2 * SCALE), SPAWN_EXTRA_Y = 50 * SCALE;
|
||||
|
||||
/* collision tuning */
|
||||
const CONTACT_OFFSET = 0.08 * SCALE, MAX_SUBSTEP_DIST = 0.25 * CAPSULE_RADIUS;
|
||||
|
||||
/* ground + wall */
|
||||
const SNAP_CAST_DIST = 3.0 * CAPSULE_RADIUS, SNAP_EPS = 0.15 * SCALE;
|
||||
const WALL_MARGIN = 0.16 * SCALE, WALL_ITER = 3, RAY_FAN_COUNT = 16;
|
||||
|
||||
/* net cadence */
|
||||
const SEND_RATE_MS = 1000 / 12;
|
||||
|
||||
/* remote visuals */
|
||||
const SPRITE_HEIGHT = Math.max(1.6 * SCALE, PLAYER_EYE_HEIGHT * 1.05);
|
||||
const SPRITE_ASPECT = 0.55;
|
||||
const NAME_PAD = 0.24 * SCALE;
|
||||
const PLAYER_SPRITE_URL = null;
|
||||
|
||||
/* renderer + post */
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.id = "three-bg";
|
||||
Object.assign(canvas.style, {
|
||||
position:"fixed",
|
||||
inset:"0",
|
||||
width:"100vw",
|
||||
height:"100vh",
|
||||
display:"block",
|
||||
zIndex:"-1",
|
||||
pointerEvents:"none",
|
||||
opacity:"0",
|
||||
transition:"opacity 600ms ease",
|
||||
imageRendering:"pixelated",
|
||||
background:"transparent"
|
||||
});
|
||||
document.body.prepend(canvas);
|
||||
|
||||
const renderer = new THREE.WebGLRenderer({ canvas, antialias:false, alpha:true, powerPreference:"high-performance" });
|
||||
renderer.outputColorSpace = THREE.SRGBColorSpace;
|
||||
renderer.toneMapping = THREE.NoToneMapping;
|
||||
renderer.shadowMap.enabled = false;
|
||||
renderer.setPixelRatio(1);
|
||||
renderer.setClearColor(0x000000, 0);
|
||||
|
||||
/* 2D labels layer */
|
||||
const labelsLayer = document.createElement("div");
|
||||
Object.assign(labelsLayer.style, {
|
||||
position:"fixed",
|
||||
inset:"0",
|
||||
pointerEvents:"none",
|
||||
zIndex:"-1",
|
||||
fontFamily:"Inter, system-ui, -apple-system, Segoe UI, Roboto, sans-serif"
|
||||
});
|
||||
document.body.appendChild(labelsLayer);
|
||||
|
||||
let lowW=0, lowH=0, rt=null;
|
||||
const postScene = new THREE.Scene();
|
||||
const postCam = new THREE.OrthographicCamera(-1,1,1,-1,0,1);
|
||||
const postMat = new THREE.ShaderMaterial({
|
||||
uniforms:{ tDiffuse:{value:null}, uLowRes:{value:new THREE.Vector2(1,1)}, uLevels:{value:COLOR_LEVELS}, uDither:{value:USE_DITHER?1:0}, uTime:{value:0} },
|
||||
vertexShader:`varying vec2 vUv; void main(){ vUv=(position.xy+1.)*.5; gl_Position=vec4(position.xy,0.,1.); }`,
|
||||
fragmentShader:`
|
||||
precision mediump float; uniform sampler2D tDiffuse; uniform vec2 uLowRes; uniform int uLevels,uDither; uniform float uTime; varying vec2 vUv;
|
||||
float hash(vec2 p){ p=fract(p*vec2(123.34,345.45)); p+=dot(p,p+34.345); return fract(p.x*p.y); }
|
||||
vec3 quantize(vec3 c, vec2 pix){ float L=float(uLevels); float t=(uDither==1)?(hash(pix+uTime)-.5):0.; return floor(clamp(c+t/L,0.,1.)*(L-1.)+.5)/(L-1.); }
|
||||
void main(){ vec2 p=vUv*uLowRes; vec2 uv=(floor(p)+.5)/uLowRes; vec3 col=texture2D(tDiffuse,uv).rgb; col=quantize(col,p); gl_FragColor=vec4(col,1.); }
|
||||
`,
|
||||
depthTest:false, depthWrite:false
|
||||
});
|
||||
postScene.add(new THREE.Mesh(new THREE.PlaneGeometry(2,2), postMat));
|
||||
function allocRT(){ const w=innerWidth,h=innerHeight; lowW=Math.max(1,Math.floor(w/RENDER_SCALE)); lowH=Math.max(1,Math.floor(h/RENDER_SCALE)); renderer.setSize(w,h,false); if(rt) rt.dispose(); rt=new THREE.WebGLRenderTarget(lowW,lowH,{minFilter:THREE.NearestFilter,magFilter:THREE.NearestFilter,depthBuffer:true,stencilBuffer:false,type:THREE.UnsignedByteType,samples:0}); postMat.uniforms.uLowRes.value.set(lowW,lowH); }
|
||||
allocRT();
|
||||
|
||||
/* scene + idle cam */
|
||||
const scene = new THREE.Scene();
|
||||
scene.environment = null;
|
||||
scene.fog = USE_FOG ? new THREE.FogExp2(0x0b1020, 0.02) : null;
|
||||
const camera = new THREE.PerspectiveCamera(CAM_FOV, innerWidth/innerHeight, 0.005, 5000);
|
||||
const BASE_YAW = THREE.MathUtils.degToRad(((CAM_ROT_DEG.yaw%360)+360)%360);
|
||||
const BASE_PITCH = THREE.MathUtils.degToRad(CAM_ROT_DEG.pitch);
|
||||
camera.position.copy(CAM_POS);
|
||||
camera.rotation.set(BASE_PITCH, BASE_YAW, 0, "YXZ");
|
||||
camera.updateProjectionMatrix();
|
||||
const MAX_YAW_DELTA = THREE.MathUtils.degToRad(6), MAX_PITCH_DELTA = THREE.MathUtils.degToRad(4);
|
||||
let aimYaw=BASE_YAW, aimPitch=BASE_PITCH, curYaw=BASE_YAW, curPitch=BASE_PITCH, playMode=false;
|
||||
addEventListener("pointermove",(e)=>{ if(playMode || spectateMode) return; const nx=(e.clientX/innerWidth)*2-1, ny=(e.clientY/innerHeight)*2-1; aimYaw=BASE_YAW - nx*MAX_YAW_DELTA; aimPitch=BASE_PITCH + ny*MAX_PITCH_DELTA; },{passive:true});
|
||||
function updateCameraHover(dt){ const s=1.0 - Math.pow(0.2, dt*60); curYaw += (aimYaw-curYaw)*s; curPitch += (aimPitch-curPitch)*s; camera.rotation.set(curPitch,curYaw,0,"YXZ"); }
|
||||
scene.add(new THREE.HemisphereLight(0xb0c8ff,0x0b1020,0.28)); const sun=new THREE.DirectionalLight(0xffffff,0.6); sun.position.set(3,5,4); scene.add(sun);
|
||||
|
||||
/* loader + bvh */
|
||||
THREE.Mesh.prototype.raycast = acceleratedRaycast;
|
||||
const basePath = MODEL_URL.slice(0, MODEL_URL.lastIndexOf("/") + 1) || "/";
|
||||
const manager = new THREE.LoadingManager(); manager.addHandler(/\.tga$/i, new TGALoader(manager));
|
||||
const loader = new FBXLoader(manager); loader.setResourcePath(basePath);
|
||||
let model, mixer, levelReady=false, colliderGeom=null, colliderBVH=null, colliderMesh=null, colliderMinY=-Infinity, colliderMaxY=Infinity;
|
||||
const patchedMaterials = new Set(); const perFrame = [];
|
||||
|
||||
/* shader uniform cache for resize */
|
||||
const ps1Uniforms = new WeakMap();
|
||||
|
||||
/* patch material for PS1 look */
|
||||
function ps1ifyLambert(mat){
|
||||
["map","emissiveMap","aoMap","specularMap"].forEach((k)=>{ const t=mat[k]; if(!t) return; t.generateMipmaps=false; t.minFilter=THREE.NearestFilter; t.magFilter=THREE.NearestFilter; t.anisotropy=0; t.needsUpdate=true; });
|
||||
mat.depthWrite=true; mat.depthTest=true; mat.dithering=false; mat.polygonOffset=true; mat.polygonOffsetFactor=-0.5; mat.polygonOffsetUnits=1.0;
|
||||
mat.onBeforeCompile=(shader)=>{
|
||||
shader.uniforms.uResolution = { value:new THREE.Vector2(innerWidth,innerHeight) };
|
||||
shader.uniforms.uSnapPixels = { value:VERTEX_SNAP_PIXELS };
|
||||
if(!/uniform\s+vec2\s+uResolution/.test(shader.vertexShader)){
|
||||
shader.vertexShader = `uniform vec2 uResolution;\nuniform float uSnapPixels;\n` + shader.vertexShader;
|
||||
}
|
||||
shader.vertexShader = shader.vertexShader.replace(
|
||||
'#include <project_vertex>',
|
||||
`
|
||||
#include <project_vertex>
|
||||
vec2 ndc = gl_Position.xy / gl_Position.w;
|
||||
vec2 pix = (ndc*0.5 + 0.5) * uResolution;
|
||||
pix = floor(pix / uSnapPixels) * uSnapPixels;
|
||||
vec2 ndc2 = (pix / uResolution) * 2.0 - 1.0;
|
||||
gl_Position.xy = ndc2 * gl_Position.w;
|
||||
`
|
||||
);
|
||||
ps1Uniforms.set(mat, shader.uniforms);
|
||||
patchedMaterials.add(mat);
|
||||
};
|
||||
return mat;
|
||||
}
|
||||
|
||||
/* convert imported model to PS1 style and build collider */
|
||||
function ps1ifyMaterialsAndBuildCollider(root){
|
||||
const geos=[]; root.updateWorldMatrix(true,true);
|
||||
root.traverse((n)=>{
|
||||
if(!n.isMesh||!n.geometry) return;
|
||||
const src=n.material; const mats=(Array.isArray(src)?src:[src]).filter(Boolean);
|
||||
const newMats=mats.map((m)=>ps1ifyLambert(new THREE.MeshLambertMaterial({
|
||||
color:(m.color&&m.color.isColor)?m.color.clone():new THREE.Color(0xffffff),
|
||||
map:m.map||null, transparent:false, alphaTest: (m.alphaTest??0)>0?m.alphaTest: (m.map?.format===THREE.RGBAFormat?0.5:0.0), side:THREE.DoubleSide
|
||||
})));
|
||||
n.material = Array.isArray(src)?newMats:newMats[0];
|
||||
const srcGeo=n.geometry.clone(); srcGeo.applyMatrix4(n.matrixWorld); const pos=srcGeo.getAttribute("position"); if(!pos) return;
|
||||
const clean=new THREE.BufferGeometry(); clean.setAttribute("position",pos.clone()); clean.setIndex(null); geos.push(clean);
|
||||
});
|
||||
let merged=null;
|
||||
try{ merged=BufferGeometryUtils.mergeGeometries(geos,false); }
|
||||
catch{ const chunks=[]; for(let i=0;i<geos.length;i+=64){ chunks.push(BufferGeometryUtils.mergeGeometries(geos.slice(i,i+64),false)); } merged=BufferGeometryUtils.mergeGeometries(chunks,false); }
|
||||
merged = BufferGeometryUtils.mergeVertices(merged,1e-3); merged.computeBoundingBox(); merged.computeBoundingSphere();
|
||||
colliderGeom=merged; colliderBVH=new MeshBVH(colliderGeom,{maxLeafTris:32}); colliderGeom.boundsTree=colliderBVH;
|
||||
colliderMesh=new THREE.Mesh(colliderGeom,new THREE.MeshBasicMaterial({visible:false}));
|
||||
colliderMinY = colliderGeom.boundingBox ? colliderGeom.boundingBox.min.y : -1e6;
|
||||
colliderMaxY = colliderGeom.boundingBox ? colliderGeom.boundingBox.max.y : +1e6;
|
||||
}
|
||||
|
||||
/* fog tuning vs scene size */
|
||||
function autoFogFor(target){
|
||||
const box=new THREE.Box3().setFromObject(target), size=box.getSize(new THREE.Vector3());
|
||||
const k=0.03, density=Math.min(0.06, Math.max(0.000005, k/(Math.max(size.x,size.y,size.z)*0.5 || 1)));
|
||||
scene.fog = USE_FOG ? new THREE.FogExp2(0x0b1020, density) : null;
|
||||
}
|
||||
|
||||
/* campfire */
|
||||
let fireGroup=null, fireLight=null, fireLight2=null, fireSprite=null;
|
||||
function makeFlameTexture(size=128){
|
||||
const c=document.createElement("canvas"); c.width=c.height=size; const g=c.getContext("2d");
|
||||
const grd=g.createRadialGradient(size*.5,size*.6,size*.05,size*.5,size*.6,size*.5);
|
||||
grd.addColorStop(0.0,"rgba(255,255,255,1)"); grd.addColorStop(0.25,"rgba(255,200,80,0.95)");
|
||||
grd.addColorStop(0.55,"rgba(255,120,30,0.65)"); grd.addColorStop(0.85,"rgba(200,40,10,0.25)"); grd.addColorStop(1.0,"rgba(0,0,0,0)");
|
||||
g.fillStyle=grd; g.fillRect(0,0,size,size);
|
||||
const tex=new THREE.CanvasTexture(c); tex.generateMipmaps=false; tex.minFilter=THREE.NearestFilter; tex.magFilter=THREE.NearestFilter; tex.anisotropy=0; return tex;
|
||||
}
|
||||
function addCampfire(pos){
|
||||
fireGroup=new THREE.Group(); fireGroup.position.copy(pos); scene.add(fireGroup);
|
||||
fireLight=new THREE.PointLight(0xff7a2a, FIRE_MAIN_INTENSITY, FIRE_MAIN_DISTANCE, FIRE_DECAY); fireLight.position.set(0, FIRE_HEIGHT_OFFSET+0.6, 0); fireGroup.add(fireLight);
|
||||
fireLight2=new THREE.PointLight(0xff3300, FIRE_SUB_INTENSITY, FIRE_SUB_DISTANCE, FIRE_DECAY); fireLight2.position.set(0.35, FIRE_HEIGHT_OFFSET+0.4, -0.2); fireGroup.add(fireLight2);
|
||||
const flameTex=makeFlameTexture(128);
|
||||
fireSprite=new THREE.Sprite(new THREE.SpriteMaterial({ map:flameTex, color:0xffffff, transparent:true, depthWrite:false, blending:THREE.AdditiveBlending, depthTest:true }));
|
||||
fireSprite.position.set(0, FIRE_HEIGHT_OFFSET+0.25, 0); fireSprite.scale.set(FIRE_SPRITE_SIZE, FIRE_SPRITE_SIZE*1.35, 1); fireGroup.add(fireSprite);
|
||||
let t=0; perFrame.push((dt)=>{ t+=dt; const pulse=0.45*Math.sin(t*5.4)+0.28*Math.sin(t*8.7+1.1);
|
||||
fireLight.intensity=FIRE_MAIN_INTENSITY + pulse; fireLight2.intensity=FIRE_SUB_INTENSITY + pulse*0.75;
|
||||
fireLight.color.setHSL(0.06+Math.sin(t*1.6)*0.01,1.0,0.55); fireLight2.color.setHSL(0.03+Math.sin(t*1.9+0.8)*0.012,1.0,0.47);
|
||||
fireSprite.material.rotation += dt*0.5; const j=1.0+Math.sin(t*6.0)*0.06; fireSprite.scale.set(FIRE_SPRITE_SIZE*j, FIRE_SPRITE_SIZE*1.35*j, 1);
|
||||
});
|
||||
}
|
||||
|
||||
/* load world */
|
||||
loader.load(MODEL_URL, (fbx)=>{
|
||||
model=fbx; scene.add(model); ps1ifyMaterialsAndBuildCollider(model);
|
||||
if(fbx.animations?.length){ mixer=new THREE.AnimationMixer(model); mixer.clipAction(fbx.animations[0]).play(); }
|
||||
autoFogFor(model); addCampfire(FIRE_POS);
|
||||
levelReady=true; setStatus("world loaded");
|
||||
if(playMode) initialPlace(true);
|
||||
}, undefined, ()=> setStatus("ERR loading model"));
|
||||
|
||||
/* Music: autoplay + 'M' toggle */
|
||||
const audio=new Audio("https://world.seppjm.com/3js/audio/stalker.mp3");
|
||||
audio.loop=true; audio.preload="auto"; audio.crossOrigin="anonymous"; audio.volume=0.5;
|
||||
let isPlaying=false, fadeRAF=null;
|
||||
const fadeTo=(target,ms=700)=>{ cancelAnimationFrame(fadeRAF); const start=audio.volume,d=target-start,t0=performance.now(); const tick=(now)=>{ const p=Math.min(1,(now-t0)/ms); audio.volume=Math.max(0,Math.min(1,start+d*p)); if(p<1) fadeRAF=requestAnimationFrame(tick); }; fadeRAF=requestAnimationFrame(tick); };
|
||||
async function playMusic(auto=false){ try{ if(auto) audio.volume=0.0; await audio.play(); isPlaying=true; if(auto) fadeTo(0.5,800); }catch{} }
|
||||
function pauseMusic(){ fadeTo(0.0,300); setTimeout(()=>audio.pause(),320); isPlaying=false; }
|
||||
playMusic(true);
|
||||
["pointerdown","keydown","visibilitychange"].forEach((ev)=> addEventListener(ev, ()=>{ if(!isPlaying) playMusic(true); }, { once:true }));
|
||||
|
||||
/* fps controller + collisions (player) */
|
||||
let controls=null; const keys=new Set(); const velocity=new THREE.Vector3(); let onGround=false, physicsEnabled=false;
|
||||
const lastSafePos=new THREE.Vector3(); let timeSinceGrounded=0, lastGroundedAt=0;
|
||||
let playerLight=null; function ensurePlayerLight(obj){ if(playerLight) return; playerLight=new THREE.PointLight(0xffa25a,0.9,1500*SCALE,1.4); playerLight.position.set(0,-PLAYER_EYE_HEIGHT*0.2,0); obj.add(playerLight); }
|
||||
|
||||
/* spectator freecam */
|
||||
let spectateMode=false, specControls=null;
|
||||
function onSpecKeyDown(e){
|
||||
keys.add(e.code);
|
||||
if(e.code==="KeyM"){ if(isPlaying) pauseMusic(); else playMusic(); }
|
||||
}
|
||||
function onSpecKeyUp(e){ keys.delete(e.code); }
|
||||
function makeSpectateHint(){
|
||||
const hint=document.createElement("div");
|
||||
Object.assign(hint.style,{ position:"fixed", left:"16px", bottom:"16px", zIndex:20, color:"#fff", font:"600 14px Inter, system-ui", opacity:"0.9", pointerEvents:"none", textAlign:"left", lineHeight:"1.35", background:"rgba(0,0,0,0.45)", padding:"8px 10px", borderRadius:"10px", maxWidth:"44ch" });
|
||||
hint.textContent="Spectator freecam — WASD move • Mouse look • Q/E down/up • Shift boost • M music • ESC cursor";
|
||||
document.body.appendChild(hint);
|
||||
}
|
||||
function startSpectate(){
|
||||
if(spectateMode || playMode) return;
|
||||
spectateMode=true;
|
||||
|
||||
canvas.style.zIndex = "10";
|
||||
canvas.style.pointerEvents = "auto";
|
||||
canvas.style.opacity = "1";
|
||||
labelsLayer.style.zIndex = "15";
|
||||
|
||||
specControls = new PointerLockControls(camera, canvas);
|
||||
scene.add(specControls.getObject());
|
||||
specControls.lock();
|
||||
canvas.addEventListener("click", ()=> specControls.lock());
|
||||
specControls.addEventListener("lock", ()=> setStatus("spectate: locked (WASD, mouse, Q/E, Shift, M)"));
|
||||
specControls.addEventListener("unlock", ()=> setStatus("spectate: unlocked (click to lock)"));
|
||||
|
||||
addEventListener("keydown", onSpecKeyDown);
|
||||
addEventListener("keyup", onSpecKeyUp);
|
||||
makeSpectateHint();
|
||||
}
|
||||
function stopSpectate(){
|
||||
if(!spectateMode) return;
|
||||
removeEventListener("keydown", onSpecKeyDown);
|
||||
removeEventListener("keyup", onSpecKeyUp);
|
||||
if(specControls){
|
||||
try{ specControls.unlock(); }catch{}
|
||||
scene.remove(specControls.getObject());
|
||||
}
|
||||
specControls=null;
|
||||
spectateMode=false;
|
||||
}
|
||||
function updateFreecam(dt){
|
||||
if(!spectateMode) return;
|
||||
const boost = (keys.has("ShiftLeft") || keys.has("ShiftRight")) ? 3.0 : 1.0;
|
||||
const speed = FREECAM_SPEED * boost;
|
||||
const fwd=new THREE.Vector3(); camera.getWorldDirection(fwd); fwd.normalize();
|
||||
const right=new THREE.Vector3().crossVectors(fwd,new THREE.Vector3(0,1,0)).normalize();
|
||||
const up=new THREE.Vector3(0,1,0);
|
||||
const move=new THREE.Vector3();
|
||||
if(keys.has("KeyW")) move.add(fwd);
|
||||
if(keys.has("KeyS")) move.addScaledVector(fwd,-1);
|
||||
if(keys.has("KeyA")) move.addScaledVector(right,-1);
|
||||
if(keys.has("KeyD")) move.add(right);
|
||||
if(keys.has("KeyE")) move.add(up);
|
||||
if(keys.has("KeyQ")) move.addScaledVector(up,-1);
|
||||
if(move.lengthSq()>0){
|
||||
move.normalize().multiplyScalar(speed*dt);
|
||||
camera.position.add(move);
|
||||
}
|
||||
}
|
||||
|
||||
/* rays */
|
||||
const dirFan=Array.from({length:RAY_FAN_COUNT},(_,i)=>{ const a=(i/RAY_FAN_COUNT)*Math.PI*2; return new THREE.Vector3(Math.sin(a),0,Math.cos(a)).normalize(); });
|
||||
const raycaster=new THREE.Raycaster(); raycaster.firstHitOnly=true;
|
||||
|
||||
/* helpers */
|
||||
const feetYFromEye=(eyeY)=> eyeY - (PLAYER_EYE_HEIGHT - CAPSULE_RADIUS);
|
||||
function groundSnap(eyePos, maxUp=SNAP_EPS){
|
||||
if(!colliderMesh) return false;
|
||||
const feetY=feetYFromEye(eyePos.y), origin=new THREE.Vector3(eyePos.x, feetY+CAPSULE_RADIUS*0.75, eyePos.z), dir=new THREE.Vector3(0,-1,0);
|
||||
raycaster.set(origin,dir); raycaster.near=0; raycaster.far=SNAP_CAST_DIST;
|
||||
const hit=raycaster.intersectObject(colliderMesh,false)[0]; if(!hit) return false;
|
||||
const n=hit.face?.normal ?? new THREE.Vector3(0,1,0); if(n.y < WALL_NORMAL_Y) return false;
|
||||
const desiredFeet=hit.point.y + CAPSULE_RADIUS + CONTACT_OFFSET, delta=desiredFeet - feetY;
|
||||
if(delta>-maxUp && delta<maxUp){ eyePos.y += delta; return true; } return false;
|
||||
}
|
||||
function pushOutWalls(eyePos){
|
||||
if(!colliderMesh) return;
|
||||
const feet=feetYFromEye(eyePos.y), heights=[ feet+CAPSULE_RADIUS*0.2, feet+CAPSULE_HEIGHT*0.5, feet+CAPSULE_HEIGHT-CAPSULE_RADIUS*0.2 ];
|
||||
const radius=CAPSULE_RADIUS + WALL_MARGIN;
|
||||
for(let iter=0; iter<WALL_ITER; iter++){
|
||||
for(const h of heights){
|
||||
for(const d of dirFan){
|
||||
const o=new THREE.Vector3(eyePos.x,h,eyePos.z); raycaster.set(o,d); raycaster.near=0; raycaster.far=radius;
|
||||
const hit=raycaster.intersectObject(colliderMesh,false)[0]; if(!hit) continue;
|
||||
const n=hit.face?.normal ?? new THREE.Vector3(0,1,0); if(n.y>=WALL_NORMAL_Y) continue;
|
||||
const push=radius - hit.distance + CONTACT_OFFSET; if(push>0) eyePos.addScaledVector(d,-push);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
function sweepClampMove(eyePos, moveXZ){
|
||||
if(!colliderMesh) return moveXZ; const len=moveXZ.length(); if(len<1e-6) return moveXZ;
|
||||
const dir=moveXZ.clone().normalize(), feet=feetYFromEye(eyePos.y);
|
||||
const heights=[ feet+CAPSULE_RADIUS*0.2, feet+CAPSULE_HEIGHT*0.5, feet+CAPSULE_HEIGHT-CAPSULE_RADIUS*0.2 ];
|
||||
const radius=CAPSULE_RADIUS + WALL_MARGIN; let maxLen=len;
|
||||
for(const h of heights){
|
||||
const origin=new THREE.Vector3(eyePos.x,h,eyePos.z); raycaster.set(origin,dir); raycaster.near=0; raycaster.far=len+radius;
|
||||
const hit=raycaster.intersectObject(colliderMesh,false)[0]; if(!hit) continue;
|
||||
const n=hit.face?.normal ?? new THREE.Vector3(0,1,0); if(n.y>=WALL_NORMAL_Y) continue;
|
||||
const allowed=Math.max(0, hit.distance - (radius+CONTACT_OFFSET)); if(allowed<maxLen) maxLen=allowed;
|
||||
}
|
||||
if(maxLen<len) moveXZ.setLength(maxLen); return moveXZ;
|
||||
}
|
||||
|
||||
/* spawn at fire */
|
||||
function initialPlace(forceHigh=false){
|
||||
if(!levelReady) return;
|
||||
const obj=controls.getObject(); const spawn=FIRE_POS.clone().add(SPAWN_OFFSET); const y=(forceHigh?SPAWN_EXTRA_Y:5*SCALE);
|
||||
obj.position.copy(spawn).add(new THREE.Vector3(0,y,0));
|
||||
const toFire=new THREE.Vector3().subVectors(FIRE_POS,spawn), yaw=Math.atan2(toFire.x,toFire.z);
|
||||
obj.rotation.set(0,yaw,0,"YXZ"); camera.rotation.set(0,yaw,0,"YXZ");
|
||||
physicsEnabled=true; velocity.set(0,0,0); onGround=false; timeSinceGrounded=0; lastGroundedAt=0; lastSafePos.copy(obj.position); setStatus("ready");
|
||||
}
|
||||
function respawnAtFire(){ const obj=controls.getObject(), spawn=FIRE_POS.clone().add(SPAWN_OFFSET); obj.position.copy(spawn).add(new THREE.Vector3(0,SPAWN_EXTRA_Y,0)); velocity.set(0,0,0); onGround=false; timeSinceGrounded=0; setStatus("respawn"); }
|
||||
|
||||
/* physics step */
|
||||
function integrateSubstep(subDt){
|
||||
const obj=controls.getObject(), eye=obj.position, move=velocity.clone().multiplyScalar(subDt), moveXZ=new THREE.Vector3(move.x,0,move.z);
|
||||
sweepClampMove(eye,moveXZ); eye.add(moveXZ); pushOutWalls(eye);
|
||||
eye.y += move.y; pushOutWalls(eye);
|
||||
|
||||
if (velocity.y <= 0) {
|
||||
const snapped=groundSnap(eye, SNAP_EPS + Math.max(0,-velocity.y*subDt + CONTACT_OFFSET));
|
||||
if(snapped){ onGround=true; if(velocity.y<0) velocity.y=0; lastGroundedAt=performance.now(); }
|
||||
}
|
||||
|
||||
if(Number.isFinite(colliderMinY)){ const minEye=colliderMinY + (PLAYER_EYE_HEIGHT - CAPSULE_RADIUS) + 0.25*SCALE; if(eye.y<minEye){ eye.y=minEye; velocity.y=Math.max(0,velocity.y); } }
|
||||
if(Number.isFinite(colliderMaxY) && eye.y>colliderMaxY+200*SCALE){ eye.y=colliderMaxY+200*SCALE; velocity.y=Math.min(0,velocity.y); }
|
||||
}
|
||||
function updateFPS(dt){
|
||||
if(!playMode || !levelReady || !physicsEnabled) return;
|
||||
const obj=controls.getObject();
|
||||
const fwd=new THREE.Vector3(); camera.getWorldDirection(fwd); fwd.y=0; fwd.normalize();
|
||||
const right=new THREE.Vector3().crossVectors(fwd,new THREE.Vector3(0,1,0)).normalize();
|
||||
const wish=new THREE.Vector3(); if(keys.has("KeyW")) wish.add(fwd); if(keys.has("KeyS")) wish.addScaledVector(fwd,-1); if(keys.has("KeyA")) wish.addScaledVector(right,-1); if(keys.has("KeyD")) wish.add(right); if(wish.lengthSq()>0) wish.normalize();
|
||||
const accel=onGround?ACCEL:AIR_ACCEL, targetVel=wish.multiplyScalar(WALK_SPEED), horizVel=new THREE.Vector3(velocity.x,0,velocity.z), add=new THREE.Vector3().subVectors(targetVel,horizVel).multiplyScalar(accel*dt);
|
||||
horizVel.add(add); velocity.x=horizVel.x; velocity.z=horizVel.z;
|
||||
velocity.y -= GRAVITY*dt;
|
||||
|
||||
const moveLen=velocity.clone().multiplyScalar(dt).length(), steps=Math.max(1, Math.ceil(moveLen / MAX_SUBSTEP_DIST)); onGround=false; const subDt=dt/steps;
|
||||
for(let i=0;i<steps;i++) integrateSubstep(subDt);
|
||||
|
||||
if(velocity.y <= 0 && groundSnap(obj.position)) { onGround=true; lastGroundedAt=performance.now(); }
|
||||
|
||||
if(onGround){ const f=Math.max(0,1-FRICTION*dt); velocity.x*=f; velocity.z*=f; if(velocity.y<0) velocity.y=0; timeSinceGrounded=0; lastSafePos.copy(obj.position); setStatus("grounded"); }
|
||||
else { timeSinceGrounded+=dt; setStatus("air"); }
|
||||
|
||||
const minEye=colliderMinY + (PLAYER_EYE_HEIGHT - CAPSULE_RADIUS) - 10*SCALE; if(obj.position.y<minEye || timeSinceGrounded>4.0){ respawnAtFire(); }
|
||||
ensurePlayerLight(obj);
|
||||
}
|
||||
|
||||
/* remote players + 2D name labels */
|
||||
const players=new Map();
|
||||
function makeLabelEl(text){
|
||||
const el=document.createElement("div");
|
||||
el.textContent=text;
|
||||
Object.assign(el.style,{
|
||||
position:"absolute",
|
||||
transform:"translate(-50%,-100%)",
|
||||
color:"#fff",
|
||||
fontWeight:"800",
|
||||
fontSize:"22px",
|
||||
lineHeight:"1",
|
||||
padding:"4px 8px",
|
||||
borderRadius:"8px",
|
||||
background:"rgba(0,0,0,0.55)",
|
||||
textShadow:"0 1px 2px rgba(0,0,0,0.65)",
|
||||
whiteSpace:"nowrap",
|
||||
pointerEvents:"none",
|
||||
willChange:"transform",
|
||||
});
|
||||
labelsLayer.appendChild(el);
|
||||
return el;
|
||||
}
|
||||
function updateLabelPosition(label, worldPos){
|
||||
const v = worldPos.clone().project(camera);
|
||||
if (v.z < 0 || v.z > 1) { label.style.display="none"; return; }
|
||||
const x = (v.x * 0.5 + 0.5) * innerWidth;
|
||||
const y = ( -v.y * 0.5 + 0.5) * innerHeight;
|
||||
label.style.display="";
|
||||
label.style.left = `${x}px`;
|
||||
label.style.top = `${y}px`;
|
||||
}
|
||||
|
||||
function makeBillboardTexture(cb){
|
||||
if(PLAYER_SPRITE_URL){
|
||||
const img=new Image(); img.crossOrigin="anonymous";
|
||||
img.onload=()=>{ const tex=new THREE.Texture(img); tex.needsUpdate=true; tex.generateMipmaps=false; tex.minFilter=THREE.NearestFilter; tex.magFilter=THREE.NearestFilter; cb(tex); };
|
||||
img.onerror=()=>cb(makeProceduralBillboard()); img.src=PLAYER_SPRITE_URL;
|
||||
} else cb(makeProceduralBillboard());
|
||||
}
|
||||
function makeProceduralBillboard(){
|
||||
const W=64,H=128,c=document.createElement("canvas"); c.width=W; c.height=H; const g=c.getContext("2d"); g.fillStyle="rgba(0,0,0,0)"; g.fillRect(0,0,W,H);
|
||||
g.fillStyle="#d6e0ff"; g.fillRect(18,20,28,78); g.beginPath(); g.arc(32,30,18,0,Math.PI*2); g.fill(); g.fillRect(18,98,10,24); g.fillRect(36,98,10,24);
|
||||
g.strokeStyle="#131a2f"; g.lineWidth=3; g.strokeRect(18,20,28,78); g.beginPath(); g.arc(32,30,18,0,Math.PI*2); g.stroke();
|
||||
const tex=new THREE.CanvasTexture(c); tex.generateMipmaps=false; tex.minFilter=THREE.NearestFilter; tex.magFilter=THREE.NearestFilter; return tex;
|
||||
}
|
||||
function makeBillboardSprite(onReady){
|
||||
makeBillboardTexture((tex)=>{
|
||||
const spr=new THREE.Sprite(new THREE.SpriteMaterial({ map:tex, transparent:true, depthWrite:true, depthTest:true }));
|
||||
spr.center.set(0.5, 0.0); // bottom at ground
|
||||
spr.position.y = 0;
|
||||
spr.scale.set(SPRITE_HEIGHT*SPRITE_ASPECT, SPRITE_HEIGHT, 1);
|
||||
onReady(spr);
|
||||
});
|
||||
}
|
||||
|
||||
/* spawn/update remote, anchor to ground (pos is eye from server) */
|
||||
function spawnOrUpdate(p){
|
||||
if (myID && p?.id === myID) return; // ignore self
|
||||
|
||||
const baseY = (p.pos?.[1] ?? 0) - PLAYER_EYE_HEIGHT;
|
||||
let entry = players.get(p.id);
|
||||
if(!entry){
|
||||
const group=new THREE.Group(); group.position.set(p.pos?.[0]??0, baseY, p.pos?.[2]??0); group.rotation.y=p.rotY||0;
|
||||
makeBillboardSprite((body)=>{ group.add(body); });
|
||||
scene.add(group);
|
||||
const labelEl = makeLabelEl(p.name || "Player");
|
||||
entry = { group, labelEl, target:new THREE.Vector3(p.pos?.[0]??0, baseY, p.pos?.[2]??0), rotY:p.rotY||0, name:p.name||"Player" };
|
||||
players.set(p.id, entry);
|
||||
} else {
|
||||
entry.target.set(p.pos?.[0]??0, baseY, p.pos?.[2]??0);
|
||||
entry.rotY = p.rotY || 0;
|
||||
if (p.name && p.name !== entry.name) { entry.name = p.name; entry.labelEl.textContent = p.name; }
|
||||
}
|
||||
}
|
||||
function removePlayer(id){
|
||||
const e=players.get(id); if(!e) return;
|
||||
scene.remove(e.group);
|
||||
if(e.labelEl?.parentNode) e.labelEl.parentNode.removeChild(e.labelEl);
|
||||
players.delete(id);
|
||||
}
|
||||
|
||||
/* chat UI (only when playing) */
|
||||
function makeChatUI(){
|
||||
const hint=document.createElement("div");
|
||||
Object.assign(hint.style,{ position:"fixed", left:"16px", bottom:"16px", zIndex:20, color:"#fff", font:"600 14px Inter, system-ui", opacity:"0.9", pointerEvents:"none", textAlign:"left", lineHeight:"1.35", background:"rgba(0,0,0,0.45)", padding:"8px 10px", borderRadius:"10px", maxWidth:"44ch" });
|
||||
hint.innerHTML=`Pointer-lock FPS<br>WASD move • <b>SPACE</b> jump • <b>T</b> chat • <b>M</b> music • <b>ESC</b> cursor`;
|
||||
document.body.appendChild(hint);
|
||||
|
||||
const log=document.createElement("div"); Object.assign(log.style,{ position:"fixed", left:"16px", bottom:"96px", width:"420px", maxHeight:"40vh", overflow:"hidden", display:"flex", flexDirection:"column-reverse", gap:"6px", zIndex:20, font:"15px/1.35 Inter, system-ui", color:"#fff" }); log.id="chat-log"; document.body.appendChild(log);
|
||||
|
||||
const form=document.createElement("form"); form.id="chat-form"; Object.assign(form.style,{ position:"fixed", left:"16px", bottom:"16px", zIndex:21, display:"none" });
|
||||
const inp=document.createElement("input"); inp.type="text"; inp.placeholder="type to chat…"; Object.assign(inp.style,{ width:"400px", padding:"10px 12px", borderRadius:"10px", border:"1px solid rgba(255,255,255,.2)", background:"rgba(0,0,0,.5)", color:"#fff" }); form.appendChild(inp); document.body.appendChild(form);
|
||||
|
||||
form.addEventListener("submit",(e)=>{ e.preventDefault(); const t=inp.value.trim(); if(!t) return; send({type:"chat", text:t}); inp.value=""; hideChat(); });
|
||||
function showChat(){ form.style.display="block"; inp.focus(); controls.unlock(); }
|
||||
function hideChat(){ form.style.display="none"; controls.lock(); }
|
||||
addEventListener("keydown",(e)=>{ if(e.key==="t"||e.key==="T"){ e.preventDefault(); showChat(); }});
|
||||
|
||||
addEventListener("keydown",(e)=>{
|
||||
if(e.code==="KeyM"){
|
||||
if(isPlaying) pauseMusic(); else playMusic();
|
||||
setStatus(isPlaying ? "music: playing" : "music: paused");
|
||||
}
|
||||
});
|
||||
}
|
||||
function addChat(logEl, name, text){ if(!logEl) return; const row=document.createElement("div"); row.textContent=`${name}: ${text}`; row.style.background="rgba(0,0,0,.45)"; row.style.padding="6px 10px"; row.style.borderRadius="8px"; logEl.prepend(row); const kids=[...logEl.children]; while(kids.length>24){ logEl.removeChild(kids.pop()); } }
|
||||
|
||||
/* networking */
|
||||
let ws=null, myID=null, lastSend=0, currentRole="spectator", suppressToast=false;
|
||||
function connect(role="spectator", name="Viewer"){
|
||||
try{
|
||||
if(ws && ws.readyState<=1){ suppressToast=true; try{ ws.close(); }catch{} }
|
||||
currentRole=role;
|
||||
ws=new WebSocket(WS_URL); ws.binaryType="arraybuffer";
|
||||
ws.addEventListener("open", ()=>{
|
||||
setStatus(`ws: connected (${role})`);
|
||||
send({ type:"join", name, role });
|
||||
if(role==="player"){ const p=controls?.getObject?.().position; if(p) send({type:"state", pos:[p.x,p.y,p.z], rotY:camera.rotation.y}); }
|
||||
});
|
||||
ws.addEventListener("message",(ev)=>{ try{ onMessage(ev); }catch(e){ setStatus("ws msg err: "+e.message); } });
|
||||
ws.addEventListener("close", ()=>{
|
||||
if(!suppressToast){ const toast=document.createElement("div"); Object.assign(toast.style,{ position:"fixed", left:"50%", top:"14px", transform:"translateX(-50%)", background:"rgba(200,0,0,0.75)", color:"#fff", padding:"8px 12px", borderRadius:"10px", zIndex:50, font:"600 14px Inter, system-ui" }); toast.textContent="Disconnected from server"; document.body.appendChild(toast); setTimeout(()=>toast.remove(),3500); }
|
||||
suppressToast=false; setStatus("ws: disconnected");
|
||||
});
|
||||
ws.addEventListener("error", ()=> setStatus("ws: error"));
|
||||
}catch(e){ setStatus("ws init err: "+e.message); }
|
||||
}
|
||||
function send(obj){ if(ws && ws.readyState===1) ws.send(encode(obj)); }
|
||||
function onMessage(ev){
|
||||
const msg=decode(ev.data);
|
||||
switch(msg.type){
|
||||
case "welcome":
|
||||
myID = msg.id;
|
||||
removePlayer(myID);
|
||||
(msg.players||[]).forEach((p)=>{ if(p.id!==myID) spawnOrUpdate(p); });
|
||||
break;
|
||||
case "player_join":
|
||||
if(msg.player && msg.player.id !== myID) spawnOrUpdate(msg.player);
|
||||
break;
|
||||
case "player_leave":
|
||||
if(msg.id) removePlayer(msg.id);
|
||||
break;
|
||||
case "state":
|
||||
if(Array.isArray(msg.updates)) msg.updates.forEach((u)=>{ if(u.id!==myID) spawnOrUpdate(u); });
|
||||
else if(msg.id && msg.pos){ if(msg.id!==myID) spawnOrUpdate(msg); }
|
||||
break;
|
||||
case "player_state":
|
||||
if(msg.id && msg.pos && msg.id!==myID) spawnOrUpdate(msg);
|
||||
break;
|
||||
case "chat":
|
||||
addChat(document.getElementById("chat-log"), msg.name||"Player", msg.text||"");
|
||||
break;
|
||||
case "full":
|
||||
alert(`World is full (max ${msg.maxPlayers ?? 10})`);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* enter play */
|
||||
function startPlay(){
|
||||
if(playMode) return;
|
||||
// if we were spectating, clean it up
|
||||
if(spectateMode) stopSpectate();
|
||||
|
||||
playMode=true;
|
||||
canvas.style.zIndex = "10";
|
||||
canvas.style.pointerEvents = "auto";
|
||||
canvas.style.opacity = "1";
|
||||
labelsLayer.style.zIndex = "15";
|
||||
|
||||
const controlsLocal=new PointerLockControls(camera, canvas); controls=controlsLocal; scene.add(controls.getObject());
|
||||
controls.lock(); canvas.addEventListener("click", ()=>controls.lock());
|
||||
controls.addEventListener("lock", ()=> setStatus("locked (WASD, SPACE jump, T chat, M music)"));
|
||||
controls.addEventListener("unlock", ()=> setStatus("unlocked (click to lock)"));
|
||||
makeChatUI();
|
||||
if(levelReady) initialPlace(true);
|
||||
const name = (prompt("Authentication not implemented; for now enter a nickname:", "Guest") || "Guest").slice(0,25);
|
||||
connect("player", name);
|
||||
addEventListener("keydown",(e)=>{ keys.add(e.code);
|
||||
if(e.code==="Space" && playMode){
|
||||
const now=performance.now();
|
||||
if(onGround || (now - lastGroundedAt) < COYOTE_TIME*1000){
|
||||
velocity.y = JUMP_STRENGTH;
|
||||
onGround=false;
|
||||
}
|
||||
}
|
||||
});
|
||||
addEventListener("keyup",(e)=> keys.delete(e.code));
|
||||
}
|
||||
|
||||
/* join hooks — match your exact buttons and href */
|
||||
(function hookJoin(){
|
||||
const candidates=[
|
||||
'#join-btn', '#spectate-btn',
|
||||
'a[href="#Join"]','a[href="#join"]',
|
||||
'a.button[href="#About"]','#join','[data-join]','.join','button.join'
|
||||
];
|
||||
for(const sel of candidates){
|
||||
const el=document.querySelector(sel);
|
||||
if(el){
|
||||
el.addEventListener("click",(e)=>{
|
||||
e.preventDefault();
|
||||
if(el.id === "spectate-btn"){
|
||||
startSpectate();
|
||||
setStatus("Spectating…");
|
||||
}else{
|
||||
startPlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
addEventListener("keydown",(e)=>{ if(e.code==="Enter" && !playMode) startPlay(); });
|
||||
})();
|
||||
|
||||
/* spectator connect on boot */
|
||||
const defaultSpectatorName = `Viewer${Math.floor((Math.random()*9000)+1000)}`;
|
||||
connect("spectator", defaultSpectatorName);
|
||||
|
||||
/* loop */
|
||||
const clock=new THREE.Clock(); let active=true;
|
||||
addEventListener("visibilitychange",()=>{ active=document.visibilityState==="visible"; if(active) requestAnimationFrame(animate); });
|
||||
requestAnimationFrame(()=>{ animate(); canvas.style.opacity="1"; });
|
||||
|
||||
let fpsAccum=0,fpsCount=0,scaleCooldown=0;
|
||||
function animate(){
|
||||
if(!active) return;
|
||||
const dt=Math.min(0.05, clock.getDelta()); const now=performance.now();
|
||||
if(mixer) mixer.update(dt);
|
||||
if(playMode) updateFPS(dt);
|
||||
if(spectateMode) updateFreecam(dt);
|
||||
|
||||
// smooth remote players and update 2D labels
|
||||
players.forEach(({group,target,rotY,labelEl})=>{
|
||||
const k=1 - Math.pow(0.0001, dt*60);
|
||||
group.position.lerp(target,k);
|
||||
group.rotation.y += (rotY - group.rotation.y)*k;
|
||||
|
||||
const headWorld = new THREE.Vector3(
|
||||
group.position.x,
|
||||
group.position.y + SPRITE_HEIGHT + NAME_PAD,
|
||||
group.position.z
|
||||
);
|
||||
updateLabelPosition(labelEl, headWorld);
|
||||
});
|
||||
|
||||
perFrame.forEach((fn)=>fn(dt));
|
||||
|
||||
renderer.setRenderTarget(rt); postMat.uniforms.tDiffuse.value=null; renderer.clear(); renderer.render(scene,camera); renderer.setRenderTarget(null);
|
||||
postMat.uniforms.tDiffuse.value=rt.texture; postMat.uniforms.uTime.value += dt; renderer.render(postScene,postCam);
|
||||
|
||||
fpsAccum += dt; fpsCount++;
|
||||
if(now - scaleCooldown > 1000){
|
||||
const avg=fpsAccum/Math.max(1,fpsCount);
|
||||
if(avg>0.03 && RENDER_SCALE<6){ RENDER_SCALE+=0.5; allocRT(); }
|
||||
else if(avg<0.017 && RENDER_SCALE>2){ RENDER_SCALE-=0.5; allocRT(); }
|
||||
fpsAccum=0; fpsCount=0; scaleCooldown=now;
|
||||
}
|
||||
|
||||
if(currentRole==="player" && ws && ws.readyState===1 && now - lastSend >= SEND_RATE_MS){
|
||||
lastSend=now; const p=controls.getObject().position; send({type:"state", pos:[p.x,p.y,p.z], rotY:camera.rotation.y});
|
||||
}
|
||||
|
||||
if(!playMode && !spectateMode) updateCameraHover(dt);
|
||||
requestAnimationFrame(animate);
|
||||
}
|
||||
|
||||
/* resize */
|
||||
addEventListener("resize",()=>{
|
||||
camera.aspect=innerWidth/innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
allocRT();
|
||||
patchedMaterials.forEach((m)=>{
|
||||
const u = ps1Uniforms.get(m);
|
||||
if(u?.uResolution?.value){ u.uResolution.value.set(innerWidth, innerHeight); }
|
||||
});
|
||||
});
|
8
World-SEPPJM-Client/frontend/src/main.js
Normal file
8
World-SEPPJM-Client/frontend/src/main.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import './style.css'
|
||||
import App from './App.svelte'
|
||||
|
||||
const app = new App({
|
||||
target: document.getElementById('app')
|
||||
})
|
||||
|
||||
export default app
|
3
World-SEPPJM-Client/frontend/src/style.css
Normal file
3
World-SEPPJM-Client/frontend/src/style.css
Normal file
File diff suppressed because one or more lines are too long
2
World-SEPPJM-Client/frontend/src/vite-env.d.ts
vendored
Normal file
2
World-SEPPJM-Client/frontend/src/vite-env.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
/// <reference types="svelte" />
|
||||
/// <reference types="vite/client" />
|
7
World-SEPPJM-Client/frontend/vite.config.js
Normal file
7
World-SEPPJM-Client/frontend/vite.config.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import {defineConfig} from 'vite'
|
||||
import {svelte} from '@sveltejs/vite-plugin-svelte'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [svelte()]
|
||||
})
|
4
World-SEPPJM-Client/frontend/wailsjs/go/main/App.d.ts
vendored
Normal file
4
World-SEPPJM-Client/frontend/wailsjs/go/main/App.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function Greet(arg1:string):Promise<string>;
|
7
World-SEPPJM-Client/frontend/wailsjs/go/main/App.js
Normal file
7
World-SEPPJM-Client/frontend/wailsjs/go/main/App.js
Normal file
@@ -0,0 +1,7 @@
|
||||
// @ts-check
|
||||
// Cynhyrchwyd y ffeil hon yn awtomatig. PEIDIWCH Â MODIWL
|
||||
// This file is automatically generated. DO NOT EDIT
|
||||
|
||||
export function Greet(arg1) {
|
||||
return window['go']['main']['App']['Greet'](arg1);
|
||||
}
|
24
World-SEPPJM-Client/frontend/wailsjs/runtime/package.json
Normal file
24
World-SEPPJM-Client/frontend/wailsjs/runtime/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "@wailsapp/runtime",
|
||||
"version": "2.0.0",
|
||||
"description": "Wails Javascript runtime library",
|
||||
"main": "runtime.js",
|
||||
"types": "runtime.d.ts",
|
||||
"scripts": {
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/wailsapp/wails.git"
|
||||
},
|
||||
"keywords": [
|
||||
"Wails",
|
||||
"Javascript",
|
||||
"Go"
|
||||
],
|
||||
"author": "Lea Anthony <lea.anthony@gmail.com>",
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/wailsapp/wails/issues"
|
||||
},
|
||||
"homepage": "https://github.com/wailsapp/wails#readme"
|
||||
}
|
249
World-SEPPJM-Client/frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file
249
World-SEPPJM-Client/frontend/wailsjs/runtime/runtime.d.ts
vendored
Normal file
@@ -0,0 +1,249 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
export interface Position {
|
||||
x: number;
|
||||
y: number;
|
||||
}
|
||||
|
||||
export interface Size {
|
||||
w: number;
|
||||
h: number;
|
||||
}
|
||||
|
||||
export interface Screen {
|
||||
isCurrent: boolean;
|
||||
isPrimary: boolean;
|
||||
width : number
|
||||
height : number
|
||||
}
|
||||
|
||||
// Environment information such as platform, buildtype, ...
|
||||
export interface EnvironmentInfo {
|
||||
buildType: string;
|
||||
platform: string;
|
||||
arch: string;
|
||||
}
|
||||
|
||||
// [EventsEmit](https://wails.io/docs/reference/runtime/events#eventsemit)
|
||||
// emits the given event. Optional data may be passed with the event.
|
||||
// This will trigger any event listeners.
|
||||
export function EventsEmit(eventName: string, ...data: any): void;
|
||||
|
||||
// [EventsOn](https://wails.io/docs/reference/runtime/events#eventson) sets up a listener for the given event name.
|
||||
export function EventsOn(eventName: string, callback: (...data: any) => void): () => void;
|
||||
|
||||
// [EventsOnMultiple](https://wails.io/docs/reference/runtime/events#eventsonmultiple)
|
||||
// sets up a listener for the given event name, but will only trigger a given number times.
|
||||
export function EventsOnMultiple(eventName: string, callback: (...data: any) => void, maxCallbacks: number): () => void;
|
||||
|
||||
// [EventsOnce](https://wails.io/docs/reference/runtime/events#eventsonce)
|
||||
// sets up a listener for the given event name, but will only trigger once.
|
||||
export function EventsOnce(eventName: string, callback: (...data: any) => void): () => void;
|
||||
|
||||
// [EventsOff](https://wails.io/docs/reference/runtime/events#eventsoff)
|
||||
// unregisters the listener for the given event name.
|
||||
export function EventsOff(eventName: string, ...additionalEventNames: string[]): void;
|
||||
|
||||
// [EventsOffAll](https://wails.io/docs/reference/runtime/events#eventsoffall)
|
||||
// unregisters all listeners.
|
||||
export function EventsOffAll(): void;
|
||||
|
||||
// [LogPrint](https://wails.io/docs/reference/runtime/log#logprint)
|
||||
// logs the given message as a raw message
|
||||
export function LogPrint(message: string): void;
|
||||
|
||||
// [LogTrace](https://wails.io/docs/reference/runtime/log#logtrace)
|
||||
// logs the given message at the `trace` log level.
|
||||
export function LogTrace(message: string): void;
|
||||
|
||||
// [LogDebug](https://wails.io/docs/reference/runtime/log#logdebug)
|
||||
// logs the given message at the `debug` log level.
|
||||
export function LogDebug(message: string): void;
|
||||
|
||||
// [LogError](https://wails.io/docs/reference/runtime/log#logerror)
|
||||
// logs the given message at the `error` log level.
|
||||
export function LogError(message: string): void;
|
||||
|
||||
// [LogFatal](https://wails.io/docs/reference/runtime/log#logfatal)
|
||||
// logs the given message at the `fatal` log level.
|
||||
// The application will quit after calling this method.
|
||||
export function LogFatal(message: string): void;
|
||||
|
||||
// [LogInfo](https://wails.io/docs/reference/runtime/log#loginfo)
|
||||
// logs the given message at the `info` log level.
|
||||
export function LogInfo(message: string): void;
|
||||
|
||||
// [LogWarning](https://wails.io/docs/reference/runtime/log#logwarning)
|
||||
// logs the given message at the `warning` log level.
|
||||
export function LogWarning(message: string): void;
|
||||
|
||||
// [WindowReload](https://wails.io/docs/reference/runtime/window#windowreload)
|
||||
// Forces a reload by the main application as well as connected browsers.
|
||||
export function WindowReload(): void;
|
||||
|
||||
// [WindowReloadApp](https://wails.io/docs/reference/runtime/window#windowreloadapp)
|
||||
// Reloads the application frontend.
|
||||
export function WindowReloadApp(): void;
|
||||
|
||||
// [WindowSetAlwaysOnTop](https://wails.io/docs/reference/runtime/window#windowsetalwaysontop)
|
||||
// Sets the window AlwaysOnTop or not on top.
|
||||
export function WindowSetAlwaysOnTop(b: boolean): void;
|
||||
|
||||
// [WindowSetSystemDefaultTheme](https://wails.io/docs/next/reference/runtime/window#windowsetsystemdefaulttheme)
|
||||
// *Windows only*
|
||||
// Sets window theme to system default (dark/light).
|
||||
export function WindowSetSystemDefaultTheme(): void;
|
||||
|
||||
// [WindowSetLightTheme](https://wails.io/docs/next/reference/runtime/window#windowsetlighttheme)
|
||||
// *Windows only*
|
||||
// Sets window to light theme.
|
||||
export function WindowSetLightTheme(): void;
|
||||
|
||||
// [WindowSetDarkTheme](https://wails.io/docs/next/reference/runtime/window#windowsetdarktheme)
|
||||
// *Windows only*
|
||||
// Sets window to dark theme.
|
||||
export function WindowSetDarkTheme(): void;
|
||||
|
||||
// [WindowCenter](https://wails.io/docs/reference/runtime/window#windowcenter)
|
||||
// Centers the window on the monitor the window is currently on.
|
||||
export function WindowCenter(): void;
|
||||
|
||||
// [WindowSetTitle](https://wails.io/docs/reference/runtime/window#windowsettitle)
|
||||
// Sets the text in the window title bar.
|
||||
export function WindowSetTitle(title: string): void;
|
||||
|
||||
// [WindowFullscreen](https://wails.io/docs/reference/runtime/window#windowfullscreen)
|
||||
// Makes the window full screen.
|
||||
export function WindowFullscreen(): void;
|
||||
|
||||
// [WindowUnfullscreen](https://wails.io/docs/reference/runtime/window#windowunfullscreen)
|
||||
// Restores the previous window dimensions and position prior to full screen.
|
||||
export function WindowUnfullscreen(): void;
|
||||
|
||||
// [WindowIsFullscreen](https://wails.io/docs/reference/runtime/window#windowisfullscreen)
|
||||
// Returns the state of the window, i.e. whether the window is in full screen mode or not.
|
||||
export function WindowIsFullscreen(): Promise<boolean>;
|
||||
|
||||
// [WindowSetSize](https://wails.io/docs/reference/runtime/window#windowsetsize)
|
||||
// Sets the width and height of the window.
|
||||
export function WindowSetSize(width: number, height: number): void;
|
||||
|
||||
// [WindowGetSize](https://wails.io/docs/reference/runtime/window#windowgetsize)
|
||||
// Gets the width and height of the window.
|
||||
export function WindowGetSize(): Promise<Size>;
|
||||
|
||||
// [WindowSetMaxSize](https://wails.io/docs/reference/runtime/window#windowsetmaxsize)
|
||||
// Sets the maximum window size. Will resize the window if the window is currently larger than the given dimensions.
|
||||
// Setting a size of 0,0 will disable this constraint.
|
||||
export function WindowSetMaxSize(width: number, height: number): void;
|
||||
|
||||
// [WindowSetMinSize](https://wails.io/docs/reference/runtime/window#windowsetminsize)
|
||||
// Sets the minimum window size. Will resize the window if the window is currently smaller than the given dimensions.
|
||||
// Setting a size of 0,0 will disable this constraint.
|
||||
export function WindowSetMinSize(width: number, height: number): void;
|
||||
|
||||
// [WindowSetPosition](https://wails.io/docs/reference/runtime/window#windowsetposition)
|
||||
// Sets the window position relative to the monitor the window is currently on.
|
||||
export function WindowSetPosition(x: number, y: number): void;
|
||||
|
||||
// [WindowGetPosition](https://wails.io/docs/reference/runtime/window#windowgetposition)
|
||||
// Gets the window position relative to the monitor the window is currently on.
|
||||
export function WindowGetPosition(): Promise<Position>;
|
||||
|
||||
// [WindowHide](https://wails.io/docs/reference/runtime/window#windowhide)
|
||||
// Hides the window.
|
||||
export function WindowHide(): void;
|
||||
|
||||
// [WindowShow](https://wails.io/docs/reference/runtime/window#windowshow)
|
||||
// Shows the window, if it is currently hidden.
|
||||
export function WindowShow(): void;
|
||||
|
||||
// [WindowMaximise](https://wails.io/docs/reference/runtime/window#windowmaximise)
|
||||
// Maximises the window to fill the screen.
|
||||
export function WindowMaximise(): void;
|
||||
|
||||
// [WindowToggleMaximise](https://wails.io/docs/reference/runtime/window#windowtogglemaximise)
|
||||
// Toggles between Maximised and UnMaximised.
|
||||
export function WindowToggleMaximise(): void;
|
||||
|
||||
// [WindowUnmaximise](https://wails.io/docs/reference/runtime/window#windowunmaximise)
|
||||
// Restores the window to the dimensions and position prior to maximising.
|
||||
export function WindowUnmaximise(): void;
|
||||
|
||||
// [WindowIsMaximised](https://wails.io/docs/reference/runtime/window#windowismaximised)
|
||||
// Returns the state of the window, i.e. whether the window is maximised or not.
|
||||
export function WindowIsMaximised(): Promise<boolean>;
|
||||
|
||||
// [WindowMinimise](https://wails.io/docs/reference/runtime/window#windowminimise)
|
||||
// Minimises the window.
|
||||
export function WindowMinimise(): void;
|
||||
|
||||
// [WindowUnminimise](https://wails.io/docs/reference/runtime/window#windowunminimise)
|
||||
// Restores the window to the dimensions and position prior to minimising.
|
||||
export function WindowUnminimise(): void;
|
||||
|
||||
// [WindowIsMinimised](https://wails.io/docs/reference/runtime/window#windowisminimised)
|
||||
// Returns the state of the window, i.e. whether the window is minimised or not.
|
||||
export function WindowIsMinimised(): Promise<boolean>;
|
||||
|
||||
// [WindowIsNormal](https://wails.io/docs/reference/runtime/window#windowisnormal)
|
||||
// Returns the state of the window, i.e. whether the window is normal or not.
|
||||
export function WindowIsNormal(): Promise<boolean>;
|
||||
|
||||
// [WindowSetBackgroundColour](https://wails.io/docs/reference/runtime/window#windowsetbackgroundcolour)
|
||||
// Sets the background colour of the window to the given RGBA colour definition. This colour will show through for all transparent pixels.
|
||||
export function WindowSetBackgroundColour(R: number, G: number, B: number, A: number): void;
|
||||
|
||||
// [ScreenGetAll](https://wails.io/docs/reference/runtime/window#screengetall)
|
||||
// Gets the all screens. Call this anew each time you want to refresh data from the underlying windowing system.
|
||||
export function ScreenGetAll(): Promise<Screen[]>;
|
||||
|
||||
// [BrowserOpenURL](https://wails.io/docs/reference/runtime/browser#browseropenurl)
|
||||
// Opens the given URL in the system browser.
|
||||
export function BrowserOpenURL(url: string): void;
|
||||
|
||||
// [Environment](https://wails.io/docs/reference/runtime/intro#environment)
|
||||
// Returns information about the environment
|
||||
export function Environment(): Promise<EnvironmentInfo>;
|
||||
|
||||
// [Quit](https://wails.io/docs/reference/runtime/intro#quit)
|
||||
// Quits the application.
|
||||
export function Quit(): void;
|
||||
|
||||
// [Hide](https://wails.io/docs/reference/runtime/intro#hide)
|
||||
// Hides the application.
|
||||
export function Hide(): void;
|
||||
|
||||
// [Show](https://wails.io/docs/reference/runtime/intro#show)
|
||||
// Shows the application.
|
||||
export function Show(): void;
|
||||
|
||||
// [ClipboardGetText](https://wails.io/docs/reference/runtime/clipboard#clipboardgettext)
|
||||
// Returns the current text stored on clipboard
|
||||
export function ClipboardGetText(): Promise<string>;
|
||||
|
||||
// [ClipboardSetText](https://wails.io/docs/reference/runtime/clipboard#clipboardsettext)
|
||||
// Sets a text on the clipboard
|
||||
export function ClipboardSetText(text: string): Promise<boolean>;
|
||||
|
||||
// [OnFileDrop](https://wails.io/docs/reference/runtime/draganddrop#onfiledrop)
|
||||
// OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||
export function OnFileDrop(callback: (x: number, y: number ,paths: string[]) => void, useDropTarget: boolean) :void
|
||||
|
||||
// [OnFileDropOff](https://wails.io/docs/reference/runtime/draganddrop#dragandddropoff)
|
||||
// OnFileDropOff removes the drag and drop listeners and handlers.
|
||||
export function OnFileDropOff() :void
|
||||
|
||||
// Check if the file path resolver is available
|
||||
export function CanResolveFilePaths(): boolean;
|
||||
|
||||
// Resolves file paths for an array of files
|
||||
export function ResolveFilePaths(files: File[]): void
|
238
World-SEPPJM-Client/frontend/wailsjs/runtime/runtime.js
Normal file
238
World-SEPPJM-Client/frontend/wailsjs/runtime/runtime.js
Normal file
@@ -0,0 +1,238 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
export function LogPrint(message) {
|
||||
window.runtime.LogPrint(message);
|
||||
}
|
||||
|
||||
export function LogTrace(message) {
|
||||
window.runtime.LogTrace(message);
|
||||
}
|
||||
|
||||
export function LogDebug(message) {
|
||||
window.runtime.LogDebug(message);
|
||||
}
|
||||
|
||||
export function LogInfo(message) {
|
||||
window.runtime.LogInfo(message);
|
||||
}
|
||||
|
||||
export function LogWarning(message) {
|
||||
window.runtime.LogWarning(message);
|
||||
}
|
||||
|
||||
export function LogError(message) {
|
||||
window.runtime.LogError(message);
|
||||
}
|
||||
|
||||
export function LogFatal(message) {
|
||||
window.runtime.LogFatal(message);
|
||||
}
|
||||
|
||||
export function EventsOnMultiple(eventName, callback, maxCallbacks) {
|
||||
return window.runtime.EventsOnMultiple(eventName, callback, maxCallbacks);
|
||||
}
|
||||
|
||||
export function EventsOn(eventName, callback) {
|
||||
return EventsOnMultiple(eventName, callback, -1);
|
||||
}
|
||||
|
||||
export function EventsOff(eventName, ...additionalEventNames) {
|
||||
return window.runtime.EventsOff(eventName, ...additionalEventNames);
|
||||
}
|
||||
|
||||
export function EventsOnce(eventName, callback) {
|
||||
return EventsOnMultiple(eventName, callback, 1);
|
||||
}
|
||||
|
||||
export function EventsEmit(eventName) {
|
||||
let args = [eventName].slice.call(arguments);
|
||||
return window.runtime.EventsEmit.apply(null, args);
|
||||
}
|
||||
|
||||
export function WindowReload() {
|
||||
window.runtime.WindowReload();
|
||||
}
|
||||
|
||||
export function WindowReloadApp() {
|
||||
window.runtime.WindowReloadApp();
|
||||
}
|
||||
|
||||
export function WindowSetAlwaysOnTop(b) {
|
||||
window.runtime.WindowSetAlwaysOnTop(b);
|
||||
}
|
||||
|
||||
export function WindowSetSystemDefaultTheme() {
|
||||
window.runtime.WindowSetSystemDefaultTheme();
|
||||
}
|
||||
|
||||
export function WindowSetLightTheme() {
|
||||
window.runtime.WindowSetLightTheme();
|
||||
}
|
||||
|
||||
export function WindowSetDarkTheme() {
|
||||
window.runtime.WindowSetDarkTheme();
|
||||
}
|
||||
|
||||
export function WindowCenter() {
|
||||
window.runtime.WindowCenter();
|
||||
}
|
||||
|
||||
export function WindowSetTitle(title) {
|
||||
window.runtime.WindowSetTitle(title);
|
||||
}
|
||||
|
||||
export function WindowFullscreen() {
|
||||
window.runtime.WindowFullscreen();
|
||||
}
|
||||
|
||||
export function WindowUnfullscreen() {
|
||||
window.runtime.WindowUnfullscreen();
|
||||
}
|
||||
|
||||
export function WindowIsFullscreen() {
|
||||
return window.runtime.WindowIsFullscreen();
|
||||
}
|
||||
|
||||
export function WindowGetSize() {
|
||||
return window.runtime.WindowGetSize();
|
||||
}
|
||||
|
||||
export function WindowSetSize(width, height) {
|
||||
window.runtime.WindowSetSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetMaxSize(width, height) {
|
||||
window.runtime.WindowSetMaxSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetMinSize(width, height) {
|
||||
window.runtime.WindowSetMinSize(width, height);
|
||||
}
|
||||
|
||||
export function WindowSetPosition(x, y) {
|
||||
window.runtime.WindowSetPosition(x, y);
|
||||
}
|
||||
|
||||
export function WindowGetPosition() {
|
||||
return window.runtime.WindowGetPosition();
|
||||
}
|
||||
|
||||
export function WindowHide() {
|
||||
window.runtime.WindowHide();
|
||||
}
|
||||
|
||||
export function WindowShow() {
|
||||
window.runtime.WindowShow();
|
||||
}
|
||||
|
||||
export function WindowMaximise() {
|
||||
window.runtime.WindowMaximise();
|
||||
}
|
||||
|
||||
export function WindowToggleMaximise() {
|
||||
window.runtime.WindowToggleMaximise();
|
||||
}
|
||||
|
||||
export function WindowUnmaximise() {
|
||||
window.runtime.WindowUnmaximise();
|
||||
}
|
||||
|
||||
export function WindowIsMaximised() {
|
||||
return window.runtime.WindowIsMaximised();
|
||||
}
|
||||
|
||||
export function WindowMinimise() {
|
||||
window.runtime.WindowMinimise();
|
||||
}
|
||||
|
||||
export function WindowUnminimise() {
|
||||
window.runtime.WindowUnminimise();
|
||||
}
|
||||
|
||||
export function WindowSetBackgroundColour(R, G, B, A) {
|
||||
window.runtime.WindowSetBackgroundColour(R, G, B, A);
|
||||
}
|
||||
|
||||
export function ScreenGetAll() {
|
||||
return window.runtime.ScreenGetAll();
|
||||
}
|
||||
|
||||
export function WindowIsMinimised() {
|
||||
return window.runtime.WindowIsMinimised();
|
||||
}
|
||||
|
||||
export function WindowIsNormal() {
|
||||
return window.runtime.WindowIsNormal();
|
||||
}
|
||||
|
||||
export function BrowserOpenURL(url) {
|
||||
window.runtime.BrowserOpenURL(url);
|
||||
}
|
||||
|
||||
export function Environment() {
|
||||
return window.runtime.Environment();
|
||||
}
|
||||
|
||||
export function Quit() {
|
||||
window.runtime.Quit();
|
||||
}
|
||||
|
||||
export function Hide() {
|
||||
window.runtime.Hide();
|
||||
}
|
||||
|
||||
export function Show() {
|
||||
window.runtime.Show();
|
||||
}
|
||||
|
||||
export function ClipboardGetText() {
|
||||
return window.runtime.ClipboardGetText();
|
||||
}
|
||||
|
||||
export function ClipboardSetText(text) {
|
||||
return window.runtime.ClipboardSetText(text);
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||
*
|
||||
* @export
|
||||
* @callback OnFileDropCallback
|
||||
* @param {number} x - x coordinate of the drop
|
||||
* @param {number} y - y coordinate of the drop
|
||||
* @param {string[]} paths - A list of file paths.
|
||||
*/
|
||||
|
||||
/**
|
||||
* OnFileDrop listens to drag and drop events and calls the callback with the coordinates of the drop and an array of path strings.
|
||||
*
|
||||
* @export
|
||||
* @param {OnFileDropCallback} callback - Callback for OnFileDrop returns a slice of file path strings when a drop is finished.
|
||||
* @param {boolean} [useDropTarget=true] - Only call the callback when the drop finished on an element that has the drop target style. (--wails-drop-target)
|
||||
*/
|
||||
export function OnFileDrop(callback, useDropTarget) {
|
||||
return window.runtime.OnFileDrop(callback, useDropTarget);
|
||||
}
|
||||
|
||||
/**
|
||||
* OnFileDropOff removes the drag and drop listeners and handlers.
|
||||
*/
|
||||
export function OnFileDropOff() {
|
||||
return window.runtime.OnFileDropOff();
|
||||
}
|
||||
|
||||
export function CanResolveFilePaths() {
|
||||
return window.runtime.CanResolveFilePaths();
|
||||
}
|
||||
|
||||
export function ResolveFilePaths(files) {
|
||||
return window.runtime.ResolveFilePaths(files);
|
||||
}
|
Reference in New Issue
Block a user