pixospritz-core 0.10.1 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -286
- package/dist/bundle.js +13 -3
- package/dist/bundle.js.map +1 -1
- package/dist/style.css +1 -0
- package/package.json +43 -44
- package/src/components/WebGLView.jsx +318 -0
- package/src/css/pixos.css +372 -0
- package/src/engine/actions/animate.js +41 -0
- package/src/engine/actions/changezone.js +135 -0
- package/src/engine/actions/chat.js +109 -0
- package/src/engine/actions/dialogue.js +90 -0
- package/src/engine/actions/face.js +22 -0
- package/src/engine/actions/greeting.js +28 -0
- package/src/engine/actions/interact.js +86 -0
- package/src/engine/actions/move.js +67 -0
- package/src/engine/actions/patrol.js +109 -0
- package/src/engine/actions/prompt.js +185 -0
- package/src/engine/actions/script.js +42 -0
- package/src/engine/core/audio/AudioSystem.js +543 -0
- package/src/engine/core/cutscene/PxcPlayer.js +956 -0
- package/src/engine/core/cutscene/manager.js +243 -0
- package/src/engine/core/database/index.js +75 -0
- package/src/engine/core/debug/index.js +371 -0
- package/src/engine/core/hud/index.js +765 -0
- package/src/engine/core/index.js +540 -0
- package/src/engine/core/input/gamepad/Controller.js +71 -0
- package/src/engine/core/input/gamepad/ControllerButtons.js +231 -0
- package/src/engine/core/input/gamepad/ControllerStick.js +173 -0
- package/src/engine/core/input/gamepad/index.js +592 -0
- package/src/engine/core/input/keyboard.js +196 -0
- package/src/engine/core/input/manager.js +485 -0
- package/src/engine/core/input/mouse.js +203 -0
- package/src/engine/core/input/touch.js +175 -0
- package/src/engine/core/mode/manager.js +199 -0
- package/src/engine/core/net/manager.js +535 -0
- package/src/engine/core/queue/action.js +83 -0
- package/src/engine/core/queue/event.js +82 -0
- package/src/engine/core/queue/index.js +44 -0
- package/src/engine/core/queue/loadable.js +33 -0
- package/src/engine/core/render/CameraEffects.js +494 -0
- package/src/engine/core/render/FrustumCuller.js +417 -0
- package/src/engine/core/render/LODManager.js +285 -0
- package/src/engine/core/render/ParticleManager.js +529 -0
- package/src/engine/core/render/TextureAtlas.js +465 -0
- package/src/engine/core/render/camera.js +338 -0
- package/src/engine/core/render/light.js +197 -0
- package/src/engine/core/render/manager.js +1079 -0
- package/src/engine/core/render/shaders.js +110 -0
- package/src/engine/core/render/skybox.js +342 -0
- package/src/engine/core/resource/manager.js +133 -0
- package/src/engine/core/resource/object.js +611 -0
- package/src/engine/core/resource/texture.js +103 -0
- package/src/engine/core/resource/tileset.js +177 -0
- package/src/engine/core/scene/avatar.js +215 -0
- package/src/engine/core/scene/speech.js +138 -0
- package/src/engine/core/scene/sprite.js +702 -0
- package/src/engine/core/scene/spritz.js +189 -0
- package/src/engine/core/scene/world.js +681 -0
- package/src/engine/core/scene/zone.js +1167 -0
- package/src/engine/core/store/index.js +110 -0
- package/src/engine/dynamic/animatedSprite.js +64 -0
- package/src/engine/dynamic/animatedTile.js +98 -0
- package/src/engine/dynamic/avatar.js +110 -0
- package/src/engine/dynamic/map.js +174 -0
- package/src/engine/dynamic/sprite.js +255 -0
- package/src/engine/dynamic/spritz.js +119 -0
- package/src/engine/events/EventSystem.js +609 -0
- package/src/engine/events/camera.js +142 -0
- package/src/engine/events/chat.js +75 -0
- package/src/engine/events/menu.js +186 -0
- package/src/engine/scripting/CallbackManager.js +514 -0
- package/src/engine/scripting/PixoScriptInterpreter.js +81 -0
- package/src/engine/scripting/PixoScriptLibrary.js +704 -0
- package/src/engine/shaders/effects/index.js +450 -0
- package/src/engine/shaders/fs.js +222 -0
- package/src/engine/shaders/particles/fs.js +41 -0
- package/src/engine/shaders/particles/vs.js +61 -0
- package/src/engine/shaders/picker/fs.js +34 -0
- package/src/engine/shaders/picker/init.js +62 -0
- package/src/engine/shaders/picker/vs.js +42 -0
- package/src/engine/shaders/pxsl/README.md +250 -0
- package/src/engine/shaders/pxsl/index.js +25 -0
- package/src/engine/shaders/pxsl/library.js +608 -0
- package/src/engine/shaders/pxsl/manager.js +338 -0
- package/src/engine/shaders/pxsl/specification.js +363 -0
- package/src/engine/shaders/pxsl/transpiler.js +753 -0
- package/src/engine/shaders/skybox/cosmic/fs.js +147 -0
- package/src/engine/shaders/skybox/cosmic/vs.js +23 -0
- package/src/engine/shaders/skybox/matrix/fs.js +127 -0
- package/src/engine/shaders/skybox/matrix/vs.js +23 -0
- package/src/engine/shaders/skybox/morning/fs.js +109 -0
- package/src/engine/shaders/skybox/morning/vs.js +23 -0
- package/src/engine/shaders/skybox/neon/fs.js +119 -0
- package/src/engine/shaders/skybox/neon/vs.js +23 -0
- package/src/engine/shaders/skybox/sky/fs.js +114 -0
- package/src/engine/shaders/skybox/sky/vs.js +23 -0
- package/src/engine/shaders/skybox/sunset/fs.js +101 -0
- package/src/engine/shaders/skybox/sunset/vs.js +23 -0
- package/src/engine/shaders/transition/blur/fs.js +42 -0
- package/src/engine/shaders/transition/blur/vs.js +26 -0
- package/src/engine/shaders/transition/cross/fs.js +36 -0
- package/src/engine/shaders/transition/cross/vs.js +26 -0
- package/src/engine/shaders/transition/crossBlur/fs.js +41 -0
- package/src/engine/shaders/transition/crossBlur/vs.js +25 -0
- package/src/engine/shaders/transition/dissolve/fs.js +78 -0
- package/src/engine/shaders/transition/dissolve/vs.js +24 -0
- package/src/engine/shaders/transition/fade/fs.js +31 -0
- package/src/engine/shaders/transition/fade/vs.js +27 -0
- package/src/engine/shaders/transition/iris/fs.js +52 -0
- package/src/engine/shaders/transition/iris/vs.js +24 -0
- package/src/engine/shaders/transition/pixelate/fs.js +44 -0
- package/src/engine/shaders/transition/pixelate/vs.js +24 -0
- package/src/engine/shaders/transition/slide/fs.js +53 -0
- package/src/engine/shaders/transition/slide/vs.js +24 -0
- package/src/engine/shaders/transition/swirl/fs.js +39 -0
- package/src/engine/shaders/transition/swirl/vs.js +26 -0
- package/src/engine/shaders/transition/wipe/fs.js +50 -0
- package/src/engine/shaders/transition/wipe/vs.js +24 -0
- package/src/engine/shaders/vs.js +60 -0
- package/src/engine/utils/CameraController.js +506 -0
- package/src/engine/utils/ObjHelper.js +551 -0
- package/src/engine/utils/debug-logger.js +110 -0
- package/src/engine/utils/enums.js +305 -0
- package/src/engine/utils/generator.js +156 -0
- package/src/engine/utils/index.js +21 -0
- package/src/engine/utils/loaders/ActionLoader.js +77 -0
- package/src/engine/utils/loaders/AudioLoader.js +157 -0
- package/src/engine/utils/loaders/EventLoader.js +66 -0
- package/src/engine/utils/loaders/ObjectLoader.js +67 -0
- package/src/engine/utils/loaders/SpriteLoader.js +77 -0
- package/src/engine/utils/loaders/TilesetLoader.js +103 -0
- package/src/engine/utils/loaders/index.js +21 -0
- package/src/engine/utils/math/matrix4.js +367 -0
- package/src/engine/utils/math/vector.js +458 -0
- package/src/engine/utils/obj/_old_js/index.js +46 -0
- package/src/engine/utils/obj/_old_js/layout.js +308 -0
- package/src/engine/utils/obj/_old_js/material.js +711 -0
- package/src/engine/utils/obj/_old_js/mesh.js +761 -0
- package/src/engine/utils/obj/_old_js/utils.js +647 -0
- package/src/engine/utils/obj/index.js +24 -0
- package/src/engine/utils/obj/js/index.js +277 -0
- package/src/engine/utils/obj/js/loader.js +232 -0
- package/src/engine/utils/obj/layout.js +246 -0
- package/src/engine/utils/obj/material.js +665 -0
- package/src/engine/utils/obj/mesh.js +657 -0
- package/src/engine/utils/obj/ts/index.ts +72 -0
- package/src/engine/utils/obj/ts/layout.ts +265 -0
- package/src/engine/utils/obj/ts/material.ts +760 -0
- package/src/engine/utils/obj/ts/mesh.ts +785 -0
- package/src/engine/utils/obj/ts/utils.ts +501 -0
- package/src/engine/utils/obj/utils.js +428 -0
- package/src/engine/utils/resources.js +18 -0
- package/src/index.jsx +55 -0
- package/src/spritz/player.js +18 -0
- package/src/spritz/readme.md +18 -0
- package/LICENSE +0 -437
- package/dist/bundle.js.LICENSE.txt +0 -31
package/dist/style.css
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
:root{--color-bg: #0a0a0f;--color-primary: #00ff88;--color-secondary: #00ccff;--color-accent: #ff0055;--color-border: #2a2a3e;--glow-primary: rgba(0, 255, 136, .5);--glow-secondary: rgba(0, 204, 255, .5)}.pixos{font-family:"Press Start 2P",Courier New,monospace;font-size:16px;width:100%;text-shadow:#000 2px 2px 0px;position:relative;align-items:center;align-content:center}.renderSurface{height:100%;left:0;position:absolute;top:0;width:100%}.materialSelector{background:#0a0a0ff2;margin:auto;position:relative;border:2px solid var(--color-border);border-radius:4px;box-shadow:0 0 20px #000c}.materialSelector tr{height:70px}.materialSelector td{background-position:0px 0px;cursor:pointer;margin:0;opacity:.5;padding:0;width:70px;transition:opacity .2s}.materialSelector td:hover{opacity:1;box-shadow:0 0 10px var(--glow-primary)}.nickname{color:var(--color-primary);cursor:default;left:42%;position:absolute;top:40%;width:300px;text-shadow:0 0 10px var(--glow-primary)}.nickname input{background:#0a0a0fcc;border-bottom:2px solid var(--color-primary);border:1px solid var(--color-border);border-radius:4px;color:var(--color-primary);font-family:"Press Start 2P",Courier New,monospace;font-size:16px;outline:none;width:100%;padding:8px;box-shadow:0 0 10px #00000080}.nickname input:focus{border-color:var(--color-primary);box-shadow:0 0 15px var(--glow-primary)}.joininfo{color:var(--color-primary);cursor:default;font-size:16px;position:absolute;text-align:center;top:42%;width:99%;text-shadow:0 0 10px var(--glow-primary)}.chatbox{background:#0a0a0ff2;border:2px solid var(--color-border);border-radius:8px;bottom:55px;color:var(--color-primary);cursor:default;height:195px;left:20px;overflow:hidden;padding:10px;position:absolute;width:600px;box-shadow:0 0 20px #000c,inset 0 0 10px #00000080}.chatbox_text{bottom:8px;position:absolute;text-shadow:none;font-size:12px;line-height:1.6}.chatbox_entry{background:#0a0a0ff2;border:2px solid var(--color-border);border-radius:4px;bottom:18px;color:var(--color-primary);font-family:"Press Start 2P",Courier New,monospace;font-size:12px;height:30px;left:20px;outline:none;padding:8px 10px;position:absolute;width:610px;box-shadow:0 0 10px #00000080}.chatbox_entry:focus{border-color:var(--color-primary);box-shadow:0 0 15px var(--glow-primary)}html{height:100%}.pixos-body{height:100%;margin:0;overflow:hidden;background:linear-gradient(to bottom,#202020,#111119)}.rain,.snow{position:absolute;left:0;width:100%;height:100%;z-index:2}.rain.back-row{z-index:1;bottom:60px;opacity:.5}.snow.back-row{z-index:1;bottom:60px;opacity:.8}body.back-row-toggle .rain.back-row .snow.back-row{display:block}.drop{position:absolute;bottom:100%;width:15px;height:120px;pointer-events:none;animation:drop .5s linear infinite}.flake{position:absolute;bottom:100%;width:24px;height:24px;pointer-events:none;animation:snow 2.5s linear infinite}@keyframes drop{0%{transform:translateY(0)}75%{transform:translateY(90vh)}to{transform:translateY(90vh)}}@keyframes snow{0%{transform:translateY(0)}70%{transform:translateY(50vh)}85%{transform:translateY(85vh)}75%{transform:translateY(75vh)}to{transform:translateY(95vh);transform:translate(30vw)}}.stem{width:1px;height:60%;margin-left:7px;background:linear-gradient(to bottom,#fff0,#ffffff40);animation:stem .5s linear infinite}@keyframes stem{0%{opacity:1}65%{opacity:1}75%{opacity:0}to{opacity:0}}.splat{width:15px;height:10px;border-top:2px dotted rgba(255,255,255,.5);border-radius:50%;opacity:1;transform:scale(0);animation:splat .5s linear infinite}body.splat-toggle .splat{display:block}@keyframes splat{0%{opacity:1;transform:scale(0)}80%{opacity:1;transform:scale(0)}90%{opacity:.5;transform:scale(1)}to{opacity:0;transform:scale(1.5)}}.toggles{position:absolute;top:0;left:0;z-index:3}.toggle{position:absolute;left:20px;width:50px;height:50px;line-height:51px;box-sizing:border-box;text-align:center;font-family:sans-serif;font-size:10px;font-weight:700;background-color:#fff3;color:#00000080;border-radius:50%;cursor:pointer;transition:background-color .3s}.toggle:hover{background-color:#ffffff40}.toggle:active{background-color:#ffffff4d}.toggle.active{background-color:#fff6}.splat-toggle{top:20px}.back-row-toggle{top:90px;line-height:12px;padding-top:14px}.single-toggle{top:160px}body.single-toggle .drop{display:none}body.single-toggle .drop:nth-child(10){display:block}
|
package/package.json
CHANGED
|
@@ -1,33 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pixospritz-core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "PixoSpritz Core Engine - WebGL-based game engine",
|
|
5
|
+
"type": "module",
|
|
5
6
|
"main": "dist/bundle.js",
|
|
7
|
+
"module": "dist/bundle.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/bundle.js",
|
|
10
|
+
"./engine/*": "./src/engine/*",
|
|
11
|
+
"./components/*": "./src/components/*",
|
|
12
|
+
"./spritz/*": "./src/spritz/*"
|
|
13
|
+
},
|
|
6
14
|
"scripts": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"start:player": "cd player && yarn start",
|
|
15
|
-
"start:editor": "cd editor && yarn start",
|
|
16
|
-
"start:server": "node server/v2/main.js",
|
|
17
|
-
"start:server:legacy": "node server/v1/main.js"
|
|
15
|
+
"clean": "rimraf dist build",
|
|
16
|
+
"build": "vite build",
|
|
17
|
+
"dev": "vite",
|
|
18
|
+
"preview": "vite preview",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"test:coverage": "vitest run --coverage"
|
|
18
22
|
},
|
|
19
23
|
"files": [
|
|
20
24
|
"dist",
|
|
25
|
+
"src",
|
|
21
26
|
"README.md"
|
|
22
27
|
],
|
|
23
28
|
"keywords": [
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"html5",
|
|
27
|
-
"game",
|
|
28
|
-
"react",
|
|
29
|
+
"pixospritz",
|
|
30
|
+
"game-engine",
|
|
29
31
|
"webgl",
|
|
30
|
-
"canvas"
|
|
32
|
+
"canvas",
|
|
33
|
+
"react"
|
|
31
34
|
],
|
|
32
35
|
"homepage": "https://pixospritz.com",
|
|
33
36
|
"repository": {
|
|
@@ -35,42 +38,38 @@
|
|
|
35
38
|
"type": "git"
|
|
36
39
|
},
|
|
37
40
|
"author": "Kyle Derby MacInnis",
|
|
38
|
-
"license": "
|
|
39
|
-
"devDependencies": {
|
|
40
|
-
"@babel/cli": "^7.17.10",
|
|
41
|
-
"@babel/core": "^7.18.0",
|
|
42
|
-
"@babel/node": "^7.17.10",
|
|
43
|
-
"@babel/preset-env": "^7.18.0",
|
|
44
|
-
"@babel/preset-react": "^7.17.12",
|
|
45
|
-
"@babel/register": "^7.17.7",
|
|
46
|
-
"babel-plugin-macros": "^3.1.0",
|
|
47
|
-
"babel-register": "^6.26.0",
|
|
48
|
-
"buffer": "^6.0.3",
|
|
49
|
-
"cross-env": "^7.0.3",
|
|
50
|
-
"react-recollect": "^5.2.3",
|
|
51
|
-
"webpack": "^5.72.1",
|
|
52
|
-
"webpack-cli": "^4.9.2",
|
|
53
|
-
"webpack-dev-server": "^4.9.0"
|
|
54
|
-
},
|
|
41
|
+
"license": "CC-BY-NC-SA-4.0",
|
|
55
42
|
"peerDependencies": {
|
|
56
43
|
"react": "^17.0.0 || ^18.0.0",
|
|
57
|
-
"react-dom": "^17.0.0 || ^18.0.0"
|
|
58
|
-
"react-recollect": "^5.2.3"
|
|
44
|
+
"react-dom": "^17.0.0 || ^18.0.0"
|
|
59
45
|
},
|
|
60
46
|
"dependencies": {
|
|
61
|
-
"babel-loader": "^8.2.5",
|
|
62
|
-
"css-loader": "^6.7.1",
|
|
63
47
|
"dexie": "^3.2.0",
|
|
64
48
|
"file-saver": "^2.0.5",
|
|
65
49
|
"gl-transition": "^1.13.0",
|
|
66
50
|
"jszip": "^3.7.1",
|
|
67
|
-
"
|
|
68
|
-
"
|
|
51
|
+
"pixoscript": "*",
|
|
52
|
+
"pixospritz-math": "*",
|
|
69
53
|
"printj": "^1.3.1",
|
|
70
54
|
"prop-types": "^15.7.2",
|
|
71
55
|
"realtime-bpm-analyzer": "^2.1.6",
|
|
56
|
+
"uuid": "^13.0.0"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@babel/cli": "^7.17.10",
|
|
60
|
+
"@babel/core": "^7.18.0",
|
|
61
|
+
"@babel/preset-env": "^7.18.0",
|
|
62
|
+
"@babel/preset-react": "^7.17.12",
|
|
63
|
+
"@testing-library/jest-dom": "^6.9.1",
|
|
64
|
+
"@testing-library/react": "^16.3.0",
|
|
65
|
+
"@testing-library/user-event": "^14.6.1",
|
|
66
|
+
"babel-loader": "^8.2.5",
|
|
67
|
+
"cross-env": "^7.0.3",
|
|
68
|
+
"css-loader": "^6.7.1",
|
|
69
|
+
"identity-obj-proxy": "^3.0.0",
|
|
70
|
+
"rimraf": "^5.0.0",
|
|
72
71
|
"style-loader": "^3.3.1",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
72
|
+
"webpack": "^5.72.1",
|
|
73
|
+
"webpack-cli": "^4.9.2"
|
|
75
74
|
}
|
|
76
75
|
}
|
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
/* *\
|
|
2
|
+
** ----------------------------------------------- **
|
|
3
|
+
** Calliope - Pixos Game Engine **
|
|
4
|
+
** ----------------------------------------------- **
|
|
5
|
+
** Copyright (c) 2020-2025 - Kyle Derby MacInnis **
|
|
6
|
+
** **
|
|
7
|
+
** Any unauthorized distribution or transfer **
|
|
8
|
+
** of this work is strictly prohibited. **
|
|
9
|
+
** **
|
|
10
|
+
** All Rights Reserved. **
|
|
11
|
+
** ----------------------------------------------- **
|
|
12
|
+
\* */
|
|
13
|
+
|
|
14
|
+
import React, { useEffect, useRef, useState } from 'react';
|
|
15
|
+
import PropTypes from 'prop-types';
|
|
16
|
+
|
|
17
|
+
import glEngine from '@Engine/core/index.js';
|
|
18
|
+
import { minecraftia } from '@Engine/core/hud/index.js';
|
|
19
|
+
//
|
|
20
|
+
const WebGLView = ({ width, height, SpritzProvider, class: string, zipData }) => {
|
|
21
|
+
// Canvas
|
|
22
|
+
const ref = useRef();
|
|
23
|
+
const hudRef = useRef();
|
|
24
|
+
const gamepadRef = useRef();
|
|
25
|
+
const fileRef = useRef();
|
|
26
|
+
const mmRef = useRef();
|
|
27
|
+
|
|
28
|
+
// keyboard & touch - use wrapper functions to guard against uninitialized engine
|
|
29
|
+
const onKeyEvent = (e) => {
|
|
30
|
+
try {
|
|
31
|
+
if (SpritzProvider && SpritzProvider.onKeyEvent) SpritzProvider.onKeyEvent(e);
|
|
32
|
+
} catch (err) {
|
|
33
|
+
// swallow until engine initialized
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Handles touch/mouse events with proper coordinate transformation.
|
|
39
|
+
* The canvas element may be scaled via CSS to fit the viewport, but its
|
|
40
|
+
* internal resolution (width/height attributes) can differ from the display
|
|
41
|
+
* size (getBoundingClientRect). This function computes the correct canvas
|
|
42
|
+
* coordinates by accounting for the scale difference and any offset.
|
|
43
|
+
*/
|
|
44
|
+
const onTouchEvent = (e) => {
|
|
45
|
+
try {
|
|
46
|
+
const canvas = hudRef.current;
|
|
47
|
+
if (!canvas) {
|
|
48
|
+
if (SpritzProvider && SpritzProvider.onTouchEvent) SpritzProvider.onTouchEvent(e);
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const rect = canvas.getBoundingClientRect();
|
|
53
|
+
|
|
54
|
+
// Handle both mouse and touch events
|
|
55
|
+
let clientX, clientY;
|
|
56
|
+
if (e.touches && e.touches.length > 0) {
|
|
57
|
+
clientX = e.touches[0].clientX;
|
|
58
|
+
clientY = e.touches[0].clientY;
|
|
59
|
+
} else if (e.changedTouches && e.changedTouches.length > 0) {
|
|
60
|
+
clientX = e.changedTouches[0].clientX;
|
|
61
|
+
clientY = e.changedTouches[0].clientY;
|
|
62
|
+
} else {
|
|
63
|
+
clientX = e.clientX;
|
|
64
|
+
clientY = e.clientY;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Calculate scale factors between internal canvas size and displayed size
|
|
68
|
+
const scaleX = canvas.width / rect.width;
|
|
69
|
+
const scaleY = canvas.height / rect.height;
|
|
70
|
+
|
|
71
|
+
// Calculate position relative to canvas with proper scaling
|
|
72
|
+
const canvasX = (clientX - rect.left) * scaleX;
|
|
73
|
+
const canvasY = (clientY - rect.top) * scaleY;
|
|
74
|
+
|
|
75
|
+
// Create adjusted event with canvas-relative coordinates
|
|
76
|
+
const adjustedEvent = {
|
|
77
|
+
...e,
|
|
78
|
+
type: e.type,
|
|
79
|
+
clientX: clientX,
|
|
80
|
+
clientY: clientY,
|
|
81
|
+
// Pre-computed canvas coordinates for the engine
|
|
82
|
+
canvasX: canvasX,
|
|
83
|
+
canvasY: canvasY,
|
|
84
|
+
pageX: canvasX + rect.left,
|
|
85
|
+
pageY: canvasY + rect.top,
|
|
86
|
+
_canvasRect: rect,
|
|
87
|
+
_scaleX: scaleX,
|
|
88
|
+
_scaleY: scaleY
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
if (SpritzProvider && SpritzProvider.onTouchEvent) {
|
|
92
|
+
SpritzProvider.onTouchEvent(adjustedEvent);
|
|
93
|
+
}
|
|
94
|
+
} catch (err) {
|
|
95
|
+
console.warn('onTouchEvent error:', err);
|
|
96
|
+
}
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
let engine = null;
|
|
100
|
+
|
|
101
|
+
// Resize
|
|
102
|
+
const [screenSize, getDimension] = useState({
|
|
103
|
+
dynamicWidth: window.innerWidth,
|
|
104
|
+
dynamicHeight: window.innerHeight,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
// window dimensions
|
|
108
|
+
const setDimension = () => {
|
|
109
|
+
getDimension({
|
|
110
|
+
dynamicWidth: window.innerWidth,
|
|
111
|
+
dynamicHeight: window.innerHeight,
|
|
112
|
+
});
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// load fonts
|
|
116
|
+
async function loadFonts() {
|
|
117
|
+
await minecraftia.load();
|
|
118
|
+
document.fonts.add(minecraftia);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function stopTouchScrolling(canvas) {
|
|
122
|
+
// Prevent scrolling when touching the canvas
|
|
123
|
+
document.body.addEventListener(
|
|
124
|
+
'touchstart',
|
|
125
|
+
function (e) {
|
|
126
|
+
if (e.target == canvas) {
|
|
127
|
+
e.preventDefault();
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
{ passive: false }
|
|
131
|
+
);
|
|
132
|
+
document.body.addEventListener(
|
|
133
|
+
'touchend',
|
|
134
|
+
function (e) {
|
|
135
|
+
if (e.target == canvas) {
|
|
136
|
+
e.preventDefault();
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
{ passive: false }
|
|
140
|
+
);
|
|
141
|
+
document.body.addEventListener(
|
|
142
|
+
'touchmove',
|
|
143
|
+
function (e) {
|
|
144
|
+
if (e.target == canvas) {
|
|
145
|
+
e.preventDefault();
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
{ passive: false }
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
useEffect(async () => {
|
|
153
|
+
// handle resize
|
|
154
|
+
window.addEventListener('resize', setDimension);
|
|
155
|
+
|
|
156
|
+
// setup canvases
|
|
157
|
+
const canvas = ref.current;
|
|
158
|
+
const hud = hudRef.current;
|
|
159
|
+
const mipmap = mmRef.current;
|
|
160
|
+
const gamepad = gamepadRef.current;
|
|
161
|
+
const fileUpload = fileRef.current;
|
|
162
|
+
|
|
163
|
+
// Webgl Engine
|
|
164
|
+
engine = new glEngine(canvas, hud, mipmap, gamepad, fileUpload, width, height);
|
|
165
|
+
|
|
166
|
+
// load fonts
|
|
167
|
+
await loadFonts();
|
|
168
|
+
|
|
169
|
+
// Initialize Spritz
|
|
170
|
+
await engine.init(SpritzProvider);
|
|
171
|
+
|
|
172
|
+
// Create ResizeObserver for proper canvas resize handling
|
|
173
|
+
let resizeObserver = null;
|
|
174
|
+
if (typeof ResizeObserver !== 'undefined') {
|
|
175
|
+
resizeObserver = new ResizeObserver((entries) => {
|
|
176
|
+
for (const entry of entries) {
|
|
177
|
+
if (entry.target === canvas || entry.target === hud) {
|
|
178
|
+
// Notify engine of resize
|
|
179
|
+
if (engine && engine.handleResize) {
|
|
180
|
+
engine.handleResize();
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
resizeObserver.observe(canvas);
|
|
186
|
+
resizeObserver.observe(hud);
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// render loop
|
|
190
|
+
engine.render();
|
|
191
|
+
|
|
192
|
+
// cleanup
|
|
193
|
+
return () => {
|
|
194
|
+
stopTouchScrolling(canvas);
|
|
195
|
+
stopTouchScrolling(gamepad);
|
|
196
|
+
stopTouchScrolling(hud);
|
|
197
|
+
window.removeEventListener('resize', setDimension);
|
|
198
|
+
if (resizeObserver) {
|
|
199
|
+
resizeObserver.disconnect();
|
|
200
|
+
}
|
|
201
|
+
engine.close();
|
|
202
|
+
};
|
|
203
|
+
}, [SpritzProvider]);
|
|
204
|
+
|
|
205
|
+
let wrapperHeight = (screenSize.dynamicWidth * 3) / 4 > 1080 ? 1080 : screenSize.dynamicHeight;
|
|
206
|
+
let canvasHeight = (screenSize.dynamicWidth * 3) / 4 > 1080 ? wrapperHeight : wrapperHeight - 200;
|
|
207
|
+
let canvasWidth = screenSize.dynamicWidth > 1920 ? 1920 : screenSize.dynamicWidth;
|
|
208
|
+
let showGamepad = screenSize.dynamicWidth <= 900;
|
|
209
|
+
let gamepadHeight = 200;
|
|
210
|
+
|
|
211
|
+
return (
|
|
212
|
+
<div style={{ marginLeft: 'auto', marginRight: 'auto' }}>
|
|
213
|
+
<div
|
|
214
|
+
style={{
|
|
215
|
+
position: 'relative',
|
|
216
|
+
padding: 'none',
|
|
217
|
+
background: 'var(--color-bg, #0a0a0f)',
|
|
218
|
+
height: canvasHeight + 'px',
|
|
219
|
+
width: canvasWidth + 'px',
|
|
220
|
+
}}
|
|
221
|
+
onKeyDownCapture={(e) => onKeyEvent(e.nativeEvent)}
|
|
222
|
+
onKeyUpCapture={(e) => onKeyEvent(e.nativeEvent)}
|
|
223
|
+
tabIndex={0}
|
|
224
|
+
>
|
|
225
|
+
{/* Game */}
|
|
226
|
+
<div>
|
|
227
|
+
{/* // WEBGL - For 3D Rendering */}
|
|
228
|
+
<canvas
|
|
229
|
+
style={{
|
|
230
|
+
position: 'absolute',
|
|
231
|
+
zIndex: 1,
|
|
232
|
+
top: 0,
|
|
233
|
+
left: 0,
|
|
234
|
+
width: '100%',
|
|
235
|
+
height: '100%',
|
|
236
|
+
}}
|
|
237
|
+
ref={ref}
|
|
238
|
+
width={canvasWidth}
|
|
239
|
+
height={canvasHeight}
|
|
240
|
+
className={string}
|
|
241
|
+
/>
|
|
242
|
+
{/* HUD - For Dialogue / Menus / Overlays */}
|
|
243
|
+
<canvas
|
|
244
|
+
style={{
|
|
245
|
+
position: 'absolute',
|
|
246
|
+
zIndex: 2,
|
|
247
|
+
top: 0,
|
|
248
|
+
left: 0,
|
|
249
|
+
background: 'none',
|
|
250
|
+
width: '100%',
|
|
251
|
+
height: '100%',
|
|
252
|
+
touchAction: 'none', // Prevent browser gestures
|
|
253
|
+
cursor: 'pointer',
|
|
254
|
+
}}
|
|
255
|
+
ref={hudRef}
|
|
256
|
+
width={canvasWidth}
|
|
257
|
+
height={canvasHeight}
|
|
258
|
+
className={string}
|
|
259
|
+
onMouseUp={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
260
|
+
onMouseDown={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
261
|
+
onMouseMove={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
262
|
+
onClick={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
263
|
+
onTouchStart={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
264
|
+
onTouchEnd={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
265
|
+
onTouchMove={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
266
|
+
onTouchCancel={(e) => { e.stopPropagation(); onTouchEvent(e.nativeEvent); }}
|
|
267
|
+
/>
|
|
268
|
+
{/* MIPMAP - For Sprite Text / Speech / Titles */}
|
|
269
|
+
<canvas style={{ display: 'none' }} ref={mmRef} width={256} height={256} />
|
|
270
|
+
</div>
|
|
271
|
+
</div>
|
|
272
|
+
{/* Gamepad - For controls on Mobile Only - Positioned BELOW game canvas */}
|
|
273
|
+
<div style={{
|
|
274
|
+
width: canvasWidth + 'px',
|
|
275
|
+
height: showGamepad ? gamepadHeight + 'px' : '1px',
|
|
276
|
+
marginTop: showGamepad ? '10px' : '0px',
|
|
277
|
+
position: 'relative',
|
|
278
|
+
overflow: 'hidden',
|
|
279
|
+
}}>
|
|
280
|
+
<canvas
|
|
281
|
+
style={{
|
|
282
|
+
position: 'absolute',
|
|
283
|
+
zIndex: 5,
|
|
284
|
+
top: 0,
|
|
285
|
+
left: 0,
|
|
286
|
+
background: 'none',
|
|
287
|
+
width: '100%',
|
|
288
|
+
height: '100%',
|
|
289
|
+
display: showGamepad ? 'block' : 'none',
|
|
290
|
+
}}
|
|
291
|
+
ref={gamepadRef}
|
|
292
|
+
width={canvasWidth}
|
|
293
|
+
height={gamepadHeight}
|
|
294
|
+
className={string}
|
|
295
|
+
onMouseUp={(e) => onTouchEvent(e.nativeEvent)}
|
|
296
|
+
onMouseDown={(e) => onTouchEvent(e.nativeEvent)}
|
|
297
|
+
onMouseMove={(e) => onTouchEvent(e.nativeEvent)}
|
|
298
|
+
onTouchMoveCapture={(e) => onTouchEvent(e.nativeEvent)}
|
|
299
|
+
onTouchCancelCapture={(e) => onTouchEvent(e.nativeEvent)}
|
|
300
|
+
onTouchStartCapture={(e) => onTouchEvent(e.nativeEvent)}
|
|
301
|
+
onTouchEndCapture={(e) => onTouchEvent(e.nativeEvent)}
|
|
302
|
+
/>
|
|
303
|
+
</div>
|
|
304
|
+
<div>
|
|
305
|
+
<input type="file" ref={fileRef} src={zipData ?? null} hidden />
|
|
306
|
+
</div>
|
|
307
|
+
</div>
|
|
308
|
+
);
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
WebGLView.propTypes = {
|
|
312
|
+
width: PropTypes.number.isRequired,
|
|
313
|
+
height: PropTypes.number.isRequired,
|
|
314
|
+
SpritzProvider: PropTypes.object.isRequired,
|
|
315
|
+
class: PropTypes.string.isRequired,
|
|
316
|
+
};
|
|
317
|
+
|
|
318
|
+
export default WebGLView;
|