├── .editorconfig
├── .github
├── ISSUE_TEMPLATE
│ ├── 01_bug_report.md
│ ├── 02_feature_request.md
│ └── 03_development_problem.md
└── workflows
│ └── release.yml
├── .gitignore
├── .prettierrc
├── LICENSE.md
├── README.md
├── assets
├── preview1.png
├── preview2.jpg
├── preview3.jpg
├── record1.gif
├── record2.gif
├── ubuntu.jpg
└── win10.jpg
├── configs
├── vite.main.ts
├── vite.preload.ts
└── vite.renderer.ts
├── electron-builder.json
├── package.json
├── paths.json
├── pnpm-lock.yaml
├── scripts
├── build.mjs
└── watch.mjs
├── src
├── common
│ ├── config.ts
│ ├── index.ts
│ └── paths.ts
├── interfaces
│ └── index.ts
├── main
│ ├── index.ts
│ ├── initConfig.ts
│ ├── tray.ts
│ └── window.ts
├── preload
│ └── index.ts
└── renderer
│ ├── index.html
│ ├── public
│ └── scripts
│ │ ├── howler.min.js
│ │ ├── live2d.min.js
│ │ ├── live2dcubismcore.min.js
│ │ ├── live2dv3.min.js
│ │ └── pixi.min.js
│ └── src
│ ├── App.tsx
│ ├── global.d.ts
│ ├── main.tsx
│ ├── models
│ ├── config.ts
│ ├── index.ts
│ ├── models.json
│ └── win.ts
│ ├── pages
│ ├── Model
│ │ ├── Current.tsx
│ │ ├── Legacy.tsx
│ │ ├── Tips.tsx
│ │ ├── Toolbar.tsx
│ │ ├── index.tsx
│ │ └── tips
│ │ │ ├── en.json
│ │ │ └── zh.json
│ └── Setting
│ │ └── index.tsx
│ ├── store.ts
│ ├── styles
│ ├── GlobalStyles.ts
│ └── Variables.ts
│ ├── utils
│ ├── ga.ts
│ └── index.ts
│ └── vite-env.d.ts
├── static
├── icons
│ ├── mac
│ │ └── icon.icns
│ ├── png
│ │ ├── 1024x1024.png
│ │ ├── 128x128.png
│ │ ├── 16x16.png
│ │ ├── 24x24.png
│ │ ├── 256x256.png
│ │ ├── 32x32.png
│ │ ├── 48x48.png
│ │ ├── 512x512.png
│ │ └── 64x64.png
│ ├── strip-tray.png
│ ├── strip-tray@2x.png
│ ├── strip-tray@3x.png
│ ├── tray.png
│ ├── tray@2x.png
│ ├── tray@3x.png
│ └── win
│ │ └── icon.ico
└── logo.png
└── tsconfig.json
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 | root = true
3 |
4 | [*]
5 | indent_style = space
6 | indent_size = 2
7 | end_of_line = lf
8 | charset = utf-8
9 | trim_trailing_whitespace = true
10 | insert_final_newline = true
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
15 | [Makefile]
16 | indent_style = tab
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/01_bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug Report
3 | about: 报告一个问题
4 | ---
5 |
6 | **请先确认是否为[最新版本](https://github.com/zenghongtu/PPet/releases/latest)**
7 |
8 | #### 问题描述
9 |
10 | **_平台信息(win/mac/linux):_**
11 |
12 | #### 截图(可选)
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/02_feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: 提交一个新特性/功能
4 | ---
5 |
6 | ### 描述
7 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/03_development_problem.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Development Problem
3 | about: 开发方面的问题
4 | ---
5 |
6 | ### 描述
7 |
8 | ### 截图(可选)
9 |
--------------------------------------------------------------------------------
/.github/workflows/release.yml:
--------------------------------------------------------------------------------
1 | name: Build/release
2 |
3 | on:
4 | push:
5 | tags:
6 | - '*'
7 |
8 | jobs:
9 | release:
10 | runs-on: ${{ matrix.os }}
11 |
12 | strategy:
13 | matrix:
14 | os: [macos-latest, ubuntu-latest, windows-2019]
15 |
16 | steps:
17 | - name: Check out Git repository
18 | uses: actions/checkout@v2
19 |
20 | - name: Install Node.js, NPM and Yarn
21 | uses: actions/setup-node@v1
22 | with:
23 | node-version: 14
24 |
25 | - name: Build/release Electron app
26 | uses: samuelmeuli/action-electron-builder@v1
27 | with:
28 | # GitHub token, automatically provided to the action
29 | # (No need to define this secret in the repo settings)
30 | github_token: ${{ secrets.github_token }}
31 |
32 | # macOS code signing certificate
33 | mac_certs: ${{ secrets.mac_certs }}
34 | mac_certs_password: ${{ secrets.mac_certs_password }}
35 |
36 | # If the commit is tagged with a version (e.g. "v1.0.0"),
37 | # release the app after building
38 | release: ${{ startsWith(github.ref, 'refs/tags/v') }}
39 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 |
8 | # Runtime data
9 | pids
10 | *.pid
11 | *.seed
12 | *.pid.lock
13 |
14 | # Directory for instrumented libs generated by jscoverage/JSCover
15 | lib-cov
16 |
17 | # Coverage directory used by tools like istanbul
18 | coverage
19 |
20 | # nyc test coverage
21 | .nyc_output
22 |
23 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
24 | .grunt
25 |
26 | # Bower dependency directory (https://bower.io/)
27 | bower_components
28 |
29 | # node-waf configuration
30 | .lock-wscript
31 |
32 | # Compiled binary addons (https://nodejs.org/api/addons.html)
33 | build/Release
34 |
35 | # Dependency directories
36 | node_modules/
37 | jspm_packages/
38 |
39 | # TypeScript v1 declaration files
40 | typings/
41 |
42 | # Optional npm cache directory
43 | .npm
44 |
45 | # Optional eslint cache
46 | .eslintcache
47 |
48 | # Optional REPL history
49 | .node_repl_history
50 |
51 | # Output of 'npm pack'
52 | *.tgz
53 |
54 | # Yarn Integrity file
55 | .yarn-integrity
56 |
57 | # dotenv environment variables file
58 | .env
59 | .env.test
60 |
61 | # parcel-bundler cache (https://parceljs.org/)
62 | .cache
63 |
64 | # next.js build output
65 | .next
66 |
67 | # nuxt.js build output
68 | .nuxt
69 |
70 | # vuepress build output
71 | .vuepress/dist
72 |
73 | # Serverless directories
74 | .serverless/
75 |
76 | # FuseBox cache
77 | .fusebox/
78 |
79 | # DynamoDB Local files
80 | .dynamodb/
81 |
82 | # ----
83 | dist
84 | **/.tmp
85 | release
86 | .DS_Store
87 | dist-ssr
88 | *.local
89 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "semi": false,
3 | "singleQuote": true,
4 | "trailingComma": "all",
5 | "printWidth": 80,
6 | "tabWidth": 2,
7 | "endOfLine": "auto"
8 | }
9 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2020-present zenghongtu (zenghongtu@gmail.com)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # PPet
4 |
5 | > 给你的桌面多一点趣味~😁
6 |
7 | **支持 Live2d v3 啦~**
8 |
9 | [](https://github.com/zenghongtu/PPet/releases)
10 | 
11 |
12 | ## 预览
13 |
14 |
15 |
16 | 小工具:
17 |
18 |
19 |
20 |
21 | 设置(可以使用在线/本地 Model):
22 |
23 |
24 |
25 | 托盘:
26 |
27 |
28 |
29 |
30 | ## 功能
31 |
32 | - [x] 支持 Live2d v2/v3
33 | - [x] 导入本地/在线 Model
34 | - [x] 调整渲染大小
35 | - [x] @置顶
36 | - [x] 忽略点击
37 | - [x] 开机启动
38 | - [x] 拖动位置
39 | - [ ] ...
40 |
41 | ## 安装
42 |
43 | [这里](https://github.com/zenghongtu/PPet/releases/latest)去下载最新版本,Mac使用.dmg, Window使用.exe,Linux使用.deb。
44 |
45 | (可以使用 [GitHub Proxy 代理加速](https://ghproxy.com/) 下载)
46 |
47 | ## 使用
48 |
49 | ### 导入模型
50 |
51 | 两种方式:
52 |
53 | - 在设置 -> 模型列表中添加 `json` 文件(本地模型以`file://`开头)。
54 |
55 | - 本地模型将文件夹拖入窗口中,导入成功会更新到模型列表中
56 |
57 |
58 |
59 |
60 |
61 |
62 | ## 开发
63 |
64 | ```
65 | $ pnpm i
66 | $ pnpm start
67 | ```
68 |
69 | ## 欢迎参与贡献
70 |
71 | 发现了错误? 向我发起一个 PR 吧! 参考 [Commit message 和 Change log 编写指南 - 阮一峰的网络日志](http://www.ruanyifeng.com/blog/2016/01/commit_message_change_log.html) 提交 commit 即可。
72 | ## 其他
73 |
74 | Model资源: [zenghongtu/live2d-model-assets](https://github.com/zenghongtu/live2d-model-assets)
75 |
76 | [前往旧版](https://github.com/zenghongtu/PPet/blob/master/README.md)
77 |
78 |
--------------------------------------------------------------------------------
/assets/preview1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/assets/preview1.png
--------------------------------------------------------------------------------
/assets/preview2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/assets/preview2.jpg
--------------------------------------------------------------------------------
/assets/preview3.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/assets/preview3.jpg
--------------------------------------------------------------------------------
/assets/record1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/assets/record1.gif
--------------------------------------------------------------------------------
/assets/record2.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/assets/record2.gif
--------------------------------------------------------------------------------
/assets/ubuntu.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/assets/ubuntu.jpg
--------------------------------------------------------------------------------
/assets/win10.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/assets/win10.jpg
--------------------------------------------------------------------------------
/configs/vite.main.ts:
--------------------------------------------------------------------------------
1 | import { join } from 'path'
2 | import { builtinModules } from 'module'
3 | import { defineConfig } from 'vite'
4 |
5 | export default defineConfig({
6 | mode: process.env.NODE_ENV,
7 | root: join(__dirname, '../src/main'),
8 | build: {
9 | outDir: '../../dist/main',
10 | lib: {
11 | entry: 'index.ts',
12 | formats: ['cjs'],
13 | },
14 | minify: process.env.NODE_ENV === 'production',
15 | emptyOutDir: true,
16 | rollupOptions: {
17 | external: [...builtinModules, 'electron'],
18 | output: {
19 | entryFileNames: '[name].cjs',
20 | },
21 | },
22 | },
23 | resolve: {
24 | alias: {
25 | '@src': join(__dirname, '../src'),
26 | },
27 | },
28 | })
29 |
--------------------------------------------------------------------------------
/configs/vite.preload.ts:
--------------------------------------------------------------------------------
1 | import { join } from 'path'
2 | import { builtinModules } from 'module'
3 | import { defineConfig } from 'vite'
4 |
5 | export default defineConfig({
6 | mode: process.env.NODE_ENV,
7 | root: join(__dirname, '../src/preload'),
8 | build: {
9 | outDir: '../../dist/preload',
10 | lib: {
11 | entry: 'index.ts',
12 | formats: ['cjs'],
13 | },
14 | minify: process.env.NODE_ENV === 'production',
15 | emptyOutDir: true,
16 | rollupOptions: {
17 | external: [...builtinModules, 'electron'],
18 | output: {
19 | entryFileNames: '[name].cjs',
20 | },
21 | },
22 | },
23 | resolve: {
24 | alias: {
25 | '@src': join(__dirname, '../src'),
26 | },
27 | },
28 | })
29 |
--------------------------------------------------------------------------------
/configs/vite.renderer.ts:
--------------------------------------------------------------------------------
1 | import { join } from 'path'
2 | import { defineConfig } from 'vite'
3 | import react from '@vitejs/plugin-react'
4 | import vitePluginImp from 'vite-plugin-imp'
5 | import pkg from '../package.json'
6 |
7 | // https://vitejs.dev/config/
8 | export default defineConfig({
9 | mode: process.env.NODE_ENV,
10 | root: join(__dirname, '../src/renderer'),
11 | plugins: [
12 | react(),
13 | vitePluginImp({
14 | libList: [
15 | {
16 | libName: 'antd',
17 | style(name) {
18 | // use less
19 | return `antd/es/${name}/style/index.js`
20 | },
21 | },
22 | ],
23 | }),
24 | ],
25 | css: {
26 | preprocessorOptions: {
27 | less: {
28 | javascriptEnabled: true,
29 | },
30 | },
31 | },
32 | base: './',
33 | build: {
34 | emptyOutDir: true,
35 | outDir: '../../dist/renderer',
36 | },
37 | resolve: {
38 | alias: {
39 | '@src': join(__dirname, '../src'),
40 | },
41 | },
42 | server: {
43 | host: pkg.env.HOST,
44 | port: pkg.env.PORT,
45 | },
46 | })
47 |
--------------------------------------------------------------------------------
/electron-builder.json:
--------------------------------------------------------------------------------
1 | {
2 | "productName": "PPet3",
3 | "artifactName": "PPet3-${version}.${ext}",
4 | "appId": "com.zenghongtu.ppet-v3",
5 | "asar": true,
6 | "files": ["dist", "package.json", "static/**/*"],
7 | "mac": {
8 | "artifactName": "${productName}_${version}.${ext}",
9 | "target": ["dmg", "zip"],
10 | "category": "public.app-category.development",
11 | "icon": "static/icons/mac/icon.icns",
12 | "darkModeSupport": true
13 | },
14 | "win": {
15 | "icon": "static/icons/win/icon.ico",
16 | "artifactName": "${productName}-v${version}-${os}-${arch}.${ext}",
17 | "target": [
18 | {
19 | "target": "nsis",
20 | "arch": ["x64", "ia32"]
21 | },
22 | {
23 | "target": "zip",
24 | "arch": ["x64", "ia32"]
25 | }
26 | ]
27 | },
28 | "nsis": {
29 | "createDesktopShortcut": "always",
30 | "createStartMenuShortcut": true,
31 | "shortcutName": "PPet",
32 | "oneClick": false,
33 | "perMachine": true,
34 | "allowToChangeInstallationDirectory": true,
35 | "artifactName": "${productName}_${version}.${ext}",
36 | "unicode": true
37 | },
38 | "extraFiles": [],
39 | "dmg": {
40 | "contents": [
41 | {
42 | "x": 130,
43 | "y": 220
44 | },
45 | {
46 | "x": 410,
47 | "y": 220,
48 | "type": "link",
49 | "path": "/Applications"
50 | }
51 | ]
52 | },
53 | "linux": {
54 | "icon": "static/icons/png",
55 | "target": [
56 | {
57 | "target": "AppImage",
58 | "arch": ["x64"]
59 | },
60 | {
61 | "target": "deb",
62 | "arch": ["x64"]
63 | }
64 | ],
65 | "category": "Development"
66 | },
67 | "publish": [
68 | {
69 | "provider": "github",
70 | "owner": "zenghongtu",
71 | "repo": "PPet"
72 | }
73 | ],
74 | "directories": {
75 | "output": "./release"
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PPet3",
3 | "version": "3.3.0",
4 | "description": "给你的桌面添加一点趣味~",
5 | "license": "MIT",
6 | "private": true,
7 | "main": "dist/main/index.cjs",
8 | "repository": "https://github.com/zenghongtu/PPet.git",
9 | "homepage": "https://github.com/zenghongtu/PPet",
10 | "author": "zenghongtu ",
11 | "scripts": {
12 | "start": "node scripts/watch.mjs",
13 | "build": "node scripts/build.mjs",
14 | "dist": "yarn build && electron-builder",
15 | "dist:dir": "yarn dist --dir -c.compression=store -c.mac.identity=null",
16 | "dist:all": "yarn run dist -wml",
17 | "dist:win": "yarn run dist --win --ia32",
18 | "dist:mac": "yarn run dist -m",
19 | "dist:linux": "yarn run dist -l",
20 | "release": "yarn dist -wml -p always",
21 | "patch": "yarn version --patch",
22 | "minor": "yarn version --minor",
23 | "major": "yarn version --major"
24 | },
25 | "engines": {
26 | "node": ">=14.17.0"
27 | },
28 | "devDependencies": {
29 | "@ant-design/icons": "^4.7.0",
30 | "@electron/remote": "^2.0.1",
31 | "@rematch/core": "^2.2.0",
32 | "@rematch/persist": "^2.1.2",
33 | "@types/react": "^17.0.33",
34 | "@types/react-dom": "^17.0.10",
35 | "@types/redux-state-sync": "^3.1.2",
36 | "@types/styled-components": "^5.1.19",
37 | "@vitejs/plugin-react": "^1.1.4",
38 | "antd": "^4.16.13",
39 | "chalk": "^5.0.0",
40 | "electron": "16.0.6",
41 | "electron-builder": "^22.14.5",
42 | "electron-store": "^8.0.1",
43 | "electron-window-state": "^5.0.3",
44 | "font-awesome": "^4.7.0",
45 | "globby": "^11.0.4",
46 | "less": "^4.1.2",
47 | "prettier": "^2.5.1",
48 | "react": "^17.0.2",
49 | "react-dom": "^17.0.2",
50 | "react-ga": "^3.3.0",
51 | "react-redux": "^7.2.6",
52 | "react-router-dom": "^6.2.1",
53 | "redux": "^4.1.2",
54 | "redux-persist": "^6.0.0",
55 | "redux-state-sync": "^3.1.2",
56 | "styled-components": "^5.3.3",
57 | "typescript": "^4.4.4",
58 | "vite": "^2.7.10",
59 | "vite-plugin-imp": "^2.1.3"
60 | },
61 | "env": {
62 | "//": "Used in build scripts",
63 | "HOST": "127.0.0.1",
64 | "PORT": 3344
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/paths.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "compilerOptions": {
4 | "baseUrl": "./",
5 | "paths": {
6 | "@src/*": ["src/*"]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/scripts/build.mjs:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'production'
2 |
3 | import { build as viteBuild } from 'vite'
4 | import chalk from 'chalk'
5 |
6 | const TAG = chalk.bgBlue('[build.mjs]')
7 |
8 | const viteConfigs = {
9 | main: 'configs/vite.main.ts',
10 | preload: 'configs/vite.preload.ts',
11 | renderer: 'configs/vite.renderer.ts',
12 | }
13 |
14 | async function buildElectron() {
15 | for (const [name, configPath] of Object.entries(viteConfigs)) {
16 | console.group(TAG, name)
17 | await viteBuild({
18 | configFile: configPath,
19 | mode: process.env.NODE_ENV,
20 | })
21 | console.groupEnd()
22 | console.log() // for beautiful log.
23 | }
24 | }
25 |
26 | // bootstrap
27 | await buildElectron()
28 |
--------------------------------------------------------------------------------
/scripts/watch.mjs:
--------------------------------------------------------------------------------
1 | process.env.NODE_ENV = 'development'
2 |
3 | import { readFileSync } from 'fs'
4 | import { resolve, join } from 'path'
5 | import electron from 'electron'
6 | import { spawn } from 'child_process'
7 | import { createServer, build as viteBuild } from 'vite'
8 |
9 | const pkg = JSON.parse(
10 | readFileSync(join(process.cwd(), 'package.json'), 'utf8')
11 | )
12 |
13 | /**
14 | * @param {{ name: string; configFile: string; writeBundle: import('rollup').OutputPlugin['writeBundle'] }} param0
15 | * @returns {import('rollup').RollupWatcher}
16 | */
17 | function getWatcher({ name, configFile, writeBundle }) {
18 | return viteBuild({
19 | // Options here precedence over configFile
20 | mode: process.env.NODE_ENV,
21 | build: {
22 | watch: {},
23 | },
24 | configFile,
25 | plugins: [{ name, writeBundle }],
26 | })
27 | }
28 |
29 | /**
30 | * @returns {Promise}
31 | */
32 | async function watchMain() {
33 | /**
34 | * @type {import('child_process').ChildProcessWithoutNullStreams | null}
35 | */
36 | let electronProcess = null
37 |
38 | /**
39 | * @type {import('rollup').RollupWatcher}
40 | */
41 | const watcher = await getWatcher({
42 | name: 'electron-main-watcher',
43 | configFile: 'configs/vite.main.ts',
44 | writeBundle() {
45 | electronProcess && electronProcess.kill()
46 | electronProcess = spawn(electron, ['.'], {
47 | stdio: 'inherit',
48 | env: Object.assign(process.env, pkg.env),
49 | })
50 | },
51 | })
52 |
53 | return watcher
54 | }
55 |
56 | /**
57 | * @param {import('vite').ViteDevServer} viteDevServer
58 | * @returns {Promise}
59 | */
60 | async function watchPreload(viteDevServer) {
61 | return getWatcher({
62 | name: 'electron-preload-watcher',
63 | configFile: 'configs/vite.preload.ts',
64 | writeBundle() {
65 | viteDevServer.ws.send({
66 | type: 'full-reload',
67 | })
68 | },
69 | })
70 | }
71 |
72 | // bootstrap
73 | const viteDevServer = await createServer({
74 | configFile: 'configs/vite.renderer.ts',
75 | })
76 |
77 | await viteDevServer.listen()
78 | await watchPreload(viteDevServer)
79 | await watchMain()
80 |
--------------------------------------------------------------------------------
/src/common/config.ts:
--------------------------------------------------------------------------------
1 | import { app } from 'electron'
2 | import Store from 'electron-store'
3 |
4 | const store = new Store<{
5 | alwaysOnTop: boolean
6 | ignoreMouseEvents: boolean
7 | showTool: boolean
8 | language: 'zh' | 'en'
9 | }>({
10 | name: 'ppet-config',
11 | defaults: {
12 | alwaysOnTop: true,
13 | ignoreMouseEvents: false,
14 | showTool: true,
15 | language: app.getLocale().includes('zh') ? 'zh' : 'en',
16 | },
17 | })
18 |
19 | export default store
20 |
--------------------------------------------------------------------------------
/src/common/index.ts:
--------------------------------------------------------------------------------
1 | import config from './config'
2 | export * from './paths'
3 |
4 | export { config }
5 |
--------------------------------------------------------------------------------
/src/common/paths.ts:
--------------------------------------------------------------------------------
1 | import path from 'path'
2 | import { app } from 'electron'
3 |
4 | /** 当前应用程序所在目录 */
5 | export const APP_PATH: string = app.getAppPath()
6 |
7 | /** 当前用户的应用数据文件夹 */
8 | export const APP_DATA_PATH: string = app.getPath('appData')
9 |
10 | /** 储存你应用程序设置文件的文件夹 */
11 | export const USER_DATA_PATH: string = app.getPath('userData')
12 |
13 | /** 应用程序的日志文件夹 */
14 | export const LOGS_PATH: string =
15 | process.platform === 'darwin'
16 | ? path.resolve(app.getPath('logs'), `../${app.name}`)
17 | : path.resolve(USER_DATA_PATH, 'logs')
18 |
19 | /** 资源文件夹 */
20 | export const ASSETS_PATH: string =
21 | process.env.NODE_ENV === 'development'
22 | ? 'assets'
23 | : path.join(APP_PATH, 'assets')
24 |
--------------------------------------------------------------------------------
/src/interfaces/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/zenghongtu/PPet/2185c3f90600e3f809d55dbeedc7b82a341d06ca/src/interfaces/index.ts
--------------------------------------------------------------------------------
/src/main/index.ts:
--------------------------------------------------------------------------------
1 | import os from 'os'
2 | import { join } from 'path'
3 | import { app, BrowserWindow, protocol, session } from 'electron'
4 | import windowStateKeeper from 'electron-window-state'
5 | import remoteMain from '@electron/remote/main'
6 |
7 | import './initConfig'
8 | import initTray from './tray'
9 | import { createWindow, winPagePathMap } from './window'
10 |
11 | remoteMain.initialize()
12 |
13 | const isWin7 = os.release().startsWith('6.1')
14 | if (isWin7) app.disableHardwareAcceleration()
15 |
16 | if (app.isPackaged) {
17 | if (!app.requestSingleInstanceLock()) {
18 | app.quit()
19 | process.exit(0)
20 | }
21 | if (process.platform === 'darwin') {
22 | app.dock.hide()
23 | }
24 | }
25 |
26 | app.commandLine.appendSwitch('disable-renderer-backgrounding')
27 | app.commandLine.appendSwitch('disable-background-timer-throttling')
28 | app.commandLine.appendSwitch('autoplay-policy', 'no-user-gesture-required')
29 |
30 | let mainWindowState: windowStateKeeper.State
31 |
32 | app
33 | .whenReady()
34 | .then(() => {
35 | protocol.registerFileProtocol('file', (request, callback) => {
36 | const url = request.url.replace('file://', '')
37 | const decodedUrl = decodeURI(url)
38 | try {
39 | return callback(decodedUrl)
40 | } catch (error) {
41 | console.error('Could not get file path:', error)
42 | return callback('404')
43 | }
44 | })
45 | })
46 | .then(() => {
47 | mainWindowState = windowStateKeeper({
48 | defaultHeight: 600,
49 | defaultWidth: 350,
50 | })
51 | })
52 | .then(async () => {
53 | const options = {
54 | title: 'PPet',
55 | alwaysOnTop: true,
56 | autoHideMenuBar: true,
57 | hasShadow: false,
58 | transparent: true,
59 | frame: false,
60 | x: mainWindowState.x,
61 | y: mainWindowState.y,
62 | width: mainWindowState.width,
63 | height: mainWindowState.height,
64 | skipTaskbar: true,
65 | minimizable: false,
66 | maximizable: false,
67 | resizable: false,
68 | // titleBarStyle: 'hidden',
69 | webPreferences: {
70 | preload: join(__dirname, '../preload/index.cjs'),
71 | webSecurity: false,
72 | backgroundThrottling: false,
73 | },
74 | }
75 |
76 | const win = await createWindow(options)
77 | if (win) {
78 | mainWindowState.manage(win)
79 |
80 | initTray(win)
81 | }
82 | })
83 |
84 | app.on('window-all-closed', () => {
85 | winPagePathMap.clear()
86 | app.quit()
87 | })
88 |
89 | app.on('browser-window-created', (ev, win) => {
90 | remoteMain.enable(win.webContents)
91 | })
92 |
93 | app.on('second-instance', () => {
94 | const win = BrowserWindow.getAllWindows()[0]
95 | if (win) {
96 | // Someone tried to run a second instance, we should focus our window.
97 | if (win.isMinimized()) win.restore()
98 | win.focus()
99 | }
100 | })
101 |
102 | app.on('activate', () => {
103 | const allWindows = BrowserWindow.getAllWindows()
104 | if (allWindows.length) {
105 | allWindows[0].focus()
106 | }
107 | })
108 |
--------------------------------------------------------------------------------
/src/main/initConfig.ts:
--------------------------------------------------------------------------------
1 | import { config } from '@src/common'
2 | ;(global as any).config = config.store
3 |
4 | config.onDidAnyChange((newValue) => {
5 | ;(global as any).config = newValue || {}
6 | })
7 |
--------------------------------------------------------------------------------
/src/main/tray.ts:
--------------------------------------------------------------------------------
1 | import { join } from 'path'
2 | import electron, {
3 | Tray,
4 | nativeImage,
5 | app,
6 | MenuItemConstructorOptions,
7 | MenuItem,
8 | shell,
9 | BrowserWindow,
10 | Menu,
11 | } from 'electron'
12 | import { config } from '@src/common'
13 |
14 | import { createWindow } from './window'
15 | import stripTrayIcon from '../../static/icons/strip-tray.png'
16 | import trayIcon from '../../static/icons/tray.png'
17 |
18 | const currentIcon = process.platform === 'darwin' ? stripTrayIcon : trayIcon
19 |
20 | const langs = {
21 | zh: {
22 | alwaysOnTop: '@置顶',
23 | ignoreMouseEvents: '忽略点击',
24 | openAtLogin: '开机启动',
25 | plugins: '插件中心',
26 | tools: '小工具',
27 | language: '语言',
28 | zoomIn: '放大',
29 | zoomOut: '缩小',
30 | zoomReset: '原始大小',
31 | canvasSettings: '画布设置',
32 | clearSettings: '清除设置',
33 | importModel: '导入模型',
34 | importOnlineModel: '导入在线模型',
35 | removeModel: '移除模型',
36 | reRender: '重新渲染',
37 | debug: '调试',
38 | feedback: '反馈',
39 | about: '关于',
40 | quit: '退出',
41 | next: '下一个模型',
42 | prev: '上一个模型',
43 | model: {
44 | title: '请选择模型配置文件',
45 | buttonLabel: '导入模型',
46 | filtersName: '模型配置文件',
47 | },
48 | errorBox: {
49 | title: '导入模型失败',
50 | title1: '移除模型失败',
51 | getContent: (text: string) =>
52 | `无效的model配置文件,该文件为'.json'结尾,会包含${text}等字段`,
53 | },
54 | settings: '配置',
55 | },
56 | en: {
57 | alwaysOnTop: 'Always On Top',
58 | ignoreMouseEvents: 'Ignore Mouse Events',
59 | openAtLogin: 'Open At Login',
60 | plugins: 'Plugins',
61 | tools: 'Tools',
62 | language: 'Language',
63 | zoomIn: 'Zoom In',
64 | zoomOut: 'Zoom Out',
65 | zoomReset: 'Zoom Reset',
66 | canvasSettings: 'Canvas Settings',
67 | clearSettings: 'Clear Canvas Settings',
68 | importModel: 'Import Model',
69 | importOnlineModel: 'Import Online Model',
70 | removeModel: 'Remove Model',
71 | reRender: 'ReRender',
72 | debug: 'Debug',
73 | feedback: 'Feedback',
74 | about: 'About',
75 | quit: 'Quit',
76 | next: 'Next Model',
77 | prev: 'Prev Model',
78 | model: {
79 | title: 'Please select model configuration file',
80 | buttonLabel: 'Import model',
81 | filtersName: 'model configuration file',
82 | },
83 | errorBox: {
84 | title: 'Import model failed',
85 | title1: 'Remove model failed',
86 | getContent: (text: string) =>
87 | `Invalid model configuration file. The file ends with '.json' and should contain fields such as ${text}`,
88 | },
89 | settings: 'Settings',
90 | },
91 | }
92 |
93 | type langType = 'zh' | 'en'
94 |
95 | let tray: electron.Tray
96 |
97 | const initTray = (mainWindow: BrowserWindow) => {
98 | if (!tray) {
99 | tray = new Tray(nativeImage.createFromDataURL(currentIcon))
100 | }
101 |
102 | const handleClickLangRadio = (lang: langType) => {
103 | config.set('language', lang)
104 | initTray(mainWindow)
105 | mainWindow.webContents.executeJavaScript(`window.setLanguage('${lang}')`)
106 | }
107 |
108 | const alwaysOnTop = config.get('alwaysOnTop')
109 | const ignoreMouseEvents = config.get('ignoreMouseEvents')
110 | const showTool = config.get('showTool')
111 | const lang = config.get('language')
112 |
113 | const cl = langs[lang]
114 | mainWindow.setAlwaysOnTop(alwaysOnTop)
115 | mainWindow.setIgnoreMouseEvents(ignoreMouseEvents, { forward: true })
116 |
117 | const template: Array = [
118 | {
119 | label: cl.alwaysOnTop,
120 | type: 'checkbox',
121 | checked: alwaysOnTop,
122 | click: (item) => {
123 | const { checked } = item
124 | mainWindow.setAlwaysOnTop(checked)
125 | config.set('alwaysOnTop', checked)
126 | },
127 | },
128 | {
129 | label: cl.tools,
130 | type: 'checkbox',
131 | accelerator: 'CmdOrCtrl+t',
132 | checked: showTool,
133 | click: (item) => {
134 | const { checked } = item
135 | mainWindow.webContents.executeJavaScript(
136 | `window.setSwitchTool(${checked})`,
137 | )
138 | config.set('showTool', checked)
139 | },
140 | },
141 | {
142 | label: cl.ignoreMouseEvents,
143 | accelerator: 'CmdOrCtrl+i',
144 | type: 'checkbox',
145 | checked: ignoreMouseEvents,
146 | click: (item) => {
147 | const { checked } = item
148 | mainWindow.setIgnoreMouseEvents(checked, { forward: true })
149 | config.set('ignoreMouseEvents', checked)
150 | },
151 | },
152 | {
153 | label: cl.settings,
154 | accelerator: 'CmdOrCtrl+,',
155 | click: async () => {
156 | await createWindow(
157 | {
158 | title: cl.settings,
159 | width: 800,
160 | height: 600,
161 | webPreferences: {
162 | preload: join(__dirname, '../preload/index.cjs'),
163 | webSecurity: false,
164 | backgroundThrottling: false,
165 | },
166 | },
167 | '/setting',
168 | )
169 | },
170 | },
171 | {
172 | type: 'separator',
173 | },
174 | {
175 | label: cl.prev,
176 | accelerator: 'CmdOrCtrl+p',
177 | click: () => {
178 | mainWindow.webContents.executeJavaScript('window.prevModel()')
179 | },
180 | },
181 | {
182 | label: cl.next,
183 | accelerator: 'CmdOrCtrl+n',
184 | click: () => {
185 | mainWindow.webContents.executeJavaScript('window.nextModel()')
186 | },
187 | },
188 | {
189 | type: 'separator',
190 | },
191 | {
192 | label: cl.language,
193 | type: 'submenu',
194 | submenu: [
195 | {
196 | label: '简体中文',
197 | type: 'radio',
198 | checked: lang === 'zh',
199 | click: handleClickLangRadio.bind(null, 'zh'),
200 | },
201 | {
202 | label: 'English',
203 | type: 'radio',
204 | checked: lang === 'en',
205 | click: handleClickLangRadio.bind(null, 'en'),
206 | },
207 | ],
208 | },
209 | {
210 | type: 'separator',
211 | },
212 | {
213 | label: cl.reRender,
214 | accelerator: 'CmdOrCtrl+r',
215 | click: () => {
216 | mainWindow.reload()
217 | },
218 | },
219 | {
220 | label: cl.debug,
221 | accelerator: 'CmdOrCtrl+d',
222 | click: () => {
223 | mainWindow.webContents.openDevTools({ mode: 'undocked' })
224 | },
225 | },
226 | {
227 | type: 'separator',
228 | },
229 | {
230 | label: cl.openAtLogin,
231 | type: 'checkbox',
232 | checked: app.getLoginItemSettings().openAtLogin,
233 | click: (item) => {
234 | const { checked } = item
235 | app.setLoginItemSettings({ openAtLogin: checked })
236 | },
237 | },
238 | {
239 | type: 'separator',
240 | },
241 | {
242 | label: cl.feedback,
243 | click: () => {
244 | shell.openExternal('https://github.com/zenghongtu/PPet/issues')
245 | },
246 | },
247 | {
248 | label: cl.about,
249 | role: 'about',
250 | },
251 | {
252 | type: 'separator',
253 | },
254 | {
255 | label: cl.quit,
256 | click: (item) => {
257 | app.quit()
258 | },
259 | },
260 | ]
261 |
262 | const menu = Menu.buildFromTemplate(template)
263 |
264 | tray.setContextMenu(menu)
265 | }
266 |
267 | export default initTray
268 |
--------------------------------------------------------------------------------
/src/main/window.ts:
--------------------------------------------------------------------------------
1 | import { app, BrowserWindow } from 'electron'
2 | import { join } from 'path'
3 |
4 | export const winPagePathMap: Map = new Map()
5 |
6 | export async function createWindow(
7 | options: Electron.BrowserWindowConstructorOptions,
8 | pagePath: string = '',
9 | ) {
10 | const lastWin = winPagePathMap.get(pagePath)
11 | if (lastWin && !lastWin.isDestroyed()) {
12 | lastWin.focus()
13 | return
14 | }
15 |
16 | const win = new BrowserWindow({ ...options, show: false })
17 |
18 | if (app.isPackaged) {
19 | const file = join(__dirname, '../renderer/index.html')
20 |
21 | win.loadFile(file, { hash: pagePath })
22 | } else {
23 | const pkg = await import('../../package.json')
24 | const url = `http://${pkg.env.HOST || '127.0.0.1'}:${
25 | pkg.env.PORT
26 | }#${pagePath}`
27 |
28 | win.loadURL(url, {
29 | // userAgent:
30 | // 'Mozilla/5.0 (iPhone; CPU iPhone OS 10_3 like Mac OS X) AppleWebKit/603.1.23 (KHTML, like Gecko) Version/10.0 Mobile/14E5239e Safari/602.1',
31 | })
32 | win.webContents.openDevTools()
33 | }
34 |
35 | win.once('ready-to-show', () => {
36 | win.show()
37 | win.focus()
38 | })
39 |
40 | winPagePathMap.set(pagePath, win)
41 |
42 | return win
43 | }
44 |
--------------------------------------------------------------------------------
/src/preload/index.ts:
--------------------------------------------------------------------------------
1 | import { contextBridge, ipcRenderer } from 'electron'
2 | import electron from '@electron/remote'
3 | import fs from 'fs/promises'
4 | import path from 'path'
5 | import globby from 'globby'
6 |
7 | const getModels = async (file: File) => {
8 | const filePath = file.path
9 | if (filePath.endsWith('model.json') || filePath.endsWith('.model3.json')) {
10 | return [filePath]
11 | }
12 |
13 | console.log('getModels: ', filePath)
14 | return fs.stat(filePath).then(async (f) => {
15 | if (f.isDirectory()) {
16 | const result = await globby(['**/*model.json', '**.model3.json'], {
17 | cwd: filePath,
18 | })
19 | return result.map((f) => path.join(filePath, f))
20 | }
21 | return []
22 | })
23 | }
24 |
25 | const setWinResizable = (resizable: boolean) => {
26 | electron.getCurrentWindow().setResizable(resizable)
27 | }
28 |
29 | const isWinResizable = () => {
30 | return electron.getCurrentWindow().isResizable()
31 | }
32 |
33 | const getConfig = () => electron.getGlobal('config')
34 |
35 | contextBridge.exposeInMainWorld('bridge', {
36 | __dirname,
37 | __filename,
38 | getModels,
39 | setWinResizable,
40 | isWinResizable,
41 | getConfig,
42 | })
43 |
--------------------------------------------------------------------------------
/src/renderer/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/src/renderer/public/scripts/howler.min.js:
--------------------------------------------------------------------------------
1 | /*! howler.js v2.1.3 | (c) 2013-2019, James Simpson of GoldFire Studios | MIT License | howlerjs.com */
2 | !function(){"use strict";var e=function(){this.init()};e.prototype={init:function(){var e=this||n;return e._counter=1e3,e._html5AudioPool=[],e.html5PoolSize=10,e._codecs={},e._howls=[],e._muted=!1,e._volume=1,e._canPlayEvent="canplaythrough",e._navigator="undefined"!=typeof window&&window.navigator?window.navigator:null,e.masterGain=null,e.noAudio=!1,e.usingWebAudio=!0,e.autoSuspend=!0,e.ctx=null,e.autoUnlock=!0,e._setup(),e},volume:function(e){var o=this||n;if(e=parseFloat(e),o.ctx||_(),void 0!==e&&e>=0&&e<=1){if(o._volume=e,o._muted)return o;o.usingWebAudio&&o.masterGain.gain.setValueAtTime(e,n.ctx.currentTime);for(var t=0;t=0;o--)e._howls[o].unload();return e.usingWebAudio&&e.ctx&&void 0!==e.ctx.close&&(e.ctx.close(),e.ctx=null,_()),e},codecs:function(e){return(this||n)._codecs[e.replace(/^x-/,"")]},_setup:function(){var e=this||n;if(e.state=e.ctx?e.ctx.state||"suspended":"suspended",e._autoSuspend(),!e.usingWebAudio)if("undefined"!=typeof Audio)try{var o=new Audio;void 0===o.oncanplaythrough&&(e._canPlayEvent="canplay")}catch(n){e.noAudio=!0}else e.noAudio=!0;try{var o=new Audio;o.muted&&(e.noAudio=!0)}catch(e){}return e.noAudio||e._setupCodecs(),e},_setupCodecs:function(){var e=this||n,o=null;try{o="undefined"!=typeof Audio?new Audio:null}catch(n){return e}if(!o||"function"!=typeof o.canPlayType)return e;var t=o.canPlayType("audio/mpeg;").replace(/^no$/,""),r=e._navigator&&e._navigator.userAgent.match(/OPR\/([0-6].)/g),a=r&&parseInt(r[0].split("/")[1],10)<33;return e._codecs={mp3:!(a||!t&&!o.canPlayType("audio/mp3;").replace(/^no$/,"")),mpeg:!!t,opus:!!o.canPlayType('audio/ogg; codecs="opus"').replace(/^no$/,""),ogg:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),oga:!!o.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,""),wav:!!o.canPlayType('audio/wav; codecs="1"').replace(/^no$/,""),aac:!!o.canPlayType("audio/aac;").replace(/^no$/,""),caf:!!o.canPlayType("audio/x-caf;").replace(/^no$/,""),m4a:!!(o.canPlayType("audio/x-m4a;")||o.canPlayType("audio/m4a;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),mp4:!!(o.canPlayType("audio/x-mp4;")||o.canPlayType("audio/mp4;")||o.canPlayType("audio/aac;")).replace(/^no$/,""),weba:!!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),webm:!!o.canPlayType('audio/webm; codecs="vorbis"').replace(/^no$/,""),dolby:!!o.canPlayType('audio/mp4; codecs="ec-3"').replace(/^no$/,""),flac:!!(o.canPlayType("audio/x-flac;")||o.canPlayType("audio/flac;")).replace(/^no$/,"")},e},_unlockAudio:function(){var e=this||n;if(!e._audioUnlocked&&e.ctx){e._audioUnlocked=!1,e.autoUnlock=!1,e._mobileUnloaded||44100===e.ctx.sampleRate||(e._mobileUnloaded=!0,e.unload()),e._scratchBuffer=e.ctx.createBuffer(1,1,22050);var o=function(n){for(var t=0;t0?i._seek:t._sprite[e][0]/1e3),s=Math.max(0,(t._sprite[e][0]+t._sprite[e][1])/1e3-_),l=1e3*s/Math.abs(i._rate),c=t._sprite[e][0]/1e3,f=(t._sprite[e][0]+t._sprite[e][1])/1e3;i._sprite=e,i._ended=!1;var p=function(){i._paused=!1,i._seek=_,i._start=c,i._stop=f,i._loop=!(!i._loop&&!t._sprite[e][2])};if(_>=f)return void t._ended(i);var m=i._node;if(t._webAudio){var v=function(){t._playLock=!1,p(),t._refreshBuffer(i);var e=i._muted||t._muted?0:i._volume;m.gain.setValueAtTime(e,n.ctx.currentTime),i._playStart=n.ctx.currentTime,void 0===m.bufferSource.start?i._loop?m.bufferSource.noteGrainOn(0,_,86400):m.bufferSource.noteGrainOn(0,_,s):i._loop?m.bufferSource.start(0,_,86400):m.bufferSource.start(0,_,s),l!==1/0&&(t._endTimers[i._id]=setTimeout(t._ended.bind(t,i),l)),o||setTimeout(function(){t._emit("play",i._id),t._loadQueue()},0)};"running"===n.state?v():(t._playLock=!0,t.once("resume",v),t._clearTimer(i._id))}else{var h=function(){m.currentTime=_,m.muted=i._muted||t._muted||n._muted||m.muted,m.volume=i._volume*n.volume(),m.playbackRate=i._rate;try{var r=m.play();if(r&&"undefined"!=typeof Promise&&(r instanceof Promise||"function"==typeof r.then)?(t._playLock=!0,p(),r.then(function(){t._playLock=!1,m._unlocked=!0,o||(t._emit("play",i._id),t._loadQueue())}).catch(function(){t._playLock=!1,t._emit("playerror",i._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction."),i._ended=!0,i._paused=!0})):o||(t._playLock=!1,p(),t._emit("play",i._id),t._loadQueue()),m.playbackRate=i._rate,m.paused)return void t._emit("playerror",i._id,"Playback was unable to start. This is most commonly an issue on mobile devices and Chrome where playback was not within a user interaction.");"__default"!==e||i._loop?t._endTimers[i._id]=setTimeout(t._ended.bind(t,i),l):(t._endTimers[i._id]=function(){t._ended(i),m.removeEventListener("ended",t._endTimers[i._id],!1)},m.addEventListener("ended",t._endTimers[i._id],!1))}catch(e){t._emit("playerror",i._id,e)}};"data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA"===m.src&&(m.src=t._src,m.load());var y=window&&window.ejecta||!m.readyState&&n._navigator.isCocoonJS;if(m.readyState>=3||y)h();else{t._playLock=!0;var g=function(){h(),m.removeEventListener(n._canPlayEvent,g,!1)};m.addEventListener(n._canPlayEvent,g,!1),t._clearTimer(i._id)}}return i._id},pause:function(e){var n=this;if("loaded"!==n._state||n._playLock)return n._queue.push({event:"pause",action:function(){n.pause(e)}}),n;for(var o=n._getSoundIds(e),t=0;t=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else r.length>=2&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var a;if(!(void 0!==e&&e>=0&&e<=1))return a=o?t._soundById(o):t._sounds[0],a?a._volume:0;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"volume",action:function(){t.volume.apply(t,r)}}),t;void 0===o&&(t._volume=e),o=t._getSoundIds(o);for(var u=0;u0?t/_:t),l=Date.now();e._fadeTo=o,e._interval=setInterval(function(){var r=(Date.now()-l)/t;l=Date.now(),i+=d*r,i=Math.max(0,i),i=Math.min(1,i),i=Math.round(100*i)/100,u._webAudio?e._volume=i:u.volume(i,e._id,!0),a&&(u._volume=i),(on&&i>=o)&&(clearInterval(e._interval),e._interval=null,e._fadeTo=null,u.volume(o,e._id),u._emit("fade",e._id))},s)},_stopFade:function(e){var o=this,t=o._soundById(e);return t&&t._interval&&(o._webAudio&&t._node.gain.cancelScheduledValues(n.ctx.currentTime),clearInterval(t._interval),t._interval=null,o.volume(t._fadeTo,e),t._fadeTo=null,o._emit("fade",e)),o},loop:function(){var e,n,o,t=this,r=arguments;if(0===r.length)return t._loop;if(1===r.length){if("boolean"!=typeof r[0])return!!(o=t._soundById(parseInt(r[0],10)))&&o._loop;e=r[0],t._loop=e}else 2===r.length&&(e=r[0],n=parseInt(r[1],10));for(var a=t._getSoundIds(n),u=0;u=0?o=parseInt(r[0],10):e=parseFloat(r[0])}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));var i;if("number"!=typeof e)return i=t._soundById(o),i?i._rate:t._rate;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"rate",action:function(){t.rate.apply(t,r)}}),t;void 0===o&&(t._rate=e),o=t._getSoundIds(o);for(var d=0;d=0?o=parseInt(r[0],10):t._sounds.length&&(o=t._sounds[0]._id,e=parseFloat(r[0]))}else 2===r.length&&(e=parseFloat(r[0]),o=parseInt(r[1],10));if(void 0===o)return t;if("loaded"!==t._state||t._playLock)return t._queue.push({event:"seek",action:function(){t.seek.apply(t,r)}}),t;var i=t._soundById(o);if(i){if(!("number"==typeof e&&e>=0)){if(t._webAudio){var d=t.playing(o)?n.ctx.currentTime-i._playStart:0,_=i._rateSeek?i._rateSeek-i._seek:0;return i._seek+(_+d*Math.abs(i._rate))}return i._node.currentTime}var s=t.playing(o);s&&t.pause(o,!0),i._seek=e,i._ended=!1,t._clearTimer(o),t._webAudio||!i._node||isNaN(i._node.duration)||(i._node.currentTime=e);var l=function(){t._emit("seek",o),s&&t.play(o,!0)};if(s&&!t._webAudio){var c=function(){t._playLock?setTimeout(c,0):l()};setTimeout(c,0)}else l()}return t},playing:function(e){var n=this;if("number"==typeof e){var o=n._soundById(e);return!!o&&!o._paused}for(var t=0;t=0&&n._howls.splice(a,1);var u=!0;for(t=0;t=0){u=!1;break}return r&&u&&delete r[e._src],n.noAudio=!1,e._state="unloaded",e._sounds=[],e=null,null},on:function(e,n,o,t){var r=this,a=r["_on"+e];return"function"==typeof n&&a.push(t?{id:o,fn:n,once:t}:{id:o,fn:n}),r},off:function(e,n,o){var t=this,r=t["_on"+e],a=0;if("number"==typeof n&&(o=n,n=null),n||o)for(a=0;a=0;a--)r[a].id&&r[a].id!==n&&"load"!==e||(setTimeout(function(e){e.call(this,n,o)}.bind(t,r[a].fn),0),r[a].once&&t.off(e,r[a].fn,r[a].id));return t._loadQueue(e),t},_loadQueue:function(e){var n=this;if(n._queue.length>0){var o=n._queue[0];o.event===e&&(n._queue.shift(),n._loadQueue()),e||o.action()}return n},_ended:function(e){var o=this,t=e._sprite;if(!o._webAudio&&e._node&&!e._node.paused&&!e._node.ended&&e._node.currentTime=0;t--){if(o<=n)return;e._sounds[t]._ended&&(e._webAudio&&e._sounds[t]._node&&e._sounds[t]._node.disconnect(0),e._sounds.splice(t,1),o--)}}},_getSoundIds:function(e){var n=this;if(void 0===e){for(var o=[],t=0;t=0;if(n._scratchBuffer&&e.bufferSource&&(e.bufferSource.onended=null,e.bufferSource.disconnect(0),t))try{e.bufferSource.buffer=n._scratchBuffer}catch(e){}return e.bufferSource=null,o},_clearSound:function(e){/MSIE |Trident\//.test(n._navigator&&n._navigator.userAgent)||(e.src="data:audio/wav;base64,UklGRigAAABXQVZFZm10IBIAAAABAAEARKwAAIhYAQACABAAAABkYXRhAgAAAAEA")}};var t=function(e){this._parent=e,this.init()};t.prototype={init:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,o._sounds.push(e),e.create(),e},create:function(){var e=this,o=e._parent,t=n._muted||e._muted||e._parent._muted?0:e._volume;return o._webAudio?(e._node=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),e._node.gain.setValueAtTime(t,n.ctx.currentTime),e._node.paused=!0,e._node.connect(n.masterGain)):n.noAudio||(e._node=n._obtainHtml5Audio(),e._errorFn=e._errorListener.bind(e),e._node.addEventListener("error",e._errorFn,!1),e._loadFn=e._loadListener.bind(e),e._node.addEventListener(n._canPlayEvent,e._loadFn,!1),e._node.src=o._src,e._node.preload="auto",e._node.volume=t*n.volume(),e._node.load()),e},reset:function(){var e=this,o=e._parent;return e._muted=o._muted,e._loop=o._loop,e._volume=o._volume,e._rate=o._rate,e._seek=0,e._rateSeek=0,e._paused=!0,e._ended=!0,e._sprite="__default",e._id=++n._counter,e},_errorListener:function(){var e=this;e._parent._emit("loaderror",e._id,e._node.error?e._node.error.code:0),e._node.removeEventListener("error",e._errorFn,!1)},_loadListener:function(){var e=this,o=e._parent;o._duration=Math.ceil(10*e._node.duration)/10,0===Object.keys(o._sprite).length&&(o._sprite={__default:[0,1e3*o._duration]}),"loaded"!==o._state&&(o._state="loaded",o._emit("load"),o._loadQueue()),e._node.removeEventListener(n._canPlayEvent,e._loadFn,!1)}};var r={},a=function(e){var n=e._src;if(r[n])return e._duration=r[n].duration,void d(e);if(/^data:[^;]+;base64,/.test(n)){for(var o=atob(n.split(",")[1]),t=new Uint8Array(o.length),a=0;a0?(r[o._src]=e,d(o,e)):t()};"undefined"!=typeof Promise&&1===n.ctx.decodeAudioData.length?n.ctx.decodeAudioData(e).then(a).catch(t):n.ctx.decodeAudioData(e,a,t)},d=function(e,n){n&&!e._duration&&(e._duration=n.duration),0===Object.keys(e._sprite).length&&(e._sprite={__default:[0,1e3*e._duration]}),"loaded"!==e._state&&(e._state="loaded",e._emit("load"),e._loadQueue())},_=function(){if(n.usingWebAudio){try{"undefined"!=typeof AudioContext?n.ctx=new AudioContext:"undefined"!=typeof webkitAudioContext?n.ctx=new webkitAudioContext:n.usingWebAudio=!1}catch(e){n.usingWebAudio=!1}n.ctx||(n.usingWebAudio=!1);var e=/iP(hone|od|ad)/.test(n._navigator&&n._navigator.platform),o=n._navigator&&n._navigator.appVersion.match(/OS (\d+)_(\d+)_?(\d+)?/),t=o?parseInt(o[1],10):null;if(e&&t&&t<9){var r=/safari/.test(n._navigator&&n._navigator.userAgent.toLowerCase());(n._navigator&&n._navigator.standalone&&!r||n._navigator&&!n._navigator.standalone&&!r)&&(n.usingWebAudio=!1)}n.usingWebAudio&&(n.masterGain=void 0===n.ctx.createGain?n.ctx.createGainNode():n.ctx.createGain(),n.masterGain.gain.setValueAtTime(n._muted?0:n._volume,n.ctx.currentTime),n.masterGain.connect(n.ctx.destination)),n._setup()}};"function"==typeof define&&define.amd&&define([],function(){return{Howler:n,Howl:o}}),"undefined"!=typeof exports&&(exports.Howler=n,exports.Howl=o),"undefined"!=typeof window?(window.HowlerGlobal=e,window.Howler=n,window.Howl=o,window.Sound=t):"undefined"!=typeof global&&(global.HowlerGlobal=e,global.Howler=n,global.Howl=o,global.Sound=t)}();
3 | /*! Spatial Plugin */
4 | !function(){"use strict";HowlerGlobal.prototype._pos=[0,0,0],HowlerGlobal.prototype._orientation=[0,0,-1,0,1,0],HowlerGlobal.prototype.stereo=function(e){var n=this;if(!n.ctx||!n.ctx.listener)return n;for(var t=n._howls.length-1;t>=0;t--)n._howls[t].stereo(e);return n},HowlerGlobal.prototype.pos=function(e,n,t){var r=this;return r.ctx&&r.ctx.listener?(n="number"!=typeof n?r._pos[1]:n,t="number"!=typeof t?r._pos[2]:t,"number"!=typeof e?r._pos:(r._pos=[e,n,t],void 0!==r.ctx.listener.positionX?(r.ctx.listener.positionX.setTargetAtTime(r._pos[0],Howler.ctx.currentTime,.1),r.ctx.listener.positionY.setTargetAtTime(r._pos[1],Howler.ctx.currentTime,.1),r.ctx.listener.positionZ.setTargetAtTime(r._pos[2],Howler.ctx.currentTime,.1)):r.ctx.listener.setPosition(r._pos[0],r._pos[1],r._pos[2]),r)):r},HowlerGlobal.prototype.orientation=function(e,n,t,r,o,i){var a=this;if(!a.ctx||!a.ctx.listener)return a;var s=a._orientation;return n="number"!=typeof n?s[1]:n,t="number"!=typeof t?s[2]:t,r="number"!=typeof r?s[3]:r,o="number"!=typeof o?s[4]:o,i="number"!=typeof i?s[5]:i,"number"!=typeof e?s:(a._orientation=[e,n,t,r,o,i],void 0!==a.ctx.listener.forwardX?(a.ctx.listener.forwardX.setTargetAtTime(e,Howler.ctx.currentTime,.1),a.ctx.listener.forwardY.setTargetAtTime(n,Howler.ctx.currentTime,.1),a.ctx.listener.forwardZ.setTargetAtTime(t,Howler.ctx.currentTime,.1),a.ctx.listener.upX.setTargetAtTime(r,Howler.ctx.currentTime,.1),a.ctx.listener.upY.setTargetAtTime(o,Howler.ctx.currentTime,.1),a.ctx.listener.upZ.setTargetAtTime(i,Howler.ctx.currentTime,.1)):a.ctx.listener.setOrientation(e,n,t,r,o,i),a)},Howl.prototype.init=function(e){return function(n){var t=this;return t._orientation=n.orientation||[1,0,0],t._stereo=n.stereo||null,t._pos=n.pos||null,t._pannerAttr={coneInnerAngle:void 0!==n.coneInnerAngle?n.coneInnerAngle:360,coneOuterAngle:void 0!==n.coneOuterAngle?n.coneOuterAngle:360,coneOuterGain:void 0!==n.coneOuterGain?n.coneOuterGain:0,distanceModel:void 0!==n.distanceModel?n.distanceModel:"inverse",maxDistance:void 0!==n.maxDistance?n.maxDistance:1e4,panningModel:void 0!==n.panningModel?n.panningModel:"HRTF",refDistance:void 0!==n.refDistance?n.refDistance:1,rolloffFactor:void 0!==n.rolloffFactor?n.rolloffFactor:1},t._onstereo=n.onstereo?[{fn:n.onstereo}]:[],t._onpos=n.onpos?[{fn:n.onpos}]:[],t._onorientation=n.onorientation?[{fn:n.onorientation}]:[],e.call(this,n)}}(Howl.prototype.init),Howl.prototype.stereo=function(n,t){var r=this;if(!r._webAudio)return r;if("loaded"!==r._state)return r._queue.push({event:"stereo",action:function(){r.stereo(n,t)}}),r;var o=void 0===Howler.ctx.createStereoPanner?"spatial":"stereo";if(void 0===t){if("number"!=typeof n)return r._stereo;r._stereo=n,r._pos=[n,0,0]}for(var i=r._getSoundIds(t),a=0;a=0&&this._callbackFunctions.splice(t,1)}},e.prototype.clearAnimationCallback=function(){this._callbackFunctions=[]},e.prototype.callAnimationCallback=function(e){this._callbackFunctions.length>0&&this._callbackFunctions.forEach(function(t){t(e)})},e.prototype.evaluate=function(e,t,i,r,s,a){if(void 0===a&&(a=null),!(t<=.01)){if(this.loop)for(;e>this.duration;)e-=this.duration;if(this.parameterTracks.forEach(function(a){var n=r.parameters.ids.indexOf(a.targetId);if(n>=0){var o=a.evaluate(e);!0!==s[0][n]&&(r.parameters.values[n]=r.parameters.defaultValues[n],s[0][n]=!0),r.parameters.values[n]=i(r.parameters.values[n],o,a.evaluate(0),t)}}),this.partOpacityTracks.forEach(function(a){var n=r.parts.ids.indexOf(a.targetId);if(n>=0){var o=a.evaluate(e);!0!==s[1][n]&&(r.parts.opacities[n]=1,s[1][n]=!0),r.parts.opacities[n]=i(r.parts.opacities[n],o,a.evaluate(0),t)}}),this.modelTracks.forEach(function(n){if(null!=a){var o=a.getGroupById(n.targetId);if(null!=o&&"Parameter"===o.target)for(var l=0,u=o.ids;l=0){var d=n.evaluate(e);!0!==s[0][c]&&(r.parameters.values[c]=r.parameters.defaultValues[c],s[0][c]=!0),r.parameters.values[c]=i(r.parameters.values[c],d,n.evaluate(0),t)}}}}),null!=this._callbackFunctions)for(var n=0,o=this.userDataBodys;ni){if(e>i&&e0&&ei&&e0?(this._goalAnimation=e,this._goalTime=0,this._fadeTime=0,this._fadeDuration=t):(this._animation=e,this.currentTime=0,this._play=!0)},e.prototype.resume=function(){this._play=!0},e.prototype.pause=function(){this._play=!1},e.prototype.stop=function(){this._play=!1,this.currentTime=0},e.prototype._update=function(e){this._play&&(this._time+=e,this._goalTime+=e,this._fadeTime+=e,(null==this._animation||!this._animation.loop&&this._time>this._animation.duration)&&(this.stop(),this._animation=null))},e.prototype._evaluate=function(e,t){if(null!=this._animation){var i=this.weight<1?this.weight:1,r=null!=this._goalAnimation?i*this.weightCrossfade(this._fadeTime,this._fadeDuration):i;this._animation.evaluate(this._time,r,this.blend,e,t,this.groups),null!=this._goalAnimation&&(r=1-i*this.weightCrossfade(this._fadeTime,this._fadeDuration),this._goalAnimation.evaluate(this._goalTime,r,this.blend,e,t,this.groups),this._fadeTime>this._fadeDuration&&(this._animation=this._goalAnimation,this._time=this._goalTime,this._goalAnimation=null))}},e}();e.AnimationLayer=h;var c=function(){function e(e,t,i){this._target=e,this.timeScale=t,this._layers=i}return Object.defineProperty(e.prototype,"target",{get:function(){return this._target},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"isPlaying",{get:function(){var e=!1;return this._layers.forEach(function(t){t.isPlaying&&(e=!0)}),e},enumerable:!0,configurable:!0}),e.prototype.addLayer=function(e,t,i){void 0===t&&(t=u.OVERRIDE),void 0===i&&(i=1);var r=new h;r.blend=t,r.weightCrossfade=o.LINEAR,r.weight=i,r.groups=this.groups,this._layers.set(e,r)},e.prototype.getLayer=function(e){return this._layers.has(e)?this._layers.get(e):null},e.prototype.removeLayer=function(e){return this._layers.has(e)?this._layers.delete(e):null},e.prototype.clearLayers=function(){this._layers.clear()},e.prototype.updateAndEvaluate=function(e){var t=this;(e*=this.timeScale>0?this.timeScale:0)>.001&&this._layers.forEach(function(t){t._update(e)});var i=new Array(this._target.parameters.count).fill(!1),r=new Array(this._target.parts.count).fill(!1),s=new Array(i,r);this._layers.forEach(function(e){e._evaluate(t._target,s)})},e._create=function(t,i,r){var s=new e(t,i,r);return s.isValid?s:null},Object.defineProperty(e.prototype,"isValid",{get:function(){return null!=this._target},enumerable:!0,configurable:!0}),e}();e.Animator=c;var d=function(){function e(){this._timeScale=1,this._layerNames=[],this._layerBlenders=[],this._layerCrossfadeWeighters=[],this._layerWeights=[]}return e.prototype.setTarget=function(e){return this._target=e,this},e.prototype.setTimeScale=function(e){return this._timeScale=e,this},e.prototype.addLayer=function(e,t,i){return void 0===t&&(t=u.OVERRIDE),void 0===i&&(i=1),this._layerNames.push(e),this._layerBlenders.push(t),this._layerCrossfadeWeighters.push(o.LINEAR),this._layerWeights.push(i),this},e.prototype.build=function(){for(var e=new Map,t=0;ti?i:e},e.directionToDegrees=function(t,i){var r=e.directionToRadians(t,i),s=e.radiansToDegrees(r);return i.x-t.x>0?-s:s},e.radiansToDegrees=function(e){return 180*e/Math.PI},e.radiansToDirection=function(e){return new p(Math.sin(e),Math.cos(e))},e.degreesToRadians=function(e){return e/180*Math.PI},e.directionToRadians=function(e,t){var i=p.dot(e,t),r=e.length*t.length;if(0===r)return 0;var s=i/r;return Math.abs(s)<=1?Math.acos(s):0},e.gravity=new p(0,-1),e.wind=new p(0,0),e.maximumWeight=100,e.airResistance=5,e.movementThreshold=.001,e.correctAngles=!0,e}();e.Physics=f;var m=function(){return function(e,t,i,r,s){this.initialPosition=e,this.mobility=t,this.delay=i,this.acceleration=r,this.radius=s,this.position=e,this.lastPosition=this.position,this.lastGravity=new p(0,-1),this.force=new p(0,0),this.velocity=new p(0,0)}}();e.PhysicsParticle=m;var y=function(){function e(e,t,i){this.x=e,this.y=t,this.angle=i}return e.prototype.add=function(t){return new e(this.x+t.x,this.y+t.y,this.angle+t.angle)},e}();e.PhysicsFactorTuple=y;var g=function(){return function(e,t,i){this.minimum=e,this.maximum=t,this.def=i}}();e.PhysicsNormalizationTuple=g;var _=function(){return function(e,t){this.position=e,this.angle=t}}();e.PhysicsNormalizationOptions=_;var v=function(){function e(e,t,i,r){this.targetId=e,this.weight=t,this.factor=i,this.invert=r}return Object.defineProperty(e.prototype,"normalizedWeight",{get:function(){return f.clampScalar(this.weight/f.maximumWeight,0,1)},enumerable:!0,configurable:!0}),e.prototype.evaluateFactor=function(e,t,i,r,s){console.assert(i>t);var a=this.getMiddleValue(t,i),n=e-a;switch(Math.sign(n)){case 1:{const e=i-a;if(0===e)n=s.angle.def;else{const t=s.angle.maximum-s.angle.def;0===t?n=s.angle.maximum:(n*=Math.abs(t/e),n+=s.angle.def)}}break;case-1:{const e=a-t;if(0===e)n=s.angle.def;else{const t=s.angle.def-s.angle.minimum;0===t?n=s.angle.minimum:(n*=Math.abs(t/e),n+=s.angle.def)}}break;case 0:n=s.angle.def}var o=this.weight/f.maximumWeight;return n*=this.invert?1:-1,new y(n*this.factor.x*o,n*this.factor.y*o,n*this.factor.angle*o)},e.prototype.getRangeValue=function(e,t){var i=Math.max(e,t),r=Math.min(e,t);return Math.abs(i-r)},e.prototype.getMiddleValue=function(e,t){return Math.min(e,t)+this.getRangeValue(e,t)/2},e}();e.PhysicsInput=v;var b=function(){function e(e,t,i,r,s,a){this.targetId=e,this.particleIndex=t,this.weight=i,this.factor=s,this.invert=a,this.factor.angle*=r}return Object.defineProperty(e.prototype,"normalizedWeight",{get:function(){return f.clampScalar(this.weight/f.maximumWeight,0,1)},enumerable:!0,configurable:!0}),e.prototype.evaluateValue=function(e,t){var i=e.x*this.factor.x+e.y*this.factor.y;if(this.factor.angle>0){var r=f.gravity;f.correctAngles&&this.particleIndex>1&&(r=t[this.particleIndex-2].position.substract(t[this.particleIndex-1].position));var s=f.directionToRadians(r,e);i+=(e.x-r.x>0?-s:s)*this.factor.angle}return i*=this.invert?-1:1},e}();e.PhysicsOutput=b;var w=function(){function e(e,t,i,r){this.input=e,this.output=t,this.particles=i,this.normalization=r}return e.prototype._update=function(e,t){var i=this,r=t.parameters,s=new y(0,0,0);this.input.forEach(function(e){var t=r.ids.indexOf(e.targetId);-1!==t&&(s=s.add(e.evaluateFactor(r.values[t],r.minimumValues[t],r.maximumValues[t],r.defaultValues[t],i.normalization)))});var a=f.degreesToRadians(-s.angle),n=new p(s.x,s.y).rotateByRadians(a);s.x=n.x,s.y=n.y;var o=a,l=f.radiansToDirection(o).normalize();this.particles.forEach(function(t,r){if(0!==r){t.force=l.multiplyByScalar(t.acceleration).add(f.wind),t.lastPosition=t.position;var a=t.delay*e*30,n=t.position.substract(i.particles[r-1].position),o=p.distance(p.zero,n),u=f.directionToDegrees(t.lastGravity,l),h=f.degreesToRadians(u)/f.airResistance;n=n.rotateByRadians(h).normalize(),t.position=i.particles[r-1].position.add(n.multiplyByScalar(o));var c=t.velocity.multiplyByScalar(a),d=t.force.multiplyByScalar(a).multiplyByScalar(a);t.position=t.position.add(c).add(d);var m=t.position.substract(i.particles[r-1].position).normalize();t.position=i.particles[r-1].position.add(m.multiplyByScalar(t.radius)),Math.abs(t.position.x)=t.particles.length)){var r=i.ids.indexOf(e.targetId);if(-1!==r){var s=t.particles[e.particleIndex-1].position.substract(t.particles[e.particleIndex].position),a=f.clampScalar(e.evaluateValue(s,t.particles),i.minimumValues[r],i.maximumValues[r]),n=i.values[r]*(1-e.normalizedWeight)+a*e.normalizedWeight;i.values[r]=f.clampScalar(n,i.minimumValues[r],i.maximumValues[r])}}})},e}();e.PhysicsSubRig=w;var P=function(){function e(e,t,i){var r=this;this.timeScale=1,this.timeScale=t,this._target=e,e&&(this._subRigs=[],i.PhysicsSettings.forEach(function(e){var t=[];e.Input.forEach(function(e){var i=new y(1,0,0);"Y"===e.Type?(i.x=0,i.y=1):"Angle"===e.Type&&(i.x=0,i.angle=1),t.push(new v(e.Source.Id,e.Weight,i,e.Reflect))});var i=[];e.Output.forEach(function(e){var t=new y(1,0,0);"Y"===e.Type?(t.x=0,t.y=1):"Angle"===e.Type&&(t.x=0,t.angle=1),i.push(new b(e.Destination.Id,e.VertexIndex,e.Weight,e.Scale,t,e.Reflect))});var s=[];e.Vertices.forEach(function(e){var t=new p(e.Position.X,e.Position.Y);s.push(new m(t,e.Mobility,e.Delay,e.Acceleration,e.Radius))});var a=e.Normalization,n=new g(a.Position.Minimum,a.Position.Maximum,a.Position.Default),o=new g(a.Angle.Minimum,a.Angle.Maximum,a.Angle.Default),l=new _(n,o);r._subRigs.push(new w(t,i,s,l))}))}return e.prototype.updateAndEvaluate=function(e){var t=this;(e*=this.timeScale>0?this.timeScale:0)>.01&&this._subRigs.forEach(function(i){i._update(e,t._target)}),this._subRigs.forEach(function(e){e._evaluate(t._target)})},e._fromPhysics3Json=function(t,i,r){var s=new e(t,i,r);return s._isValid?s:null},Object.defineProperty(e.prototype,"_isValid",{get:function(){return null!=this._target},enumerable:!0,configurable:!0}),e}();e.PhysicsRig=P;var M=function(){function e(){this._timeScale=1}return e.prototype.setTarget=function(e){return this._target=e,this},e.prototype.setTimeScale=function(e){return this._timeScale=e,this},e.prototype.setPhysics3Json=function(e){return this._physics3Json=e,this},e.prototype.build=function(){return P._fromPhysics3Json(this._target,this._timeScale,this._physics3Json)},e}();e.PhysicsRigBuilder=M;var x=function(){function e(e,t){var i=this;this._target=e,e&&(this._version=t.Version,this._userDataCount=t.Meta.UserDataCount,this._totalUserDataSize=t.Meta.TotalUserDataSize,null!=t.UserData&&(this._userDataBodys=[],t.UserData.forEach(function(e){i._userDataBodys.push(new B(e.Target,e.Id,e.Value))}),console.assert(this._userDataBodys.length===this._userDataCount)))}return e._fromUserData3Json=function(t,i){var r=new e(t,i);return r._isValid?r:null},Object.defineProperty(e.prototype,"_isValid",{get:function(){return null!=this._target},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"userDataCount",{get:function(){return null==this._userDataBodys?0:this._userDataCount},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"totalUserDataSize",{get:function(){return null==this._userDataBodys?0:this._totalUserDataSize},enumerable:!0,configurable:!0}),Object.defineProperty(e.prototype,"userDataBodys",{get:function(){return null==this._userDataBodys?null:this._userDataBodys},enumerable:!0,configurable:!0}),e.prototype.isExistUserDataById=function(e){if(null==this._userDataBodys)return!1;for(var t=0,i=this._userDataBodys;t0){var p=new PIXI.Filter;p.blendMode=PIXI.BLEND_MODES.ADD,u._meshes[h].filters=[p]}else u._meshes[h].blendMode=PIXI.BLEND_MODES.ADD;else if(Live2DCubismCore.Utils.hasBlendMultiplicativeBit(u._coreModel.drawables.constantFlags[h]))if(u._coreModel.drawables.maskCounts[h]>0){var f=new PIXI.Filter;f.blendMode=PIXI.BLEND_MODES.MULTIPLY,u._meshes[h].filters=[f]}else u._meshes[h].blendMode=PIXI.BLEND_MODES.MULTIPLY;u.addChild(u._meshes[h])}return u._maskSpriteContainer=new s(t,u),u}return r(t,e),Object.defineProperty(t.prototype,"parameters",{get:function(){return this._coreModel.parameters},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"parts",{get:function(){return this._coreModel.parts},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"drawables",{get:function(){return this._coreModel.drawables},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"canvasinfo",{get:function(){return this._coreModel.canvasinfo},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"textures",{get:function(){return this._textures},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"animator",{get:function(){return this._animator},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"userData",{get:function(){return this._userData},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"meshes",{get:function(){return this._meshes},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"masks",{get:function(){return this._maskSpriteContainer},enumerable:!0,configurable:!0}),Object.defineProperty(t.prototype,"groups",{get:function(){return this._groups},enumerable:!0,configurable:!0}),t.prototype.update=function(e){var t=this,i=.016*e;this._animator.updateAndEvaluate(i),this._physicsRig&&this._physicsRig.updateAndEvaluate(i),this._coreModel.update();for(var r=!1,s=0;s0){for(var l=new PIXI.Container,u=0;u{const h=u[t+"_model"].data;if(void 0!==h.FileReferences.Moc&&a.add(t+"_moc",s+h.FileReferences.Moc,{xhrType:PIXI.loaders.Resource.XHR_RESPONSE_TYPE.BUFFER}),void 0!==h.FileReferences.Textures&&h.FileReferences.Textures.forEach(e=>{a.add(t+"_texture"+o,s+e),o++}),void 0!==h.FileReferences.Physics&&a.add(t+"_physics",s+h.FileReferences.Physics,{xhrType:PIXI.loaders.Resource.XHR_RESPONSE_TYPE.JSON}),void 0!==h.FileReferences.Motions)for(const e in h.FileReferences.Motions)h.FileReferences.Motions[e].forEach(e=>{const i=e.File.split("/").pop().split(".").shift();if(l.includes(t+"_"+i)){var r=t+"_"+i+String(Date.now());a.add(r,s+e.File,{xhrType:PIXI.loaders.Resource.XHR_RESPONSE_TYPE.JSON}),l.push(t+"_"+i)}else a.add(t+"_"+i,s+e.File,{xhrType:PIXI.loaders.Resource.XHR_RESPONSE_TYPE.JSON}),l.push(t+"_"+i)});let c=null;void 0!==h.Groups&&(c=e.Groups.fromModel3Json(h)),a.load((s,a)=>{let u=null;if(void 0!==a[t+"_moc"]&&(u=Live2DCubismCore.Moc.fromArrayBuffer(a[t+"_moc"].data)),void 0!==a[t+"_texture0"])for(let e=0;e{const r=i.split(t+"_").pop();h.set(r,e.Animation.fromMotion3Json(a[i].data))});let d=null;const p=Live2DCubismCore.Model.fromMoc(u);if(null==p)return;const f=this.animatorBuilder.setTarget(p).setTimeScale(this.timeScale).build(),m=this.physicsRigBuilder.setTarget(p).setTimeScale(this.timeScale).build();(d=i.Model._create(p,n,f,m,null,c)).motions=h,this.models[t]=d,r.changeCanvas(d)})})}}}class a{constructor({basePath:e,modelName:t,width:i=500,height:r=300,el:a,sizeLimit:n,mobileLimit:o,sounds:l}){if("undefined"!=typeof Live2DCubismCore)if("undefined"!=typeof PIXI)if(a){if(!this.isDom(a)){if(!(a.length>0))return void console.error("live2dv3 failed to load:\n",a,"is not a HTMLElement object");if(!this.isDom(a[0]))return void console.error("live2dv3 failed to load:\n",a[0],"is not a HTMLElement object");a=a[0]}n&&(document.documentElement.clientWidth{this.model&&(this.model.update(e),this.model.masks.update(this.app.renderer))}),window.onresize=(e=>{void 0===e&&(e=null),this.app.view.style.width=i+"px",this.app.view.style.height=r+"px",this.app.renderer.resize(i,r),this.model&&(this.model.position=new PIXI.Point(.5*i,.5*r),this.model.scale=new PIXI.Point(.06*this.model.position.x,.06*this.model.position.x),this.model.masks.resize(this.app.view.width,this.app.view.height))}),this.isClick=!1,this.app.view.addEventListener("mousedown",e=>{this.isClick=!0}),this.app.view.addEventListener("mousemove",e=>{if(this.isClick&&(this.isClick=!1,this.model&&(this.model.inDrag=!0)),this.model){const t=this.model.position.x-e.offsetX,i=this.model.position.y-e.offsetY;this.model.pointerX=-t/this.app.view.height,this.model.pointerY=-i/this.app.view.width}}),this.app.view.addEventListener("mouseup",i=>{if(this.model){if(this.isClick){if(this.isHit("TouchHead",i.offsetX,i.offsetY))this.startAnimation("touch_head","base");else if(this.isHit("TouchSpecial",i.offsetX,i.offsetY))this.startAnimation("touch_special","base");else{const e=["touch_body","main_1","main_2","main_3"],t=e[Math.floor(Math.random()*e.length)];this.startAnimation(t,"base")}if(l&&l.length>0){const i=l[Math.floor(Math.random()*l.length)],r=/^https?:\/\//.test(i)?i:[e,t,i].join("/").replace(/(?" tag.\nLook at https://github.com/HCLonely/Live2dV3');else console.error('live2dv3 failed to load:\nMissing live2dcubismcore.js\nPlease add "https://cdn.jsdelivr.net/gh/HCLonely/Live2dV3/js/live2dcubismcore.min.js" to the "