feat(node): re-write using node
@@ -1,10 +1,11 @@
|
||||
VITE_OPERATOR=chen
|
||||
VITE_TITLE="Arknights: Ch'en/Chen the Holungday - 明日方舟:假日威龙陈"
|
||||
VITE_FILENAME=dyn_illust_char_1013_chen2
|
||||
VITE_LOGO=logo_rhodes_override
|
||||
VITE_OPACITY=100
|
||||
VITE_LOGO_FILENAME=logo_rhodes_override
|
||||
VITE_FALLBACK_FILENAME=char_1013_chen2_2
|
||||
VITE_VIEWPORT_LEFT=0
|
||||
VITE_VIEWPORT_RIGHT=0
|
||||
VITE_VIEWPORT_TOP=1
|
||||
VITE_VIEWPORT_BOTTOM=1
|
||||
VITE_INVERT_FILTER=false
|
||||
VITE_IMAGE_WIDTH=2048
|
||||
VITE_IMAGE_HEIGHT=2048
|
||||
26
.gitignore
vendored
@@ -12,3 +12,29 @@ test.db
|
||||
download
|
||||
*.user.*
|
||||
.wip
|
||||
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
node_modules
|
||||
15
Pipfile
@@ -1,15 +0,0 @@
|
||||
[[source]]
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
name = "pypi"
|
||||
|
||||
[packages]
|
||||
pillow = "*"
|
||||
pyyaml = "*"
|
||||
pyyaml-include = "*"
|
||||
|
||||
[dev-packages]
|
||||
autopep8 = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.10"
|
||||
169
Pipfile.lock
generated
@@ -1,169 +0,0 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "b630762e087910062c726a8b7b09ae028f57619798e709018d2c23e500760325"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.10"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:0845adc64fe9886db00f5ab68c4a8cd933ab749a87747555cec1c95acea64b0b",
|
||||
"sha256:0884ba7b515163a1a05440a138adeb722b8a6ae2c2b33aea93ea3118dd3a899e",
|
||||
"sha256:09b89ddc95c248ee788328528e6a2996e09eaccddeeb82a5356e92645733be35",
|
||||
"sha256:0dd4c681b82214b36273c18ca7ee87065a50e013112eea7d78c7a1b89a739153",
|
||||
"sha256:0e51f608da093e5d9038c592b5b575cadc12fd748af1479b5e858045fff955a9",
|
||||
"sha256:0f3269304c1a7ce82f1759c12ce731ef9b6e95b6df829dccd9fe42912cc48569",
|
||||
"sha256:16a8df99701f9095bea8a6c4b3197da105df6f74e6176c5b410bc2df2fd29a57",
|
||||
"sha256:19005a8e58b7c1796bc0167862b1f54a64d3b44ee5d48152b06bb861458bc0f8",
|
||||
"sha256:28676836c7796805914b76b1837a40f76827ee0d5398f72f7dcc634bae7c6264",
|
||||
"sha256:2968c58feca624bb6c8502f9564dd187d0e1389964898f5e9e1fbc8533169157",
|
||||
"sha256:3fa1284762aacca6dc97474ee9c16f83990b8eeb6697f2ba17140d54b453e133",
|
||||
"sha256:451f10ef963918e65b8869e17d67db5e2f4ab40e716ee6ce7129b0cde2876eab",
|
||||
"sha256:46c259e87199041583658457372a183636ae8cd56dbf3f0755e0f376a7f9d0e6",
|
||||
"sha256:46f39cab8bbf4a384ba7cb0bc8bae7b7062b6a11cfac1ca4bc144dea90d4a9f5",
|
||||
"sha256:519e14e2c49fcf7616d6d2cfc5c70adae95682ae20f0395e9280db85e8d6c4df",
|
||||
"sha256:53dcb50fbdc3fb2c55431a9b30caeb2f7027fcd2aeb501459464f0214200a503",
|
||||
"sha256:54614444887e0d3043557d9dbc697dbb16cfb5a35d672b7a0fcc1ed0cf1c600b",
|
||||
"sha256:575d8912dca808edd9acd6f7795199332696d3469665ef26163cd090fa1f8bfa",
|
||||
"sha256:5dd5a9c3091a0f414a963d427f920368e2b6a4c2f7527fdd82cde8ef0bc7a327",
|
||||
"sha256:5f532a2ad4d174eb73494e7397988e22bf427f91acc8e6ebf5bb10597b49c493",
|
||||
"sha256:60e7da3a3ad1812c128750fc1bc14a7ceeb8d29f77e0a2356a8fb2aa8925287d",
|
||||
"sha256:653d7fb2df65efefbcbf81ef5fe5e5be931f1ee4332c2893ca638c9b11a409c4",
|
||||
"sha256:6663977496d616b618b6cfa43ec86e479ee62b942e1da76a2c3daa1c75933ef4",
|
||||
"sha256:6abfb51a82e919e3933eb137e17c4ae9c0475a25508ea88993bb59faf82f3b35",
|
||||
"sha256:6c6b1389ed66cdd174d040105123a5a1bc91d0aa7059c7261d20e583b6d8cbd2",
|
||||
"sha256:6d9dfb9959a3b0039ee06c1a1a90dc23bac3b430842dcb97908ddde05870601c",
|
||||
"sha256:765cb54c0b8724a7c12c55146ae4647e0274a839fb6de7bcba841e04298e1011",
|
||||
"sha256:7a21222644ab69ddd9967cfe6f2bb420b460dae4289c9d40ff9a4896e7c35c9a",
|
||||
"sha256:7ac7594397698f77bce84382929747130765f66406dc2cd8b4ab4da68ade4c6e",
|
||||
"sha256:7cfc287da09f9d2a7ec146ee4d72d6ea1342e770d975e49a8621bf54eaa8f30f",
|
||||
"sha256:847b114580c5cc9ebaf216dd8c8dbc6b00a3b7ab0131e173d7120e6deade1f57",
|
||||
"sha256:8f127e7b028900421cad64f51f75c051b628db17fb00e099eb148761eed598c9",
|
||||
"sha256:94cdff45173b1919350601f82d61365e792895e3c3a3443cf99819e6fbf717a5",
|
||||
"sha256:9a3049a10261d7f2b6514d35bbb7a4dfc3ece4c4de14ef5876c4b7a23a0e566d",
|
||||
"sha256:a1c2d7780448eb93fbcc3789bf3916aa5720d942e37945f4056680317f1cd23e",
|
||||
"sha256:a2e0f87144fcbbe54297cae708c5e7f9da21a4646523456b00cc956bd4c65815",
|
||||
"sha256:a4dfdae195335abb4e89cc9762b2edc524f3c6e80d647a9a81bf81e17e3fb6f0",
|
||||
"sha256:a96e6e23f2b79433390273eaf8cc94fec9c6370842e577ab10dabdcc7ea0a66b",
|
||||
"sha256:aabdab8ec1e7ca7f1434d042bf8b1e92056245fb179790dc97ed040361f16bfd",
|
||||
"sha256:b222090c455d6d1a64e6b7bb5f4035c4dff479e22455c9eaa1bdd4c75b52c80c",
|
||||
"sha256:b52ff4f4e002f828ea6483faf4c4e8deea8d743cf801b74910243c58acc6eda3",
|
||||
"sha256:b9b752ab91e78234941e44abdecc07f1f0d8f51fb62941d32995b8161f68cfe5",
|
||||
"sha256:ba6612b6548220ff5e9df85261bddc811a057b0b465a1226b39bfb8550616aee",
|
||||
"sha256:bd752c5ff1b4a870b7661234694f24b1d2b9076b8bf337321a814c612665f343",
|
||||
"sha256:c3c4ed2ff6760e98d262e0cc9c9a7f7b8a9f61aa4d47c58835cdaf7b0b8811bb",
|
||||
"sha256:c5c1362c14aee73f50143d74389b2c158707b4abce2cb055b7ad37ce60738d47",
|
||||
"sha256:cb362e3b0976dc994857391b776ddaa8c13c28a16f80ac6522c23d5257156bed",
|
||||
"sha256:d197df5489004db87d90b918033edbeee0bd6df3848a204bca3ff0a903bef837",
|
||||
"sha256:d3b56206244dc8711f7e8b7d6cad4663917cd5b2d950799425076681e8766286",
|
||||
"sha256:d5b2f8a31bd43e0f18172d8ac82347c8f37ef3e0b414431157718aa234991b28",
|
||||
"sha256:d7081c084ceb58278dd3cf81f836bc818978c0ccc770cbbb202125ddabec6628",
|
||||
"sha256:db74f5562c09953b2c5f8ec4b7dfd3f5421f31811e97d1dbc0a7c93d6e3a24df",
|
||||
"sha256:df41112ccce5d47770a0c13651479fbcd8793f34232a2dd9faeccb75eb5d0d0d",
|
||||
"sha256:e1339790c083c5a4de48f688b4841f18df839eb3c9584a770cbd818b33e26d5d",
|
||||
"sha256:e621b0246192d3b9cb1dc62c78cfa4c6f6d2ddc0ec207d43c0dedecb914f152a",
|
||||
"sha256:e8c5cf126889a4de385c02a2c3d3aba4b00f70234bfddae82a5eaa3ee6d5e3e6",
|
||||
"sha256:e9d7747847c53a16a729b6ee5e737cf170f7a16611c143d95aa60a109a59c336",
|
||||
"sha256:eaef5d2de3c7e9b21f1e762f289d17b726c2239a42b11e25446abf82b26ac132",
|
||||
"sha256:ed3e4b4e1e6de75fdc16d3259098de7c6571b1a6cc863b1a49e7d3d53e036070",
|
||||
"sha256:ef21af928e807f10bf4141cad4746eee692a0dd3ff56cfb25fce076ec3cc8abe",
|
||||
"sha256:f09598b416ba39a8f489c124447b007fe865f786a89dbfa48bb5cf395693132a",
|
||||
"sha256:f6e78171be3fb7941f9910ea15b4b14ec27725865a73c15277bc39f5ca4f8391",
|
||||
"sha256:f715c32e774a60a337b2bb8ad9839b4abf75b267a0f18806f6f4f5f1688c4b5a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==9.4.0"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf",
|
||||
"sha256:0283c35a6a9fbf047493e3a0ce8d79ef5030852c51e9d911a27badfde0605293",
|
||||
"sha256:055d937d65826939cb044fc8c9b08889e8c743fdc6a32b33e2390f66013e449b",
|
||||
"sha256:07751360502caac1c067a8132d150cf3d61339af5691fe9e87803040dbc5db57",
|
||||
"sha256:0b4624f379dab24d3725ffde76559cff63d9ec94e1736b556dacdfebe5ab6d4b",
|
||||
"sha256:0ce82d761c532fe4ec3f87fc45688bdd3a4c1dc5e0b4a19814b9009a29baefd4",
|
||||
"sha256:1e4747bc279b4f613a09eb64bba2ba602d8a6664c6ce6396a4d0cd413a50ce07",
|
||||
"sha256:213c60cd50106436cc818accf5baa1aba61c0189ff610f64f4a3e8c6726218ba",
|
||||
"sha256:231710d57adfd809ef5d34183b8ed1eeae3f76459c18fb4a0b373ad56bedcdd9",
|
||||
"sha256:277a0ef2981ca40581a47093e9e2d13b3f1fbbeffae064c1d21bfceba2030287",
|
||||
"sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513",
|
||||
"sha256:40527857252b61eacd1d9af500c3337ba8deb8fc298940291486c465c8b46ec0",
|
||||
"sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782",
|
||||
"sha256:473f9edb243cb1935ab5a084eb238d842fb8f404ed2193a915d1784b5a6b5fc0",
|
||||
"sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92",
|
||||
"sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f",
|
||||
"sha256:68fb519c14306fec9720a2a5b45bc9f0c8d1b9c72adf45c37baedfcd949c35a2",
|
||||
"sha256:77f396e6ef4c73fdc33a9157446466f1cff553d979bd00ecb64385760c6babdc",
|
||||
"sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1",
|
||||
"sha256:819b3830a1543db06c4d4b865e70ded25be52a2e0631ccd2f6a47a2822f2fd7c",
|
||||
"sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86",
|
||||
"sha256:98c4d36e99714e55cfbaaee6dd5badbc9a1ec339ebfc3b1f52e293aee6bb71a4",
|
||||
"sha256:9df7ed3b3d2e0ecfe09e14741b857df43adb5a3ddadc919a2d94fbdf78fea53c",
|
||||
"sha256:9fa600030013c4de8165339db93d182b9431076eb98eb40ee068700c9c813e34",
|
||||
"sha256:a80a78046a72361de73f8f395f1f1e49f956c6be882eed58505a15f3e430962b",
|
||||
"sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d",
|
||||
"sha256:b3d267842bf12586ba6c734f89d1f5b871df0273157918b0ccefa29deb05c21c",
|
||||
"sha256:b5b9eccad747aabaaffbc6064800670f0c297e52c12754eb1d976c57e4f74dcb",
|
||||
"sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7",
|
||||
"sha256:c5687b8d43cf58545ade1fe3e055f70eac7a5a1a0bf42824308d868289a95737",
|
||||
"sha256:cba8c411ef271aa037d7357a2bc8f9ee8b58b9965831d9e51baf703280dc73d3",
|
||||
"sha256:d15a181d1ecd0d4270dc32edb46f7cb7733c7c508857278d3d378d14d606db2d",
|
||||
"sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358",
|
||||
"sha256:d4db7c7aef085872ef65a8fd7d6d09a14ae91f691dec3e87ee5ee0539d516f53",
|
||||
"sha256:d4eccecf9adf6fbcc6861a38015c2a64f38b9d94838ac1810a9023a0609e1b78",
|
||||
"sha256:d67d839ede4ed1b28a4e8909735fc992a923cdb84e618544973d7dfc71540803",
|
||||
"sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a",
|
||||
"sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f",
|
||||
"sha256:e61ceaab6f49fb8bdfaa0f92c4b57bcfbea54c09277b1b4f7ac376bfb7a7c174",
|
||||
"sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==6.0"
|
||||
},
|
||||
"pyyaml-include": {
|
||||
"hashes": [
|
||||
"sha256:5142a0b0f93d9b1e5872d5a814f3681ffbc70638128ced1acfd9fb57da7825ca",
|
||||
"sha256:f7fbeb8e71b50be0e6e07472f7c79dbfb1a15bade9c93a078369ff49e57e6771"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.3"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"autopep8": {
|
||||
"hashes": [
|
||||
"sha256:be5bc98c33515b67475420b7b1feafc8d32c1a69862498eda4983b45bffd2687",
|
||||
"sha256:d27a8929d8dcd21c0f4b3859d2d07c6c25273727b98afc984c039df0f0d86566"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:347187bdb476329d98f695c213d7295a846d1152ff4fe9bacb8a9590b8ee7053",
|
||||
"sha256:8a4eaf0d0495c7395bdab3589ac2db602797d76207242c17d470186815706610"
|
||||
],
|
||||
"markers": "python_version >= '3.6'",
|
||||
"version": "==2.10.0"
|
||||
},
|
||||
"tomli": {
|
||||
"hashes": [
|
||||
"sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc",
|
||||
"sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"
|
||||
],
|
||||
"markers": "python_version < '3.11'",
|
||||
"version": "==2.0.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
246
README.md
@@ -2,6 +2,113 @@
|
||||
|
||||
A project that builds showcase webpage for Arknights Live2D-equipped operators. Showcase webpage can be used as a wallpaper for Wallpaper Engine on Windows or [Plash](https://github.com/sindresorhus/Plash) on macOS (not tested).
|
||||
|
||||
## Softwares
|
||||
- For Windows users: Use [Wallpaper Engine](https://www.wallpaperengine.io/en) or other softwares that support using webpage as desktop wallpaper.
|
||||
- For macOS users: Use [Plash](https://github.com/sindresorhus/Plash), however, I don't have macOS machine, so your mileage may vary.
|
||||
- For Linux users: You power user should be able to find your solutions!
|
||||
|
||||
## Usage
|
||||
### Command Line Tool
|
||||
|
||||
``` bash
|
||||
$ O={operator_name} node preprocessing.js
|
||||
To generate operator assets for showcase page
|
||||
```
|
||||
``` bash
|
||||
$ O={operator_name} node preprocessing.js -i
|
||||
To initialize folder and config file for an operator
|
||||
```
|
||||
``` bash
|
||||
$ O={operator_name} pnpm run dev
|
||||
Live showcase page server for development
|
||||
```
|
||||
``` bash
|
||||
$ O={operator_name} pnpm run build
|
||||
Build showcase webpage for an operator
|
||||
```
|
||||
``` bash
|
||||
$ node build_all.js
|
||||
Build showcase webpages for all operators
|
||||
```
|
||||
### Webpage & JavaScript
|
||||
|
||||
Add query string `settings` to bring up the settings panel to adjust your settings. Then use appropriate JavaScript code to load your settings
|
||||
|
||||
``` javascript
|
||||
settings.setFPS(integer) // set FPS
|
||||
settings.displayLogo(boolean) // display logo or not
|
||||
settings.resizeLogo(float) // the ratio of the logo
|
||||
settings.opacityLogo(float) // the opacity of the logo
|
||||
settings.setLogo(url) // change the logo, url: image url, removeInvert: boolean
|
||||
settings.setBackground(url) // change the background, url: image url
|
||||
settings.positionPadding("left", integer) // left padding
|
||||
settings.positionPadding("right", integer) // right padding
|
||||
settings.positionPadding("top", integer) // top padding
|
||||
settings.positionPadding("bottom", integer) // bottom padding
|
||||
|
||||
settings.open() // open settings panel
|
||||
settings.close() // close settings panel
|
||||
settings.reset() // reset settings
|
||||
```
|
||||
|
||||
## Config
|
||||
### General Config
|
||||
``` yaml
|
||||
folder:
|
||||
operator: ./operator/ # folder for operator assets
|
||||
release: ./release/ # folder for released showcase page
|
||||
operators:
|
||||
chen: !include config/chen.yaml # include the config for the operator under folder `config/chen.yaml`
|
||||
dusk: !include config/dusk.yaml
|
||||
dusk_everything_is_a_miracle: !include config/dusk_everything_is_a_miracle.yaml
|
||||
ling: !include config/ling.yaml
|
||||
nearl: !include config/nearl.yaml
|
||||
nian: !include config/nian.yaml
|
||||
nian_unfettered_freedom: !include config/nian_unfettered_freedom.yaml
|
||||
phatom_focus: !include config/phatom_focus.yaml
|
||||
rosmontis: !include config/rosmontis.yaml
|
||||
skadi: !include config/skadi.yaml
|
||||
skadi_sublimation: !include config/skadi_sublimation.yaml
|
||||
w: !include config/w.yaml
|
||||
w_fugue: !include config/w_fugue.yaml
|
||||
specter: !include config/specter.yaml
|
||||
gavial: !include config/gavial.yaml
|
||||
surtr_colorful_wonderland: !include config/surtr_colorful_wonderland.yaml
|
||||
lee_trust_your_eyes: !include config/lee_trust_your_eyes.yaml
|
||||
texas_the_omertosa: !include config/texas_the_omertosa.yaml
|
||||
nearl_relight: !include config/nearl_relight.yaml
|
||||
rosmontis_become_anew: !include config/rosmontis_become_anew.yaml
|
||||
passager_dream_in_a_moment: !include config/passager_dream_in_a_moment.yaml
|
||||
mizuki_summer_feast: !include config/mizuki_summer_feast.yaml
|
||||
```
|
||||
### Operator Config
|
||||
```yaml
|
||||
link: chen # the link to access showcase page for this operator
|
||||
type: operator # operator live2d or skin live2d
|
||||
date: 2021/08 # release date
|
||||
title: 'Arknights: Ch''en/Chen the Holungday - 明日方舟:假日威龙陈' # page title
|
||||
filename: dyn_illust_char_1013_chen2 # live2d assets name
|
||||
logo: logo_rhodes_override # operator logo
|
||||
fallback_name: char_1013_chen2_2 # fallback image name
|
||||
viewport_left: 0 # live2d view port settings
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
viewport_bottom: 1
|
||||
invert_filter: false # operator logo invert filter
|
||||
```
|
||||
## LICENSE
|
||||
|
||||
The `LICENSE` file applies to all files unless listed specifically.
|
||||
|
||||
`LICENSE_SPINE` file applies to following files including adapted code for this repo:
|
||||
|
||||
- `src/libs/spine-player.css`
|
||||
- `src/libs/spine-player.js`
|
||||
|
||||
`Copyright © 2017 - 2023 Arknights/Hypergryph Co., Ltd` applies to following files:
|
||||
|
||||
- all files under `operator` folder and its sub-folders
|
||||
|
||||
## Supported Operators
|
||||
|
||||
| Operator | Live Preview | Steam Workshop |
|
||||
@@ -28,142 +135,3 @@ A project that builds showcase webpage for Arknights Live2D-equipped operators.
|
||||
| Become Anew / Rosmontis | [Link](https://arknights.halyul.dev/rosmontis_become_anew/) | [Link](https://steamcommunity.com/sharedfiles/filedetails/?id=2883012349) |
|
||||
| Dream in a Moment / Passager | [Link](https://arknights.halyul.dev/passager_dream_in_a_moment/) | [Link](https://steamcommunity.com/sharedfiles/filedetails/?id=2883021565) |
|
||||
| Summer Feast / Mizuki | [Link](https://arknights.halyul.dev/mizuki_summer_feast/) | [Link](https://steamcommunity.com/sharedfiles/filedetails/?id=2895953271) |
|
||||
|
||||
- For Windows users: Use [Wallpaper Engine](https://www.wallpaperengine.io/en) or other softwares that support using webpage as desktop wallpaper.
|
||||
- For macOS users: Use [Plash](https://github.com/sindresorhus/Plash), however, I don't have macOS machine, so your mileage may vary.
|
||||
- For Linux users: You power user should be able to find your solutions!
|
||||
|
||||
## Usage
|
||||
### Command Line Tool
|
||||
|
||||
``` bash
|
||||
$ python3 aklive2d.py -h
|
||||
usage: aklive2d [-h] {server,s,build,b,init,i} ...
|
||||
|
||||
Arknights Live 2D Wallpaper Builder
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
|
||||
Available commands:
|
||||
{server,s,build,b,init,i}
|
||||
<Required> Select the command to run
|
||||
server (s) Development Server
|
||||
build (b) Build releases
|
||||
init (i) Initialize a new operator
|
||||
```
|
||||
``` bash
|
||||
$ python3 aklive2d.py s -h
|
||||
usage: aklive2d server [-h] [-p PORT] -o OPERATOR_NAME [-r]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-p PORT, --port PORT Development server port (default: 8080)
|
||||
-o OPERATOR_NAME, --operator OPERATOR_NAME
|
||||
<Required> Operator to develop (default: None)
|
||||
-r, --rebuild Rebuild assets (default: False)
|
||||
```
|
||||
``` bash
|
||||
$ python3 aklive2d.py b -h
|
||||
usage: aklive2d build [-h] [-o OPERATOR_NAMES [OPERATOR_NAMES ...]] [-r]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-o OPERATOR_NAMES [OPERATOR_NAMES ...], --operators OPERATOR_NAMES [OPERATOR_NAMES ...]
|
||||
Operators to build (default: ['all'])
|
||||
-r, --rebuild Rebuild assets (default: False)
|
||||
```
|
||||
``` bash
|
||||
$ python3 aklive2d.py i -h
|
||||
usage: aklive2d init [-h] [-c OPERATOR_NAME]
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
-c OPERATOR_NAME, --copy OPERATOR_NAME
|
||||
YAML pre-defined Operator assets to copy (default: None)
|
||||
```
|
||||
### Webpage & JavaScript
|
||||
|
||||
Add query string `settings` to bring up the settings panel to adjust your settings. Then use appropriate JavaScript code to load your settings
|
||||
|
||||
``` javascript
|
||||
settings.setFPS(integer) // set FPS
|
||||
settings.displayLogo(boolean) // display logo or not
|
||||
settings.resizeLogo(float) // the ratio of the logo
|
||||
settings.opacityLogo(float) // the opacity of the logo
|
||||
settings.setLogo(url, removeInvert) // change the logo, url: image url, removeInvert: boolean
|
||||
settings.setBackground(url) // change the background, url: image url
|
||||
settings.positionPadding("padLeft", integer) // left padding
|
||||
settings.positionPadding("padRight", integer) // right padding
|
||||
settings.positionPadding("padTop", integer) // top padding
|
||||
settings.positionPadding("padBottom", integer) // bottom padding
|
||||
|
||||
settings.open() // open settings panel
|
||||
settings.close() // close settings panel
|
||||
settings.reset() // reset settings
|
||||
```
|
||||
|
||||
## Config
|
||||
``` yaml
|
||||
# share properties for all operators
|
||||
operator:
|
||||
preview: preview.jpg # Steam workshop preview image file
|
||||
project_json: project.json # Steam workshop project file
|
||||
source_folder: ./operator/{name}/extracted/ # The folder that stores extracted game files
|
||||
target_folder: ./operator/{name}/processed/ # The folder that stores processed game files
|
||||
# Development server settings
|
||||
# List all the supported operators under <operators> block
|
||||
operators:
|
||||
chen: # <operator name>/<folder name under "operator" folder>, will be used to replace <{name}> above
|
||||
_operator_settings.js: # refer to char_1013_chen2_2_settings.js under operator folder
|
||||
fallbackImage_height: 2048 # fallback image height
|
||||
fallbackImage_width: 2048 # fallback image width
|
||||
filename: dyn_illust_char_1013_chen2 # common file name
|
||||
fps: 60 # default fps target in the webpage
|
||||
opacity: 100 # optional property, can be used in the file
|
||||
viewport_bottom: 1 # bottom padding of the model
|
||||
viewport_left: 0 # left padding of the model
|
||||
viewport_right: 0 # right padding of the model
|
||||
viewport_top: 1 # top padding of the model
|
||||
index.html: # refer to index.html under template folder
|
||||
fallback_name: char_1013_chen2_2 # fallback image name
|
||||
id: char_1013_chen2 # id of the operator
|
||||
operator_logo: logo_rhodes_override # operator logo
|
||||
title: Ch'en the Holungday # webpage title
|
||||
version: __get_version # eval __get_version() function
|
||||
project.json: # refer to project.json under operator folder
|
||||
description: 'Arknights: Ch''en/Chen the Holungday Live 2D\n明日方舟:假日威龙陈 Live
|
||||
2D\nThe model is extracted from game with Spine support.\n模型来自游戏内提取,支持Spine\nPlease
|
||||
set your FPS target in Wallpaper Engine > Settings > Performance > FPS\n请在
|
||||
Wallpaper Engine > 设置 > 性能 > FPS 下设置FPS\n\nLive preview on: https://arknights.halyul.dev/chen\nGithub:
|
||||
https://github.com/Halyul/aklive2d' # Steam Workshop description
|
||||
title: 'Arknights: Ch''en/Chen the Holungday - 明日方舟:假日威龙陈' # Steam Workshop title
|
||||
ui_logo_opacity: 100 # logo opacity setting in WE
|
||||
ui_logo_ratio: 61.8 # logo ratio setting in WE
|
||||
ui_operator_logo: 'true' # enable/disable logo in WE
|
||||
ui_position_padding_bottom: 1 # bottom padding of the model in WE
|
||||
ui_position_padding_left: 0 # left padding of the model in WE
|
||||
ui_position_padding_right: 0 # right padding of the model in WE
|
||||
ui_position_padding_top: 1 # top padding of the model in WE
|
||||
workshopid: 2564643862 # Steam Workshop id
|
||||
server:
|
||||
operator_folder: ./operator/ # The path that the showcase webpage accesses game files
|
||||
release_folder: ./release/ # The folder that stores the showcase webpage
|
||||
template_folder: ./template/ # The folder that stores the showcase template
|
||||
```
|
||||
## LICENSE
|
||||
|
||||
The `LICENSE` file applies to all files unless listed specifically.
|
||||
|
||||
`LICENSE_SPINE` file applies to following files including adapted code for this repo:
|
||||
|
||||
- `template/assets/spine-player.css`
|
||||
- `template/assets/spine-player.js`
|
||||
- `release/*/assets/spine-player.css`
|
||||
- `release/*/assets/spine-player.js`
|
||||
|
||||
`Copyright © 2017 - 2021 Arknights/Hypergryph Co., Ltd` applies to following files:
|
||||
|
||||
- all files under `operator` folder and its sub-folders
|
||||
- all files under `release/*/operator/*` folder
|
||||
- `release/*/operator/operator_assets.js`
|
||||
|
||||
115
aklive2d.py
@@ -1,115 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
import argparse
|
||||
import sys
|
||||
|
||||
from lib.config import Config
|
||||
from lib.server import Server
|
||||
from lib.builder import Builder
|
||||
from lib.initializer import Initializer
|
||||
|
||||
class AkLive2D:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.config = Config().read()
|
||||
self.args = None
|
||||
self.running = None
|
||||
|
||||
def start(self):
|
||||
parser = argparse.ArgumentParser(
|
||||
prog="aklive2d",
|
||||
description="Arknights Live 2D Wallpaper Builder",
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
||||
)
|
||||
|
||||
subprasers = parser.add_subparsers(
|
||||
title="Available commands",
|
||||
dest="command",
|
||||
required=True,
|
||||
help="<Required> Select the command to run"
|
||||
)
|
||||
|
||||
server = subprasers.add_parser(
|
||||
"server",
|
||||
help="Development Server",
|
||||
aliases=['s'],
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
||||
)
|
||||
server.add_argument(
|
||||
"-p",
|
||||
"--port",
|
||||
dest="port",
|
||||
type=int,
|
||||
default=8080,
|
||||
help="Development server port"
|
||||
)
|
||||
server.add_argument(
|
||||
"-o",
|
||||
"--operator",
|
||||
dest="operator_name",
|
||||
type=str,
|
||||
required=True,
|
||||
help="<Required> Operator to develop",
|
||||
)
|
||||
server.add_argument(
|
||||
"-r",
|
||||
"--rebuild",
|
||||
dest="rebuild",
|
||||
action='store_true',
|
||||
help="Rebuild assets"
|
||||
)
|
||||
|
||||
build = subprasers.add_parser(
|
||||
"build",
|
||||
help="Build releases",
|
||||
aliases=['b'],
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
||||
)
|
||||
build.add_argument(
|
||||
"-o",
|
||||
"--operators",
|
||||
dest="operator_names",
|
||||
type=str,
|
||||
default=["all"],
|
||||
nargs='+',
|
||||
help="Operators to build"
|
||||
)
|
||||
build.add_argument(
|
||||
"-r",
|
||||
"--rebuild",
|
||||
dest="rebuild",
|
||||
action='store_true',
|
||||
help="Rebuild assets"
|
||||
)
|
||||
|
||||
initializer = subprasers.add_parser(
|
||||
"init",
|
||||
help="Initialize a new operator",
|
||||
aliases=['i'],
|
||||
formatter_class=argparse.ArgumentDefaultsHelpFormatter
|
||||
)
|
||||
initializer.add_argument(
|
||||
"-o",
|
||||
"--operator",
|
||||
dest="operator_name",
|
||||
type=str,
|
||||
required=True,
|
||||
help="YAML pre-defined Operator assets to copy",
|
||||
)
|
||||
|
||||
self.args = parser.parse_args()
|
||||
if self.args.command == "server" or self.args.command == "s":
|
||||
self.running = Server(self.args.port, self.args.operator_name, self.config, self.args.rebuild)
|
||||
elif self.args.command == "build" or self.args.command == "b":
|
||||
self.running = Builder(self.config, self.args.operator_names, self.args.rebuild)
|
||||
elif self.args.command == "init" or self.args.command == "i":
|
||||
self.running = Initializer(self.config, self.args.operator_name)
|
||||
|
||||
self.running.start()
|
||||
|
||||
if __name__ == "__main__":
|
||||
aklive2d = AkLive2D()
|
||||
try:
|
||||
aklive2d.start()
|
||||
except KeyboardInterrupt:
|
||||
print("\nInterrupted, exiting...")
|
||||
sys.exit()
|
||||
15
build_all.js
Normal file
@@ -0,0 +1,15 @@
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import { execSync } from 'child_process'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
let __dirname
|
||||
__dirname = __dirname || path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const directory = path.join(__dirname, 'operator');
|
||||
fs.readdir(directory, function (err, files) {
|
||||
files.forEach(function (file) {
|
||||
if (file.startsWith('_')) return;
|
||||
console.log(execSync(`O=${file} node preprocessing.js && O=${file} pnpm run build`).toString());
|
||||
});
|
||||
});
|
||||
15
config.yaml
@@ -1,8 +1,6 @@
|
||||
operator:
|
||||
preview: preview.jpg
|
||||
project_json: project.json
|
||||
source_folder: ./operator/{name}/extracted/
|
||||
target_folder: ./operator/{name}/processed/
|
||||
folder:
|
||||
operator: ./operator/
|
||||
release: ./release/
|
||||
operators:
|
||||
chen: !include config/chen.yaml
|
||||
dusk: !include config/dusk.yaml
|
||||
@@ -26,9 +24,4 @@ operators:
|
||||
rosmontis_become_anew: !include config/rosmontis_become_anew.yaml
|
||||
passager_dream_in_a_moment: !include config/passager_dream_in_a_moment.yaml
|
||||
mizuki_summer_feast: !include config/mizuki_summer_feast.yaml
|
||||
server:
|
||||
operator_folder: ./operator/
|
||||
release_folder: ./release/
|
||||
template_folder: ./template/operator/
|
||||
index:
|
||||
src_folder: ./template/index/src/assets
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
title: ${var:index.html->title}
|
||||
description: '${func:split("project.json->title" ," - ")[0]} Live 2D\n${func:split("project.json->title" ," - ")[1]} Live 2D\nThe model is extracted from game with Spine support.\n模型来自游戏内提取,支持Spine\nPlease set your FPS target in Wallpaper Engine > Settings > Performance > FPS\n请在 Wallpaper Engine > 设置 > 性能 > FPS 下设置FPS\n\nLive preview on: https://arknights.halyul.dev/${var:link}\nGithub: https://github.com/Halyul/aklive2d'
|
||||
ui_logo_opacity: ${var:_operator_settings.js->opacity}
|
||||
ui_logo_ratio: 61.8
|
||||
ui_operator_logo: 'true'
|
||||
ui_position_padding_bottom: ${var:_operator_settings.js->viewport_bottom}
|
||||
ui_position_padding_left: ${var:_operator_settings.js->viewport_left}
|
||||
ui_position_padding_right: ${var:_operator_settings.js->viewport_right}
|
||||
ui_position_padding_top: ${var:_operator_settings.js->viewport_top}
|
||||
12
config/_template.yaml
Normal file
@@ -0,0 +1,12 @@
|
||||
link: chen
|
||||
type: operator
|
||||
date: 2021/08
|
||||
title: 'Arknights: Ch''en/Chen the Holungday - 明日方舟:假日威龙陈'
|
||||
filename: dyn_illust_char_1013_chen2
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1013_chen2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
viewport_bottom: 1
|
||||
invert_filter: false
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1013_chen2
|
||||
fps: 60
|
||||
opacity: 100
|
||||
viewport_bottom: 1
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
invert_filter: false
|
||||
index.html:
|
||||
fallback_name: char_1013_chen2_2
|
||||
id: char_1013_chen2
|
||||
operator_logo: logo_rhodes_override
|
||||
title: 'Arknights: Ch''en/Chen the Holungday - 明日方舟:假日威龙陈'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: chen
|
||||
type: operator
|
||||
date: 2021/08
|
||||
title: 'Arknights: Ch''en/Chen the Holungday - 明日方舟:假日威龙陈'
|
||||
filename: dyn_illust_char_1013_chen2
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1013_chen2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
viewport_bottom: 1
|
||||
invert_filter: false
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_2015_dusk
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_2015_dusk_2
|
||||
id: char_2015_dusk
|
||||
operator_logo: logo_sui
|
||||
title: 'Arknights: Dusk - 明日方舟:夕'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: dusk
|
||||
type: operator
|
||||
date: 2021/02
|
||||
title: 'Arknights: Dusk - 明日方舟:夕'
|
||||
filename: dyn_illust_char_2015_dusk
|
||||
logo: logo_sui
|
||||
fallback_name: char_2015_dusk_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,20 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_2015_dusk_nian#7
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 10
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
index.html:
|
||||
fallback_name: char_2015_dusk_nian%237
|
||||
id: char_2015_dusk_nian%237
|
||||
operator_logo: logo_sui
|
||||
title: 'Arknights: Everything is a Miracle / Dusk - 明日方舟:染尘烟·夕'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: dusk_everything_is_a_miracle
|
||||
type: skin
|
||||
date: 2022/01
|
||||
title: 'Arknights: Everything is a Miracle / Dusk - 明日方舟:染尘烟·夕'
|
||||
filename: dyn_illust_char_2015_dusk_nian#7
|
||||
logo: logo_sui
|
||||
fallback_name: char_2015_dusk_nian#7
|
||||
viewport_left: 10
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1026_gvial2
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: false
|
||||
index.html:
|
||||
fallback_name: char_1026_gvial2_2
|
||||
id: char_1026_gvial2_2
|
||||
operator_logo: logo_rhodes_override
|
||||
title: 'Arknights: Gavial the Invincible - 明日方舟:百练嘉维尔'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: gavial
|
||||
type: operator
|
||||
date: 2022/08
|
||||
title: 'Arknights: Gavial the Invincible - 明日方舟:百练嘉维尔'
|
||||
filename: dyn_illust_char_1026_gvial2
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_1026_gvial2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_322_lmlee_witch#3
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_322_lmlee_witch%233
|
||||
id: char_322_lmlee_witch%233
|
||||
operator_logo: logo_lee
|
||||
title: 'Arknights: Trust Your Eyes / Lee - 明日方舟:手到牌来·老鲤'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: lee_trust_your_eyes
|
||||
type: skin
|
||||
date: 2022/10
|
||||
title: 'Arknights: Trust Your Eyes / Lee - 明日方舟:手到牌来·老鲤'
|
||||
filename: dyn_illust_char_322_lmlee_witch#3
|
||||
logo: logo_lee
|
||||
fallback_name: char_322_lmlee_witch#3
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_2023_ling
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_2023_ling_2
|
||||
id: char_2023_ling
|
||||
operator_logo: logo_sui
|
||||
title: 'Arknights: Ling - 明日方舟:令'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: ling
|
||||
type: operator
|
||||
date: 2022/01
|
||||
title: 'Arknights: Ling - 明日方舟:令'
|
||||
filename: dyn_illust_char_2023_ling
|
||||
logo: logo_sui
|
||||
fallback_name: char_2023_ling_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_437_mizuki_sale#7
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_437_mizuki_sale%237
|
||||
id: char_437_mizuki_sale%237
|
||||
operator_logo: logo_higashi
|
||||
title: 'Arknights: Summer Feast / Mizuki - 明日方舟:夏日餮宴·水月'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: mizuki_summer_feast
|
||||
type: skin
|
||||
date: 2022/12
|
||||
title: 'Arknights: Summer Feast / Mizuki - 明日方舟:夏日餮宴·水月'
|
||||
filename: dyn_illust_char_437_mizuki_sale#7
|
||||
logo: logo_higashi
|
||||
fallback_name: char_437_mizuki_sale#7
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1014_nearl2
|
||||
fps: 60
|
||||
opacity: 100
|
||||
viewport_bottom: 0
|
||||
viewport_left: 2
|
||||
viewport_right: 3
|
||||
viewport_top: 10
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_1014_nearl2_2
|
||||
id: char_1014_nearl2
|
||||
operator_logo: logo_kazimierz
|
||||
title: 'Arknights: Nearl the Radiant Knight - 明日方舟:耀骑士临光'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: nearl
|
||||
type: operator
|
||||
date: 2021/11
|
||||
title: 'Arknights: Nearl the Radiant Knight - 明日方舟:耀骑士临光'
|
||||
filename: dyn_illust_char_1014_nearl2
|
||||
logo: logo_kazimierz
|
||||
fallback_name: char_1014_nearl2_2
|
||||
viewport_left: 2
|
||||
viewport_right: 3
|
||||
viewport_top: 10
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1014_nearl2_epoque#17
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_1014_nearl2_epoque%2317
|
||||
id: char_1014_nearl2%2317
|
||||
operator_logo: logo_kazimierz
|
||||
title: 'Arknights: Relight / Nearl - 明日方舟:复现荣光·耀骑士临光'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: nearl_relight
|
||||
type: skin
|
||||
date: 2022/11
|
||||
title: 'Arknights: Relight / Nearl - 明日方舟:复现荣光·耀骑士临光'
|
||||
filename: dyn_illust_char_1014_nearl2_epoque#17
|
||||
logo: logo_kazimierz
|
||||
fallback_name: char_1014_nearl2_epoque#17
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_2014_nian
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 5
|
||||
viewport_left: 2
|
||||
viewport_right: 2
|
||||
viewport_top: 3
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_2014_nian_2
|
||||
id: char_2014_nian
|
||||
operator_logo: logo_sui
|
||||
title: 'Arknights: Nian - 明日方舟:年'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: nian
|
||||
type: operator
|
||||
date: 2020/01
|
||||
title: 'Arknights: Nian - 明日方舟:年'
|
||||
filename: dyn_illust_char_2014_nian
|
||||
logo: logo_sui
|
||||
fallback_name: char_2014_nian_2
|
||||
viewport_left: 2
|
||||
viewport_right: 2
|
||||
viewport_top: 3
|
||||
viewport_bottom: 5
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_2014_nian_nian#4
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_2014_nian_nian%234
|
||||
id: char_2014_nian_nian%234
|
||||
operator_logo: logo_sui
|
||||
title: 'Arknights: Unfettered Freedom / Nian - 明日方舟:乐逍遥·年'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: nian_unfettered_freedom
|
||||
type: skin
|
||||
date: 2021/02
|
||||
title: 'Arknights: Unfettered Freedom / Nian - 明日方舟:乐逍遥·年'
|
||||
filename: dyn_illust_char_2014_nian_nian#4
|
||||
logo: logo_sui
|
||||
fallback_name: char_2014_nian_nian#4
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_472_pasngr_epoque#17
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_472_pasngr_epoque%2317
|
||||
id: char_472_pasngr%2317
|
||||
operator_logo: logo_sargon
|
||||
title: 'Arknights: Dream in a Moment / Passager - 明日方舟:今昔须臾之梦 · 异客'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: passager_dream_in_a_moment
|
||||
type: skin
|
||||
date: 2022/11
|
||||
title: 'Arknights: Dream in a Moment / Passager - 明日方舟:今昔须臾之梦 · 异客'
|
||||
filename: dyn_illust_char_472_pasngr_epoque#17
|
||||
logo: logo_sargon
|
||||
fallback_name: char_472_pasngr_epoque#17
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_250_phatom_sale#4
|
||||
fps: 60
|
||||
opacity: 100
|
||||
viewport_bottom: 1
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 5
|
||||
invert_filter: false
|
||||
index.html:
|
||||
fallback_name: char_250_phatom_sale%234
|
||||
id: char_250_phatom_sale%234
|
||||
operator_logo: logo_victoria
|
||||
title: 'Arknights: Focus / Phatom - 明日方舟:焦点·傀影'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: phatom_focus
|
||||
type: skin
|
||||
date: 2022/04
|
||||
title: 'Arknights: Focus / Phatom - 明日方舟:焦点·傀影'
|
||||
filename: dyn_illust_char_250_phatom_sale#4
|
||||
logo: logo_victoria
|
||||
fallback_name: char_250_phatom_sale#4
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 5
|
||||
viewport_bottom: 1
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_391_rosmon
|
||||
fps: 60
|
||||
opacity: 100
|
||||
viewport_bottom: -1
|
||||
viewport_left: 0
|
||||
viewport_right: -14
|
||||
viewport_top: -38
|
||||
invert_filter: false
|
||||
index.html:
|
||||
fallback_name: char_391_rosmon_2
|
||||
id: char_391_rosmon
|
||||
operator_logo: logo_elite
|
||||
title: 'Arknights: Rosmontis - 明日方舟:迷迭香'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: rosmontis
|
||||
type: operator
|
||||
date: 2020/11
|
||||
title: 'Arknights: Rosmontis - 明日方舟:迷迭香'
|
||||
filename: dyn_illust_char_391_rosmon
|
||||
logo: logo_elite
|
||||
fallback_name: char_391_rosmon_2
|
||||
viewport_left: 0
|
||||
viewport_right: -14
|
||||
viewport_top: -38
|
||||
viewport_bottom: -1
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_391_rosmon_epoque#17
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_391_rosmon_epoque%2317
|
||||
id: char_391_rosmon%2317
|
||||
operator_logo: logo_elite
|
||||
title: 'Arknights: Become Anew / Rosmontis - 明日方舟:拥抱新生·迷迭香'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: rosmontis_become_anew
|
||||
type: skin
|
||||
date: 2022/11
|
||||
title: 'Arknights: Become Anew / Rosmontis - 明日方舟:拥抱新生·迷迭香'
|
||||
filename: dyn_illust_char_391_rosmon_epoque#17
|
||||
logo: logo_elite
|
||||
fallback_name: char_391_rosmon_epoque#17
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1012_skadi2
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: -12
|
||||
viewport_left: -5
|
||||
viewport_right: -10
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_1012_skadi2_2
|
||||
id: char_1012_skadi2
|
||||
operator_logo: logo_egir
|
||||
title: 'Arknights: Skadi the Corrupting Heart - 明日方舟:浊心斯卡蒂'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: skadi
|
||||
type: operator
|
||||
date: 2021/05
|
||||
title: 'Arknights: Skadi the Corrupting Heart - 明日方舟:浊心斯卡蒂'
|
||||
filename: dyn_illust_char_1012_skadi2
|
||||
logo: logo_egir
|
||||
fallback_name: char_1012_skadi2_2
|
||||
viewport_left: -5
|
||||
viewport_right: -10
|
||||
viewport_top: 0
|
||||
viewport_bottom: -12
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1012_skadi2_boc#4
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_1012_skadi2_boc%234
|
||||
id: char_1012_skadi2_boc%234
|
||||
operator_logo: logo_egir
|
||||
title: 'Arknights: Sublimation / Skadi the Corrupting Heart - 明日方舟:升华·浊心斯卡蒂'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: skadi_sublimation
|
||||
type: skin
|
||||
date: 2022/05
|
||||
title: 'Arknights: Sublimation / Skadi the Corrupting Heart - 明日方舟:升华·浊心斯卡蒂'
|
||||
filename: dyn_illust_char_1012_skadi2_boc#4
|
||||
logo: logo_egir
|
||||
fallback_name: char_1012_skadi2_boc#4
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1023_ghost2
|
||||
fps: 60
|
||||
opacity: 100
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: false
|
||||
index.html:
|
||||
fallback_name: char_1023_ghost2_2
|
||||
id: char_1023_ghost2
|
||||
operator_logo: logo_abyssal
|
||||
title: 'Arknights: Specter the Unchained - 明日方舟:归溟幽灵鲨'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: specter
|
||||
type: operator
|
||||
date: 2022/05
|
||||
title: 'Arknights: Specter the Unchained - 明日方舟:归溟幽灵鲨'
|
||||
filename: dyn_illust_char_1023_ghost2
|
||||
logo: logo_abyssal
|
||||
fallback_name: char_1023_ghost2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_350_surtr_summer#9
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 6
|
||||
viewport_top: 1
|
||||
invert_filter: false
|
||||
index.html:
|
||||
fallback_name: char_350_surtr_summer%239
|
||||
id: char_350_surtr_summer%239
|
||||
operator_logo: logo_rhodes_override
|
||||
title: 'Arknights: Colorful Wonderland CW03 / Surtr - 明日方舟:缤纷奇境 CW03·史尔特尔'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: surtr_colorful_wonderland
|
||||
type: skin
|
||||
date: 2022/08
|
||||
title: 'Arknights: Colorful Wonderland CW03 / Surtr - 明日方舟:缤纷奇境 CW03·史尔特尔'
|
||||
filename: dyn_illust_char_350_surtr_summer#9
|
||||
logo: logo_rhodes_override
|
||||
fallback_name: char_350_surtr_summer#9
|
||||
viewport_left: 0
|
||||
viewport_right: 6
|
||||
viewport_top: 1
|
||||
viewport_bottom: 0
|
||||
invert_filter: false
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_1028_texas2
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 0
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_1028_texas2_2
|
||||
id: char_1028_texas2
|
||||
operator_logo: logo_penguin
|
||||
title: 'Arknights: Texas the Omertosa - 明日方舟:缄默德克萨斯'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: texas_the_omertosa
|
||||
type: operator
|
||||
date: 2022/11
|
||||
title: 'Arknights: Texas the Omertosa - 明日方舟:缄默德克萨斯'
|
||||
filename: dyn_illust_char_1028_texas2
|
||||
logo: logo_penguin
|
||||
fallback_name: char_1028_texas2_2
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 0
|
||||
viewport_bottom: 0
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_113_cqbw
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_bottom: 1
|
||||
viewport_left: 3
|
||||
viewport_right: -3
|
||||
viewport_top: 0
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_113_cqbw_2
|
||||
id: char_113_cqbw
|
||||
operator_logo: logo_babel
|
||||
title: 'Arknights: W - 明日方舟:W'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: w
|
||||
type: operator
|
||||
date: 2020/05
|
||||
title: 'Arknights: W - 明日方舟: W'
|
||||
filename: dyn_illust_char_113_cqbw
|
||||
logo: logo_babel
|
||||
fallback_name: char_113_cqbw_2
|
||||
viewport_left: 3
|
||||
viewport_right: -3
|
||||
viewport_top: 0
|
||||
viewport_bottom: 1
|
||||
invert_filter: true
|
||||
@@ -1,21 +1,12 @@
|
||||
_operator_settings.js:
|
||||
fallbackImage_height: 2048
|
||||
fallbackImage_width: 2048
|
||||
filename: dyn_illust_char_113_cqbw_epoque#7
|
||||
fps: 60
|
||||
opacity: 30
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
viewport_bottom: -4
|
||||
invert_filter: true
|
||||
index.html:
|
||||
fallback_name: char_113_cqbw_epoque%237
|
||||
id: char_113_cqbw_epoque%237
|
||||
operator_logo: logo_babel
|
||||
title: 'Arknights: Fugue / W - 明日方舟:恍惚·W'
|
||||
version: ${func:get_version()}
|
||||
project.json: !include config/_project.json.yaml
|
||||
link: w_fugue
|
||||
type: skin
|
||||
date: 2020/11
|
||||
title: 'Arknights: Fugue / W - 明日方舟:恍惚·W'
|
||||
filename: dyn_illust_char_113_cqbw_epoque#7
|
||||
logo: logo_babel
|
||||
fallback_name: char_113_cqbw_epoque#7
|
||||
viewport_left: 0
|
||||
viewport_right: 0
|
||||
viewport_top: 1
|
||||
viewport_bottom: -4
|
||||
invert_filter: true
|
||||
@@ -4,5 +4,6 @@
|
||||
"paths": {
|
||||
"@/*": ["src/*"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"exclude": ["node_modules", "**/node_modules", "dist", "operator", "release"]
|
||||
}
|
||||
31
lib/alpha_composite.js
Normal file
@@ -0,0 +1,31 @@
|
||||
import sharp from "sharp";
|
||||
import path from "path";
|
||||
|
||||
export default class AlphaComposite {
|
||||
#config
|
||||
#operatorName
|
||||
#operatorSourceFolder
|
||||
|
||||
constructor(config, operatorName, rootDir) {
|
||||
this.#config = config
|
||||
this.#operatorName = operatorName
|
||||
this.#operatorSourceFolder = path.join(rootDir, this.#config.folder.operator, this.#operatorName)
|
||||
}
|
||||
|
||||
async process(filename, extractedDir) {
|
||||
const image = sharp(path.join(extractedDir, filename))
|
||||
.removeAlpha()
|
||||
const imageMeta = await image.metadata()
|
||||
const imageBuffer = await image.toBuffer()
|
||||
const mask = await sharp(path.join(extractedDir, `${path.parse(filename).name}[alpha].png`))
|
||||
.extractChannel("blue")
|
||||
.resize(imageMeta.width, imageMeta.height)
|
||||
.toBuffer();
|
||||
|
||||
return sharp(imageBuffer)
|
||||
.joinChannel(mask)
|
||||
.toBuffer()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import pathlib
|
||||
from PIL import Image
|
||||
|
||||
class AlphaComposite:
|
||||
|
||||
def __init__(self, image_path: str, save_path) -> None:
|
||||
if image_path.strip().endswith(".png") is True:
|
||||
image_path = image_path.replace(".png", "")
|
||||
if save_path.strip().endswith(".png") is False:
|
||||
save_path += ".png"
|
||||
self.image_path = pathlib.Path.cwd().joinpath(image_path + ".png")
|
||||
self.mask_path = pathlib.Path.cwd().joinpath(image_path + "[alpha].png")
|
||||
self.save_path = save_path
|
||||
self.image = None
|
||||
self.mask = None
|
||||
self.loaded_image = None
|
||||
self.loaded_mask = None
|
||||
self.__open_image()
|
||||
self.__alpha_composite()
|
||||
pass
|
||||
|
||||
def __open_image(self):
|
||||
self.image = Image.open(self.image_path)
|
||||
self.mask = Image.open(self.mask_path)
|
||||
if self.image.size != self.mask.size:
|
||||
# resize mask
|
||||
self.mask = self.__resize(self.mask, self.image.size[0], self.image.size[1])
|
||||
self.loaded_image = self.image.load()
|
||||
self.loaded_mask = self.mask.load()
|
||||
|
||||
def __alpha_composite(self):
|
||||
for y in range(self.mask.size[1]):
|
||||
for x in range(self.mask.size[0]):
|
||||
self.loaded_image[x, y] = (self.loaded_image[x, y][0], self.loaded_image[x, y][1], self.loaded_image[x, y][2], self.loaded_mask[x, y][2])
|
||||
self.image.save(pathlib.Path.cwd().joinpath(self.save_path))
|
||||
|
||||
# resize image
|
||||
def __resize(self, image, width: int, height: int):
|
||||
return image.resize((width, height))
|
||||
44
lib/assets_processor.js
Normal file
@@ -0,0 +1,44 @@
|
||||
import path from 'path'
|
||||
import { copy, read, write } from './file.js'
|
||||
import AlphaComposite from './alpha_composite.js'
|
||||
|
||||
export default class AssetsProcessor {
|
||||
#config
|
||||
#operatorName
|
||||
#operatorSourceFolder
|
||||
#alphaCompositer
|
||||
|
||||
constructor(config, operatorName, rootDir) {
|
||||
this.#config = config
|
||||
this.#operatorName = operatorName
|
||||
this.#operatorSourceFolder = path.join(rootDir, this.#config.folder.operator)
|
||||
this.#alphaCompositer = new AlphaComposite(config, operatorName, rootDir)
|
||||
}
|
||||
|
||||
async process(publicAssetsDir, extractedDir) {
|
||||
const BASE64_BINARY_PREFIX = 'data:application/octet-stream;base64,'
|
||||
const BASE64_PNG_PREFIX = 'data:image/png;base64,'
|
||||
const assetsJson = {}
|
||||
const skelFilename = `${this.#config.operators[this.#operatorName].filename}.skel`
|
||||
const skel = await read(path.join(extractedDir, skelFilename), null)
|
||||
const atlasFilename = `${this.#config.operators[this.#operatorName].filename}.atlas`
|
||||
const atlas = await read(path.join(extractedDir, atlasFilename))
|
||||
const dimensions = atlas.match(new RegExp(/^size:(.*),(.*)/gm))[0].replace('size: ', '').split(',')
|
||||
const matches = atlas.match(new RegExp(/(.*).png/g))
|
||||
for (const item of matches) {
|
||||
const buffer = await this.#alphaCompositer.process(item, extractedDir)
|
||||
assetsJson[`./assets/${item}`] = BASE64_PNG_PREFIX + buffer.toString('base64')
|
||||
}
|
||||
assetsJson[`./assets/${skelFilename.replace('#', '%23')}`] = BASE64_BINARY_PREFIX + skel.toString('base64')
|
||||
assetsJson[`./assets/${atlasFilename.replace('#', '%23')}`] = BASE64_BINARY_PREFIX + Buffer.from(atlas).toString('base64')
|
||||
|
||||
const fallbackFilename = `${this.#config.operators[this.#operatorName].fallback_name}.png`
|
||||
const fallbackBuffer = await this.#alphaCompositer.process(fallbackFilename, extractedDir)
|
||||
await write(fallbackBuffer, path.join(this.#operatorSourceFolder, this.#operatorName, fallbackFilename))
|
||||
await copy(path.join(this.#operatorSourceFolder, this.#operatorName, fallbackFilename), path.join(publicAssetsDir, fallbackFilename))
|
||||
return {
|
||||
dimensions,
|
||||
assetsJson
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
class AtlasReader:
|
||||
|
||||
def __init__(self, file_path: str, save_path: str) -> None:
|
||||
if file_path.strip().endswith(".atlas") is False:
|
||||
file_path += ".atlas"
|
||||
if save_path.strip().endswith(".atlas") is False:
|
||||
save_path += ".atlas"
|
||||
|
||||
self.file_path = pathlib.Path.cwd().joinpath(file_path)
|
||||
self.save_path = pathlib.Path.cwd().joinpath(save_path)
|
||||
self.images = list()
|
||||
|
||||
def get_images(self):
|
||||
with open(self.file_path, "r") as f:
|
||||
line = f.readline()
|
||||
while line:
|
||||
line = line.strip()
|
||||
if line.endswith(".png") is True:
|
||||
self.images.append(line)
|
||||
line = f.readline()
|
||||
self.copy()
|
||||
return self.images
|
||||
|
||||
def copy(self):
|
||||
shutil.copyfile(
|
||||
self.file_path,
|
||||
self.save_path
|
||||
)
|
||||
@@ -1,49 +0,0 @@
|
||||
import base64
|
||||
import pathlib
|
||||
|
||||
def encode_binary(data=None, type="application/octet-stream", path=None, prefix=True):
|
||||
if data is None and path is None:
|
||||
raise ValueError("Both data and path arguments are None")
|
||||
if data is not None:
|
||||
bytes = data
|
||||
elif path is not None:
|
||||
with open(pathlib.Path.cwd().joinpath(path), "rb") as f:
|
||||
bytes = f.read()
|
||||
encoded_bytes = base64.b64encode(bytes)
|
||||
humanreadable_data = encoded_bytes.decode("utf-8")
|
||||
if prefix is True:
|
||||
result = "data:{};base64,".format(type) + humanreadable_data
|
||||
else:
|
||||
result = humanreadable_data
|
||||
return result
|
||||
|
||||
def decode_binary(data: str, path):
|
||||
if data.strip().startswith("data:") is True:
|
||||
data = data.split(",")[1]
|
||||
encoded_bytes = data.encode("utf-8")
|
||||
with open(pathlib.Path.cwd().joinpath(path), "wb") as f:
|
||||
bytes = base64.decodebytes(encoded_bytes)
|
||||
f.write(bytes)
|
||||
|
||||
def encode_string(data=None, type="text/plain", path=None, prefix=True, encoding="utf-8"):
|
||||
if data is None and path is None:
|
||||
raise ValueError("Both data and path arguments are None")
|
||||
if data is not None:
|
||||
bytes = data.encode(encoding)
|
||||
elif path is not None:
|
||||
with open(pathlib.Path.cwd().joinpath(path), "r") as f:
|
||||
bytes = f.read()
|
||||
encoded_bytes = base64.b64encode(bytes)
|
||||
humanreadable_data = encoded_bytes.decode(encoding)
|
||||
if prefix is True:
|
||||
result = "data:{};base64,".format(type) + humanreadable_data
|
||||
else:
|
||||
result = humanreadable_data
|
||||
return result
|
||||
|
||||
def decode_string(data:str, encoding="utf-8"):
|
||||
if data.strip().startswith("data:") is True:
|
||||
data = data.split(",")[1]
|
||||
encoded_bytes = data.encode(encoding)
|
||||
bytes = base64.decodebytes(encoded_bytes)
|
||||
return bytes.decode(encoding)
|
||||
286
lib/builder.py
@@ -1,286 +0,0 @@
|
||||
from multiprocessing import Process, Manager
|
||||
import shutil
|
||||
import json
|
||||
import operator
|
||||
from lib.alpha_composite import AlphaComposite
|
||||
from lib.atlas_reader import AtlasReader
|
||||
from lib.base64_util import *
|
||||
from lib.content_processor import ContentProcessor
|
||||
|
||||
class Builder:
|
||||
|
||||
def __init__(self, config, operator_names=list(), rebuild=False) -> None:
|
||||
self.operator_names = operator_names
|
||||
self.config = config
|
||||
self.rebuild = rebuild
|
||||
self.content_processor = None
|
||||
|
||||
def start(self):
|
||||
if "all" in self.operator_names:
|
||||
self.operator_names = [operator_name for operator_name in self.config["operators"]]
|
||||
for operator_name in self.operator_names:
|
||||
self.build(operator_name)
|
||||
self.__release_file(operator_name)
|
||||
return
|
||||
|
||||
def stop(self):
|
||||
return
|
||||
|
||||
def build(self, operator_name):
|
||||
thread_map = [
|
||||
dict(
|
||||
target=self.__build_assets,
|
||||
args=(operator_name,),
|
||||
),
|
||||
dict(
|
||||
target=self.__build_settings,
|
||||
args=(operator_name,),
|
||||
)
|
||||
]
|
||||
threads = list()
|
||||
self.content_processor = ContentProcessor(self.config, operator_name)
|
||||
|
||||
for item in thread_map:
|
||||
thread = Process(**item)
|
||||
threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
# use content processor to generate operator settings
|
||||
def __build_settings(self, operator_name):
|
||||
source_path = pathlib.Path.cwd().joinpath("operator", operator_name, "config")
|
||||
target_path = pathlib.Path.cwd().joinpath("operator", operator_name)
|
||||
for file in source_path.iterdir():
|
||||
if file.is_file() is True:
|
||||
file_path = pathlib.Path.cwd().joinpath(target_path, file.name)
|
||||
self.content_processor.build(
|
||||
file,
|
||||
file_path
|
||||
)
|
||||
return
|
||||
|
||||
def __build_assets(self, operator_name):
|
||||
file_paths = dict(
|
||||
source=self.config["operator"]["source_folder"].format(name=operator_name),
|
||||
target=self.config["operator"]["target_folder"].format(name=operator_name),
|
||||
common_name=self.config["operators"][operator_name]["_operator_settings.js"]["filename"],
|
||||
fallback_name=self.config["operators"][operator_name]["index.html"]["fallback_name"].replace("%23", "#") if self.config["operators"][operator_name]["index.html"]["fallback_name"] is not None else None,
|
||||
id_name=self.config["operators"][operator_name]["index.html"]["id"].replace("%23", "#")
|
||||
)
|
||||
|
||||
operator_file = pathlib.Path.cwd().joinpath(file_paths["target"], "..", "{}_assets.js".format(file_paths["id_name"]))
|
||||
if operator_file.exists() is False or self.rebuild is True:
|
||||
print("Building operator data for {}...".format(operator_name))
|
||||
|
||||
prefix = "window.operatorAssets = "
|
||||
manager = Manager()
|
||||
data = manager.dict()
|
||||
|
||||
thread_map = [
|
||||
dict(
|
||||
target=self.__ar_thread,
|
||||
args=(
|
||||
file_paths,
|
||||
data
|
||||
),
|
||||
),
|
||||
dict(
|
||||
target=self.__skeleton_binary_thread,
|
||||
args=(
|
||||
file_paths,
|
||||
data
|
||||
),
|
||||
),
|
||||
dict(
|
||||
target=self.__fallback_thread,
|
||||
args=(
|
||||
file_paths,
|
||||
data
|
||||
),
|
||||
),
|
||||
]
|
||||
threads = list()
|
||||
for item in thread_map:
|
||||
thread = Process(**item)
|
||||
threads.append(thread)
|
||||
thread.start()
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
sorted_data = dict()
|
||||
for i in sorted(data.keys()):
|
||||
sorted_data[i] = data[i]
|
||||
|
||||
json_content = prefix + str(sorted_data)
|
||||
with open(operator_file, "w") as f:
|
||||
f.write(json_content)
|
||||
|
||||
print("Finished building operator data for {}.".format(operator_name))
|
||||
else:
|
||||
print("Operator data for {} has been built.".format(operator_name))
|
||||
return
|
||||
|
||||
def __ar_thread(self, file_paths, data):
|
||||
source_path = file_paths["source"]
|
||||
target_path = file_paths["target"]
|
||||
common_name = file_paths["common_name"]
|
||||
|
||||
png_to_base64_threads = list()
|
||||
alpha_composite_threads = list()
|
||||
ar = AtlasReader(source_path + common_name, target_path + common_name)
|
||||
images = ar.get_images()
|
||||
atlas_to_base64_thread = Process(
|
||||
target=self.__atlas_to_base64,
|
||||
args=(
|
||||
target_path + common_name + ".atlas",
|
||||
data,
|
||||
self.config["server"]["operator_folder"] + common_name + ".atlas",
|
||||
),
|
||||
)
|
||||
atlas_to_base64_thread.start()
|
||||
|
||||
for item in images:
|
||||
alpha_composite_thread = Process(
|
||||
target=AlphaComposite,
|
||||
args=(source_path + item, target_path + item),
|
||||
)
|
||||
alpha_composite_threads.append(alpha_composite_thread)
|
||||
alpha_composite_thread.start()
|
||||
for thread in alpha_composite_threads:
|
||||
thread.join()
|
||||
|
||||
for item in images:
|
||||
png_to_base64_thread = Process(
|
||||
target=self.__png_to_base64,
|
||||
args=(
|
||||
target_path + item,
|
||||
data,
|
||||
self.config["server"]["operator_folder"] + item,
|
||||
),
|
||||
)
|
||||
|
||||
png_to_base64_threads.append(png_to_base64_thread)
|
||||
png_to_base64_thread.start()
|
||||
for thread in png_to_base64_threads:
|
||||
thread.join()
|
||||
atlas_to_base64_thread.join()
|
||||
|
||||
def __skeleton_binary_thread(self, file_paths, data):
|
||||
source_path = file_paths["source"]
|
||||
target_path = file_paths["target"]
|
||||
common_name = file_paths["common_name"]
|
||||
if common_name.strip().endswith(".skel") is False:
|
||||
common_name += ".skel"
|
||||
file_path = pathlib.Path.cwd().joinpath(source_path + common_name)
|
||||
save_path = pathlib.Path.cwd().joinpath(target_path + common_name)
|
||||
shutil.copyfile(
|
||||
file_path,
|
||||
save_path
|
||||
)
|
||||
self.__skel_to_base64(
|
||||
save_path,
|
||||
data,
|
||||
self.config["server"]["operator_folder"] + common_name,
|
||||
)
|
||||
|
||||
def __fallback_thread(self, file_paths, data):
|
||||
source_path = file_paths["source"]
|
||||
target_path = file_paths["target"]
|
||||
fallback_name = file_paths["fallback_name"]
|
||||
if fallback_name is not None:
|
||||
AlphaComposite(source_path + fallback_name, target_path + "../{}".format(fallback_name))
|
||||
|
||||
def __json_to_base64(self, path, dict=None, key=None):
|
||||
with open(pathlib.Path.cwd().joinpath(path), "r") as f:
|
||||
data = f.read()
|
||||
result = encode_string(data, type="application/json")
|
||||
if dict is not None and key is not None:
|
||||
dict[key] = result
|
||||
else:
|
||||
return result
|
||||
|
||||
def __skel_to_base64(self, path, dict=None, key=None):
|
||||
result = encode_binary(
|
||||
path=path
|
||||
)
|
||||
if dict is not None and key is not None:
|
||||
dict[key] = result
|
||||
else:
|
||||
return result
|
||||
|
||||
def __atlas_to_base64(self, path, dict=None, key=None):
|
||||
with open(pathlib.Path.cwd().joinpath(path), "r") as f:
|
||||
data = f.read()
|
||||
result = encode_string(data, type="application/octet-stream")
|
||||
if dict is not None and key is not None:
|
||||
dict[key] = result
|
||||
else:
|
||||
return result
|
||||
|
||||
def __png_to_base64(self, path, dict=None, key=None):
|
||||
result = encode_binary(
|
||||
path=path,
|
||||
type="image/png"
|
||||
)
|
||||
if dict is not None and key is not None:
|
||||
dict[key] = result
|
||||
else:
|
||||
return result
|
||||
|
||||
def __release_file(self, operator_name):
|
||||
target_path = self.config["server"]["release_folder"]
|
||||
operator_release_path = pathlib.Path.cwd().joinpath(target_path, operator_name)
|
||||
release_operator_assets_path = pathlib.Path.cwd().joinpath(operator_release_path, self.config["server"]["operator_folder"])
|
||||
operator_assets_path = pathlib.Path.cwd().joinpath(self.config["operator"]["target_folder"].format(name=operator_name), "..")
|
||||
template_path = pathlib.Path.cwd().joinpath(self.config["server"]["template_folder"])
|
||||
|
||||
if operator_release_path.exists() is True:
|
||||
shutil.rmtree(operator_release_path)
|
||||
operator_release_path.mkdir()
|
||||
release_operator_assets_path.mkdir()
|
||||
|
||||
for file in operator_assets_path.iterdir():
|
||||
if file.is_file() is True:
|
||||
filename = file.name
|
||||
if filename == self.config["operator"]["project_json"] or filename == self.config["operator"]["preview"]:
|
||||
file_path = pathlib.Path.cwd().joinpath(operator_release_path, filename)
|
||||
else:
|
||||
file_path = pathlib.Path.cwd().joinpath(release_operator_assets_path, filename)
|
||||
|
||||
shutil.copyfile(
|
||||
file,
|
||||
file_path
|
||||
)
|
||||
|
||||
# template folder uses content processor to generate files
|
||||
for file in template_path.iterdir():
|
||||
if file.is_file() is True:
|
||||
file_path = pathlib.Path.cwd().joinpath(operator_release_path, file.name)
|
||||
|
||||
self.content_processor.build(file, file_path)
|
||||
elif file.is_dir() is True:
|
||||
file_path = pathlib.Path.cwd().joinpath(operator_release_path, file.name)
|
||||
|
||||
shutil.copytree(
|
||||
file,
|
||||
file_path
|
||||
)
|
||||
|
||||
# generate a directory.json for index page
|
||||
save_path = pathlib.Path.cwd().joinpath(
|
||||
self.config["index"]["src_folder"], "directory.json")
|
||||
directory_json = []
|
||||
for key, value in self.config["operators"].items():
|
||||
directory_json.append(dict(
|
||||
name=key,
|
||||
link=value["link"],
|
||||
type=value["type"],
|
||||
date=value["date"]
|
||||
))
|
||||
directory_json.sort(key=operator.itemgetter("date", "name"), reverse=True)
|
||||
with open(save_path, 'w', encoding='utf8') as fp:
|
||||
json.dump(directory_json, fp)
|
||||
return
|
||||
9
lib/config.js
Normal file
@@ -0,0 +1,9 @@
|
||||
import path from 'path'
|
||||
import { read } from './yaml.js'
|
||||
|
||||
export default function (dirname) {
|
||||
return {
|
||||
basedir: dirname,
|
||||
...read(path.join(dirname, 'config.yaml'))
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import pathlib, yaml
|
||||
from yamlinclude import YamlIncludeConstructor
|
||||
|
||||
class Config:
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.config_path = pathlib.Path.cwd().joinpath("config.yaml")
|
||||
|
||||
def read(self):
|
||||
return self.__read_config()
|
||||
|
||||
def __read_config(self):
|
||||
try:
|
||||
YamlIncludeConstructor.add_to_loader_class(loader_class=yaml.FullLoader, base_dir=pathlib.Path.cwd())
|
||||
return yaml.load(open(self.config_path, "r"), Loader=yaml.FullLoader)
|
||||
except Exception as e:
|
||||
raise
|
||||
72
lib/content_processor.js
Normal file
@@ -0,0 +1,72 @@
|
||||
export default class Matcher {
|
||||
#start
|
||||
#end
|
||||
#content
|
||||
#reExp
|
||||
#config
|
||||
|
||||
constructor(content, start, end, config) {
|
||||
this.#start = start
|
||||
this.#end = end
|
||||
this.#content = content
|
||||
this.#reExp = new RegExp(`\\${start}.+?${end}`, 'g')
|
||||
this.#config = config
|
||||
}
|
||||
|
||||
match() {
|
||||
return this.#content.match(this.#reExp)
|
||||
}
|
||||
|
||||
process() {
|
||||
const matches = this.match()
|
||||
if (matches !== null) {
|
||||
matches.forEach((match) => {
|
||||
const matchTypeName = match.replace(this.#start, '').replace(this.#end, '')
|
||||
const type = matchTypeName.split(':')[0]
|
||||
const name = matchTypeName.split(':')[1]
|
||||
switch (type) {
|
||||
case 'var':
|
||||
let replaceValue = this.#config
|
||||
name.split('->').forEach((item) => {
|
||||
try {
|
||||
replaceValue = replaceValue[item]
|
||||
} catch (e) {
|
||||
throw new Error(`Cannot find variable ${name}.`)
|
||||
}
|
||||
this.#content = this.#content.replace(match, replaceValue)
|
||||
})
|
||||
break
|
||||
case 'func':
|
||||
try {
|
||||
this.#content = this.#content.replace(match, (new Function('Evalable', 'config', `return new Evalable(config).${name}`))(Evalable, this.#config))
|
||||
} catch (e) {
|
||||
throw new Error(e)
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Cannot find type ${type}.`)
|
||||
}
|
||||
})
|
||||
}
|
||||
return this.#content
|
||||
}
|
||||
}
|
||||
|
||||
class Evalable {
|
||||
#config
|
||||
|
||||
constructor(config) {
|
||||
this.#config = config
|
||||
}
|
||||
|
||||
split(varName, separator) {
|
||||
varName.split("->").forEach((item) => {
|
||||
try {
|
||||
this.#config = this.#config[item]
|
||||
} catch (e) {
|
||||
throw new Error(`Cannot split ${varName} with separator ${separator}.`)
|
||||
}
|
||||
})
|
||||
return this.#config.split(separator)
|
||||
}
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
import pathlib
|
||||
import shutil
|
||||
import re
|
||||
|
||||
class ContentProcessor:
|
||||
|
||||
def __init__(self, config, operator_name):
|
||||
self.config = config["operators"][operator_name]
|
||||
self.file_to_process = [key for key, value in self.config.items() if key.startswith("_") is False]
|
||||
self.settings = self.config
|
||||
self.__process_value()
|
||||
|
||||
def process(self, file_path):
|
||||
file_path = pathlib.Path.cwd().joinpath(file_path)
|
||||
with open(file_path, "r") as f:
|
||||
content = f.read()
|
||||
if file_path.name in self.file_to_process:
|
||||
content = Matcher(content, "${format:", "}", self.settings)
|
||||
return content.format(file_path.name)
|
||||
else:
|
||||
return content
|
||||
|
||||
def build(self, source_path, target_path):
|
||||
if source_path.name in self.file_to_process:
|
||||
content = self.process(source_path)
|
||||
with open(pathlib.Path.cwd().joinpath(target_path), "w") as f:
|
||||
f.write(content)
|
||||
else:
|
||||
shutil.copyfile(
|
||||
source_path,
|
||||
target_path
|
||||
)
|
||||
|
||||
def __process_value(self):
|
||||
for item_key, item_value in self.settings.items():
|
||||
for key, value in item_value.items() if type(item_value) == dict else {}:
|
||||
matcher = Matcher(value, "${", "}", self.settings)
|
||||
if matcher.match():
|
||||
replace_value = matcher.process()
|
||||
else:
|
||||
replace_value = value
|
||||
self.settings[item_key][key] = replace_value
|
||||
# copy dict value _operator_settings.js to {id}_settings.js
|
||||
settings_filename = "{}_settings.js".format(self.settings["index.html"]["id"].replace("%23", "#"))
|
||||
self.settings[settings_filename] = self.settings["_operator_settings.js"]
|
||||
self.file_to_process.append(settings_filename)
|
||||
|
||||
class Evalable:
|
||||
def __init__(self, settings):
|
||||
self.settings = settings
|
||||
|
||||
def get_version(self):
|
||||
with open(pathlib.Path.cwd().joinpath("Version"), "r") as f:
|
||||
version = f.read()
|
||||
return version
|
||||
|
||||
def split(self, var_name, separator):
|
||||
for var in var_name.split("->"):
|
||||
try:
|
||||
self.settings = self.settings[var]
|
||||
except Exception as e:
|
||||
raise e
|
||||
return self.settings.split(separator)
|
||||
|
||||
class Matcher:
|
||||
def __init__(self, content, start, end, settings):
|
||||
self.start = start
|
||||
self.end = end
|
||||
self.content = str(content)
|
||||
self.settings = settings
|
||||
self.re_exp = re.compile("\{}.+?{}".format(start, end))
|
||||
|
||||
def match(self):
|
||||
return re.search(self.re_exp, self.content) is not None
|
||||
|
||||
def process(self):
|
||||
for match in re.findall(self.re_exp, self.content):
|
||||
type = match.replace(self.start, "").replace(self.end, "").split(":")[0]
|
||||
name = match.replace(self.start, "").replace(self.end, "").split(":")[1]
|
||||
if type == "func":
|
||||
try:
|
||||
self.content = self.content.replace(match, eval("Evalable(self.settings)." + name))
|
||||
except Exception as e:
|
||||
raise e
|
||||
elif type == "var":
|
||||
replace_value = self.settings
|
||||
for var in name.split("->"):
|
||||
try:
|
||||
replace_value = replace_value[var]
|
||||
except Exception as e:
|
||||
raise e
|
||||
self.content = self.content.replace(match, str(replace_value))
|
||||
else:
|
||||
raise Exception("Unsupported type: {}".format(type))
|
||||
return self.content
|
||||
|
||||
def format(self, filename):
|
||||
for key, value in self.settings[filename].items():
|
||||
identifier = self.start + key + self.end
|
||||
self.content = self.content.replace(identifier, str(value))
|
||||
return self.content
|
||||
32
lib/env_generator.js
Normal file
@@ -0,0 +1,32 @@
|
||||
import path from 'path'
|
||||
|
||||
export default class EnvGenerator {
|
||||
#config
|
||||
|
||||
constructor(config, operatorName) {
|
||||
this.#config = config.operators[operatorName]
|
||||
}
|
||||
|
||||
async generate(dimensions) {
|
||||
return await this.#promise(dimensions)
|
||||
}
|
||||
|
||||
#promise(dimensions) {
|
||||
return new Promise((resolve, reject) => {
|
||||
resolve([
|
||||
`VITE_TITLE="${this.#config.title}"`,
|
||||
`VITE_FILENAME=${this.#config.filename.replace('#', '%23')}`,
|
||||
`VITE_LOGO_FILENAME=${this.#config.logo}`,
|
||||
`VITE_FALLBACK_FILENAME=${this.#config.fallback_name.replace('#', '%23')}`,
|
||||
`VITE_VIEWPORT_LEFT=${this.#config.viewport_left}`,
|
||||
`VITE_VIEWPORT_RIGHT=${this.#config.viewport_right}`,
|
||||
`VITE_VIEWPORT_TOP=${this.#config.viewport_top}`,
|
||||
`VITE_VIEWPORT_BOTTOM=${this.#config.viewport_bottom}`,
|
||||
`VITE_INVERT_FILTER=${this.#config.invert_filter}`,
|
||||
`VITE_IMAGE_WIDTH=${dimensions[0]}`,
|
||||
`VITE_IMAGE_HEIGHT=${dimensions[1]}`,
|
||||
].join('\n'))
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
42
lib/file.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import fs, { promises as fsP } from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
export async function write(content, filePath) {
|
||||
mkdir(path.dirname(filePath))
|
||||
return await fsP.writeFile(filePath, content, { flag: 'w' })
|
||||
}
|
||||
|
||||
export async function read(filePath, encoding = 'utf8') {
|
||||
return await fsP.readFile(filePath, encoding, { flag: 'r' })
|
||||
}
|
||||
|
||||
export function exists(filePath) {
|
||||
return fs.existsSync(filePath)
|
||||
}
|
||||
|
||||
export function rmdir(dir) {
|
||||
if (exists(dir)) {
|
||||
fs.rmSync(dir, { recursive: true })
|
||||
}
|
||||
}
|
||||
|
||||
export function rm(file) {
|
||||
if (exists(file)) {
|
||||
fs.rmSync(file)
|
||||
}
|
||||
}
|
||||
|
||||
export function mkdir(dir) {
|
||||
if (!exists(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true })
|
||||
}
|
||||
}
|
||||
|
||||
export async function copy(sourcePath, targetPath) {
|
||||
if (!exists(sourcePath)) {
|
||||
console.warn(`Source file ${sourcePath} does not exist.`)
|
||||
return
|
||||
}
|
||||
mkdir(path.dirname(targetPath))
|
||||
return await fsP.copyFile(sourcePath, targetPath)
|
||||
}
|
||||
7
lib/initializer.js
Normal file
@@ -0,0 +1,7 @@
|
||||
import path from 'path'
|
||||
import { mkdir, copy } from './file.js'
|
||||
|
||||
export default function init(operatorName, __dirname, extractedDir) {
|
||||
mkdir(extractedDir)
|
||||
copy(path.join(__dirname, 'config', '_template.yaml'), path.join(__dirname, 'config', `${operatorName}.yaml`))
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
import pathlib, shutil
|
||||
|
||||
class Initializer:
|
||||
|
||||
def __init__(self, config, operator_name) -> None:
|
||||
self.config = config
|
||||
self.operator_name = operator_name
|
||||
pass
|
||||
|
||||
def start(self):
|
||||
self.__copy_files()
|
||||
return
|
||||
|
||||
def __copy_files(self):
|
||||
# ./operator/<operator_name>
|
||||
operator_assets_path = pathlib.Path.cwd().joinpath(self.config["server"]["operator_folder"], self.operator_name)
|
||||
if operator_assets_path.exists() is True:
|
||||
shutil.rmtree(operator_assets_path)
|
||||
operator_assets_path.mkdir()
|
||||
|
||||
dir_map = dict(
|
||||
config=pathlib.Path.cwd().joinpath(operator_assets_path, "config"),
|
||||
extracted=pathlib.Path.cwd().joinpath(operator_assets_path, "extracted"),
|
||||
processed=pathlib.Path.cwd().joinpath(operator_assets_path, "processed")
|
||||
)
|
||||
|
||||
for key, path in dir_map.items():
|
||||
path.mkdir()
|
||||
|
||||
# copy file
|
||||
operator_settings_path = pathlib.Path.cwd().joinpath(self.config["server"]["operator_folder"], "_share")
|
||||
logo_path = pathlib.Path.cwd().joinpath(operator_settings_path, "logo")
|
||||
copy_map = [
|
||||
dict(
|
||||
source_name="operator_settings.js",
|
||||
target_name="{}_settings.js".format(self.config["operators"][self.operator_name]["index.html"]["id"].replace("%23", "#")),
|
||||
source_path=operator_settings_path,
|
||||
target_path=dir_map["config"],
|
||||
),
|
||||
dict(
|
||||
source_name="project.json",
|
||||
target_name="project.json",
|
||||
source_path=operator_settings_path,
|
||||
target_path=dir_map["config"],
|
||||
),
|
||||
dict(
|
||||
source_name="operator_bg.png",
|
||||
target_name="operator_bg.png",
|
||||
source_path=operator_settings_path,
|
||||
target_path=operator_assets_path,
|
||||
),
|
||||
dict(
|
||||
source_name="{}.png".format(self.config["operators"][self.operator_name]["index.html"]["operator_logo"]),
|
||||
target_name="{}.png".format(self.config["operators"][self.operator_name]["index.html"]["operator_logo"]),
|
||||
source_path=logo_path,
|
||||
target_path=operator_assets_path,
|
||||
),
|
||||
]
|
||||
for item in copy_map:
|
||||
shutil.copy(
|
||||
pathlib.Path.cwd().joinpath(item["source_path"], item["source_name"]),
|
||||
pathlib.Path.cwd().joinpath(item["target_path"], item["target_name"])
|
||||
)
|
||||
return
|
||||
70
lib/project_json.js
Normal file
@@ -0,0 +1,70 @@
|
||||
import path from 'path'
|
||||
import Matcher from './content_processor.js'
|
||||
import { read, exists } from './file.js'
|
||||
|
||||
export default class ProjectJson {
|
||||
#json
|
||||
#config
|
||||
#operatorName
|
||||
#operatorSourceFolder
|
||||
#operatorShareFolder
|
||||
|
||||
constructor(config, operatorName, __dirname, operatorShareFolder) {
|
||||
this.#config = config
|
||||
this.#operatorName = operatorName
|
||||
this.#operatorSourceFolder = path.join(__dirname, this.#config.folder.operator)
|
||||
this.#operatorShareFolder = operatorShareFolder
|
||||
}
|
||||
|
||||
async load() {
|
||||
// load json from file
|
||||
this.#json = JSON.parse(await read(this.#getPath()))
|
||||
this.#process()
|
||||
return this.#json
|
||||
}
|
||||
|
||||
#getPath() {
|
||||
// if exists, do not use the template
|
||||
const defaultPath = path.join(this.#operatorSourceFolder, this.#operatorName, 'project.json')
|
||||
if (exists(defaultPath)) {
|
||||
return defaultPath
|
||||
} else {
|
||||
return path.join(this.#operatorShareFolder, 'project.json')
|
||||
}
|
||||
}
|
||||
|
||||
#process() {
|
||||
const matcher = new Matcher(this.#json.description, '${', '}', this.#config.operators[this.#operatorName])
|
||||
if (matcher.match() !== null) {
|
||||
this.#json.description = matcher.process()
|
||||
}
|
||||
this.#json = {
|
||||
...this.#json,
|
||||
description: this.#json.description,
|
||||
title: this.#config.operators[this.#operatorName].title,
|
||||
general: {
|
||||
...this.#json.general,
|
||||
properties: {
|
||||
...this.#json.general.properties,
|
||||
paddingbottom: {
|
||||
...this.#json.general.properties.paddingbottom,
|
||||
value: this.#config.operators[this.#operatorName].viewport_bottom
|
||||
},
|
||||
paddingleft: {
|
||||
...this.#json.general.properties.paddingleft,
|
||||
value: this.#config.operators[this.#operatorName].viewport_left
|
||||
},
|
||||
paddingright: {
|
||||
...this.#json.general.properties.paddingright,
|
||||
value: this.#config.operators[this.#operatorName].viewport_right
|
||||
},
|
||||
paddingtop: {
|
||||
...this.#json.general.properties.paddingtop,
|
||||
value: this.#config.operators[this.#operatorName].viewport_top
|
||||
},
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
import pathlib
|
||||
from http.server import SimpleHTTPRequestHandler
|
||||
from socketserver import TCPServer
|
||||
|
||||
from lib.builder import Builder
|
||||
from lib.content_processor import ContentProcessor
|
||||
class Server:
|
||||
|
||||
def __init__(self, port, operator, config, rebuild) -> None:
|
||||
self.config = config
|
||||
self.operator = operator
|
||||
self.port = port
|
||||
self.rebuild = rebuild
|
||||
self.httpd = TCPServer(("", port), httpd(operator, config, directory=str(pathlib.Path.cwd())))
|
||||
|
||||
def start(self):
|
||||
# build assets first
|
||||
Builder(self.config, rebuild=self.rebuild).build(self.operator)
|
||||
print("Server is up at 0.0.0.0:{port}".format(port=self.port))
|
||||
self.httpd.serve_forever()
|
||||
return
|
||||
|
||||
def stop(self):
|
||||
self.httpd.server_close()
|
||||
return
|
||||
|
||||
class httpd(SimpleHTTPRequestHandler):
|
||||
|
||||
def __init__(self, operator, config, directory):
|
||||
self.config = config["server"]
|
||||
self.operator = operator
|
||||
self.template_path = directory
|
||||
self.content_processor = ContentProcessor(config, operator)
|
||||
|
||||
def __call__(self, *args, **kwds):
|
||||
super().__init__(*args, directory=self.template_path, **kwds)
|
||||
|
||||
def do_GET(self):
|
||||
# ignore query string
|
||||
if "?" in self.path:
|
||||
self.path = self.path.split("?")[0]
|
||||
|
||||
split_path = self.path.split("/")
|
||||
access_path = "./{}/".format(split_path[1])
|
||||
|
||||
if self.path == "/":
|
||||
# self.path = self.config["template_folder"] + "index.html"
|
||||
self.send_response(200)
|
||||
self.send_header("Content-type", "text/html")
|
||||
self.end_headers()
|
||||
html = self.content_processor.process(self.config["template_folder"] + "index.html")
|
||||
self.wfile.write(bytes(html, "utf8"))
|
||||
return
|
||||
elif access_path == "./assets/":
|
||||
# assets folder
|
||||
self.path = self.config["template_folder"] + "assets/" + "/".join([i for i in split_path[2:]])
|
||||
elif self.config["operator_folder"] == access_path:
|
||||
# operator folder
|
||||
self.path = self.config["operator_folder"] + "{}/".format(self.operator) + split_path[-1]
|
||||
return SimpleHTTPRequestHandler.do_GET(self)
|
||||
19
lib/yaml.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import path from 'path'
|
||||
import { parse } from 'yaml'
|
||||
import fs from 'fs'
|
||||
|
||||
export function read(file_dir) {
|
||||
const include = {
|
||||
identify: value => value.startsWith('!include'),
|
||||
tag: '!include',
|
||||
resolve(str) {
|
||||
const dir = path.resolve(path.dirname(file_dir), str)
|
||||
const data = read(dir)
|
||||
return data
|
||||
}
|
||||
}
|
||||
const file = fs.readFileSync(file_dir, 'utf8')
|
||||
return parse(file, {
|
||||
customTags: [include],
|
||||
})
|
||||
}
|
||||
@@ -9,7 +9,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"preact": "^10.11.3"
|
||||
"preact": "^10.11.3",
|
||||
"sharp": "^0.31.3",
|
||||
"yaml": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "^2.4.0",
|
||||
291
template/showcase/pnpm-lock.yaml → pnpm-lock.yaml
generated
@@ -3,10 +3,14 @@ lockfileVersion: 5.4
|
||||
specifiers:
|
||||
'@preact/preset-vite': ^2.4.0
|
||||
preact: ^10.11.3
|
||||
sharp: ^0.31.3
|
||||
vite: ^4.0.0
|
||||
yaml: ^2.2.1
|
||||
|
||||
dependencies:
|
||||
preact: 10.11.3
|
||||
sharp: 0.31.3
|
||||
yaml: 2.2.1
|
||||
|
||||
devDependencies:
|
||||
'@preact/preset-vite': 2.5.0_6lv424qzfa5w4k4pp4rg6latw4
|
||||
@@ -575,6 +579,18 @@ packages:
|
||||
'@babel/core': 7.20.7
|
||||
dev: true
|
||||
|
||||
/base64-js/1.5.1:
|
||||
resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==}
|
||||
dev: false
|
||||
|
||||
/bl/4.1.0:
|
||||
resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==}
|
||||
dependencies:
|
||||
buffer: 5.7.1
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
dev: false
|
||||
|
||||
/browserslist/4.21.4:
|
||||
resolution: {integrity: sha512-CBHJJdDmgjl3daYjN5Cp5kbTf1mUhZoS+beLklHIvkOWscs83YAhLlF3Wsh/lciQYAcbBJgTOD44VtG31ZM4Hw==}
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
@@ -586,6 +602,13 @@ packages:
|
||||
update-browserslist-db: 1.0.10_browserslist@4.21.4
|
||||
dev: true
|
||||
|
||||
/buffer/5.7.1:
|
||||
resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==}
|
||||
dependencies:
|
||||
base64-js: 1.5.1
|
||||
ieee754: 1.2.1
|
||||
dev: false
|
||||
|
||||
/caniuse-lite/1.0.30001441:
|
||||
resolution: {integrity: sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==}
|
||||
dev: true
|
||||
@@ -599,15 +622,44 @@ packages:
|
||||
supports-color: 5.5.0
|
||||
dev: true
|
||||
|
||||
/chownr/1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
dev: false
|
||||
|
||||
/color-convert/1.9.3:
|
||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||
dependencies:
|
||||
color-name: 1.1.3
|
||||
dev: true
|
||||
|
||||
/color-convert/2.0.1:
|
||||
resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==}
|
||||
engines: {node: '>=7.0.0'}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
dev: false
|
||||
|
||||
/color-name/1.1.3:
|
||||
resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==}
|
||||
dev: true
|
||||
|
||||
/color-name/1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
dev: false
|
||||
|
||||
/color-string/1.9.1:
|
||||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||
dependencies:
|
||||
color-name: 1.1.3
|
||||
simple-swizzle: 0.2.2
|
||||
dev: false
|
||||
|
||||
/color/4.2.3:
|
||||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
|
||||
engines: {node: '>=12.5.0'}
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
dev: false
|
||||
|
||||
/convert-source-map/1.9.0:
|
||||
resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==}
|
||||
@@ -625,10 +677,33 @@ packages:
|
||||
ms: 2.1.2
|
||||
dev: true
|
||||
|
||||
/decompress-response/6.0.0:
|
||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
dev: false
|
||||
|
||||
/deep-extend/0.6.0:
|
||||
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
dev: false
|
||||
|
||||
/detect-libc/2.0.1:
|
||||
resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==}
|
||||
engines: {node: '>=8'}
|
||||
dev: false
|
||||
|
||||
/electron-to-chromium/1.4.284:
|
||||
resolution: {integrity: sha512-M8WEXFuKXMYMVr45fo8mq0wUrrJHheiKZf6BArTKk9ZBYCKJEOU5H8cdWgDT+qCVZf7Na4lVUaZsA+h6uA9+PA==}
|
||||
dev: true
|
||||
|
||||
/end-of-stream/1.4.4:
|
||||
resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==}
|
||||
dependencies:
|
||||
once: 1.4.0
|
||||
dev: false
|
||||
|
||||
/esbuild/0.16.13:
|
||||
resolution: {integrity: sha512-oYwFdSEIoKM1oYzyem1osgKJAvg5447XF+05ava21fOtilyb2HeQQh26/74K4WeAk5dZmj/Mx10zUqUnI14jhA==}
|
||||
engines: {node: '>=12'}
|
||||
@@ -673,6 +748,15 @@ packages:
|
||||
resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==}
|
||||
dev: true
|
||||
|
||||
/expand-template/2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: false
|
||||
|
||||
/fs-constants/1.0.0:
|
||||
resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==}
|
||||
dev: false
|
||||
|
||||
/fsevents/2.3.2:
|
||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
@@ -690,6 +774,10 @@ packages:
|
||||
engines: {node: '>=6.9.0'}
|
||||
dev: true
|
||||
|
||||
/github-from-package/0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
dev: false
|
||||
|
||||
/globals/11.12.0:
|
||||
resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -707,6 +795,22 @@ packages:
|
||||
function-bind: 1.1.1
|
||||
dev: true
|
||||
|
||||
/ieee754/1.2.1:
|
||||
resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==}
|
||||
dev: false
|
||||
|
||||
/inherits/2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
dev: false
|
||||
|
||||
/ini/1.3.8:
|
||||
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
|
||||
dev: false
|
||||
|
||||
/is-arrayish/0.3.2:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
dev: false
|
||||
|
||||
/is-core-module/2.11.0:
|
||||
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
|
||||
dependencies:
|
||||
@@ -739,6 +843,26 @@ packages:
|
||||
yallist: 3.1.1
|
||||
dev: true
|
||||
|
||||
/lru-cache/6.0.0:
|
||||
resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
yallist: 4.0.0
|
||||
dev: false
|
||||
|
||||
/mimic-response/3.1.0:
|
||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: false
|
||||
|
||||
/minimist/1.2.7:
|
||||
resolution: {integrity: sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==}
|
||||
dev: false
|
||||
|
||||
/mkdirp-classic/0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
dev: false
|
||||
|
||||
/ms/2.1.2:
|
||||
resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==}
|
||||
dev: true
|
||||
@@ -749,10 +873,31 @@ packages:
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/napi-build-utils/1.0.2:
|
||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||
dev: false
|
||||
|
||||
/node-abi/3.31.0:
|
||||
resolution: {integrity: sha512-eSKV6s+APenqVh8ubJyiu/YhZgxQpGP66ntzUb3lY1xB9ukSRaGnx0AIxI+IM+1+IVYC1oWobgG5L3Lt9ARykQ==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
semver: 7.3.8
|
||||
dev: false
|
||||
|
||||
/node-addon-api/5.1.0:
|
||||
resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==}
|
||||
dev: false
|
||||
|
||||
/node-releases/2.0.8:
|
||||
resolution: {integrity: sha512-dFSmB8fFHEH/s81Xi+Y/15DQY6VHW81nXRj86EMSL3lmuTmK1e+aT4wrFCkTbm+gSwkw4KpX+rT/pMM2c1mF+A==}
|
||||
dev: true
|
||||
|
||||
/once/1.4.0:
|
||||
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
|
||||
dependencies:
|
||||
wrappy: 1.0.2
|
||||
dev: false
|
||||
|
||||
/path-parse/1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
dev: true
|
||||
@@ -778,6 +923,51 @@ packages:
|
||||
/preact/10.11.3:
|
||||
resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==}
|
||||
|
||||
/prebuild-install/7.1.1:
|
||||
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
detect-libc: 2.0.1
|
||||
expand-template: 2.0.3
|
||||
github-from-package: 0.0.0
|
||||
minimist: 1.2.7
|
||||
mkdirp-classic: 0.5.3
|
||||
napi-build-utils: 1.0.2
|
||||
node-abi: 3.31.0
|
||||
pump: 3.0.0
|
||||
rc: 1.2.8
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: false
|
||||
|
||||
/pump/3.0.0:
|
||||
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
|
||||
dependencies:
|
||||
end-of-stream: 1.4.4
|
||||
once: 1.4.0
|
||||
dev: false
|
||||
|
||||
/rc/1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
deep-extend: 0.6.0
|
||||
ini: 1.3.8
|
||||
minimist: 1.2.7
|
||||
strip-json-comments: 2.0.1
|
||||
dev: false
|
||||
|
||||
/readable-stream/3.6.0:
|
||||
resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==}
|
||||
engines: {node: '>= 6'}
|
||||
dependencies:
|
||||
inherits: 2.0.4
|
||||
string_decoder: 1.3.0
|
||||
util-deprecate: 1.0.2
|
||||
dev: false
|
||||
|
||||
/resolve/1.22.1:
|
||||
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
|
||||
hasBin: true
|
||||
@@ -795,16 +985,72 @@ packages:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/safe-buffer/5.2.1:
|
||||
resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==}
|
||||
dev: false
|
||||
|
||||
/semver/6.3.0:
|
||||
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/semver/7.3.8:
|
||||
resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
dev: false
|
||||
|
||||
/sharp/0.31.3:
|
||||
resolution: {integrity: sha512-XcR4+FCLBFKw1bdB+GEhnUNXNXvnt0tDo4WsBsraKymuo/IAuPuCBVAL2wIkUw2r/dwFW5Q5+g66Kwl2dgDFVg==}
|
||||
engines: {node: '>=14.15.0'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
color: 4.2.3
|
||||
detect-libc: 2.0.1
|
||||
node-addon-api: 5.1.0
|
||||
prebuild-install: 7.1.1
|
||||
semver: 7.3.8
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: false
|
||||
|
||||
/simple-concat/1.0.1:
|
||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||
dev: false
|
||||
|
||||
/simple-get/4.0.1:
|
||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
||||
dependencies:
|
||||
decompress-response: 6.0.0
|
||||
once: 1.4.0
|
||||
simple-concat: 1.0.1
|
||||
dev: false
|
||||
|
||||
/simple-swizzle/0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
dev: false
|
||||
|
||||
/source-map-js/1.0.2:
|
||||
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/string_decoder/1.3.0:
|
||||
resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/strip-json-comments/2.0.1:
|
||||
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: false
|
||||
|
||||
/supports-color/5.5.0:
|
||||
resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==}
|
||||
engines: {node: '>=4'}
|
||||
@@ -817,11 +1063,37 @@ packages:
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/tar-fs/2.1.1:
|
||||
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
|
||||
dependencies:
|
||||
chownr: 1.1.4
|
||||
mkdirp-classic: 0.5.3
|
||||
pump: 3.0.0
|
||||
tar-stream: 2.2.0
|
||||
dev: false
|
||||
|
||||
/tar-stream/2.2.0:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
bl: 4.1.0
|
||||
end-of-stream: 1.4.4
|
||||
fs-constants: 1.0.0
|
||||
inherits: 2.0.4
|
||||
readable-stream: 3.6.0
|
||||
dev: false
|
||||
|
||||
/to-fast-properties/2.0.0:
|
||||
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||
engines: {node: '>=4'}
|
||||
dev: true
|
||||
|
||||
/tunnel-agent/0.6.0:
|
||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: false
|
||||
|
||||
/update-browserslist-db/1.0.10_browserslist@4.21.4:
|
||||
resolution: {integrity: sha512-OztqDenkfFkbSG+tRxBeAnCVPckDBcvibKd35yDONx6OU8N7sqgwc7rCbkJ/WcYtVRZ4ba68d6byhC21GFh7sQ==}
|
||||
hasBin: true
|
||||
@@ -833,6 +1105,10 @@ packages:
|
||||
picocolors: 1.0.0
|
||||
dev: true
|
||||
|
||||
/util-deprecate/1.0.2:
|
||||
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
|
||||
dev: false
|
||||
|
||||
/vite/4.0.4:
|
||||
resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
@@ -866,6 +1142,19 @@ packages:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/wrappy/1.0.2:
|
||||
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
|
||||
dev: false
|
||||
|
||||
/yallist/3.1.1:
|
||||
resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==}
|
||||
dev: true
|
||||
|
||||
/yallist/4.0.0:
|
||||
resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==}
|
||||
dev: false
|
||||
|
||||
/yaml/2.2.1:
|
||||
resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==}
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
89
preprocessing.js
Normal file
@@ -0,0 +1,89 @@
|
||||
import assert from 'assert'
|
||||
import getConfig from './lib/config.js'
|
||||
import ProjectJson from './lib/project_json.js'
|
||||
import EnvGenerator from './lib/env_generator.js'
|
||||
import { write, rmdir, copy } from './lib/file.js'
|
||||
import AssetsProcessor from './lib/assets_processor.js'
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
import init from './lib/initializer.js'
|
||||
|
||||
let mode = null
|
||||
const OPERATOR_NAME = process.env.O;
|
||||
if (process.argv[1].endsWith('vite.js')) {
|
||||
mode = "VITE"
|
||||
} else {
|
||||
mode = "NODE"
|
||||
}
|
||||
assert(OPERATOR_NAME !== undefined, 'Please set the environment variable O to the operator name.')
|
||||
|
||||
if (mode === null) {
|
||||
console.log('Please set the environment variable O to the operator name.')
|
||||
console.log('Or use the -o flag to specify the operator name.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
let __dirname
|
||||
__dirname = __dirname || path.dirname(fileURLToPath(import.meta.url))
|
||||
|
||||
const config = getConfig(__dirname)
|
||||
const OPERATOR_SOURCE_FOLDER = path.join(__dirname, config.folder.operator)
|
||||
const OPERATOR_RELEASE_FOLDER = path.join(__dirname, config.folder.release, OPERATOR_NAME)
|
||||
const SHOWCASE_PUBLIC_FOLDER = path.join(__dirname, "public")
|
||||
const SHOWCASE_PUBLIC_ASSSETS_FOLDER = path.join(SHOWCASE_PUBLIC_FOLDER, "assets")
|
||||
const EXTRACTED_FOLDER = path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, 'extracted')
|
||||
const OPERATOR_SHARE_FOLDER = path.join(OPERATOR_SOURCE_FOLDER, '_share')
|
||||
if (mode === 'NODE') {
|
||||
|
||||
if (process.argv[2] === '-i') {
|
||||
init(OPERATOR_NAME, __dirname, EXTRACTED_FOLDER)
|
||||
process.exit(0)
|
||||
}
|
||||
|
||||
rmdir(OPERATOR_RELEASE_FOLDER)
|
||||
rmdir(SHOWCASE_PUBLIC_FOLDER)
|
||||
|
||||
const projectJson = new ProjectJson(config, OPERATOR_NAME, __dirname, OPERATOR_SHARE_FOLDER)
|
||||
projectJson.load().then((content) => {
|
||||
write(JSON.stringify(content, null, 2), path.join(OPERATOR_RELEASE_FOLDER, 'project.json'))
|
||||
})
|
||||
|
||||
const assetsProcessor = new AssetsProcessor(config, OPERATOR_NAME, __dirname)
|
||||
assetsProcessor.process(SHOWCASE_PUBLIC_ASSSETS_FOLDER, EXTRACTED_FOLDER).then((content) => {
|
||||
const envGenerator = new EnvGenerator(config, OPERATOR_NAME)
|
||||
envGenerator.generate(content.dimensions).then((value) => {
|
||||
write(value, path.join(__dirname, '.env'))
|
||||
})
|
||||
write(JSON.stringify(content.assetsJson, null), path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME, `${config.operators[OPERATOR_NAME].filename}.json`))
|
||||
})
|
||||
}
|
||||
const filesToCopy = [
|
||||
{
|
||||
filename: 'preview.jpg',
|
||||
source: path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME),
|
||||
target: path.join(OPERATOR_RELEASE_FOLDER)
|
||||
},
|
||||
{
|
||||
filename: 'operator_bg.png',
|
||||
source: OPERATOR_SHARE_FOLDER,
|
||||
target: path.join(SHOWCASE_PUBLIC_FOLDER)
|
||||
},
|
||||
{
|
||||
filename: `${config.operators[OPERATOR_NAME].logo}.png`,
|
||||
source: path.join(OPERATOR_SHARE_FOLDER, 'logo'),
|
||||
target: path.join(SHOWCASE_PUBLIC_ASSSETS_FOLDER)
|
||||
},
|
||||
{
|
||||
filename: `${config.operators[OPERATOR_NAME].fallback_name}.png`,
|
||||
source: path.join(OPERATOR_SOURCE_FOLDER, OPERATOR_NAME),
|
||||
target: path.join(SHOWCASE_PUBLIC_ASSSETS_FOLDER)
|
||||
},
|
||||
]
|
||||
filesToCopy.forEach((file) => {
|
||||
copy(path.join(file.source, file.filename), path.join(file.target, file.filename))
|
||||
})
|
||||
|
||||
export default {
|
||||
OPERATOR_NAME,
|
||||
config,
|
||||
}
|
||||
BIN
public/assets/char_1013_chen2_2.png
Normal file
|
After Width: | Height: | Size: 2.2 MiB |
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 33 KiB After Width: | Height: | Size: 33 KiB |
@@ -1,11 +0,0 @@
|
||||
#
|
||||
# These requirements were autogenerated by pipenv
|
||||
# To regenerate from the project's Pipfile, run:
|
||||
#
|
||||
# pipenv lock --requirements
|
||||
#
|
||||
|
||||
-i https://pypi.org/simple/
|
||||
pillow==9.3.0
|
||||
pyyaml-include==1.3
|
||||
pyyaml==6.0
|
||||
16
shell.nix
@@ -1,16 +0,0 @@
|
||||
# https://github.com/DavHau/mach-nix/blob/master/examples.md
|
||||
{ pkgs ? import <nixpkgs> {} }:
|
||||
let
|
||||
mach-nix = import (
|
||||
builtins.fetchGit {
|
||||
url = "https://github.com/DavHau/mach-nix/";
|
||||
ref = "refs/tags/3.3.0";
|
||||
}
|
||||
) {
|
||||
python = "python39";
|
||||
};
|
||||
in
|
||||
|
||||
mach-nix.mkPythonShell {
|
||||
requirements = builtins.readFile ./requirements.txt;
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import { useState, useEffect, useRef } from 'preact/hooks'
|
||||
import '@/app.css'
|
||||
import '@/libs/wallpaper_engine'
|
||||
import logo from 'logo'
|
||||
import check_web_gl from '@/libs/check_web_gl'
|
||||
import Player from '@/components/player'
|
||||
import Fallback from '@/components/fallback'
|
||||
@@ -14,7 +13,7 @@ export function App() {
|
||||
const [spinePlayer, setSpinePlayer] = useState(null);
|
||||
|
||||
const [showControls, setShowControls] = useState(params.has("controls"));
|
||||
const [showSettings, setShowSettings] = useState(params.has("settings"));
|
||||
const [showSettings, setShowSettings] = useState(params.has("settings") || import.meta.env.MODE === 'development');
|
||||
|
||||
useEffect(() => {
|
||||
document.title = import.meta.env.VITE_TITLE
|
||||
@@ -23,7 +22,7 @@ export function App() {
|
||||
|
||||
return (
|
||||
<>
|
||||
<img src={logo} class="logo invert-filter" id="logo" alt="operator logo" ref={logoRef} width={16} />
|
||||
<img src={`./assets/${import.meta.env.VITE_LOGO_FILENAME}.png `} class="logo invert-filter" id="logo" alt="operator logo" ref={logoRef} width={16} />
|
||||
<Settings
|
||||
spinePlayer={spinePlayer}
|
||||
setShowSettings={setShowSettings}
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useRef, useEffect } from 'preact/hooks'
|
||||
import fallback from 'fallback'
|
||||
import '@/components/fallback.css'
|
||||
|
||||
export default function Fallback() {
|
||||
@@ -11,9 +10,9 @@ export default function Fallback() {
|
||||
return { x: window.innerWidth / width, y: window.innerHeight / height };
|
||||
}
|
||||
const fallback = () => {
|
||||
const scale = calculateScale(2048, 2048);
|
||||
fallbackRef.current.style.width = 2048 * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
||||
fallbackRef.current.style.height = 2048 * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
||||
const scale = calculateScale(import.meta.env.VITE_IMAGE_WIDTH, import.meta.env.VITE_IMAGE_HEIGHT);
|
||||
fallbackRef.current.style.width = import.meta.env.VITE_IMAGE_WIDTH * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
||||
fallbackRef.current.style.height = import.meta.env.VITE_IMAGE_HEIGHT * (scale.x > scale.y ? scale.y : scale.x) + "px";
|
||||
}
|
||||
fallback();
|
||||
window.addEventListener('resize', fallback, true);
|
||||
@@ -23,7 +22,7 @@ export default function Fallback() {
|
||||
return (
|
||||
<div id="fallback"
|
||||
style={{
|
||||
backgroundImage: `url(${fallback})`,
|
||||
backgroundImage: `url(./assets/${import.meta.env.VITE_FALLBACK_FILENAME}.png)`,
|
||||
}}
|
||||
ref={fallbackRef}
|
||||
/>
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useRef, useEffect } from 'preact/hooks'
|
||||
import '@/libs/spine-player.css'
|
||||
import spine from '@/libs/spine-player'
|
||||
import assets from '@/assets/assets.json'
|
||||
import assets from '#'
|
||||
import '@/components/player.css'
|
||||
|
||||
export default function Player({ showControls, setSpinePlayer }) {
|
||||
@@ -44,7 +44,7 @@ export default function Player({ showControls, setSpinePlayer }) {
|
||||
if (window.performance.now() - resetTime >= 8 * 1000 && Math.random() < 0.3) {
|
||||
resetTime = window.performance.now();
|
||||
let entry = widget.animationState.setAnimation(0, "Special", false, 0);
|
||||
entry.mixDuration = 0.8;
|
||||
entry.mixDuration = 0.3;
|
||||
widget.animationState.addAnimation(0, "Idle", true, 0);
|
||||
}
|
||||
},
|
||||
@@ -55,7 +55,7 @@ export default function Player({ showControls, setSpinePlayer }) {
|
||||
}
|
||||
isPlayingInteract = true;
|
||||
let entry = widget.animationState.setAnimation(0, "Interact", false, 0);
|
||||
entry.mixDuration = 0.8;
|
||||
entry.mixDuration = 0.3;
|
||||
widget.animationState.addAnimation(0, "Idle", true, 0);
|
||||
}
|
||||
},
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useState, useEffect } from 'preact/hooks'
|
||||
import '@/components/settings.css'
|
||||
import { subscribe, unsubscribe, publish } from '@/libs/events'
|
||||
import '@/libs/setting_hooks'
|
||||
|
||||
const getPercentage = (value) => parseInt(value.replace("%", ""))
|
||||
const defaultBackgroundImage = getComputedStyle(document.body).backgroundImage
|
||||
@@ -10,7 +11,7 @@ export default function Settings({
|
||||
}) {
|
||||
const defaultFps = 60
|
||||
const defaultRatio = 61.8
|
||||
const defaultOpacity = import.meta.env.VITE_OPACITY
|
||||
const defaultOpacity = 30
|
||||
const defaultShowLogo = false
|
||||
const defaultInvertFilter = import.meta.env.VITE_INVERT_FILTER === "true"
|
||||
const [defaultLogoImage, setDefaultLogoImage] = useState(null)
|
||||
@@ -43,18 +44,69 @@ export default function Settings({
|
||||
|
||||
const [isPlaying, setIsPlaying] = useState(true)
|
||||
|
||||
const resize = (value) => {
|
||||
logoEl.width = window.innerWidth / 2 * (value || ratio) / 100
|
||||
}
|
||||
const [eventFPSDelay, setEventFPSDelay] = useState(-1)
|
||||
const [eventLogoDelay, setEventLogoDelay] = useState(null)
|
||||
const [eventRatioDelay, setEventRatioDelay] = useState(-1)
|
||||
const [eventOpacityDelay, setEventOpacityDelay] = useState(-1)
|
||||
const [eventImageDelay, setEventImageDelay] = useState(null)
|
||||
const [eventPadLeftDelay, setEventPadLeftDelay] = useState(-1)
|
||||
const [eventPadRightDelay, setEventPadRightDelay] = useState(-1)
|
||||
const [eventPadTopDelay, setEventPadTopDelay] = useState(-1)
|
||||
const [eventPadBottomDelay, setEventPadBottomDelay] = useState(-1)
|
||||
const [eventPositionResetDelay, setEventPositionResetDelay] = useState(null)
|
||||
const [eventLogoResetDelay, setEventLogoResetDelay] = useState(null)
|
||||
|
||||
const readFile = (e, onload, callback) => {
|
||||
const file = e.target.files[0]
|
||||
if (!file) return
|
||||
const reader = new FileReader()
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = readerEvent => onload(readerEvent)
|
||||
callback()
|
||||
}
|
||||
useEffect(() => {
|
||||
if (spinePlayer === null) return;
|
||||
if (eventFPSDelay !== -1) {
|
||||
setFPS(eventFPSDelay)
|
||||
setEventFPSDelay(-1)
|
||||
}
|
||||
if (eventPadLeftDelay !== -1) {
|
||||
positionPadding("left", eventPadLeftDelay)
|
||||
setEventPadLeftDelay(-1)
|
||||
}
|
||||
if (eventPadRightDelay !== -1) {
|
||||
positionPadding("right", eventPadRightDelay)
|
||||
setEventPadRightDelay(-1)
|
||||
}
|
||||
if (eventPadTopDelay !== -1) {
|
||||
positionPadding("top", eventPadTopDelay)
|
||||
setEventPadTopDelay(-1)
|
||||
}
|
||||
if (eventPadBottomDelay !== -1) {
|
||||
positionPadding("bottom", eventPadBottomDelay)
|
||||
setEventPadBottomDelay(-1)
|
||||
}
|
||||
if (eventPositionResetDelay) {
|
||||
positionReset()
|
||||
setEventPositionResetDelay(null)
|
||||
}
|
||||
}, [spinePlayer])
|
||||
|
||||
useEffect(() => {
|
||||
if (logoEl === null) return;
|
||||
if (eventLogoDelay !== null) {
|
||||
setLogoDisplay(eventLogoDelay)
|
||||
setEventLogoDelay(null)
|
||||
}
|
||||
if (eventRatioDelay !== -1) {
|
||||
setLogoRatio(eventRatioDelay)
|
||||
setEventRatioDelay(-1)
|
||||
}
|
||||
if (eventOpacityDelay !== -1) {
|
||||
setLogoOpacity(eventOpacityDelay)
|
||||
setEventOpacityDelay(-1)
|
||||
}
|
||||
if (eventImageDelay !== null) {
|
||||
setLogo(eventImageDelay)
|
||||
setEventImageDelay(null)
|
||||
}
|
||||
if (eventLogoResetDelay) {
|
||||
resetLogoImage()
|
||||
setEventLogoResetDelay(null)
|
||||
}
|
||||
}, [logoEl])
|
||||
|
||||
const setFPS = (value) => {
|
||||
setFps(value)
|
||||
@@ -63,6 +115,10 @@ export default function Settings({
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = (e) => {
|
||||
if (spinePlayer === null) {
|
||||
setEventFPSDelay(e.detail)
|
||||
return
|
||||
}
|
||||
setFPS(e.detail)
|
||||
}
|
||||
subscribe("settings:fps", handleListener)
|
||||
@@ -76,18 +132,35 @@ export default function Settings({
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = (e) => {
|
||||
if (logoEl === null) {
|
||||
setEventLogoDelay(e.detail)
|
||||
return
|
||||
}
|
||||
setLogoDisplay(e.detail)
|
||||
}
|
||||
subscribe("settings:logo", handleListener)
|
||||
return () => unsubscribe("settings:logo", handleListener)
|
||||
}, [logoEl])
|
||||
|
||||
const resize = (value) => {
|
||||
logoEl.width = window.innerWidth / 2 * (value || ratio) / 100
|
||||
}
|
||||
|
||||
const setLogo = (src, invert_filter) => {
|
||||
logoEl.src = src
|
||||
resize()
|
||||
setLogoInvertFilter(invert_filter)
|
||||
}
|
||||
|
||||
const readFile = (e, onload, callback) => {
|
||||
const file = e.target.files[0]
|
||||
if (!file) return
|
||||
const reader = new FileReader()
|
||||
reader.readAsDataURL(file);
|
||||
reader.onload = readerEvent => onload(readerEvent)
|
||||
callback()
|
||||
}
|
||||
|
||||
const setLogoImage = (e) => {
|
||||
readFile(
|
||||
e,
|
||||
@@ -101,6 +174,10 @@ export default function Settings({
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = (e) => {
|
||||
if (logoEl === null) {
|
||||
setEventImageDelay(e.detail)
|
||||
return
|
||||
}
|
||||
setLogo(e.detail)
|
||||
}
|
||||
subscribe("settings:image:set", handleListener)
|
||||
@@ -113,8 +190,15 @@ export default function Settings({
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
subscribe("settings:image:reset", resetLogoImage)
|
||||
return () => unsubscribe("settings:image:reset", resetLogoImage)
|
||||
const handleListener = () => {
|
||||
if (logoEl === null) {
|
||||
setEventLogoResetDelay(true)
|
||||
return
|
||||
}
|
||||
resetLogoImage()
|
||||
}
|
||||
subscribe("settings:image:reset", handleListener)
|
||||
return () => unsubscribe("settings:image:reset", handleListener)
|
||||
}, [logoEl])
|
||||
|
||||
const setLogoRatio = (value) => {
|
||||
@@ -124,6 +208,10 @@ export default function Settings({
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = (e) => {
|
||||
if (logoEl === null) {
|
||||
setEventRatioDelay(e.detail)
|
||||
return
|
||||
}
|
||||
setLogoRatio(e.detail)
|
||||
}
|
||||
subscribe("settings:ratio", handleListener)
|
||||
@@ -137,6 +225,10 @@ export default function Settings({
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = (e) => {
|
||||
if (logoEl === null) {
|
||||
setEventOpacityDelay(e.detail)
|
||||
return
|
||||
}
|
||||
setLogoOpacity(e.detail)
|
||||
}
|
||||
subscribe("settings:opacity", handleListener)
|
||||
@@ -168,7 +260,7 @@ export default function Settings({
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = (e) => {
|
||||
setBackgoundImage(e.detail)
|
||||
setBackgoundImage(`url("${e.detail}")`)
|
||||
}
|
||||
subscribe("settings:background:set", handleListener)
|
||||
return () => unsubscribe("settings:background:set", handleListener)
|
||||
@@ -180,8 +272,8 @@ export default function Settings({
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
subscribe("settings:background:reset", resetLogoImage)
|
||||
return () => unsubscribe("settings:background:reset", resetLogoImage)
|
||||
subscribe("settings:background:reset", resetBackground)
|
||||
return () => unsubscribe("settings:background:reset", resetBackground)
|
||||
}, [])
|
||||
|
||||
const positionPadding = (key, value) => {
|
||||
@@ -219,6 +311,23 @@ export default function Settings({
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = (e) => {
|
||||
if (spinePlayer === null) {
|
||||
switch (e.detail.key) {
|
||||
case "left":
|
||||
setEventPadLeftDelay(e.detail.value)
|
||||
break;
|
||||
case "right":
|
||||
setEventPadRightDelay(e.detail.value)
|
||||
break;
|
||||
case "top":
|
||||
setEventPadTopDelay(e.detail.value)
|
||||
break;
|
||||
case "bottom":
|
||||
setEventPadBottomDelay(e.detail.value)
|
||||
break;
|
||||
}
|
||||
return
|
||||
}
|
||||
positionPadding(e.detail.key, e.detail.value)
|
||||
}
|
||||
subscribe("settings:position:set", handleListener)
|
||||
@@ -234,10 +343,52 @@ export default function Settings({
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
subscribe("settings:position:reset", positionReset)
|
||||
return () => unsubscribe("settings:position:reset", positionReset)
|
||||
const handleListener = () => {
|
||||
if (spinePlayer === null) {
|
||||
setEventPositionResetDelay(true)
|
||||
return
|
||||
}
|
||||
positionReset()
|
||||
}
|
||||
subscribe("settings:position:reset", handleListener)
|
||||
return () => unsubscribe("settings:position:reset", handleListener)
|
||||
}, [spinePlayer])
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = () => {
|
||||
setShowSettings(true)
|
||||
}
|
||||
subscribe("settings:open", handleListener)
|
||||
return () => unsubscribe("settings:open", handleListener)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = () => {
|
||||
setShowSettings(false)
|
||||
}
|
||||
subscribe("settings:close", handleListener)
|
||||
return () => unsubscribe("settings:close", handleListener)
|
||||
}, [])
|
||||
|
||||
const settingsReset = () => {
|
||||
setFPS(defaultFps)
|
||||
setLogoDisplay(defaultShowLogo)
|
||||
resetLogoImage()
|
||||
setLogoRatio(defaultRatio)
|
||||
setLogoOpacity(defaultOpacity)
|
||||
resetBackground()
|
||||
positionReset()
|
||||
spinePlayer.play()
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const handleListener = () => {
|
||||
settingsReset()
|
||||
}
|
||||
subscribe("settings:reset", handleListener)
|
||||
return () => unsubscribe("settings:reset", handleListener)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (logoEl) {
|
||||
resize()
|
||||
@@ -257,7 +408,7 @@ export default function Settings({
|
||||
return () => {
|
||||
window.removeEventListener("resize", resize, true);
|
||||
}
|
||||
}, [])
|
||||
}, [logoEl])
|
||||
|
||||
return (
|
||||
<div class="website-settings" hidden={hidden}>
|
||||
@@ -338,16 +489,7 @@ export default function Settings({
|
||||
>
|
||||
Pause
|
||||
</button>
|
||||
<button type="button" onClick={() => {
|
||||
setFPS(defaultFps)
|
||||
setLogoDisplay(defaultShowLogo)
|
||||
resetLogoImage()
|
||||
setLogoRatio(defaultRatio)
|
||||
setLogoOpacity(defaultOpacity)
|
||||
resetBackground()
|
||||
positionReset()
|
||||
spinePlayer.play()
|
||||
}}>
|
||||
<button type="button" onClick={() => settingsReset()}>
|
||||
Reset
|
||||
</button>
|
||||
<button type="button" onClick={() => setShowSettings(false)}>Close</button>
|
||||
37
src/libs/setting_hooks.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import { publish } from '@/libs/events'
|
||||
|
||||
window.settings = {
|
||||
setFPS: (fps) => {
|
||||
publish('settings:fps', fps)
|
||||
},
|
||||
displayLogo: (flag) => {
|
||||
publish('settings:logo', !flag)
|
||||
},
|
||||
resizeLogo: (value) => {
|
||||
publish('settings:ratio', value)
|
||||
},
|
||||
opacityLogo: (value) => {
|
||||
publish('settings:opacity', value)
|
||||
},
|
||||
setLogo: (url) => {
|
||||
publish('settings:image:set', 'file:///' + url)
|
||||
},
|
||||
setBackground: (url) => {
|
||||
publish('settings:background:set', 'file:///' + url)
|
||||
},
|
||||
positionPadding: (location, value) => {
|
||||
publish('settings:position:set', {
|
||||
key: location,
|
||||
value: value
|
||||
})
|
||||
},
|
||||
open: () => {
|
||||
publish('settings:open')
|
||||
},
|
||||
close: () => {
|
||||
publish('settings:close')
|
||||
},
|
||||
reset: () => {
|
||||
publish('settings:reset')
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ import { publish } from '@/libs/events'
|
||||
window.wallpaperPropertyListener = {
|
||||
applyGeneralProperties: function (properties) {
|
||||
if (properties.fps) {
|
||||
// use custom event
|
||||
publish('settings:fps', properties.fps.value)
|
||||
}
|
||||
},
|
||||
24
template/index/.gitignore
vendored
@@ -1,24 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
@@ -1,27 +0,0 @@
|
||||
import path from 'path'
|
||||
import { parse } from 'yaml'
|
||||
import fs from 'fs'
|
||||
|
||||
function read_yaml(file_dir) {
|
||||
const include = {
|
||||
identify: value => value.startsWith('!include'),
|
||||
tag: '!include',
|
||||
resolve(str) {
|
||||
const dir = path.resolve(BASEDIR, str)
|
||||
const data = read_yaml(dir)
|
||||
return data
|
||||
}
|
||||
}
|
||||
const file = fs.readFileSync(file_dir, 'utf8')
|
||||
return parse(file, {
|
||||
customTags: [include],
|
||||
})
|
||||
}
|
||||
|
||||
const BASEDIR = path.resolve(__dirname, '..', '..')
|
||||
const CONFIG = read_yaml(path.join(BASEDIR, 'config.yaml'))
|
||||
|
||||
export default {
|
||||
basedir: BASEDIR,
|
||||
...CONFIG
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" type="image/svg+xml" href="/_index/vite.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>aklive2d directory</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="root"></div>
|
||||
<script type="module" src="/src/main.jsx"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,23 +0,0 @@
|
||||
{
|
||||
"name": "index",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.6.1",
|
||||
"yaml": "^2.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^18.0.26",
|
||||
"@types/react-dom": "^18.0.9",
|
||||
"@vitejs/plugin-react-swc": "^3.0.0",
|
||||
"vite": "^4.0.0"
|
||||
}
|
||||
}
|
||||
571
template/index/pnpm-lock.yaml
generated
@@ -1,571 +0,0 @@
|
||||
lockfileVersion: 5.4
|
||||
|
||||
specifiers:
|
||||
'@types/react': ^18.0.26
|
||||
'@types/react-dom': ^18.0.9
|
||||
'@vitejs/plugin-react-swc': ^3.0.0
|
||||
react: ^18.2.0
|
||||
react-dom: ^18.2.0
|
||||
react-router-dom: ^6.6.1
|
||||
vite: ^4.0.0
|
||||
yaml: ^2.2.1
|
||||
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-router-dom: 6.6.1_biqbaboplfbrettd7655fr4n2y
|
||||
yaml: 2.2.1
|
||||
|
||||
devDependencies:
|
||||
'@types/react': 18.0.26
|
||||
'@types/react-dom': 18.0.10
|
||||
'@vitejs/plugin-react-swc': 3.0.1_vite@4.0.3
|
||||
vite: 4.0.3
|
||||
|
||||
packages:
|
||||
|
||||
/@esbuild/android-arm/0.16.12:
|
||||
resolution: {integrity: sha512-CTWgMJtpCyCltrvipZrrcjjRu+rzm6pf9V8muCsJqtKujR3kPmU4ffbckvugNNaRmhxAF1ZI3J+0FUIFLFg8KA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-arm64/0.16.12:
|
||||
resolution: {integrity: sha512-0LacmiIW+X0/LOLMZqYtZ7d4uY9fxYABAYhSSOu+OGQVBqH4N5eIYgkT7bBFnR4Nm3qo6qS3RpHKVrDASqj/uQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/android-x64/0.16.12:
|
||||
resolution: {integrity: sha512-sS5CR3XBKQXYpSGMM28VuiUnbX83Z+aWPZzClW+OB2JquKqxoiwdqucJ5qvXS8pM6Up3RtJfDnRQZkz3en2z5g==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [android]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-arm64/0.16.12:
|
||||
resolution: {integrity: sha512-Dpe5hOAQiQRH20YkFAg+wOpcd4PEuXud+aGgKBQa/VriPJA8zuVlgCOSTwna1CgYl05lf6o5els4dtuyk1qJxQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/darwin-x64/0.16.12:
|
||||
resolution: {integrity: sha512-ApGRA6X5txIcxV0095X4e4KKv87HAEXfuDRcGTniDWUUN+qPia8sl/BqG/0IomytQWajnUn4C7TOwHduk/FXBQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-arm64/0.16.12:
|
||||
resolution: {integrity: sha512-AMdK2gA9EU83ccXCWS1B/KcWYZCj4P3vDofZZkl/F/sBv/fphi2oUqUTox/g5GMcIxk8CF1CVYTC82+iBSyiUg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/freebsd-x64/0.16.12:
|
||||
resolution: {integrity: sha512-KUKB9w8G/xaAbD39t6gnRBuhQ8vIYYlxGT2I+mT6UGRnCGRr1+ePFIGBQmf5V16nxylgUuuWVW1zU2ktKkf6WQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm/0.16.12:
|
||||
resolution: {integrity: sha512-vhDdIv6z4eL0FJyNVfdr3C/vdd/Wc6h1683GJsFoJzfKb92dU/v88FhWdigg0i6+3TsbSDeWbsPUXb4dif2abg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-arm64/0.16.12:
|
||||
resolution: {integrity: sha512-29HXMLpLklDfmw7T2buGqq3HImSUaZ1ArmrPOMaNiZZQptOSZs32SQtOHEl8xWX5vfdwZqrBfNf8Te4nArVzKQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ia32/0.16.12:
|
||||
resolution: {integrity: sha512-JFDuNDTTfgD1LJg7wHA42o2uAO/9VzHYK0leAVnCQE/FdMB599YMH73ux+nS0xGr79pv/BK+hrmdRin3iLgQjg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-loong64/0.16.12:
|
||||
resolution: {integrity: sha512-xTGzVPqm6WKfCC0iuj1fryIWr1NWEM8DMhAIo+4rFgUtwy/lfHl+Obvus4oddzRDbBetLLmojfVZGmt/g/g+Rw==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [loong64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-mips64el/0.16.12:
|
||||
resolution: {integrity: sha512-zI1cNgHa3Gol+vPYjIYHzKhU6qMyOQrvZ82REr5Fv7rlh5PG6SkkuCoH7IryPqR+BK2c/7oISGsvPJPGnO2bHQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [mips64el]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-ppc64/0.16.12:
|
||||
resolution: {integrity: sha512-/C8OFXExoMmvTDIOAM54AhtmmuDHKoedUd0Otpfw3+AuuVGemA1nQK99oN909uZbLEU6Bi+7JheFMG3xGfZluQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ppc64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-riscv64/0.16.12:
|
||||
resolution: {integrity: sha512-qeouyyc8kAGV6Ni6Isz8hUsKMr00EHgVwUKWNp1r4l88fHEoNTDB8mmestvykW6MrstoGI7g2EAsgr0nxmuGYg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [riscv64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-s390x/0.16.12:
|
||||
resolution: {integrity: sha512-s9AyI/5vz1U4NNqnacEGFElqwnHusWa81pskAf8JNDM2eb6b2E6PpBmT8RzeZv6/TxE6/TADn2g9bb0jOUmXwQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [s390x]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/linux-x64/0.16.12:
|
||||
resolution: {integrity: sha512-e8YA7GQGLWhvakBecLptUiKxOk4E/EPtSckS1i0MGYctW8ouvNUoh7xnU15PGO2jz7BYl8q1R6g0gE5HFtzpqQ==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/netbsd-x64/0.16.12:
|
||||
resolution: {integrity: sha512-z2+kUxmOqBS+6SRVd57iOLIHE8oGOoEnGVAmwjm2aENSP35HPS+5cK+FL1l+rhrsJOFIPrNHqDUNechpuG96Sg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [netbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/openbsd-x64/0.16.12:
|
||||
resolution: {integrity: sha512-PAonw4LqIybwn2/vJujhbg1N9W2W8lw9RtXIvvZoyzoA/4rA4CpiuahVbASmQohiytRsixbNoIOUSjRygKXpyA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [openbsd]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/sunos-x64/0.16.12:
|
||||
resolution: {integrity: sha512-+wr1tkt1RERi+Zi/iQtkzmMH4nS8+7UIRxjcyRz7lur84wCkAITT50Olq/HiT4JN2X2bjtlOV6vt7ptW5Gw60Q==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [sunos]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-arm64/0.16.12:
|
||||
resolution: {integrity: sha512-XEjeUSHmjsAOJk8+pXJu9pFY2O5KKQbHXZWQylJzQuIBeiGrpMeq9sTVrHefHxMOyxUgoKQTcaTS+VK/K5SviA==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-ia32/0.16.12:
|
||||
resolution: {integrity: sha512-eRKPM7e0IecUAUYr2alW7JGDejrFJXmpjt4MlfonmQ5Rz9HWpKFGCjuuIRgKO7W9C/CWVFXdJ2GjddsBXqQI4A==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@esbuild/win32-x64/0.16.12:
|
||||
resolution: {integrity: sha512-iPYKN78t3op2+erv2frW568j1q0RpqX6JOLZ7oPPaAV1VaF7dDstOrNw37PVOYoTWE11pV4A1XUitpdEFNIsPg==}
|
||||
engines: {node: '>=12'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@remix-run/router/1.2.1:
|
||||
resolution: {integrity: sha512-XiY0IsyHR+DXYS5vBxpoBe/8veTeoRpMHP+vDosLZxL5bnpetzI0igkxkLZS235ldLzyfkxF+2divEwWHP3vMQ==}
|
||||
engines: {node: '>=14'}
|
||||
dev: false
|
||||
|
||||
/@swc/core-darwin-arm64/1.3.24:
|
||||
resolution: {integrity: sha512-rR+9UpWm+fGXcipsjCst2hIL1GYIbo0YTLhJZWdIpQD6KRHHJMFXiydMgQQkDj2Ml7HpqUVgxj6m4ZWYL8b0OA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-darwin-x64/1.3.24:
|
||||
resolution: {integrity: sha512-px+5vkGtgPH0m3FkkTBHynlRdS5rRz+lK+wiXIuBZFJSySWFl6RkKbvwkD+sf0MpazQlqwlv/rTOGJBw6oDffg==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm-gnueabihf/1.3.24:
|
||||
resolution: {integrity: sha512-jLs8ZOdTV4UW4J12E143QJ4mOMONQtqgAnuhBbRuWFzQ3ny1dfoC3P1jNWAJ2Xi59XdxAIXn0PggPNH4Kh34kw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm64-gnu/1.3.24:
|
||||
resolution: {integrity: sha512-A/v0h70BekrwGpp1DlzIFGcHQ3QQ2PexXcnnuIBZeMc9gNmHlcZmg3EcwAnaUDiokhNuSUFA/wV94yk1OqmSkw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-arm64-musl/1.3.24:
|
||||
resolution: {integrity: sha512-pbc9eArWPTiMrbpS/pJo0IiQNAKAQBcBIDjWBGP1tcw2iDXYLw4bruwz9kI/VjakbshWb8MoE4T5ClkeuULvSw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-x64-gnu/1.3.24:
|
||||
resolution: {integrity: sha512-pP5pOLlY1xd352qo7rTlpVPUI9/9VhOd4b3Lk+LzfZDq9bTL2NDlGfyrPiwa5DGHMSzrugH56K2J68eutkxYVA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-linux-x64-musl/1.3.24:
|
||||
resolution: {integrity: sha512-phNbP7zGp+Wcyxq1Qxlpe5KkxO7WLT2kVQUC7aDFGlVdCr+xdXsfH1MzheHtnr0kqTVQX1aiM8XXXHfFxR0oNA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-arm64-msvc/1.3.24:
|
||||
resolution: {integrity: sha512-qhbiJTWAOqyR+K9xnGmCkOWSz2EmWpDBstEJCEOTc6FZiEdbiTscDmqTcMbCKaTHGu8t+6erVA4t65/Eg6uWPA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-ia32-msvc/1.3.24:
|
||||
resolution: {integrity: sha512-JfghIlscE4Rz+Lc08lSoDh+R0cWxrISed5biogFfE6vZqhaDnw3E5Qshqw7O3pIaiq8L2u1nmzuyP581ZmpbRA==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core-win32-x64-msvc/1.3.24:
|
||||
resolution: {integrity: sha512-3AmJRr0hwciwDBbzUNqaftvppzS8v9X/iv/Wl7YaVLBVpPfQvaZzfqLycvNMGLZb5vIKXR/u58txg3dRBGsJtw==}
|
||||
engines: {node: '>=10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/@swc/core/1.3.24:
|
||||
resolution: {integrity: sha512-QMOTd0AgiUT3K1crxLRqd3gw0f3FC8hhH1vvlIlryvYqU4c+FJ/T2G4ZhMKLxQlZ/jX6Rhk0gKINZRBxy2GFyQ==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@swc/core-darwin-arm64': 1.3.24
|
||||
'@swc/core-darwin-x64': 1.3.24
|
||||
'@swc/core-linux-arm-gnueabihf': 1.3.24
|
||||
'@swc/core-linux-arm64-gnu': 1.3.24
|
||||
'@swc/core-linux-arm64-musl': 1.3.24
|
||||
'@swc/core-linux-x64-gnu': 1.3.24
|
||||
'@swc/core-linux-x64-musl': 1.3.24
|
||||
'@swc/core-win32-arm64-msvc': 1.3.24
|
||||
'@swc/core-win32-ia32-msvc': 1.3.24
|
||||
'@swc/core-win32-x64-msvc': 1.3.24
|
||||
dev: true
|
||||
|
||||
/@types/prop-types/15.7.5:
|
||||
resolution: {integrity: sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==}
|
||||
dev: true
|
||||
|
||||
/@types/react-dom/18.0.10:
|
||||
resolution: {integrity: sha512-E42GW/JA4Qv15wQdqJq8DL4JhNpB3prJgjgapN3qJT9K2zO5IIAQh4VXvCEDupoqAwnz0cY4RlXeC/ajX5SFHg==}
|
||||
dependencies:
|
||||
'@types/react': 18.0.26
|
||||
dev: true
|
||||
|
||||
/@types/react/18.0.26:
|
||||
resolution: {integrity: sha512-hCR3PJQsAIXyxhTNSiDFY//LhnMZWpNNr5etoCqx/iUfGc5gXWtQR2Phl908jVR6uPXacojQWTg4qRpkxTuGug==}
|
||||
dependencies:
|
||||
'@types/prop-types': 15.7.5
|
||||
'@types/scheduler': 0.16.2
|
||||
csstype: 3.1.1
|
||||
dev: true
|
||||
|
||||
/@types/scheduler/0.16.2:
|
||||
resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==}
|
||||
dev: true
|
||||
|
||||
/@vitejs/plugin-react-swc/3.0.1_vite@4.0.3:
|
||||
resolution: {integrity: sha512-3GQ2oruZO9j8dSHcI0MUeOZQBhjYyDQsF/pKY4Px+CJxn0M16OhgFeEzUjeuwci4zhhjoNIDE9aFNaV5GMQ09g==}
|
||||
peerDependencies:
|
||||
vite: ^4
|
||||
dependencies:
|
||||
'@swc/core': 1.3.24
|
||||
vite: 4.0.3
|
||||
dev: true
|
||||
|
||||
/csstype/3.1.1:
|
||||
resolution: {integrity: sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==}
|
||||
dev: true
|
||||
|
||||
/esbuild/0.16.12:
|
||||
resolution: {integrity: sha512-eq5KcuXajf2OmivCl4e89AD3j8fbV+UTE9vczEzq5haA07U9oOTzBWlh3+6ZdjJR7Rz2QfWZ2uxZyhZxBgJ4+g==}
|
||||
engines: {node: '>=12'}
|
||||
hasBin: true
|
||||
requiresBuild: true
|
||||
optionalDependencies:
|
||||
'@esbuild/android-arm': 0.16.12
|
||||
'@esbuild/android-arm64': 0.16.12
|
||||
'@esbuild/android-x64': 0.16.12
|
||||
'@esbuild/darwin-arm64': 0.16.12
|
||||
'@esbuild/darwin-x64': 0.16.12
|
||||
'@esbuild/freebsd-arm64': 0.16.12
|
||||
'@esbuild/freebsd-x64': 0.16.12
|
||||
'@esbuild/linux-arm': 0.16.12
|
||||
'@esbuild/linux-arm64': 0.16.12
|
||||
'@esbuild/linux-ia32': 0.16.12
|
||||
'@esbuild/linux-loong64': 0.16.12
|
||||
'@esbuild/linux-mips64el': 0.16.12
|
||||
'@esbuild/linux-ppc64': 0.16.12
|
||||
'@esbuild/linux-riscv64': 0.16.12
|
||||
'@esbuild/linux-s390x': 0.16.12
|
||||
'@esbuild/linux-x64': 0.16.12
|
||||
'@esbuild/netbsd-x64': 0.16.12
|
||||
'@esbuild/openbsd-x64': 0.16.12
|
||||
'@esbuild/sunos-x64': 0.16.12
|
||||
'@esbuild/win32-arm64': 0.16.12
|
||||
'@esbuild/win32-ia32': 0.16.12
|
||||
'@esbuild/win32-x64': 0.16.12
|
||||
dev: true
|
||||
|
||||
/fsevents/2.3.2:
|
||||
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
|
||||
engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0}
|
||||
os: [darwin]
|
||||
requiresBuild: true
|
||||
dev: true
|
||||
optional: true
|
||||
|
||||
/function-bind/1.1.1:
|
||||
resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==}
|
||||
dev: true
|
||||
|
||||
/has/1.0.3:
|
||||
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
dependencies:
|
||||
function-bind: 1.1.1
|
||||
dev: true
|
||||
|
||||
/is-core-module/2.11.0:
|
||||
resolution: {integrity: sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==}
|
||||
dependencies:
|
||||
has: 1.0.3
|
||||
dev: true
|
||||
|
||||
/js-tokens/4.0.0:
|
||||
resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==}
|
||||
dev: false
|
||||
|
||||
/loose-envify/1.4.0:
|
||||
resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
js-tokens: 4.0.0
|
||||
dev: false
|
||||
|
||||
/nanoid/3.3.4:
|
||||
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
|
||||
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
|
||||
hasBin: true
|
||||
dev: true
|
||||
|
||||
/path-parse/1.0.7:
|
||||
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
|
||||
dev: true
|
||||
|
||||
/picocolors/1.0.0:
|
||||
resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==}
|
||||
dev: true
|
||||
|
||||
/postcss/8.4.20:
|
||||
resolution: {integrity: sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==}
|
||||
engines: {node: ^10 || ^12 || >=14}
|
||||
dependencies:
|
||||
nanoid: 3.3.4
|
||||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
dev: true
|
||||
|
||||
/react-dom/18.2.0_react@18.2.0:
|
||||
resolution: {integrity: sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==}
|
||||
peerDependencies:
|
||||
react: ^18.2.0
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
react: 18.2.0
|
||||
scheduler: 0.23.0
|
||||
dev: false
|
||||
|
||||
/react-router-dom/6.6.1_biqbaboplfbrettd7655fr4n2y:
|
||||
resolution: {integrity: sha512-u+8BKUtelStKbZD5UcY0NY90WOzktrkJJhyhNg7L0APn9t1qJNLowzrM9CHdpB6+rcPt6qQrlkIXsTvhuXP68g==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
react-dom: '>=16.8'
|
||||
dependencies:
|
||||
'@remix-run/router': 1.2.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0_react@18.2.0
|
||||
react-router: 6.6.1_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/react-router/6.6.1_react@18.2.0:
|
||||
resolution: {integrity: sha512-YkvlYRusnI/IN0kDtosUCgxqHeulN5je+ew8W+iA1VvFhf86kA+JEI/X/8NqYcr11hCDDp906S+SGMpBheNeYQ==}
|
||||
engines: {node: '>=14'}
|
||||
peerDependencies:
|
||||
react: '>=16.8'
|
||||
dependencies:
|
||||
'@remix-run/router': 1.2.1
|
||||
react: 18.2.0
|
||||
dev: false
|
||||
|
||||
/react/18.2.0:
|
||||
resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/resolve/1.22.1:
|
||||
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
is-core-module: 2.11.0
|
||||
path-parse: 1.0.7
|
||||
supports-preserve-symlinks-flag: 1.0.0
|
||||
dev: true
|
||||
|
||||
/rollup/3.9.0:
|
||||
resolution: {integrity: sha512-nGGylpmblyjTpF4lEUPgmOw6OVxRvnI6Iuuh6Lz4O/X66cVOX1XJSsqP1YamxQ+mPuFE7qJxLFDSCk8rNv5dDw==}
|
||||
engines: {node: '>=14.18.0', npm: '>=8.0.0'}
|
||||
hasBin: true
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/scheduler/0.23.0:
|
||||
resolution: {integrity: sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==}
|
||||
dependencies:
|
||||
loose-envify: 1.4.0
|
||||
dev: false
|
||||
|
||||
/source-map-js/1.0.2:
|
||||
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/supports-preserve-symlinks-flag/1.0.0:
|
||||
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
|
||||
engines: {node: '>= 0.4'}
|
||||
dev: true
|
||||
|
||||
/vite/4.0.3:
|
||||
resolution: {integrity: sha512-HvuNv1RdE7deIfQb8mPk51UKjqptO/4RXZ5yXSAvurd5xOckwS/gg8h9Tky3uSbnjYTgUm0hVCet1cyhKd73ZA==}
|
||||
engines: {node: ^14.18.0 || >=16.0.0}
|
||||
hasBin: true
|
||||
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
|
||||
dependencies:
|
||||
esbuild: 0.16.12
|
||||
postcss: 8.4.20
|
||||
resolve: 1.22.1
|
||||
rollup: 3.9.0
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
dev: true
|
||||
|
||||
/yaml/2.2.1:
|
||||
resolution: {integrity: sha512-e0WHiYql7+9wr4cWMx3TVQrNwejKaEe7/rHNmQmqRjazfOP5W8PB6Jpebb5o6fIapbz9o9+2ipcaTM2ZwDI6lw==}
|
||||
engines: {node: '>= 14'}
|
||||
dev: false
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 1.5 KiB |
@@ -1,41 +0,0 @@
|
||||
#root {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
padding: 2rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.logo {
|
||||
height: 6em;
|
||||
padding: 1.5em;
|
||||
will-change: filter;
|
||||
}
|
||||
.logo:hover {
|
||||
filter: drop-shadow(0 0 2em #646cffaa);
|
||||
}
|
||||
.logo.react:hover {
|
||||
filter: drop-shadow(0 0 2em #61dafbaa);
|
||||
}
|
||||
|
||||
@keyframes logo-spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
a:nth-of-type(2) .logo {
|
||||
animation: logo-spin infinite 20s linear;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
padding: 2em;
|
||||
}
|
||||
|
||||
.read-the-docs {
|
||||
color: #888;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import { useState } from 'react'
|
||||
import reactLogo from './assets/react.svg'
|
||||
import './App.css'
|
||||
|
||||
function App() {
|
||||
const [count, setCount] = useState(0)
|
||||
|
||||
return (
|
||||
<div className="App">
|
||||
<div>
|
||||
<a href="https://vitejs.dev" target="_blank">
|
||||
<img src="/vite.svg" className="logo" alt="Vite logo" />
|
||||
</a>
|
||||
<a href="https://reactjs.org" target="_blank">
|
||||
<img src={reactLogo} className="logo react" alt="React logo" />
|
||||
</a>
|
||||
</div>
|
||||
<h1>Vite + React</h1>
|
||||
<div className="card">
|
||||
<button onClick={() => setCount((count) => count + 1)}>
|
||||
count is {count}
|
||||
</button>
|
||||
<p>
|
||||
Edit <code>src/App.jsx</code> and save to test HMR
|
||||
</p>
|
||||
</div>
|
||||
<p className="read-the-docs">
|
||||
Click on the Vite and React logos to learn more
|
||||
</p>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default App
|
||||
@@ -1 +0,0 @@
|
||||
[{"name": "mizuki_summer_feast", "link": "mizuki_summer_feast", "type": "skin", "date": "2022/12"}, {"name": "texas_the_omertosa", "link": "texas_the_omertosa", "type": "operator", "date": "2022/11"}, {"name": "rosmontis_become_anew", "link": "rosmontis_become_anew", "type": "skin", "date": "2022/11"}, {"name": "passager_dream_in_a_moment", "link": "passager_dream_in_a_moment", "type": "skin", "date": "2022/11"}, {"name": "nearl_relight", "link": "nearl_relight", "type": "skin", "date": "2022/11"}, {"name": "lee_trust_your_eyes", "link": "lee_trust_your_eyes", "type": "skin", "date": "2022/10"}, {"name": "surtr_colorful_wonderland", "link": "surtr_colorful_wonderland", "type": "skin", "date": "2022/08"}, {"name": "gavial", "link": "gavial", "type": "operator", "date": "2022/08"}, {"name": "specter", "link": "specter", "type": "operator", "date": "2022/05"}, {"name": "skadi_sublimation", "link": "skadi_sublimation", "type": "skin", "date": "2022/05"}, {"name": "phatom_focus", "link": "phatom_focus", "type": "skin", "date": "2022/04"}, {"name": "ling", "link": "ling", "type": "operator", "date": "2022/01"}, {"name": "dusk_everything_is_a_miracle", "link": "dusk_everything_is_a_miracle", "type": "skin", "date": "2022/01"}, {"name": "nearl", "link": "nearl", "type": "operator", "date": "2021/11"}, {"name": "chen", "link": "chen", "type": "operator", "date": "2021/08"}, {"name": "skadi", "link": "skadi", "type": "operator", "date": "2021/05"}, {"name": "nian_unfettered_freedom", "link": "nian_unfettered_freedom", "type": "skin", "date": "2021/02"}, {"name": "dusk", "link": "dusk", "type": "operator", "date": "2021/02"}, {"name": "w_fugue", "link": "w_fugue", "type": "skin", "date": "2020/11"}, {"name": "rosmontis", "link": "rosmontis", "type": "operator", "date": "2020/11"}, {"name": "w", "link": "w", "type": "operator", "date": "2020/05"}, {"name": "nian", "link": "nian", "type": "operator", "date": "2020/01"}]
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="35.93" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 228"><path fill="#00D8FF" d="M210.483 73.824a171.49 171.49 0 0 0-8.24-2.597c.465-1.9.893-3.777 1.273-5.621c6.238-30.281 2.16-54.676-11.769-62.708c-13.355-7.7-35.196.329-57.254 19.526a171.23 171.23 0 0 0-6.375 5.848a155.866 155.866 0 0 0-4.241-3.917C100.759 3.829 77.587-4.822 63.673 3.233C50.33 10.957 46.379 33.89 51.995 62.588a170.974 170.974 0 0 0 1.892 8.48c-3.28.932-6.445 1.924-9.474 2.98C17.309 83.498 0 98.307 0 113.668c0 15.865 18.582 31.778 46.812 41.427a145.52 145.52 0 0 0 6.921 2.165a167.467 167.467 0 0 0-2.01 9.138c-5.354 28.2-1.173 50.591 12.134 58.266c13.744 7.926 36.812-.22 59.273-19.855a145.567 145.567 0 0 0 5.342-4.923a168.064 168.064 0 0 0 6.92 6.314c21.758 18.722 43.246 26.282 56.54 18.586c13.731-7.949 18.194-32.003 12.4-61.268a145.016 145.016 0 0 0-1.535-6.842c1.62-.48 3.21-.974 4.76-1.488c29.348-9.723 48.443-25.443 48.443-41.52c0-15.417-17.868-30.326-45.517-39.844Zm-6.365 70.984c-1.4.463-2.836.91-4.3 1.345c-3.24-10.257-7.612-21.163-12.963-32.432c5.106-11 9.31-21.767 12.459-31.957c2.619.758 5.16 1.557 7.61 2.4c23.69 8.156 38.14 20.213 38.14 29.504c0 9.896-15.606 22.743-40.946 31.14Zm-10.514 20.834c2.562 12.94 2.927 24.64 1.23 33.787c-1.524 8.219-4.59 13.698-8.382 15.893c-8.067 4.67-25.32-1.4-43.927-17.412a156.726 156.726 0 0 1-6.437-5.87c7.214-7.889 14.423-17.06 21.459-27.246c12.376-1.098 24.068-2.894 34.671-5.345a134.17 134.17 0 0 1 1.386 6.193ZM87.276 214.515c-7.882 2.783-14.16 2.863-17.955.675c-8.075-4.657-11.432-22.636-6.853-46.752a156.923 156.923 0 0 1 1.869-8.499c10.486 2.32 22.093 3.988 34.498 4.994c7.084 9.967 14.501 19.128 21.976 27.15a134.668 134.668 0 0 1-4.877 4.492c-9.933 8.682-19.886 14.842-28.658 17.94ZM50.35 144.747c-12.483-4.267-22.792-9.812-29.858-15.863c-6.35-5.437-9.555-10.836-9.555-15.216c0-9.322 13.897-21.212 37.076-29.293c2.813-.98 5.757-1.905 8.812-2.773c3.204 10.42 7.406 21.315 12.477 32.332c-5.137 11.18-9.399 22.249-12.634 32.792a134.718 134.718 0 0 1-6.318-1.979Zm12.378-84.26c-4.811-24.587-1.616-43.134 6.425-47.789c8.564-4.958 27.502 2.111 47.463 19.835a144.318 144.318 0 0 1 3.841 3.545c-7.438 7.987-14.787 17.08-21.808 26.988c-12.04 1.116-23.565 2.908-34.161 5.309a160.342 160.342 0 0 1-1.76-7.887Zm110.427 27.268a347.8 347.8 0 0 0-7.785-12.803c8.168 1.033 15.994 2.404 23.343 4.08c-2.206 7.072-4.956 14.465-8.193 22.045a381.151 381.151 0 0 0-7.365-13.322Zm-45.032-43.861c5.044 5.465 10.096 11.566 15.065 18.186a322.04 322.04 0 0 0-30.257-.006c4.974-6.559 10.069-12.652 15.192-18.18ZM82.802 87.83a323.167 323.167 0 0 0-7.227 13.238c-3.184-7.553-5.909-14.98-8.134-22.152c7.304-1.634 15.093-2.97 23.209-3.984a321.524 321.524 0 0 0-7.848 12.897Zm8.081 65.352c-8.385-.936-16.291-2.203-23.593-3.793c2.26-7.3 5.045-14.885 8.298-22.6a321.187 321.187 0 0 0 7.257 13.246c2.594 4.48 5.28 8.868 8.038 13.147Zm37.542 31.03c-5.184-5.592-10.354-11.779-15.403-18.433c4.902.192 9.899.29 14.978.29c5.218 0 10.376-.117 15.453-.343c-4.985 6.774-10.018 12.97-15.028 18.486Zm52.198-57.817c3.422 7.8 6.306 15.345 8.596 22.52c-7.422 1.694-15.436 3.058-23.88 4.071a382.417 382.417 0 0 0 7.859-13.026a347.403 347.403 0 0 0 7.425-13.565Zm-16.898 8.101a358.557 358.557 0 0 1-12.281 19.815a329.4 329.4 0 0 1-23.444.823c-7.967 0-15.716-.248-23.178-.732a310.202 310.202 0 0 1-12.513-19.846h.001a307.41 307.41 0 0 1-10.923-20.627a310.278 310.278 0 0 1 10.89-20.637l-.001.001a307.318 307.318 0 0 1 12.413-19.761c7.613-.576 15.42-.876 23.31-.876H128c7.926 0 15.743.303 23.354.883a329.357 329.357 0 0 1 12.335 19.695a358.489 358.489 0 0 1 11.036 20.54a329.472 329.472 0 0 1-11 20.722Zm22.56-122.124c8.572 4.944 11.906 24.881 6.52 51.026c-.344 1.668-.73 3.367-1.15 5.09c-10.622-2.452-22.155-4.275-34.23-5.408c-7.034-10.017-14.323-19.124-21.64-27.008a160.789 160.789 0 0 1 5.888-5.4c18.9-16.447 36.564-22.941 44.612-18.3ZM128 90.808c12.625 0 22.86 10.235 22.86 22.86s-10.235 22.86-22.86 22.86s-22.86-10.235-22.86-22.86s10.235-22.86 22.86-22.86Z"></path></svg>
|
||||
|
Before Width: | Height: | Size: 4.0 KiB |
@@ -1,70 +0,0 @@
|
||||
:root {
|
||||
font-family: Inter, Avenir, Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
line-height: 24px;
|
||||
font-weight: 400;
|
||||
|
||||
color-scheme: light dark;
|
||||
color: rgba(255, 255, 255, 0.87);
|
||||
background-color: #242424;
|
||||
|
||||
font-synthesis: none;
|
||||
text-rendering: optimizeLegibility;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
-moz-osx-font-smoothing: grayscale;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
text-decoration: inherit;
|
||||
}
|
||||
a:hover {
|
||||
color: #535bf2;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
display: flex;
|
||||
place-items: center;
|
||||
min-width: 320px;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 3.2em;
|
||||
line-height: 1.1;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 8px;
|
||||
border: 1px solid transparent;
|
||||
padding: 0.6em 1.2em;
|
||||
font-size: 1em;
|
||||
font-weight: 500;
|
||||
font-family: inherit;
|
||||
background-color: #1a1a1a;
|
||||
cursor: pointer;
|
||||
transition: border-color 0.25s;
|
||||
}
|
||||
button:hover {
|
||||
border-color: #646cff;
|
||||
}
|
||||
button:focus,
|
||||
button:focus-visible {
|
||||
outline: 4px auto -webkit-focus-ring-color;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: light) {
|
||||
:root {
|
||||
color: #213547;
|
||||
background-color: #ffffff;
|
||||
}
|
||||
a:hover {
|
||||
color: #747bff;
|
||||
}
|
||||
button {
|
||||
background-color: #f9f9f9;
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom/client'
|
||||
import App from './App'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.createRoot(document.getElementById('root')).render(
|
||||
<React.StrictMode>
|
||||
<App />
|
||||
</React.StrictMode>,
|
||||
)
|
||||
@@ -1,25 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react-swc'
|
||||
import path from 'path'
|
||||
import config from './config'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: path.resolve(config.basedir, config.server.release_folder),
|
||||
assetsDir: '_index',
|
||||
emptyOutDir: false,
|
||||
rollupOptions: {
|
||||
output: {
|
||||
manualChunks: {
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
})
|
||||
24
template/showcase/.gitignore
vendored
@@ -1,24 +0,0 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
.idea
|
||||
.DS_Store
|
||||
*.suo
|
||||
*.ntvs*
|
||||
*.njsproj
|
||||
*.sln
|
||||
*.sw?
|
||||
|
Before Width: | Height: | Size: 1.9 MiB |
|
Before Width: | Height: | Size: 1.9 MiB |
@@ -1,20 +0,0 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import preact from '@preact/preset-vite'
|
||||
import path from 'path'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [preact()],
|
||||
base: "",
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
'logo': path.resolve(__dirname, `./src/assets/logo_rhodes_override.png`), // TODO: use env
|
||||
'fallback': path.resolve(__dirname, `./src/assets/char_1013_chen2_2.png`), // TODO
|
||||
},
|
||||
},
|
||||
build: {
|
||||
chunkSizeWarningLimit: 10000,
|
||||
// outDir: path.resolve(config.basedir, config.server.release_folder),
|
||||
},
|
||||
})
|
||||
22
vite.config.js
Normal file
@@ -0,0 +1,22 @@
|
||||
import { defineConfig } from 'vite'
|
||||
import preact from '@preact/preset-vite'
|
||||
import path from 'path'
|
||||
import data from './preprocessing'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
plugins: [preact()],
|
||||
base: "",
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
'!': path.resolve(data.config.basedir, data.config.folder.operator, data.OPERATOR_NAME),
|
||||
'#': path.resolve(data.config.basedir, data.config.folder.operator, data.OPERATOR_NAME, `${data.config.operators[data.OPERATOR_NAME].filename}.json`),
|
||||
},
|
||||
},
|
||||
build: {
|
||||
outDir: path.resolve(data.config.basedir, data.config.folder.release, data.OPERATOR_NAME),
|
||||
emptyOutDir: false,
|
||||
chunkSizeWarningLimit: 10000,
|
||||
},
|
||||
})
|
||||