├── .editorconfig ├── .erb ├── configs │ ├── .eslintrc │ ├── webpack.config.base.ts │ ├── webpack.config.eslint.ts │ ├── webpack.config.main.prod.ts │ ├── webpack.config.preload.dev.ts │ ├── webpack.config.renderer.dev.dll.ts │ ├── webpack.config.renderer.dev.ts │ ├── webpack.config.renderer.prod.ts │ └── webpack.paths.ts ├── img │ ├── erb-banner.svg │ ├── erb-logo.png │ └── palette-sponsor-banner.svg ├── mocks │ └── fileMock.js └── scripts │ ├── .eslintrc │ ├── check-build-exists.ts │ ├── check-native-dep.js │ ├── check-node-env.js │ ├── check-port-in-use.js │ ├── clean.js │ ├── delete-source-maps.js │ ├── electron-rebuild.js │ ├── link-modules.ts │ └── notarize.js ├── .eslintignore ├── .eslintrc.js ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── 1-Bug_report.md │ ├── 2-Question.md │ └── 3-Feature_request.md ├── config.yml ├── stale.yml └── workflows │ ├── codeql-analysis.yml │ ├── publish.yml │ └── test.yml ├── .gitignore ├── .npmrc ├── .vscode ├── extensions.json ├── launch.json └── settings.json ├── .yarnrc ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README-dev.md ├── README.md ├── assets ├── assets.d.ts ├── entitlements.mac.plist ├── icon.icns ├── icon.ico ├── icon.png ├── icon.svg └── icons │ ├── 1024x1024.png │ ├── 128x128.png │ ├── 16x16.png │ ├── 24x24.png │ ├── 256x256.png │ ├── 32x32.png │ ├── 48x48.png │ ├── 512x512.png │ ├── 64x64.png │ └── 96x96.png ├── package.json ├── pnpm-lock.yaml ├── release └── app │ ├── package-lock.json │ ├── package.json │ └── yarn.lock ├── src ├── __tests__ │ └── App.test.tsx ├── main │ ├── main.ts │ ├── menu.ts │ ├── preload.ts │ ├── systemIO.ts │ └── util.ts └── renderer │ ├── App.css │ ├── App.tsx │ ├── components │ ├── PlayGround.css │ ├── PlayGround.js │ ├── SettingPage.css │ ├── SettingPage.js │ ├── SourceGround.css │ ├── SourceGround.js │ └── tabmenu │ │ ├── BcgTab.js │ │ ├── BgmTab.js │ │ ├── CoverTab.js │ │ ├── HelpTab.js │ │ ├── SETab.js │ │ ├── SoundTab.js │ │ ├── SprTab.css │ │ ├── SprTab.js │ │ └── sametype │ │ ├── ImageTab.js │ │ └── VoiceTab.js │ ├── config │ ├── globalContext.js │ └── version.js │ ├── datamap │ ├── index.js │ └── rawjson │ │ ├── sound.json │ │ └── students.json │ ├── hooks │ └── useLocal.js │ ├── index.ejs │ ├── index.tsx │ ├── media │ ├── blockly │ │ └── sprites.png │ ├── document │ │ ├── cover.png │ │ └── easystart.png │ └── sampleproject │ │ └── demo_2.2.2.bablockly │ ├── models │ ├── README.md │ ├── charcmd.ts │ ├── imgcmd.ts │ ├── loadcmd.ts │ ├── scenecmd.ts │ ├── selectcmd.ts │ ├── soundcmd.ts │ ├── specialcmd.ts │ └── textcmd.ts │ ├── myblocks │ ├── 01load │ │ ├── Menu01.jsx │ │ ├── b_load_pic.js │ │ ├── b_load_sound.js │ │ ├── b_load_student.js │ │ ├── b_load_studentselect.js │ │ └── index.jsx │ ├── 02pic │ │ ├── Menu02.jsx │ │ ├── b_pic_alpha.js │ │ ├── b_pic_display.js │ │ ├── b_pic_move.js │ │ ├── b_pic_movexy.js │ │ ├── b_pic_scale.js │ │ ├── b_pic_shake.js │ │ ├── b_pic_shakexy.js │ │ └── index.jsx │ ├── 03char │ │ ├── Menu03.jsx │ │ ├── b_char_action.js │ │ ├── b_char_display.js │ │ ├── b_char_highlight.js │ │ ├── b_char_move.js │ │ ├── b_char_movexy.js │ │ ├── b_char_scale.js │ │ ├── b_char_shake.js │ │ ├── b_char_shakexy.js │ │ ├── b_char_status.js │ │ └── index.jsx │ ├── 04sound │ │ ├── Menu04.jsx │ │ ├── b_sound_loop.js │ │ ├── b_sound_play.js │ │ ├── b_sound_volume.js │ │ └── index.jsx │ ├── 05screen │ │ ├── Menu05.jsx │ │ ├── b_screen_effect.js │ │ └── index.jsx │ ├── 06button │ │ ├── Menu06.jsx │ │ ├── b_one_button.js │ │ ├── b_three_button.js │ │ ├── b_two_button.js │ │ └── index.jsx │ ├── 07special │ │ ├── Menu07.jsx │ │ ├── b_special_autotime.js │ │ ├── b_special_breakpoint.js │ │ ├── b_special_command.js │ │ ├── b_special_jump.js │ │ ├── b_special_switch.js │ │ ├── b_special_target.js │ │ ├── b_special_targets.js │ │ ├── b_special_wait.js │ │ └── index.jsx │ ├── 08text │ │ ├── Menu08.jsx │ │ ├── b_text_autotime.js │ │ ├── b_text_banner.js │ │ ├── b_text_hide.js │ │ ├── b_text_highlight.js │ │ ├── b_text_label.js │ │ ├── b_text_side.js │ │ ├── b_text_txt.js │ │ └── index.jsx │ ├── 100define │ │ ├── Menu100.jsx │ │ ├── b_case.jsx │ │ ├── b_case_jump.jsx │ │ ├── b_stage.jsx │ │ ├── b_user_write.jsx │ │ └── index.jsx │ ├── Toolbox.js │ ├── index.js │ └── temp.js │ ├── preload.d.ts │ └── utils │ ├── DataTool.jsx │ ├── IOdata.jsx │ ├── codetool.jsx │ ├── dialog.jsx │ ├── hashtool.jsx │ ├── imagetool.jsx │ ├── spine-player.css │ ├── spine-player.js │ ├── stateparse.jsx │ └── timestamp.jsx ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false 13 | -------------------------------------------------------------------------------- /.erb/configs/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": "off", 4 | "global-require": "off", 5 | "import/no-dynamic-require": "off" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.base.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Base webpack config used across other specific configs 3 | */ 4 | 5 | import webpack from 'webpack'; 6 | import TsconfigPathsPlugins from 'tsconfig-paths-webpack-plugin'; 7 | import webpackPaths from './webpack.paths'; 8 | import { dependencies as externals } from '../../release/app/package.json'; 9 | 10 | const configuration: webpack.Configuration = { 11 | externals: [...Object.keys(externals || {})], 12 | 13 | stats: 'errors-only', 14 | 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.[jt]sx?$/, 19 | exclude: /node_modules/, 20 | use: { 21 | loader: 'ts-loader', 22 | options: { 23 | // Remove this line to enable type checking in webpack builds 24 | transpileOnly: true, 25 | compilerOptions: { 26 | module: 'esnext', 27 | }, 28 | }, 29 | }, 30 | }, 31 | ], 32 | }, 33 | 34 | output: { 35 | path: webpackPaths.srcPath, 36 | // https://github.com/webpack/webpack/issues/1114 37 | library: { 38 | type: 'commonjs2', 39 | }, 40 | }, 41 | 42 | /** 43 | * Determine the array of extensions that should be used to resolve modules. 44 | */ 45 | resolve: { 46 | extensions: ['.js', '.jsx', '.json', '.ts', '.tsx'], 47 | modules: [webpackPaths.srcPath, 'node_modules'], 48 | // There is no need to add aliases here, the paths in tsconfig get mirrored 49 | plugins: [new TsconfigPathsPlugins()], 50 | }, 51 | 52 | plugins: [ 53 | new webpack.EnvironmentPlugin({ 54 | NODE_ENV: 'production', 55 | }), 56 | ], 57 | }; 58 | 59 | export default configuration; 60 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.eslint.ts: -------------------------------------------------------------------------------- 1 | /* eslint import/no-unresolved: off, import/no-self-import: off */ 2 | 3 | module.exports = require('./webpack.config.renderer.dev').default; 4 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.main.prod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Webpack config for production electron main process 3 | */ 4 | 5 | import path from 'path'; 6 | import webpack from 'webpack'; 7 | import { merge } from 'webpack-merge'; 8 | import TerserPlugin from 'terser-webpack-plugin'; 9 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 10 | import baseConfig from './webpack.config.base'; 11 | import webpackPaths from './webpack.paths'; 12 | import checkNodeEnv from '../scripts/check-node-env'; 13 | import deleteSourceMaps from '../scripts/delete-source-maps'; 14 | 15 | checkNodeEnv('production'); 16 | deleteSourceMaps(); 17 | 18 | const configuration: webpack.Configuration = { 19 | devtool: 'source-map', 20 | 21 | mode: 'production', 22 | 23 | target: 'electron-main', 24 | 25 | entry: { 26 | main: path.join(webpackPaths.srcMainPath, 'main.ts'), 27 | preload: path.join(webpackPaths.srcMainPath, 'preload.ts'), 28 | }, 29 | 30 | output: { 31 | path: webpackPaths.distMainPath, 32 | filename: '[name].js', 33 | library: { 34 | type: 'umd', 35 | }, 36 | }, 37 | 38 | optimization: { 39 | minimizer: [ 40 | new TerserPlugin({ 41 | parallel: true, 42 | }), 43 | ], 44 | }, 45 | 46 | plugins: [ 47 | new BundleAnalyzerPlugin({ 48 | analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', 49 | analyzerPort: 8888, 50 | }), 51 | 52 | /** 53 | * Create global constants which can be configured at compile time. 54 | * 55 | * Useful for allowing different behaviour between development builds and 56 | * release builds 57 | * 58 | * NODE_ENV should be production so that modules do not perform certain 59 | * development checks 60 | */ 61 | new webpack.EnvironmentPlugin({ 62 | NODE_ENV: 'production', 63 | DEBUG_PROD: false, 64 | START_MINIMIZED: false, 65 | }), 66 | 67 | new webpack.DefinePlugin({ 68 | 'process.type': '"browser"', 69 | }), 70 | ], 71 | 72 | /** 73 | * Disables webpack processing of __dirname and __filename. 74 | * If you run the bundle in node.js it falls back to these values of node.js. 75 | * https://github.com/webpack/webpack/issues/2010 76 | */ 77 | node: { 78 | __dirname: false, 79 | __filename: false, 80 | }, 81 | }; 82 | 83 | export default merge(baseConfig, configuration); 84 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.preload.dev.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | import webpack from 'webpack'; 3 | import { merge } from 'webpack-merge'; 4 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 5 | import baseConfig from './webpack.config.base'; 6 | import webpackPaths from './webpack.paths'; 7 | import checkNodeEnv from '../scripts/check-node-env'; 8 | 9 | // When an ESLint server is running, we can't set the NODE_ENV so we'll check if it's 10 | // at the dev webpack config is not accidentally run in a production environment 11 | if (process.env.NODE_ENV === 'production') { 12 | checkNodeEnv('development'); 13 | } 14 | 15 | const configuration: webpack.Configuration = { 16 | devtool: 'inline-source-map', 17 | 18 | mode: 'development', 19 | 20 | target: 'electron-preload', 21 | 22 | entry: path.join(webpackPaths.srcMainPath, 'preload.ts'), 23 | 24 | output: { 25 | path: webpackPaths.dllPath, 26 | filename: 'preload.js', 27 | library: { 28 | type: 'umd', 29 | }, 30 | }, 31 | 32 | plugins: [ 33 | new BundleAnalyzerPlugin({ 34 | analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', 35 | }), 36 | 37 | /** 38 | * Create global constants which can be configured at compile time. 39 | * 40 | * Useful for allowing different behaviour between development builds and 41 | * release builds 42 | * 43 | * NODE_ENV should be production so that modules do not perform certain 44 | * development checks 45 | * 46 | * By default, use 'development' as NODE_ENV. This can be overriden with 47 | * 'staging', for example, by changing the ENV variables in the npm scripts 48 | */ 49 | new webpack.EnvironmentPlugin({ 50 | NODE_ENV: 'development', 51 | }), 52 | 53 | new webpack.LoaderOptionsPlugin({ 54 | debug: true, 55 | }), 56 | ], 57 | 58 | /** 59 | * Disables webpack processing of __dirname and __filename. 60 | * If you run the bundle in node.js it falls back to these values of node.js. 61 | * https://github.com/webpack/webpack/issues/2010 62 | */ 63 | node: { 64 | __dirname: false, 65 | __filename: false, 66 | }, 67 | 68 | watch: true, 69 | }; 70 | 71 | export default merge(baseConfig, configuration); 72 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.renderer.dev.dll.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Builds the DLL for development electron renderer process 3 | */ 4 | 5 | import webpack from 'webpack'; 6 | import path from 'path'; 7 | import { merge } from 'webpack-merge'; 8 | import baseConfig from './webpack.config.base'; 9 | import webpackPaths from './webpack.paths'; 10 | import { dependencies } from '../../package.json'; 11 | import checkNodeEnv from '../scripts/check-node-env'; 12 | 13 | checkNodeEnv('development'); 14 | 15 | const dist = webpackPaths.dllPath; 16 | 17 | const configuration: webpack.Configuration = { 18 | context: webpackPaths.rootPath, 19 | 20 | devtool: 'eval', 21 | 22 | mode: 'development', 23 | 24 | target: 'electron-renderer', 25 | 26 | externals: ['fsevents', 'crypto-browserify'], 27 | 28 | /** 29 | * Use `module` from `webpack.config.renderer.dev.js` 30 | */ 31 | module: require('./webpack.config.renderer.dev').default.module, 32 | 33 | entry: { 34 | renderer: Object.keys(dependencies || {}), 35 | }, 36 | 37 | output: { 38 | path: dist, 39 | filename: '[name].dev.dll.js', 40 | library: { 41 | name: 'renderer', 42 | type: 'var', 43 | }, 44 | }, 45 | 46 | plugins: [ 47 | new webpack.DllPlugin({ 48 | path: path.join(dist, '[name].json'), 49 | name: '[name]', 50 | }), 51 | 52 | /** 53 | * Create global constants which can be configured at compile time. 54 | * 55 | * Useful for allowing different behaviour between development builds and 56 | * release builds 57 | * 58 | * NODE_ENV should be production so that modules do not perform certain 59 | * development checks 60 | */ 61 | new webpack.EnvironmentPlugin({ 62 | NODE_ENV: 'development', 63 | }), 64 | 65 | new webpack.LoaderOptionsPlugin({ 66 | debug: true, 67 | options: { 68 | context: webpackPaths.srcPath, 69 | output: { 70 | path: webpackPaths.dllPath, 71 | }, 72 | }, 73 | }), 74 | ], 75 | }; 76 | 77 | export default merge(baseConfig, configuration); 78 | -------------------------------------------------------------------------------- /.erb/configs/webpack.config.renderer.prod.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Build config for electron renderer process 3 | */ 4 | 5 | import path from 'path'; 6 | import webpack from 'webpack'; 7 | import HtmlWebpackPlugin from 'html-webpack-plugin'; 8 | import MiniCssExtractPlugin from 'mini-css-extract-plugin'; 9 | import { BundleAnalyzerPlugin } from 'webpack-bundle-analyzer'; 10 | import CssMinimizerPlugin from 'css-minimizer-webpack-plugin'; 11 | import { merge } from 'webpack-merge'; 12 | import TerserPlugin from 'terser-webpack-plugin'; 13 | import baseConfig from './webpack.config.base'; 14 | import webpackPaths from './webpack.paths'; 15 | import checkNodeEnv from '../scripts/check-node-env'; 16 | import deleteSourceMaps from '../scripts/delete-source-maps'; 17 | 18 | checkNodeEnv('production'); 19 | deleteSourceMaps(); 20 | 21 | const configuration: webpack.Configuration = { 22 | devtool: 'source-map', 23 | 24 | mode: 'production', 25 | 26 | target: ['web', 'electron-renderer'], 27 | 28 | entry: [path.join(webpackPaths.srcRendererPath, 'index.tsx')], 29 | 30 | output: { 31 | path: webpackPaths.distRendererPath, 32 | publicPath: './', 33 | filename: 'renderer.js', 34 | library: { 35 | type: 'umd', 36 | }, 37 | }, 38 | 39 | module: { 40 | rules: [ 41 | { 42 | test: /\.s?(a|c)ss$/, 43 | use: [ 44 | MiniCssExtractPlugin.loader, 45 | { 46 | loader: 'css-loader', 47 | options: { 48 | modules: true, 49 | sourceMap: true, 50 | importLoaders: 1, 51 | }, 52 | }, 53 | 'sass-loader', 54 | ], 55 | include: /\.module\.s?(c|a)ss$/, 56 | }, 57 | { 58 | test: /\.s?(a|c)ss$/, 59 | use: [MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader'], 60 | exclude: /\.module\.s?(c|a)ss$/, 61 | }, 62 | // Fonts 63 | { 64 | test: /\.(woff|woff2|eot|ttf|otf)$/i, 65 | type: 'asset/resource', 66 | }, 67 | // Images 68 | { 69 | test: /\.(png|jpg|jpeg|gif)$/i, 70 | type: 'asset/resource', 71 | }, 72 | // SVG 73 | { 74 | test: /\.svg$/, 75 | use: [ 76 | { 77 | loader: '@svgr/webpack', 78 | options: { 79 | prettier: false, 80 | svgo: false, 81 | svgoConfig: { 82 | plugins: [{ removeViewBox: false }], 83 | }, 84 | titleProp: true, 85 | ref: true, 86 | }, 87 | }, 88 | 'file-loader', 89 | ], 90 | }, 91 | ], 92 | }, 93 | 94 | optimization: { 95 | minimize: true, 96 | minimizer: [ 97 | new TerserPlugin({ 98 | parallel: true, 99 | }), 100 | new CssMinimizerPlugin(), 101 | ], 102 | }, 103 | 104 | plugins: [ 105 | /** 106 | * Create global constants which can be configured at compile time. 107 | * 108 | * Useful for allowing different behaviour between development builds and 109 | * release builds 110 | * 111 | * NODE_ENV should be production so that modules do not perform certain 112 | * development checks 113 | */ 114 | new webpack.EnvironmentPlugin({ 115 | NODE_ENV: 'production', 116 | DEBUG_PROD: false, 117 | }), 118 | 119 | new MiniCssExtractPlugin({ 120 | filename: 'style.css', 121 | }), 122 | 123 | new BundleAnalyzerPlugin({ 124 | analyzerMode: process.env.ANALYZE === 'true' ? 'server' : 'disabled', 125 | analyzerPort: 8889, 126 | }), 127 | 128 | new HtmlWebpackPlugin({ 129 | filename: 'index.html', 130 | template: path.join(webpackPaths.srcRendererPath, 'index.ejs'), 131 | minify: { 132 | collapseWhitespace: true, 133 | removeAttributeQuotes: true, 134 | removeComments: true, 135 | }, 136 | isBrowser: false, 137 | isDevelopment: process.env.NODE_ENV !== 'production', 138 | }), 139 | 140 | new webpack.DefinePlugin({ 141 | 'process.type': '"renderer"', 142 | }), 143 | ], 144 | }; 145 | 146 | export default merge(baseConfig, configuration); 147 | -------------------------------------------------------------------------------- /.erb/configs/webpack.paths.ts: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | const rootPath = path.join(__dirname, '../..'); 4 | 5 | const dllPath = path.join(__dirname, '../dll'); 6 | 7 | const srcPath = path.join(rootPath, 'src'); 8 | const srcMainPath = path.join(srcPath, 'main'); 9 | const srcRendererPath = path.join(srcPath, 'renderer'); 10 | 11 | const releasePath = path.join(rootPath, 'release'); 12 | const appPath = path.join(releasePath, 'app'); 13 | const appPackagePath = path.join(appPath, 'package.json'); 14 | const appNodeModulesPath = path.join(appPath, 'node_modules'); 15 | const srcNodeModulesPath = path.join(srcPath, 'node_modules'); 16 | 17 | const distPath = path.join(appPath, 'dist'); 18 | const distMainPath = path.join(distPath, 'main'); 19 | const distRendererPath = path.join(distPath, 'renderer'); 20 | 21 | const buildPath = path.join(releasePath, 'build'); 22 | 23 | export default { 24 | rootPath, 25 | dllPath, 26 | srcPath, 27 | srcMainPath, 28 | srcRendererPath, 29 | releasePath, 30 | appPath, 31 | appPackagePath, 32 | appNodeModulesPath, 33 | srcNodeModulesPath, 34 | distPath, 35 | distMainPath, 36 | distRendererPath, 37 | buildPath, 38 | }; 39 | -------------------------------------------------------------------------------- /.erb/img/erb-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/.erb/img/erb-logo.png -------------------------------------------------------------------------------- /.erb/mocks/fileMock.js: -------------------------------------------------------------------------------- 1 | export default 'test-file-stub'; 2 | -------------------------------------------------------------------------------- /.erb/scripts/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "no-console": "off", 4 | "global-require": "off", 5 | "import/no-dynamic-require": "off", 6 | "import/no-extraneous-dependencies": "off" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.erb/scripts/check-build-exists.ts: -------------------------------------------------------------------------------- 1 | // Check if the renderer and main bundles are built 2 | import path from 'path'; 3 | import chalk from 'chalk'; 4 | import fs from 'fs'; 5 | import webpackPaths from '../configs/webpack.paths'; 6 | 7 | const mainPath = path.join(webpackPaths.distMainPath, 'main.js'); 8 | const rendererPath = path.join(webpackPaths.distRendererPath, 'renderer.js'); 9 | 10 | if (!fs.existsSync(mainPath)) { 11 | throw new Error( 12 | chalk.whiteBright.bgRed.bold( 13 | 'The main process is not built yet. Build it by running "npm run build:main"' 14 | ) 15 | ); 16 | } 17 | 18 | if (!fs.existsSync(rendererPath)) { 19 | throw new Error( 20 | chalk.whiteBright.bgRed.bold( 21 | 'The renderer process is not built yet. Build it by running "npm run build:renderer"' 22 | ) 23 | ); 24 | } 25 | -------------------------------------------------------------------------------- /.erb/scripts/check-native-dep.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import chalk from 'chalk'; 3 | import { execSync } from 'child_process'; 4 | import { dependencies } from '../../package.json'; 5 | 6 | if (dependencies) { 7 | const dependenciesKeys = Object.keys(dependencies); 8 | const nativeDeps = fs 9 | .readdirSync('node_modules') 10 | .filter((folder) => fs.existsSync(`node_modules/${folder}/binding.gyp`)); 11 | if (nativeDeps.length === 0) { 12 | process.exit(0); 13 | } 14 | try { 15 | // Find the reason for why the dependency is installed. If it is installed 16 | // because of a devDependency then that is okay. Warn when it is installed 17 | // because of a dependency 18 | const { dependencies: dependenciesObject } = JSON.parse( 19 | execSync(`npm ls ${nativeDeps.join(' ')} --json`).toString() 20 | ); 21 | const rootDependencies = Object.keys(dependenciesObject); 22 | const filteredRootDependencies = rootDependencies.filter((rootDependency) => 23 | dependenciesKeys.includes(rootDependency) 24 | ); 25 | if (filteredRootDependencies.length > 0) { 26 | const plural = filteredRootDependencies.length > 1; 27 | console.log(` 28 | ${chalk.whiteBright.bgYellow.bold( 29 | 'Webpack does not work with native dependencies.' 30 | )} 31 | ${chalk.bold(filteredRootDependencies.join(', '))} ${ 32 | plural ? 'are native dependencies' : 'is a native dependency' 33 | } and should be installed inside of the "./release/app" folder. 34 | First, uninstall the packages from "./package.json": 35 | ${chalk.whiteBright.bgGreen.bold('npm uninstall your-package')} 36 | ${chalk.bold( 37 | 'Then, instead of installing the package to the root "./package.json":' 38 | )} 39 | ${chalk.whiteBright.bgRed.bold('npm install your-package')} 40 | ${chalk.bold('Install the package to "./release/app/package.json"')} 41 | ${chalk.whiteBright.bgGreen.bold( 42 | 'cd ./release/app && npm install your-package' 43 | )} 44 | Read more about native dependencies at: 45 | ${chalk.bold( 46 | 'https://electron-react-boilerplate.js.org/docs/adding-dependencies/#module-structure' 47 | )} 48 | `); 49 | process.exit(1); 50 | } 51 | } catch (e) { 52 | console.log('Native dependencies could not be checked'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /.erb/scripts/check-node-env.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | 3 | export default function checkNodeEnv(expectedEnv) { 4 | if (!expectedEnv) { 5 | throw new Error('"expectedEnv" not set'); 6 | } 7 | 8 | if (process.env.NODE_ENV !== expectedEnv) { 9 | console.log( 10 | chalk.whiteBright.bgRed.bold( 11 | `"process.env.NODE_ENV" must be "${expectedEnv}" to use this webpack config` 12 | ) 13 | ); 14 | process.exit(2); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.erb/scripts/check-port-in-use.js: -------------------------------------------------------------------------------- 1 | import chalk from 'chalk'; 2 | import detectPort from 'detect-port'; 3 | 4 | const port = process.env.PORT || '1212'; 5 | 6 | detectPort(port, (err, availablePort) => { 7 | if (port !== String(availablePort)) { 8 | throw new Error( 9 | chalk.whiteBright.bgRed.bold( 10 | `Port "${port}" on "localhost" is already in use. Please use another port. ex: PORT=4343 npm start` 11 | ) 12 | ); 13 | } else { 14 | process.exit(0); 15 | } 16 | }); 17 | -------------------------------------------------------------------------------- /.erb/scripts/clean.js: -------------------------------------------------------------------------------- 1 | import rimraf from 'rimraf'; 2 | import fs from 'fs'; 3 | import webpackPaths from '../configs/webpack.paths'; 4 | 5 | const foldersToRemove = [ 6 | webpackPaths.distPath, 7 | webpackPaths.buildPath, 8 | webpackPaths.dllPath, 9 | ]; 10 | 11 | foldersToRemove.forEach((folder) => { 12 | if (fs.existsSync(folder)) rimraf.sync(folder); 13 | }); 14 | -------------------------------------------------------------------------------- /.erb/scripts/delete-source-maps.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | import rimraf from 'rimraf'; 4 | import webpackPaths from '../configs/webpack.paths'; 5 | 6 | export default function deleteSourceMaps() { 7 | if (fs.existsSync(webpackPaths.distMainPath)) 8 | rimraf.sync(path.join(webpackPaths.distMainPath, '*.js.map')); 9 | if (fs.existsSync(webpackPaths.distRendererPath)) 10 | rimraf.sync(path.join(webpackPaths.distRendererPath, '*.js.map')); 11 | } 12 | -------------------------------------------------------------------------------- /.erb/scripts/electron-rebuild.js: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | import fs from 'fs'; 3 | import { dependencies } from '../../release/app/package.json'; 4 | import webpackPaths from '../configs/webpack.paths'; 5 | 6 | if ( 7 | Object.keys(dependencies || {}).length > 0 && 8 | fs.existsSync(webpackPaths.appNodeModulesPath) 9 | ) { 10 | const electronRebuildCmd = 11 | '../../node_modules/.bin/electron-rebuild --force --types prod,dev,optional --module-dir .'; 12 | const cmd = 13 | process.platform === 'win32' 14 | ? electronRebuildCmd.replace(/\//g, '\\') 15 | : electronRebuildCmd; 16 | execSync(cmd, { 17 | cwd: webpackPaths.appPath, 18 | stdio: 'inherit', 19 | }); 20 | } 21 | -------------------------------------------------------------------------------- /.erb/scripts/link-modules.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import webpackPaths from '../configs/webpack.paths'; 3 | 4 | const { srcNodeModulesPath } = webpackPaths; 5 | const { appNodeModulesPath } = webpackPaths; 6 | 7 | if (!fs.existsSync(srcNodeModulesPath) && fs.existsSync(appNodeModulesPath)) { 8 | fs.symlinkSync(appNodeModulesPath, srcNodeModulesPath, 'junction'); 9 | } 10 | -------------------------------------------------------------------------------- /.erb/scripts/notarize.js: -------------------------------------------------------------------------------- 1 | const { notarize } = require('@electron/notarize'); 2 | const { build } = require('../../package.json'); 3 | 4 | exports.default = async function notarizeMacos(context) { 5 | const { electronPlatformName, appOutDir } = context; 6 | if (electronPlatformName !== 'darwin') { 7 | return; 8 | } 9 | 10 | if (process.env.CI !== 'true') { 11 | console.warn('Skipping notarizing step. Packaging is not running in CI'); 12 | return; 13 | } 14 | 15 | if (!('APPLE_ID' in process.env && 'APPLE_ID_PASS' in process.env)) { 16 | console.warn( 17 | 'Skipping notarizing step. APPLE_ID and APPLE_ID_PASS env variables must be set' 18 | ); 19 | return; 20 | } 21 | 22 | const appName = context.packager.appInfo.productFilename; 23 | 24 | await notarize({ 25 | appBundleId: build.appId, 26 | appPath: `${appOutDir}/${appName}.app`, 27 | appleId: process.env.APPLE_ID, 28 | appleIdPassword: process.env.APPLE_ID_PASS, 29 | }); 30 | }; 31 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Coverage directory used by tools like istanbul 11 | coverage 12 | .eslintcache 13 | 14 | # Dependency directory 15 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 16 | node_modules 17 | 18 | # OSX 19 | .DS_Store 20 | 21 | release/app/dist 22 | release/build 23 | .erb/dll 24 | 25 | .idea 26 | npm-debug.log.* 27 | *.css.d.ts 28 | *.sass.d.ts 29 | *.scss.d.ts 30 | 31 | # eslint ignores hidden directories by default: 32 | # https://github.com/eslint/eslint/issues/8429 33 | !.erb 34 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | extends: 'erb', 3 | rules: { 4 | // A temporary hack related to IDE not resolving correct package.json 5 | 'import/no-extraneous-dependencies': 'off', 6 | 'react/react-in-jsx-scope': 'off', 7 | 'react/jsx-filename-extension': 'off', 8 | 'import/extensions': 'off', 9 | 'import/no-unresolved': 'off', 10 | 'import/no-import-module-exports': 'off', 11 | }, 12 | parserOptions: { 13 | ecmaVersion: 2020, 14 | sourceType: 'module', 15 | project: './tsconfig.json', 16 | tsconfigRootDir: __dirname, 17 | createDefaultProgram: true, 18 | }, 19 | settings: { 20 | 'import/resolver': { 21 | // See https://github.com/benmosher/eslint-plugin-import/issues/1396#issuecomment-575727774 for line below 22 | node: {}, 23 | webpack: { 24 | config: require.resolve('./.erb/configs/webpack.config.eslint.ts'), 25 | }, 26 | typescript: {}, 27 | }, 28 | 'import/parsers': { 29 | '@typescript-eslint/parser': ['.ts', '.tsx'], 30 | }, 31 | }, 32 | }; 33 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | *.exe binary 3 | *.png binary 4 | *.jpg binary 5 | *.jpeg binary 6 | *.ico binary 7 | *.icns binary 8 | *.eot binary 9 | *.otf binary 10 | *.ttf binary 11 | *.woff binary 12 | *.woff2 binary 13 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [electron-react-boilerplate, amilajack] 4 | patreon: amilajack 5 | open_collective: electron-react-boilerplate-594 6 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1-Bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: You're having technical issues. 🐞 4 | labels: 'bug' 5 | --- 6 | 7 | 8 | 9 | ## Prerequisites 10 | 11 | 12 | 13 | - [ ] Using npm 14 | - [ ] Using an up-to-date [`main` branch](https://github.com/electron-react-boilerplate/electron-react-boilerplate/tree/main) 15 | - [ ] Using latest version of devtools. [Check the docs for how to update](https://electron-react-boilerplate.js.org/docs/dev-tools/) 16 | - [ ] Tried solutions mentioned in [#400](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/400) 17 | - [ ] For issue in production release, add devtools output of `DEBUG_PROD=true npm run build && npm start` 18 | 19 | ## Expected Behavior 20 | 21 | 22 | 23 | ## Current Behavior 24 | 25 | 26 | 27 | ## Steps to Reproduce 28 | 29 | 30 | 31 | 32 | 1. 33 | 34 | 2. 35 | 36 | 3. 37 | 38 | 4. 39 | 40 | ## Possible Solution (Not obligatory) 41 | 42 | 43 | 44 | ## Context 45 | 46 | 47 | 48 | 49 | 50 | ## Your Environment 51 | 52 | 53 | 54 | - Node version : 55 | - electron-react-boilerplate version or branch : 56 | - Operating System and version : 57 | - Link to your project : 58 | 59 | 68 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2-Question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question.❓ 4 | labels: 'question' 5 | --- 6 | 7 | ## Summary 8 | 9 | 10 | 11 | 20 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/3-Feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: You want something added to the boilerplate. 🎉 4 | labels: 'enhancement' 5 | --- 6 | 7 | 16 | -------------------------------------------------------------------------------- /.github/config.yml: -------------------------------------------------------------------------------- 1 | requiredHeaders: 2 | - Prerequisites 3 | - Expected Behavior 4 | - Current Behavior 5 | - Possible Solution 6 | - Your Environment 7 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - discussion 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: wontfix 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false 18 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | # For most projects, this workflow file will not need changing; you simply need 2 | # to commit it to your repository. 3 | # 4 | # You may wish to alter this file to override the set of languages analyzed, 5 | # or to provide custom queries or build logic. 6 | # 7 | # ******** NOTE ******** 8 | # We have attempted to detect the languages in your repository. Please check 9 | # the `language` matrix defined below to confirm you have the correct set of 10 | # supported CodeQL languages. 11 | # 12 | name: "CodeQL" 13 | 14 | on: 15 | push: 16 | branches: [ "main" ] 17 | pull_request: 18 | # The branches below must be a subset of the branches above 19 | branches: [ "main" ] 20 | schedule: 21 | - cron: '44 16 * * 4' 22 | 23 | jobs: 24 | analyze: 25 | name: Analyze 26 | runs-on: ubuntu-latest 27 | permissions: 28 | actions: read 29 | contents: read 30 | security-events: write 31 | 32 | strategy: 33 | fail-fast: false 34 | matrix: 35 | language: [ 'javascript' ] 36 | # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] 37 | # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support 38 | 39 | steps: 40 | - name: Checkout repository 41 | uses: actions/checkout@v3 42 | 43 | # Initializes the CodeQL tools for scanning. 44 | - name: Initialize CodeQL 45 | uses: github/codeql-action/init@v2 46 | with: 47 | languages: ${{ matrix.language }} 48 | # If you wish to specify custom queries, you can do so here or in a config file. 49 | # By default, queries listed here will override any specified in a config file. 50 | # Prefix the list here with "+" to use these queries and those in the config file. 51 | 52 | # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs 53 | # queries: security-extended,security-and-quality 54 | 55 | 56 | # Autobuild attempts to build any compiled languages (C/C++, C#, or Java). 57 | # If this step fails, then you should remove it and run the build manually (see below) 58 | - name: Autobuild 59 | uses: github/codeql-action/autobuild@v2 60 | 61 | # ℹ️ Command-line programs to run using the OS shell. 62 | # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun 63 | 64 | # If the Autobuild fails above, remove it and uncomment the following three lines. 65 | # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. 66 | 67 | # - run: | 68 | # echo "Run, Build Application using script" 69 | # ./location_of_script_within_repo/buildscript.sh 70 | 71 | - name: Perform CodeQL Analysis 72 | uses: github/codeql-action/analyze@v2 73 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | jobs: 9 | publish: 10 | # To enable auto publishing to github, update your electron publisher 11 | # config in package.json > "build" and remove the conditional below 12 | if: ${{ github.repository_owner == 'electron-react-boilerplate' }} 13 | 14 | runs-on: ${{ matrix.os }} 15 | 16 | strategy: 17 | matrix: 18 | os: [macos-latest] 19 | 20 | steps: 21 | - name: Checkout git repo 22 | uses: actions/checkout@v3 23 | 24 | - name: Install Node and NPM 25 | uses: actions/setup-node@v3 26 | with: 27 | node-version: 16 28 | cache: npm 29 | 30 | - name: Install and build 31 | run: | 32 | npm install 33 | npm run postinstall 34 | npm run build 35 | 36 | - name: Publish releases 37 | env: 38 | # These values are used for auto updates signing 39 | APPLE_ID: ${{ secrets.APPLE_ID }} 40 | APPLE_ID_PASS: ${{ secrets.APPLE_ID_PASS }} 41 | CSC_LINK: ${{ secrets.CSC_LINK }} 42 | CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} 43 | # This is used for uploading release assets to github 44 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 45 | run: | 46 | npm exec electron-builder -- --publish always --win --mac --linux 47 | -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | test: 7 | runs-on: ${{ matrix.os }} 8 | 9 | strategy: 10 | matrix: 11 | os: [macos-latest, windows-latest, ubuntu-latest] 12 | 13 | steps: 14 | - name: Check out Git repository 15 | uses: actions/checkout@v3 16 | 17 | - name: Install Node.js and NPM 18 | uses: actions/setup-node@v3 19 | with: 20 | node-version: 16 21 | cache: npm 22 | 23 | - name: npm install 24 | run: | 25 | npm install 26 | 27 | - name: npm test 28 | env: 29 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 30 | run: | 31 | npm run package 32 | npm run lint 33 | npm exec tsc 34 | npm test 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | 5 | # Runtime data 6 | pids 7 | *.pid 8 | *.seed 9 | 10 | # Coverage directory used by tools like istanbul 11 | coverage 12 | .eslintcache 13 | 14 | # Dependency directory 15 | # https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git 16 | node_modules 17 | 18 | # OSX 19 | .DS_Store 20 | 21 | release/app/dist 22 | release/build 23 | .erb/dll 24 | 25 | .idea 26 | npm-debug.log.* 27 | *.css.d.ts 28 | *.sass.d.ts 29 | *.scss.d.ts 30 | 31 | 0Txt/ 32 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | electron_mirror=https://npm.taobao.org/mirrors/electron/ 2 | electron_builder_binaries_mirror=https://mirrors.huaweicloud.com/electron-builder-binaries/ 3 | chromedriver_cdnurl=https://mirrors.huaweicloud.com/chromedriver 4 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": ["dbaeumer.vscode-eslint", "EditorConfig.EditorConfig"] 3 | } 4 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Electron: Main", 6 | "type": "node", 7 | "request": "launch", 8 | "protocol": "inspector", 9 | "runtimeExecutable": "npm", 10 | "runtimeArgs": ["run", "start"], 11 | "env": { 12 | "MAIN_ARGS": "--inspect=5858 --remote-debugging-port=9223" 13 | } 14 | }, 15 | { 16 | "name": "Electron: Renderer", 17 | "type": "chrome", 18 | "request": "attach", 19 | "port": 9223, 20 | "webRoot": "${workspaceFolder}", 21 | "timeout": 15000 22 | } 23 | ], 24 | "compounds": [ 25 | { 26 | "name": "Electron: All", 27 | "configurations": ["Electron: Main", "Electron: Renderer"] 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.associations": { 3 | ".eslintrc": "jsonc", 4 | ".prettierrc": "jsonc", 5 | ".eslintignore": "ignore" 6 | }, 7 | 8 | "eslint.validate": [ 9 | "javascript", 10 | "javascriptreact", 11 | "html", 12 | "typescriptreact" 13 | ], 14 | 15 | "javascript.validate.enable": false, 16 | "javascript.format.enable": false, 17 | "typescript.format.enable": false, 18 | 19 | "search.exclude": { 20 | ".git": true, 21 | ".eslintcache": true, 22 | ".erb/dll": true, 23 | "release/{build,app/dist}": true, 24 | "node_modules": true, 25 | "npm-debug.log.*": true, 26 | "test/**/__snapshots__": true, 27 | "package-lock.json": true, 28 | "*.{css,sass,scss}.d.ts": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /.yarnrc: -------------------------------------------------------------------------------- 1 | registry "https://registry.npm.taobao.org" 2 | sass_binary_site "https://npm.taobao.org/mirrors/node-sass/" 3 | phantomjs_cdnurl "http://cnpmjs.org/downloads" 4 | electron_mirror "https://npm.taobao.org/mirrors/electron/" 5 | sqlite3_binary_host_mirror "https://foxgis.oss-cn-shanghai.aliyuncs.com/" 6 | profiler_binary_host_mirror "https://npm.taobao.org/mirrors/node-inspector/" 7 | chromedriver_cdnurl "https://cdn.npm.taobao.org/dist/chromedriver" 8 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as 6 | contributors and maintainers pledge to making participation in our project and 7 | our community a harassment-free experience for everyone, regardless of age, body 8 | size, disability, ethnicity, sex characteristics, gender identity and expression, 9 | level of experience, education, socio-economic status, nationality, personal 10 | appearance, race, religion, or sexual identity and orientation. 11 | 12 | ## Our Standards 13 | 14 | Examples of behavior that contributes to creating a positive environment 15 | include: 16 | 17 | * Using welcoming and inclusive language 18 | * Being respectful of differing viewpoints and experiences 19 | * Gracefully accepting constructive criticism 20 | * Focusing on what is best for the community 21 | * Showing empathy towards other community members 22 | 23 | Examples of unacceptable behavior by participants include: 24 | 25 | * The use of sexualized language or imagery and unwelcome sexual attention or 26 | advances 27 | * Trolling, insulting/derogatory comments, and personal or political attacks 28 | * Public or private harassment 29 | * Publishing others' private information, such as a physical or electronic 30 | address, without explicit permission 31 | * Other conduct which could reasonably be considered inappropriate in a 32 | professional setting 33 | 34 | ## Our Responsibilities 35 | 36 | Project maintainers are responsible for clarifying the standards of acceptable 37 | behavior and are expected to take appropriate and fair corrective action in 38 | response to any instances of unacceptable behavior. 39 | 40 | Project maintainers have the right and responsibility to remove, edit, or 41 | reject comments, commits, code, wiki edits, issues, and other contributions 42 | that are not aligned to this Code of Conduct, or to ban temporarily or 43 | permanently any contributor for other behaviors that they deem inappropriate, 44 | threatening, offensive, or harmful. 45 | 46 | ## Scope 47 | 48 | This Code of Conduct applies both within project spaces and in public spaces 49 | when an individual is representing the project or its community. Examples of 50 | representing a project or community include using an official project e-mail 51 | address, posting via an official social media account, or acting as an appointed 52 | representative at an online or offline event. Representation of a project may be 53 | further defined and clarified by project maintainers. 54 | 55 | ## Enforcement 56 | 57 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 58 | reported by contacting the project team at electronreactboilerplate@gmail.com. All 59 | complaints will be reviewed and investigated and will result in a response that 60 | is deemed necessary and appropriate to the circumstances. The project team is 61 | obligated to maintain confidentiality with regard to the reporter of an incident. 62 | Further details of specific enforcement policies may be posted separately. 63 | 64 | Project maintainers who do not follow or enforce the Code of Conduct in good 65 | faith may face temporary or permanent repercussions as determined by other 66 | members of the project's leadership. 67 | 68 | ## Attribution 69 | 70 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, 71 | available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html 72 | 73 | [homepage]: https://www.contributor-covenant.org 74 | 75 | For answers to common questions about this code of conduct, see 76 | https://www.contributor-covenant.org/faq 77 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015-present Electron React Boilerplate 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-dev.md: -------------------------------------------------------------------------------- 1 | # 开发小笔记: 2 | 3 | ## 参数的使用 4 | 5 | blockly变量块传出的是变量名。 6 | 7 | 假如一个blockly界面的变量名为param1,内容是字符串hello。 8 | 9 | 该变量在用到这个变量的块的值接口叫val1 10 | 11 | 定义代码块里,拼接生成脚本的代码的字符串时直接用 12 | 13 | ```javascript 14 | const blocklyparamVal1=javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 15 | return `stagelist.push(\`load \${${blocklyparamVal1}}\`);` 16 | ``` 17 | 18 | 即在生成的代码中,strlist中的这个元素为'load hello' 19 | 20 | ## 时间戳 21 | 22 | 每次触发重新构造代码块前都会重置外部时间戳`window.numinbigfunc=0` 23 | 24 | `utils/timestamp`里的generateTime函数每次被调用时,都会读取这个window.numinbigfunc,然后使其自增1。定义积木块的生成字符串时,调用generateTime,即可获得一个独一无二的字符串,便于设置各种按钮跳转结构或分支块结构。 25 | 26 | 在codetool内部,也就是blockly组装起来的js代码中,也有一个内部时间戳incnum,每次使用按钮时,都会定义一个函数,其内拼接incnum来得到每个按钮内的跳转target,这样当使用blockly函数功能复用按钮时,就不会有每次按钮结束都跳到第一次按钮结束的地方的问题了。 27 | 28 | ## 生成js码 29 | 30 | 主线:stagelist每段stage代码【1-200】,resmap存每个stage序号和结果串,errorset存冲突的序号 31 | 32 | 按钮if块:使用时间戳作id,不会重复 33 | 34 | 支线:支线相关块需要指定一个支线id(caseset记录定义过的`跳转到支线`块,caseerrorset记录重合的`跳转到支线块`,反馈给用户)。 35 | 36 | 支线承载块在数据存储上和主线块相同,不过使用主线块后面的区域,支线id是stagelist每段支线代码【201-300】,resmap存每个定义支线块序号和结果串,errorset存冲突的定义支线块的序号 37 | 38 | ### 按钮的设计 39 | 40 | 按钮被包装成一个时间戳为名字的函数(假设外部时间戳id=42,内部时间戳incnum=5) 41 | 42 | 函数内部先赋值内部时间戳副本incnum,然后给全局的这incnum+1,用时间戳命名按钮跳转。最后直接调用这个函数,将文本写入该主线的stagelist。 43 | 44 | A分支,target 42caseA5。A分支结束时,jump 42IfFinal5。 45 | 46 | B分支,target 42caseB5。B分支结束时,jump 42IfFinal5。 47 | 48 | ifcase块的最后target 42IfFinal5 49 | 50 | ### 支线的设计(弃用) 51 | 52 | 通过创建resmap里字符串的副本的方式,模拟实现多次调用,实际是核心内容复制粘贴,开头结尾不同。使得`跳转到支线n`块可以多次使用 53 | 54 | 以A块跳转块,B块定义块为例,在构造出来的js代码里新建一个引用记录case_jump_dict,广场上所有块生成代码时,记录所有`跳转到支线块B`的跳转块(A)的时间戳id( 字典内容 {支线块B的id : [ 第一个跳转到支线块B的时间戳,第二个跳转到支线块B的时间戳] ),然后在sortMap后面的循环里,每个时间戳添加一份相应的支线块B的脚本段(A知道自己时间戳和B的id,B知道自己id,B在合成阶段知道A时间戳,主线里A跳转块跳到支线B块,Z跳转块跳到支线B块,最后生成的时候B块的resMap会push两个脚本段,一个负责A,一个负责B) 55 | 56 | 具体设计如下: 57 | 58 | `codetool`开头:定义case_jump_dict 一个Map来存储调用关系 59 | 60 | `跳转到支线`块,获得用户输入id(201到300)以及时间戳:blockly代码块定义阶段,在开头stagelist.push(jump id+时间戳+'PathStart'),结尾stagelist.push(jump id+时间戳+'PathBack'),同时stagelist.push(一个逻辑代码),逻辑内容差不多是给case_jump_dict的id对应的列表添加{时间戳}作为一个新元素 61 | 62 | - 初始化met200=false, 当sortMap合并的时候遇到>200的id且还是false(说明来到支线部分),置为true,然后添加jump wholeProjectTail。整个sortMap合并完。target wholeProjectTail 63 | 64 | `定义支线`块,获得用户输入id(201到300),然后blockly代码块定义阶段内只有statement内容。在codetool代码后面resMap合并时,for循环里判断id>200,则对case_jump_dict[ id ]列表里的每个时间戳,往rescode里加 target id+时间戳+'PathStart',然后是thisvaluecode,然后是 jump id+时间戳+'PathBack' 65 | 66 | 支线块在2.2.2h版本弃用(一是解决按钮复用问题,一是与函数块冲突,内部实现改写为id命名的一个函数的形式),但仍然加载进blockly,只是在工具箱里隐藏 67 | 68 | ## 版本兼容性 69 | 70 | 目前blockly模块导入项目时,如果项目文件中某一个id的模块记录的**参数格式(每个位置对应的格式)**与现在playground里注册的同id模块不一样,则会报错。 71 | 72 | 在参数形式能对应上参数下标的情况下,如果参数数量变少,会自动删去项目文件中未知的参数。如果参数空变多,则会留空。 73 | 74 | 如果数字的允许区间变更,数字会自动修改到最靠近的合法值,不会error。 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | # Todo 3 | 4 | - [ ] ~~Add i18n~~. 5 | - [ ] ~~Use local Backend server to load source automatically~~. 6 | 7 | This project is archived since the AS is archived. 8 | 由于AS停止开发,本项目即将归档 9 | 10 | 11 | 12 | # 使用前的准备 13 | 14 | 1. 首先需要在爱丽丝工坊项目下载Releases包并解压,同时需要按照文档说明下载数据资源并放入Data文件夹,请确保你能正常使用ArisStudio.exe。 15 | 2. 下载本项目的Releases包并解压出exe文件或使用浏览器访问`https://sanmusen214.github.io/arisstudio-blockly/`,即可开始堆搭积木。使用浏览器网页的话则自动保存功能不可用。 16 | - 如果你使用的是exe程序,则可以使用自动保存功能,点击右上角的`开始设定自动导出`按钮选择一个爱丽丝工坊项目的`0Txt`文件夹下的txt文件。之后你堆搭的积木都会自动保存到该txt文件里。 17 | - 如果你使用的是浏览器网页,每次想要获得脚本时,点击页面右上角`导出脚本`即可选择保存txt至ArisStudio的`0Txt`文件夹下,或者打开脚本框进行文本的复制粘贴。 18 | 3. 在ArisStudio中加载刚才导出的txt即可。 19 | 4. 右上角的导入与导出blockly项目可以从以前的可视化项目文件中恢复内容,或把当前可视化积木保存下来。 20 | 21 | 22 | # 如何使用 23 | 24 | 25 | 26 | 简单地拖动左侧组件到主界面中即可构建用于ArisStudio的脚本,不过有以下几点需要注意: 27 | 28 | 1. 所有积木必须放在`主线块`里,先运行主线块1,随后运行主线块2,以此类推 29 | 2. 加载人物以及加载背景的块必须放在`加载块`里,`加载块`需放置于脚本开头 30 | 3. 场上不能同时有两个`主线块1`,或两个`主线块2`,以此类推 31 | 4. 所有文字块里尽量不含空格,可以使用下划线_来替代空格。被中括号包裹的区域除外 32 | 33 | # 教程 34 | 35 | 这里是视频教程 36 | 37 | ## Install 38 | 39 | Clone the repo and install dependencies: 40 | 41 | ```bash 42 | git clone --depth 1 --branch main https://github.com/electron-react-boilerplate/electron-react-boilerplate.git your-project-name 43 | cd your-project-name 44 | npm install 45 | ``` 46 | 47 | **Having issues installing? See our [debugging guide](https://github.com/electron-react-boilerplate/electron-react-boilerplate/issues/400)** 48 | 49 | ## Starting Development 50 | 51 | Start the app in the `dev` environment: 52 | 53 | ```bash 54 | npm start 55 | ``` 56 | 57 | ## Packaging for Production 58 | 59 | To package apps for the local platform: 60 | 61 | ```bash 62 | npm run package 63 | ``` 64 | # Thanks 65 | 66 |

67 | Electron React Boilerplate uses Electron, React, React Router, Webpack and React Fast Refresh. 68 | 69 | This project uses blockly and works with ArisStudio. 70 |

71 | 72 | ## Template Docs 73 | 74 | See our [docs and guides here](https://electron-react-boilerplate.js.org/docs/installation) 75 | 76 | ## Maintainers 77 | 78 | - [Amila Welihinda](https://github.com/amilajack) 79 | - [John Tran](https://github.com/jooohhn) 80 | - [C. T. Lin](https://github.com/chentsulin) 81 | - [Jhen-Jie Hong](https://github.com/jhen0409) 82 | 83 | ## License 84 | 85 | MIT © [Electron React Boilerplate](https://github.com/electron-react-boilerplate) 86 | 87 | [github-actions-status]: https://github.com/electron-react-boilerplate/electron-react-boilerplate/workflows/Test/badge.svg 88 | [github-actions-url]: https://github.com/electron-react-boilerplate/electron-react-boilerplate/actions 89 | [github-tag-image]: https://img.shields.io/github/tag/electron-react-boilerplate/electron-react-boilerplate.svg?label=version 90 | [github-tag-url]: https://github.com/electron-react-boilerplate/electron-react-boilerplate/releases/latest 91 | [stackoverflow-img]: https://img.shields.io/badge/stackoverflow-electron_react_boilerplate-blue.svg 92 | [stackoverflow-url]: https://stackoverflow.com/questions/tagged/electron-react-boilerplate 93 | -------------------------------------------------------------------------------- /assets/assets.d.ts: -------------------------------------------------------------------------------- 1 | type Styles = Record; 2 | 3 | declare module '*.svg' { 4 | import React = require('react'); 5 | 6 | export const ReactComponent: React.FC>; 7 | 8 | const content: string; 9 | export default content; 10 | } 11 | 12 | declare module '*.png' { 13 | const content: string; 14 | export default content; 15 | } 16 | 17 | declare module '*.jpg' { 18 | const content: string; 19 | export default content; 20 | } 21 | 22 | declare module '*.scss' { 23 | const content: Styles; 24 | export default content; 25 | } 26 | 27 | declare module '*.sass' { 28 | const content: Styles; 29 | export default content; 30 | } 31 | 32 | declare module '*.css' { 33 | const content: Styles; 34 | export default content; 35 | } 36 | -------------------------------------------------------------------------------- /assets/entitlements.mac.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.apple.security.cs.allow-unsigned-executable-memory 6 | 7 | com.apple.security.cs.allow-jit 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /assets/icon.icns: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icon.icns -------------------------------------------------------------------------------- /assets/icon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icon.ico -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icon.png -------------------------------------------------------------------------------- /assets/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /assets/icons/1024x1024.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/1024x1024.png -------------------------------------------------------------------------------- /assets/icons/128x128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/128x128.png -------------------------------------------------------------------------------- /assets/icons/16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/16x16.png -------------------------------------------------------------------------------- /assets/icons/24x24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/24x24.png -------------------------------------------------------------------------------- /assets/icons/256x256.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/256x256.png -------------------------------------------------------------------------------- /assets/icons/32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/32x32.png -------------------------------------------------------------------------------- /assets/icons/48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/48x48.png -------------------------------------------------------------------------------- /assets/icons/512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/512x512.png -------------------------------------------------------------------------------- /assets/icons/64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/64x64.png -------------------------------------------------------------------------------- /assets/icons/96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/assets/icons/96x96.png -------------------------------------------------------------------------------- /release/app/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arisstudioblockly", 3 | "version": "0.3.0", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "arisstudioblockly", 9 | "version": "0.3.0", 10 | "hasInstallScript": true, 11 | "license": "MIT" 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /release/app/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "arisstudioblockly", 3 | "version": "0.3.0-alpha.1", 4 | "description": "`A Website app for Aris Studio to build ba story`", 5 | "license": "MIT", 6 | "author": { 7 | "name": "sanmusen", 8 | "email": "sanmusen_wu@outlook.com", 9 | "url": "https://www.sanmusen.top" 10 | }, 11 | "main": "./dist/main/main.js", 12 | "scripts": { 13 | "rebuild": "node -r ts-node/register ../../.erb/scripts/electron-rebuild.js", 14 | "postinstall": "npm run rebuild && npm run link-modules", 15 | "link-modules": "node -r ts-node/register ../../.erb/scripts/link-modules.ts" 16 | }, 17 | "dependencies": {} 18 | } 19 | -------------------------------------------------------------------------------- /release/app/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/__tests__/App.test.tsx: -------------------------------------------------------------------------------- 1 | import '@testing-library/jest-dom'; 2 | import { render } from '@testing-library/react'; 3 | import App from '../renderer/App'; 4 | 5 | describe('App', () => { 6 | it('should render', () => { 7 | expect(render()).toBeTruthy(); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/main/main.ts: -------------------------------------------------------------------------------- 1 | /* eslint global-require: off, no-console: off, promise/always-return: off */ 2 | 3 | /** 4 | * This module executes inside of electron's main process. You can start 5 | * electron renderer process from here and communicate with the other processes 6 | * through IPC. 7 | * 8 | * When running `npm run build` or `npm run build:main`, this file is compiled to 9 | * `./src/main.js` using webpack. This gives us some performance wins. 10 | */ 11 | import path from 'path'; 12 | import { app, BrowserWindow, shell, ipcMain,nativeTheme, dialog } from 'electron'; 13 | import { autoUpdater } from 'electron-updater'; 14 | import log from 'electron-log'; 15 | import MenuBuilder from './menu'; 16 | import { resolveHtmlPath } from './util'; 17 | import { saveTxtToSystem } from './systemIO'; 18 | 19 | class AppUpdater { 20 | constructor() { 21 | log.transports.file.level = 'info'; 22 | autoUpdater.logger = log; 23 | autoUpdater.checkForUpdatesAndNotify(); 24 | } 25 | } 26 | 27 | let mainWindow: BrowserWindow | null = null; 28 | 29 | ipcMain.handle("dark-mode:toggle",(event,dark)=>{ 30 | if (!dark) { 31 | nativeTheme.themeSource = 'light' 32 | } else { 33 | nativeTheme.themeSource = 'dark' 34 | } 35 | return nativeTheme.shouldUseDarkColors 36 | }) 37 | 38 | 39 | ipcMain.on('ipc-example', async (event, [filename, content]) => { 40 | saveTxtToSystem(filename,content) 41 | event.reply('ipc-example', 'saved: '+filename+" con: "+content); 42 | }); 43 | 44 | if (process.env.NODE_ENV === 'production') { 45 | const sourceMapSupport = require('source-map-support'); 46 | sourceMapSupport.install(); 47 | } 48 | 49 | const isDebug = 50 | process.env.NODE_ENV === 'development' || process.env.DEBUG_PROD === 'true'; 51 | 52 | if (isDebug) { 53 | require('electron-debug')(); 54 | } 55 | 56 | const installExtensions = async () => { 57 | const installer = require('electron-devtools-installer'); 58 | const forceDownload = !!process.env.UPGRADE_EXTENSIONS; 59 | const extensions = ['REACT_DEVELOPER_TOOLS']; 60 | 61 | return installer 62 | .default( 63 | extensions.map((name) => installer[name]), 64 | forceDownload 65 | ) 66 | .catch(console.log); 67 | }; 68 | 69 | const createWindow = async () => { 70 | if (isDebug) { 71 | await installExtensions(); 72 | } 73 | 74 | const RESOURCES_PATH = app.isPackaged 75 | ? path.join(process.resourcesPath, 'assets') 76 | : path.join(__dirname, '../../assets'); 77 | 78 | const getAssetPath = (...paths: string[]): string => { 79 | return path.join(RESOURCES_PATH, ...paths); 80 | }; 81 | 82 | mainWindow = new BrowserWindow({ 83 | show: false, 84 | width: 1024, 85 | height: 728, 86 | icon: getAssetPath('icon.png'), 87 | webPreferences: { 88 | preload: app.isPackaged 89 | ? path.join(__dirname, 'preload.js') 90 | : path.join(__dirname, '../../.erb/dll/preload.js'), 91 | }, 92 | }); 93 | 94 | mainWindow.loadURL(resolveHtmlPath('index.html')); 95 | 96 | mainWindow.on('ready-to-show', () => { 97 | if (!mainWindow) { 98 | throw new Error('"mainWindow" is not defined'); 99 | } 100 | if (process.env.START_MINIMIZED) { 101 | mainWindow.minimize(); 102 | } else { 103 | mainWindow.show(); 104 | } 105 | }); 106 | 107 | mainWindow.on("close",e=>{ 108 | const choice = dialog.showMessageBoxSync(mainWindow, { 109 | type: "info", 110 | buttons: ["取消", "确认退出"], 111 | title: "提示", 112 | message: "确定要关闭吗", 113 | defaultId: 0, 114 | cancelId: 0 115 | }); 116 | const cancel = choice === 0; 117 | if (cancel) { 118 | e.preventDefault(); 119 | // mainWindow.minimize(); 120 | } 121 | }); 122 | 123 | 124 | mainWindow.on('closed', () => { 125 | mainWindow = null; 126 | }); 127 | 128 | const menuBuilder = new MenuBuilder(mainWindow); 129 | menuBuilder.buildMenu(); 130 | 131 | // Open urls in the user's browser 132 | mainWindow.webContents.setWindowOpenHandler((edata) => { 133 | shell.openExternal(edata.url); 134 | return { action: 'deny' }; 135 | }); 136 | 137 | // Remove this if your app does not use auto updates 138 | // eslint-disable-next-line 139 | new AppUpdater(); 140 | }; 141 | 142 | // Open urls in the user's browser 143 | 144 | app.on('web-contents-created', (e, webContents) => { 145 | webContents.setWindowOpenHandler(({ url, frameName }) => { 146 | shell.openExternal(url); 147 | return { action: 'deny' }; 148 | }); 149 | }); 150 | 151 | /** 152 | * Add event listeners... 153 | */ 154 | 155 | app.on('window-all-closed', () => { 156 | // Respect the OSX convention of having the application in memory even 157 | // after all windows have been closed 158 | if (process.platform !== 'darwin') { 159 | app.quit(); 160 | } 161 | }); 162 | 163 | app 164 | .whenReady() 165 | .then(() => { 166 | createWindow(); 167 | app.on('activate', () => { 168 | // On macOS it's common to re-create a window in the app when the 169 | // dock icon is clicked and there are no other windows open. 170 | if (mainWindow === null) createWindow(); 171 | }); 172 | }) 173 | .catch(console.log); 174 | -------------------------------------------------------------------------------- /src/main/preload.ts: -------------------------------------------------------------------------------- 1 | // Disable no-unused-vars, broken for spread args 2 | /* eslint no-unused-vars: off */ 3 | import { contextBridge, ipcRenderer, IpcRendererEvent } from 'electron'; 4 | 5 | export type Channels = 'ipc-example'; 6 | 7 | const electronHandler = { 8 | ipcRenderer: { 9 | sendMessage(channel: Channels, args: unknown[]) { 10 | ipcRenderer.send(channel, args); 11 | }, 12 | on(channel: Channels, func: (...args: unknown[]) => void) { 13 | const subscription = (_event: IpcRendererEvent, ...args: unknown[]) => 14 | func(...args); 15 | ipcRenderer.on(channel, subscription); 16 | 17 | return () => { 18 | ipcRenderer.removeListener(channel, subscription); 19 | }; 20 | }, 21 | once(channel: Channels, func: (...args: unknown[]) => void) { 22 | ipcRenderer.once(channel, (_event, ...args) => func(...args)); 23 | }, 24 | }, 25 | }; 26 | 27 | contextBridge.exposeInMainWorld('electron', electronHandler); 28 | contextBridge.exposeInMainWorld("darkMode",{ 29 | toggle:(dark:boolean)=>ipcRenderer.invoke("dark-mode:toggle",dark) 30 | }) 31 | 32 | 33 | export type ElectronHandler = typeof electronHandler; 34 | -------------------------------------------------------------------------------- /src/main/systemIO.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 文件操作工具类 3 | */ 4 | import { writeFile } from 'fs'; 5 | 6 | export let saveTxtToSystem = async (curPath: string,data: string): Promise => { 7 | // if (curPath) { 8 | await writeFile(curPath, data,(err)=>{return}) 9 | return curPath 10 | // } 11 | // else { 12 | // const { canceled, filePath } = await dialog.showSaveDialog({}) 13 | // if (!canceled) 14 | // await fs.writeFile(filePath, data) 15 | // return filePath 16 | // } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/main/util.ts: -------------------------------------------------------------------------------- 1 | /* eslint import/prefer-default-export: off */ 2 | import { URL } from 'url'; 3 | import path from 'path'; 4 | 5 | export function resolveHtmlPath(htmlFileName: string) { 6 | if (process.env.NODE_ENV === 'development') { 7 | const port = process.env.PORT || 1212; 8 | const url = new URL(`http://localhost:${port}`); 9 | url.pathname = htmlFileName; 10 | return url.href; 11 | } 12 | return `file://${path.resolve(__dirname, '../renderer/', htmlFileName)}`; 13 | } 14 | -------------------------------------------------------------------------------- /src/renderer/App.css: -------------------------------------------------------------------------------- 1 | /* 2 | * @NOTE: Prepend a `~` to css file paths that are in your node_modules 3 | * See https://github.com/webpack-contrib/sass-loader#imports 4 | */ 5 | 6 | html, 7 | body { 8 | height: 100%; 9 | width: 100%; 10 | min-width: 600px; 11 | background-color: rgb(221, 221, 221); 12 | } 13 | 14 | 15 | #root{ 16 | width: 100%; 17 | height:100%; 18 | } 19 | 20 | * { 21 | margin: 0; 22 | padding: 0; 23 | } 24 | 25 | /* button { 26 | background-color: white; 27 | padding: 10px 20px; 28 | border-radius: 10px; 29 | border: none; 30 | appearance: none; 31 | font-size: 1.3rem; 32 | box-shadow: 0px 8px 28px -6px rgba(24, 39, 75, 0.12), 33 | 0px 18px 88px -4px rgba(24, 39, 75, 0.14); 34 | transition: all ease-in 0.1s; 35 | cursor: pointer; 36 | opacity: 0.9; 37 | } */ 38 | 39 | button:hover { 40 | transform: scale(1.05); 41 | opacity: 1; 42 | } 43 | 44 | li { 45 | list-style: none; 46 | } 47 | 48 | a { 49 | text-decoration: none; 50 | height: fit-content; 51 | width: fit-content; 52 | } 53 | 54 | a:hover { 55 | opacity: 1; 56 | text-decoration: none; 57 | } 58 | -------------------------------------------------------------------------------- /src/renderer/App.tsx: -------------------------------------------------------------------------------- 1 | import { MemoryRouter as Router, Routes, Route } from 'react-router-dom'; 2 | import icon from '../../assets/icon.svg'; 3 | import './App.css'; 4 | import PlayGround from './components/PlayGround'; 5 | import Toolbox from './myblocks/Toolbox'; 6 | import { GlobalContext } from './config/globalContext'; 7 | // 引入的同时让所有自定义模块注入 8 | import './myblocks' 9 | import './utils/dialog' 10 | import { ConfigProvider, theme } from 'antd'; 11 | import { useEffect, useState } from 'react'; 12 | import { useLocalStorage } from './hooks/useLocal'; 13 | 14 | function BlocklyArea() { 15 | return ( 16 | 35 | initialXml={` 36 | 37 | 38 | `} 39 | > 40 | 41 | 42 | ); 43 | } 44 | 45 | export default function App() { 46 | 47 | const [language,setLanguage]=useState("cn") 48 | const [darktheme,setDarktheme]=useLocalStorage("darktheme",false) 49 | 50 | const [mytheme,setMytheme]=useLocalStorage("mytheme",{ 51 | algorithm:theme.defaultAlgorithm, 52 | }) 53 | 54 | useEffect(()=>{ 55 | if(!darktheme){ 56 | setMytheme({ 57 | algorithm:theme.defaultAlgorithm, 58 | }) 59 | }else{ 60 | setMytheme({ 61 | algorithm:theme.darkAlgorithm, 62 | }) 63 | } 64 | 65 | },[darktheme]) 66 | 67 | return ( 68 | 75 | 78 | 79 | 80 | } /> 81 | 82 | 83 | 84 | 85 | ); 86 | } 87 | -------------------------------------------------------------------------------- /src/renderer/components/PlayGround.css: -------------------------------------------------------------------------------- 1 | /* 顶部小工具栏 */ 2 | #toolsbox{ 3 | position:absolute; 4 | top:0; 5 | z-index: 999; 6 | text-align: right; 7 | right:0; 8 | height:22px; 9 | } 10 | #toolsbox button{ 11 | margin:0px 4px; 12 | /* height:25px; */ 13 | } 14 | 15 | #lefttools{ 16 | margin-right: 50px; 17 | } 18 | 19 | /* Playground区域 */ 20 | #blocklyDiv{ 21 | display:inline-block; 22 | width:100%; 23 | height:99%; 24 | } 25 | 26 | /* 给用户看生成的结果 */ 27 | #rescodebox{ 28 | position:absolute; 29 | right:0; 30 | top:150px; 31 | width:25%; 32 | height:60%; 33 | z-index: 10; 34 | border: 1px solid black; 35 | opacity: 0.8; 36 | } 37 | 38 | /* 修改input样式 */ 39 | .loadprojectbutton{ 40 | font-size:12px; 41 | overflow:hidden; 42 | /* width:98px; */ 43 | /* height: 25px; */ 44 | position: relative; 45 | } 46 | .projectfile{ 47 | /* width:98px; */ 48 | width:100%; 49 | height: 100%; 50 | overflow: hidden; 51 | /* height: 25px; */ 52 | position:absolute; 53 | top:0; 54 | left:0; 55 | z-index:100; 56 | opacity:0; 57 | filter:alpha(opacity=0); 58 | } 59 | 60 | /* 主界面右上角俩按钮 */ 61 | #toolsbox .settingbut{ 62 | color:rgb(67, 98, 153); 63 | margin:2px; 64 | font-size: 25px; 65 | height:50px; 66 | width: 60px; 67 | } 68 | #toolsbox .settingbut:hover{ 69 | cursor: pointer; 70 | font-size: 27px; 71 | border-color: gray; 72 | } 73 | 74 | /* 自定义blockly弹窗里的button样式 */ 75 | #customDialog{ 76 | margin:0 auto; 77 | padding:10px; 78 | width:400px; 79 | background-color: rgba(0, 0, 0, 0); 80 | } 81 | #customDialog .customDialogMessage{ 82 | color:gray; 83 | } 84 | #customDialog #customDialogInput{ 85 | width:100%; 86 | height:25px; 87 | } 88 | #customDialog .customDialogButtons{ 89 | display: flex; 90 | justify-content: space-between; 91 | } 92 | #customDialog .customDialogButtons button{ 93 | width:100px; 94 | height:30px; 95 | background-color: rgb(62, 128, 170); 96 | } -------------------------------------------------------------------------------- /src/renderer/components/SettingPage.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/src/renderer/components/SettingPage.css -------------------------------------------------------------------------------- /src/renderer/components/SettingPage.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Button, Row, Col, Popconfirm } from 'antd' 3 | import { 4 | DownloadOutlined, 5 | SaveOutlined, 6 | CodeOutlined, 7 | ContainerOutlined, 8 | SolutionOutlined, 9 | NotificationOutlined, 10 | BgColorsOutlined, 11 | UserOutlined, 12 | ProfileOutlined, 13 | CalendarOutlined 14 | } from '@ant-design/icons'; 15 | import "./SettingPage.css" 16 | 17 | 18 | export default function SettingPage({ 19 | version, 20 | loadProject, 21 | saveProject, 22 | openSourcePage, 23 | selectFilepath, 24 | downloadCode, 25 | getChattxt, 26 | getChatscript, 27 | changeTheme, 28 | darktheme, 29 | showtool, 30 | setShowtool, 31 | confirmclear 32 | }) { 33 | return ( 34 |
35 |
36 | 37 | 当前版本:{version} 38 | 39 | 40 |
41 | 导入/保存blockly项目 42 | 43 | 44 | 45 | 46 | 47 | 48 | {}} 53 | okText="清空!" 54 | cancelText="取消" 55 | > 56 | 57 | 58 | 59 | 60 |
61 | 导出脚本 62 | 63 | {window.wfilepath?<>当前自动导出: {window.wfilepath}:<>} 64 | 65 | 66 | {window.isinWebpageMode?<>:<>} 67 | 68 | 69 | 70 | {/*
71 | AI语音 72 | 73 | 74 | 75 | */} 76 |
77 | 显示模式 78 | 79 | 80 | 81 |
82 | 83 | 86 | 87 |
88 | ) 89 | } 90 | -------------------------------------------------------------------------------- /src/renderer/components/SourceGround.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/src/renderer/components/SourceGround.css -------------------------------------------------------------------------------- /src/renderer/components/SourceGround.js: -------------------------------------------------------------------------------- 1 | import React, { useEffect, useState } from 'react' 2 | import {Tabs, Input,Button, Upload} from 'antd' 3 | 4 | import BcgTab from './tabmenu/BcgTab' 5 | import BgmTab from './tabmenu/BgmTab' 6 | import CoverTab from './tabmenu/CoverTab' 7 | import SoundTab from './tabmenu/SoundTab' 8 | import SETab from './tabmenu/SETab' 9 | import SprTab from './tabmenu/SprTab' 10 | import HelpTab from './tabmenu/HelpTab' 11 | import {Howler} from 'howler' 12 | 13 | const {Search} = Input 14 | 15 | 16 | const itemstyle={height:document.body.clientHeight*0.75+"px",overflow:'auto'} 17 | 18 | /** 19 | * 给定五文件类型,构建tab列表 20 | * bgm,bcg,cover,sound,spr 21 | */ 22 | const buildItems=(itemlistmap)=>{ 23 | return [ 24 | { 25 | key: 'bgm', 26 | label: `背景音乐`, 27 | children: , 28 | }, 29 | { 30 | key: 'bcg', 31 | label: `背景图`, 32 | children: , 33 | }, 34 | { 35 | key: 'cover', 36 | label: `覆盖图`, 37 | children: , 38 | }, 39 | { 40 | key: 'sound', 41 | label: `音效`, 42 | children: , 43 | }, 44 | { 45 | key: 'sedesc', 46 | label: `音效速查`, 47 | children: , 48 | }, 49 | { 50 | key: 'spr', 51 | label: `人物`, 52 | children: , 53 | }, 54 | { 55 | key: 'help', 56 | label: `帮助`, 57 | children: , 58 | }, 59 | ] 60 | } 61 | 62 | function SourceGround(props) { 63 | 64 | // console.log(props.sourcemap) 65 | const loadData=props.loadData 66 | 67 | const [items,setItems] = useState(buildItems({ 68 | "bgm":props.sourcemap.get('bgm'), 69 | "bcg":props.sourcemap.get("bcg"), 70 | "cover":props.sourcemap.get("cover"), 71 | "sound":props.sourcemap.get("sound"), 72 | "spr":props.sourcemap.get("spr") 73 | })) 74 | 75 | useEffect(()=>{ 76 | setItems(buildItems({ 77 | "bgm":props.sourcemap.get('bgm'), 78 | "bcg":props.sourcemap.get("bcg"), 79 | "cover":props.sourcemap.get("cover"), 80 | "sound":props.sourcemap.get("sound"), 81 | "spr":props.sourcemap.get("spr") 82 | })) 83 | },[props.sourcemap]) 84 | 85 | const onSearch=(word)=>{ 86 | setItems(buildItems({ 87 | "bgm":[], 88 | "bcg":[], 89 | "cover":[], 90 | "sound":[], 91 | "spr":[], 92 | })) 93 | 94 | const searchword=word.toLowerCase() 95 | // console.log(searchword) 96 | let postlist=[[],[],[],[],[]]// 搜索结果 97 | const prelist=[props.sourcemap.get('bgm'),props.sourcemap.get('bcg'),props.sourcemap.get('cover'),props.sourcemap.get('sound'),props.sourcemap.get('spr')] 98 | if(word.length!==0){ 99 | // 搜索 100 | for(let listind in prelist){ 101 | const list=prelist[listind] 102 | for(let eachfile of list){ 103 | if(eachfile.name.toLowerCase().indexOf(searchword)!==-1){ 104 | postlist[listind].push(eachfile) 105 | } 106 | } 107 | } 108 | }else{ 109 | postlist=prelist 110 | } 111 | setTimeout(()=>{ 112 | setItems(buildItems({ 113 | "bgm":postlist[0], 114 | "bcg":postlist[1], 115 | "cover":postlist[2], 116 | "sound":postlist[3], 117 | "spr":postlist[4], 118 | })) 119 | },500) 120 | 121 | } 122 | 123 | return ( 124 |
125 | 126 | 127 | {Howler.stop()}}/> 130 |
131 | ) 132 | } 133 | 134 | export default SourceGround -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/BcgTab.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ImageTab from './sametype/ImageTab' 3 | 4 | export default function BcgTab(props) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/BgmTab.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import VoiceTab from './sametype/VoiceTab'; 3 | 4 | export default function BgmTab(props) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/CoverTab.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import ImageTab from './sametype/ImageTab' 3 | 4 | export default function CoverTab(props) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/HelpTab.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { Divider } from 'antd'; 3 | 4 | 5 | export default function HelpTab(props) { 6 | 7 | return ( 8 |
9 |

常见问题

10 | 11 | 12 |

素材导入后 AS控制台 "key does not exist in the dictionary"

13 | 素材昵称不应当有空格,最好是英文,顺便检查导入时和使用时是不是名字打的不一样
14 | 加载人物素材不需要打文件名后缀,其他导入都需要文件名后缀

15 | 错误示例: 加载人物昵称"日 富 美"人物对象 日富美 普通状态
16 | 正确示例: 加载人物昵称"rifumei"人物对象 日富美 普通状态
17 | 18 | 19 | 20 |

拖动积木区域会卡

21 | 积木多了会卡,卡的根本原因未知。建议使用鼠标滚轮来控制上下,按住Shift和滚鼠标滚轮来控制左右,减少屏幕渲染次数。 22 | 23 | 24 | 25 |

有些积木不知道怎么用

26 | 积木拽出来,鼠标悬停在上面会有提示,或者看可视化视频教程爱丽丝工坊文档或群里问人:647177204 27 | 28 | 29 | 30 |

预览脸部差分时位置不对

31 | 尝试切换‘识别脸部’与‘固定位置’两个模式,实在不行的话就取消面部差分,在普通模式下用人物右上角的Animation自己查看或用爱丽丝工坊的Preview 32 | 33 | 34 | 35 |

可视化预览素材失败或爱丽丝工坊加载素材失败

36 | 根据说明将文件放进正确的位置。注意spr文件夹是放游戏里spr人物素材的地方 37 | 38 | 39 | 40 | 41 |
) 42 | } 43 | -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/SETab.js: -------------------------------------------------------------------------------- 1 | import React,{useState} from 'react' 2 | import { sounds_datamap } from "../../datamap/index.js" 3 | import { Input,Table,Tag,Tooltip, message } from 'antd' 4 | import { QuestionCircleOutlined } from "@ant-design/icons" 5 | import { findneededFile } from 'renderer/utils/DataTool.jsx' 6 | import {Howl,Howler} from 'howler' 7 | import { getBase64 } from 'renderer/utils/imagetool' 8 | import copy from "copy-to-clipboard" 9 | 10 | 11 | 12 | const {Search}=Input 13 | 14 | 15 | const turnToRes=(datamap,judge)=>{ 16 | // 将datamap里的一对多转为一对一,对每个datamap元素判断judge 17 | const reslist=[] 18 | for(let sd of sounds_datamap){ 19 | if(judge(sd)){ 20 | for(let fn of sd.filenames){ 21 | reslist.push({ 22 | "filename":fn, 23 | "desc":sd.desc 24 | }) 25 | } 26 | } 27 | } 28 | return reslist 29 | } 30 | 31 | const playmusic=(file)=>{ 32 | getBase64(file).then((url)=>{ 33 | Howler.stop() 34 | const musicplayer=new Howl({src:url}) 35 | musicplayer.play() 36 | }) 37 | } 38 | 39 | /** 40 | * props.soundlist 41 | * props.style 42 | */ 43 | export default function SETab(props) { 44 | const soundlist=props.soundlist 45 | const [searchresult,setSearchresult]=useState(turnToRes(sounds_datamap,()=>{return true})) 46 | 47 | 48 | const columns=[ 49 | { 50 | title:"文件名", 51 | dataIndex:"filename", 52 | width:"40%", 53 | render:(_,{filename})=>{ 54 | return
{ 55 | message.destroy() 56 | message.success("复制成功") 57 | copy(filename) 58 | }}>{filename}
59 | } 60 | }, 61 | { 62 | title:"描述", 63 | dataIndex:"desc" 64 | }, 65 | { 66 | title:"操作", 67 | width:"20%", 68 | render:(_,record)=>{ 69 | return ( 70 | <> 71 | { 73 | const thatfile=findneededFile(soundlist,record.filename) 74 | if(thatfile){ 75 | playmusic(thatfile) 76 | }else{ 77 | message.destroy() 78 | message.error("未找到相关文件") 79 | } 80 | }} 81 | >播放 82 | 83 | ) 84 | } 85 | } 86 | ] 87 | 88 | const onSearch=(e)=>{ 89 | const reslist=turnToRes(sounds_datamap,(sd)=>{return sd.desc.includes(e)}) 90 | setSearchresult(reslist) 91 | } 92 | return ( 93 |
94 |
95 | 96 | 欢迎各位使用【Aris Studio】全音效一览表,此文本已整理当前版本的【Aris Studio】的全部音效【共2092条】来方便各位在使用【Aris Studio】时更快速地寻找所需要音效,由于所有注释均为本人聆听所标注的,有些差异,如果有更好的注释请告知整理者。此外该表还有一些其他不足之处,也欢迎使用者提出改进建议。 整合人:传猫猫
}> 97 | 98 | 99 |
100 | 101 | 105 | 106 | 107 | ) 108 | } 109 | -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/SoundTab.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import VoiceTab from './sametype/VoiceTab' 3 | 4 | export default function SoundTab(props) { 5 | return 6 | } 7 | -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/SprTab.css: -------------------------------------------------------------------------------- 1 | #basprbox{ 2 | 3 | } 4 | #ba-player{ 5 | 6 | } 7 | 8 | .stuname{ 9 | cursor: pointer; 10 | } 11 | 12 | .stuname:hover{ 13 | background-color: aliceblue; 14 | } 15 | 16 | .spine-player{ 17 | display: inline-block; 18 | } -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/sametype/ImageTab.js: -------------------------------------------------------------------------------- 1 | import React,{useEffect, useState} from 'react' 2 | import { Image,Pagination,Button,Typography, message } from 'antd' 3 | import { getBase64 } from 'renderer/utils/imagetool' 4 | import copy from "copy-to-clipboard" 5 | 6 | const {Text}=Typography 7 | 8 | /** 9 | * inputlist, 10 | * imgshape: 'square' 11 | * style 12 | */ 13 | export default function ImageTab(props) { 14 | 15 | const pagesize=Math.min(45,props.inputlist.length) 16 | const [page,setPage]=useState(1) 17 | // 图片data url 18 | let [srclist,setSrclist]=useState(new Array(pagesize)) 19 | // 图片名字 20 | let [namelist,setNamelist]=useState(new Array(pagesize)) 21 | const imgshape=props.imgshape 22 | 23 | useEffect(()=>{ 24 | // 先用error代替 25 | const errorarray=new Array(pagesize) 26 | errorarray.fill("") 27 | setSrclist(errorarray) 28 | const errornamearray=new Array(pagesize) 29 | errornamearray.fill("加载中") 30 | setNamelist(errornamearray) 31 | 32 | // 异步逐个加载 33 | props.inputlist.slice((page-1)*pagesize,page*pagesize).forEach((file,ind)=>{ 34 | getBase64(file).then((srcurl)=>{ 35 | const copysrclist=srclist 36 | copysrclist[ind]=srcurl 37 | setSrclist(copysrclist) 38 | const copynamelist=namelist 39 | copynamelist[ind]=file.name 40 | setNamelist(copynamelist) 41 | }) 42 | }) 43 | },[page,pagesize,props.inputlist]) 44 | 45 | return ( 46 | // 在props.style后追加会覆盖掉props.style 47 |
48 | {setPage(page)}} pageSize={pagesize} total={Math.max(props.inputlist.length,1)} style={{textAlign:'center'}}/> 49 | 50 | 51 |
52 |
53 | 54 | {srclist.map((each,ind)=>{ 55 | return 56 |
{imgshape==="square"?:}
57 | { 58 | copy(namelist[ind]) 59 | message.destroy() 60 | message.success("复制成功") 61 | }}>{namelist[ind]} 62 |
63 | })} 64 |
65 |
66 |
67 |
68 | ) 69 | } 70 | -------------------------------------------------------------------------------- /src/renderer/components/tabmenu/sametype/VoiceTab.js: -------------------------------------------------------------------------------- 1 | import React,{useEffect, useRef, useState} from 'react' 2 | import { Pagination, Button,Typography,message } from 'antd' 3 | import { 4 | CustomerServiceOutlined 5 | } from '@ant-design/icons'; 6 | import { getBase64 } from 'renderer/utils/imagetool' 7 | import {Howl,Howler} from 'howler' 8 | import copy from "copy-to-clipboard" 9 | 10 | 11 | const {Text}=Typography 12 | 13 | 14 | /** 15 | * props.inputlist 16 | * props.style 17 | */ 18 | export default function VoiceTab(props) { 19 | const pagesize=49 20 | const [page,setPage]=useState(1) 21 | let musicplayer; 22 | 23 | const playmusic=(file)=>{ 24 | getBase64(file).then((url)=>{ 25 | musicplayer?.stop() 26 | Howler.stop() 27 | musicplayer=new Howl({src:url}) 28 | musicplayer.play() 29 | }) 30 | } 31 | 32 | useEffect(()=>{ 33 | musicplayer?.stop() 34 | },[]) 35 | 36 | const musicplay=()=>{ 37 | Howler.stop() 38 | musicplayer?.play() 39 | } 40 | 41 | const musicpause=()=>{ 42 | Howler.stop() 43 | musicplayer?.pause() 44 | } 45 | 46 | const musicback=()=>{ 47 | if(musicplayer){ 48 | musicplayer.seek(Math.max(musicplayer.seek()-10,0)) 49 | } 50 | } 51 | 52 | const musicfront=()=>{ 53 | if(musicplayer){ 54 | musicplayer.seek(Math.min(musicplayer.seek()+10,musicplayer.duration())) 55 | } 56 | } 57 | 58 | return ( 59 | // 在props.style后追加会覆盖掉props.style 60 |
61 | {setPage(page)}} pageSize={pagesize} total={Math.max(props.inputlist.length,1)} style={{textAlign:'center'}}/> 62 | 63 | 64 |
65 |
66 | {props.inputlist.slice((page-1)*pagesize,page*pagesize).map((eachfile)=>{ 67 | return 68 |
69 | { 72 | copy(eachfile.name) 73 | message.destroy() 74 | message.success("复制成功") 75 | }}>{eachfile.name} 76 |
77 | {playmusic(eachfile)}}/> 78 | 79 |
80 | })} 81 |
82 |
83 |
84 | ) 85 | } 86 | -------------------------------------------------------------------------------- /src/renderer/config/globalContext.js: -------------------------------------------------------------------------------- 1 | import { createContext } from "react"; 2 | 3 | export const GlobalContext=createContext() -------------------------------------------------------------------------------- /src/renderer/config/version.js: -------------------------------------------------------------------------------- 1 | const version="0.3.0-alpha.1"; 2 | 3 | export default version -------------------------------------------------------------------------------- /src/renderer/datamap/index.js: -------------------------------------------------------------------------------- 1 | import studentsjson from "./rawjson/students.json"; 2 | import soundsjson from "./rawjson/sound.json" 3 | 4 | 5 | 6 | 7 | 8 | // 封装人物名字和素材对应表 9 | export const students_datamap=[] 10 | for(let stu of studentsjson.students){ 11 | if(stu.sprName.startsWith("CH")||stu.sprName.startsWith("NP")){ 12 | // 中文名,素材名 13 | // CH和NP开头的文件名不转小写 14 | students_datamap.push([ 15 | stu.zhName.replace(/ /g,"").toLowerCase(), 16 | stu.sprName.replace(/ /g,"") 17 | ]) 18 | }else{ 19 | // 其他文件名全转小写 20 | students_datamap.push([ 21 | stu.zhName.replace(/ /g,"").toLowerCase(), 22 | stu.sprName.replace(/ /g,"").toLowerCase() 23 | ]) 24 | } 25 | 26 | } 27 | 28 | // 封装人物名字和素材的键值对对应表,文件名改小写 29 | const student_datadict={} 30 | for(let stu of studentsjson.students){ 31 | student_datadict[stu.sprName.toLowerCase()]=stu.zhName 32 | } 33 | /** 34 | * 给定spr文件名,不含后缀。返回中文名 35 | */ 36 | export function getcnnameof(filename){ 37 | const lowfilename=filename.toLowerCase() 38 | if(student_datadict[lowfilename]){ 39 | return student_datadict[lowfilename] 40 | } 41 | return "" 42 | } 43 | 44 | // 音效 45 | export const sounds_datamap=soundsjson.sounds -------------------------------------------------------------------------------- /src/renderer/hooks/useLocal.js: -------------------------------------------------------------------------------- 1 | import { useEffect, useState } from 'react' 2 | 3 | const PREFIX = 'local-' 4 | 5 | /** 6 | * 使用localstorage 7 | */ 8 | export function useLocalStorage(key, initialValue) { 9 | const prefixedKey = PREFIX + key 10 | 11 | const [value, setValue] = useState(() => { 12 | const jsonValue = localStorage.getItem(prefixedKey) 13 | if (jsonValue != null) return JSON.parse(jsonValue) 14 | if (typeof initialValue === 'function') { 15 | return initialValue() 16 | } else { 17 | return initialValue 18 | } 19 | }) 20 | 21 | useEffect(() => { 22 | localStorage.setItem(prefixedKey, JSON.stringify(value)) 23 | }, [prefixedKey, value]) 24 | 25 | return [value, setValue] 26 | } 27 | -------------------------------------------------------------------------------- /src/renderer/index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 10 | ArisStudio Blockly 11 | 12 | 13 | 14 |
15 | 16 | 17 | -------------------------------------------------------------------------------- /src/renderer/index.tsx: -------------------------------------------------------------------------------- 1 | import { createRoot } from 'react-dom/client'; 2 | import App from './App'; 3 | 4 | const container = document.getElementById('root')!; 5 | const root = createRoot(container); 6 | root.render(); 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/renderer/media/blockly/sprites.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/src/renderer/media/blockly/sprites.png -------------------------------------------------------------------------------- /src/renderer/media/document/cover.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/src/renderer/media/document/cover.png -------------------------------------------------------------------------------- /src/renderer/media/document/easystart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sanmusen214/arisstudio-blockly/7dc799ea4d3cb1aa9fcdcfed29205eebc7633613/src/renderer/media/document/easystart.png -------------------------------------------------------------------------------- /src/renderer/models/README.md: -------------------------------------------------------------------------------- 1 | # 命令对应文件 2 | 3 | 在积木定义块那边做非法判断 4 | 默认值也在积木定义块里设 5 | 每个积木块的文件夹内的index取消注释即为更新完毕,不要动文件名 6 | 7 | ## 加载(loadcmd.js) 8 | 9 | 加载spr角色 10 | 加载自定义角色 11 | (等)加载 png 角色 12 | 加载 前景/中景/背景 图片 13 | 加载 音效/背景音乐 14 | 15 | ## 图片(imgcmd.js) 16 | 17 | 带有渐变高亮的 显示/隐藏 18 | 直接 出现/消失 19 | 透明度变化 20 | 单独设置 x/y/z 坐标 21 | 设置 x/y 坐标 22 | x/y 轴单独移动 23 | 在 x 和 y 轴移动 24 | x/y 轴抖动 25 | 随机方向抖动 26 | 在 x 和 y 轴同时缩放 27 | 28 | ## 角色(charcmd.js) 29 | 30 | 带有渐变高亮的 显示/隐藏 31 | 直接 出现/消失 32 | 高亮 33 | 透明度变化 34 | 状态 35 | 皮肤 36 | 表情 37 | 设置角色动画 (暂不可用) 38 | 单独设置 x/y/z 坐标 39 | 设置 x/y 坐标 40 | x/y 轴单独移动 41 | 在 x 和 y 轴移动 42 | x/y 轴抖动 43 | 随机方向抖动 44 | 在 x 和 y 轴同时缩放 45 | 常用缩放 靠近/返回 46 | 47 | ## 声音(soundcmd.js) 48 | 49 | 播放 50 | 暂停 51 | 结束 52 | 音量 53 | 音量渐变 54 | 循环 55 | 播放一次 56 | 57 | ## 场景命令(scenecmd.js) 58 | 59 | 注视线效果 60 | 烟雾效果 61 | 雨效果 62 | 雪效果 63 | 沙尘效果 64 | 未完继续(暂不可用) 65 | 结束(暂不可用) 66 | 启用/禁用场景音效(暂不可用) 67 | 68 | ## 选择命令(selectcmd.js) 69 | 70 | 一个选择框 71 | 两个选择框 72 | 三个选择框 73 | 74 | ## 特殊命令(specialcmd.js) 75 | 76 | 注释 77 | 断点 78 | 等待 79 | 标记 80 | 显示所有标记 81 | 跳转 82 | 设置自动播放速度 83 | 切换脚本 84 | 85 | ## 文本命令(textcmd.js) 86 | 87 | 隐藏文本 88 | 设置打字机效果时间间隔 89 | 隐藏所有文本框 90 | 默认文本框 91 | 设置文本内容 92 | 设置文本内容并不带断点 93 | 设置文本内容并高亮指定人物 94 | 设置文本内容并高亮指定人物,不带断点 95 | 中部文本框 96 | 设置文本内容 97 | 设置文本内容并不带断点 98 | 底部文本框 99 | 设置文本内容 100 | 设置文本内容并不带断点 101 | 小标题 102 | 横幅 -------------------------------------------------------------------------------- /src/renderer/models/charcmd.ts: -------------------------------------------------------------------------------- 1 | class myChar{ 2 | /** 3 | * 带有渐变高亮的 显示show/隐藏hide 4 | */ 5 | show=(nameId:string,type:string)=>{ 6 | return `${nameId} ${type}` 7 | } 8 | 9 | 10 | /** 11 | * 直接出现appear/消失disappear 12 | */ 13 | appear=(nameId:string,type:string)=>{ 14 | return `${nameId} ${type}` 15 | } 16 | 17 | /** 18 | * @param action show渐入/hide渐出/appear直接出现/disappear直接消失 19 | */ 20 | display=(nameId:string, action:string)=>{ 21 | return `${nameId} ${action}` 22 | } 23 | 24 | /** 25 | * 高亮 26 | */ 27 | highlight=(nameId:string,hl,time=0)=>{ 28 | return `${nameId} hl ${hl} ${time}` 29 | } 30 | 31 | /** 32 | * 透明度变化 33 | */ 34 | 35 | /** 36 | * 状态 37 | */ 38 | state=(nameId:string,state:string)=>{ 39 | return `${nameId} state ${state}` 40 | } 41 | 42 | /** 43 | * 皮肤 44 | */ 45 | skin=(nameId:string,skin:string)=>{ 46 | return `${nameId} skin ${skin}` 47 | } 48 | 49 | /** 50 | * 表情 51 | */ 52 | emo=(nameId:string,emo:string)=>{ 53 | return `${nameId} emo ${emo}` 54 | } 55 | 56 | /** 57 | * 设置角色动画 58 | */ 59 | 60 | /** 61 | * x,y位置 62 | */ 63 | posxy=(nameId:string,x:number,y:number)=>{ 64 | return `${nameId} pos ${x} ${y}` 65 | } 66 | 67 | /** 68 | * 单独设x,y,z位置 69 | * @param pos "x"/"y"/"z" 70 | */ 71 | pos=(nameId:string,pos:string,value:number)=>{ 72 | return `${nameId} ${pos} ${value}` 73 | } 74 | 75 | /** 76 | * 在 x 和 y 轴移动 77 | */ 78 | movexy=(nameId:string,x:number,y:number,time:number)=>{ 79 | return `${nameId} pm ${x} ${y} ${time}` 80 | } 81 | 82 | /** 83 | * x/y 轴移动 84 | * @param pos "xm"/"ym" 85 | */ 86 | move=(nameId:string,pos:string,value:number,time:number)=>{ 87 | return `${nameId} ${pos} ${value} ${time}` 88 | } 89 | 90 | /** 91 | * 固定轴抖动 92 | * @param type "xs"/"ys" 93 | */ 94 | shake=(nameId:string,type:string,strength:number,time:number=0.5,vibrato:number=6)=>{ 95 | return `${nameId} ${type} ${strength} ${time} ${vibrato}` 96 | } 97 | 98 | /** 99 | * 随机抖动 100 | */ 101 | shakerandom=(nameId:string,strength:number,time:number=0.5,vibrato:number=6)=>{ 102 | return `${nameId} shake ${strength} ${time} ${vibrato}` 103 | } 104 | 105 | /** 106 | * 缩放 107 | */ 108 | scale=(nameId:string,scale:number,time:number=0)=>{ 109 | return `${nameId} scale ${scale} ${time}` 110 | } 111 | 112 | /** 113 | * 靠近/返回 114 | * @param type "close"/"back" 115 | */ 116 | movein=(nameId:string,type:string)=>{ 117 | return `${nameId} ${type}` 118 | } 119 | 120 | nod=(nameId:string)=>{ 121 | return this.shake(nameId,"ys",-3,1,6) 122 | } 123 | 124 | jump=(nameId:string)=>{ 125 | return this.shake(nameId,"ys",3,1,6) 126 | } 127 | 128 | jump2=(nameId:string)=>{ 129 | return this.shake(nameId,"ys",3,1,6) 130 | } 131 | 132 | sshake=(nameId:string)=>{ 133 | return this.shake(nameId,"xs",3,1,6) 134 | } 135 | 136 | bshake=(nameId:string)=>{ 137 | return this.shake(nameId,"xs",3,1,6) 138 | } 139 | 140 | } 141 | 142 | const myCharer=new myChar(); 143 | export default myCharer; -------------------------------------------------------------------------------- /src/renderer/models/imgcmd.ts: -------------------------------------------------------------------------------- 1 | class myImage{ 2 | /** 3 | * 渐入 4 | * @param nameId 素材昵称 5 | */ 6 | show=(nameId)=>{ 7 | return `${nameId} show` 8 | } 9 | 10 | /** 11 | * 渐出 12 | * @param nameId 素材昵称 13 | */ 14 | hide=(nameId)=>{ 15 | return `${nameId} show` 16 | } 17 | 18 | /** 19 | * 直接出现 20 | * @param nameId 素材昵称 21 | */ 22 | appear=(nameId)=>{ 23 | return `${nameId} appear` 24 | } 25 | 26 | /** 27 | * 直接消失 28 | * @param nameId 素材昵称 29 | */ 30 | disappear=(nameId)=>{ 31 | return `${nameId} disappear` 32 | } 33 | 34 | /** 35 | * @param action show渐入/hide渐出/appear直接出现/disappear直接消失 36 | */ 37 | display=(nameId, action)=>{ 38 | return `${nameId} ${action}` 39 | } 40 | 41 | /** 42 | * 透明度变化 43 | * @param nameId 素材昵称 44 | * @param alpha 0~1 透明度 45 | * @param time 渐变时间 46 | */ 47 | fade=(nameId, alpha:number, time:number=0)=>{ 48 | return `${nameId} fade ${alpha} ${time}` 49 | } 50 | 51 | /** 52 | * 单独设置x/y/z坐标 53 | * @param nameId 素材昵称 54 | * @param axis x/y/z 55 | * @param value 值 56 | */ 57 | setaxis=(nameId, axis, value:number)=>{ 58 | return `${nameId} ${axis} ${value}` 59 | } 60 | 61 | /** 62 | * 设置x,y坐标 63 | * @param nameId 素材昵称 64 | * @param x 坐标 65 | * @param y 坐标 66 | */ 67 | position=(nameId, x:number, y:number)=>{ 68 | return `${nameId} ${x} ${y}` 69 | } 70 | 71 | /** 72 | * 单独沿着x/y移动 73 | * @param nameId 素材昵称 74 | * @param axis xm/ym 75 | * @param value 值 76 | * @param time 时间 77 | */ 78 | moveaxis=(nameId, axis, value:number, time:number=0.5)=>{ 79 | return `${nameId} ${axis} ${value} ${time}` 80 | } 81 | 82 | /** 83 | * x,y平面移动 84 | * @param nameId 素材昵称 85 | * @param x 值 86 | * @param y 值 87 | * @param time 时间 88 | */ 89 | moveposition=(nameId, x:number, y:number, time:number=0.5)=>{ 90 | return `${nameId} pm ${x} ${y} ${time}` 91 | } 92 | 93 | /** 94 | * x/y 轴抖动 95 | * @param nameId 昵称 96 | * @param axis xs/ys 97 | * @param strength 抖动强度 98 | * @param time 时间 99 | * @param vibrato 抖动频率 100 | */ 101 | shakeaxis=(nameId, axis, strength:number, time:number=0.5, vibrato:number=6)=>{ 102 | return `${nameId} ${axis} ${strength} ${time} ${vibrato}` 103 | } 104 | 105 | /** 106 | * 随机抖动 107 | * @param nameId 昵称 108 | * @param strength 抖动强度 109 | * @param time 时间 110 | * @param vibrato 抖动频率 111 | */ 112 | shakerandom=(nameId, strength, time:number=0.5, vibrato:number=6)=>{ 113 | return `${nameId} shake ${strength} ${time} ${vibrato}` 114 | } 115 | 116 | 117 | /** 118 | * 在 x 和 y 轴同时缩放 119 | * @param nameId 昵称 120 | * @param value 值 121 | * @param time 时间 122 | */ 123 | scale=(nameId, value:number, time:number=0)=>{ 124 | return `${nameId} scale ${value} ${time}` 125 | } 126 | 127 | } 128 | 129 | const myImager=new myImage() 130 | export default myImager -------------------------------------------------------------------------------- /src/renderer/models/loadcmd.ts: -------------------------------------------------------------------------------- 1 | class myLoad{ 2 | /** 3 | * 加载spr角色 4 | * @param type spr:默认,sprc:通讯 5 | * @param nameId 素材昵称 6 | * @param sprName 素材文件名称 7 | */ 8 | loadspr=(type, nameId, sprName)=>{ 9 | return `load ${type} ${nameId} ${sprName}` 10 | } 11 | 12 | /** 13 | * 加载自定义spr角色 14 | * @param type spr:默认,sprc:通讯 15 | * @param nameId 人物昵称 16 | * @param scale 缩放 17 | * @param idle 空闲状态 18 | * @param sprName 素材文件名称,带后缀 19 | * @param imageList 图片列表 20 | */ 21 | loaddefspr=(type, nameId, scale:number, idle, sprName, imageList)=>{ 22 | return `load ${type} ${nameId} ${scale} ${idle} ${sprName} ${imageList}` 23 | } 24 | 25 | /** 26 | * 加载 png 角色 27 | */ 28 | 29 | 30 | 31 | /** 32 | * 加载 前景/中景/背景 图片 33 | * @param type fg前/mg中/bg背景/sfx音效/bgm背景音乐 34 | * @param nameId 素材昵称 35 | * @param fileName 文件名带后缀 36 | */ 37 | load=(type, nameId, fileName)=>{ 38 | return `load ${type} ${nameId} ${fileName}` 39 | } 40 | } 41 | 42 | const myLoader=new myLoad() 43 | export default myLoader -------------------------------------------------------------------------------- /src/renderer/models/scenecmd.ts: -------------------------------------------------------------------------------- 1 | class Myscene{ 2 | 3 | /** 4 | * @param type focus/smoke/rain/snow/dust 5 | * @param state show/hide 6 | */ 7 | scene=(type:string,state:string)=>{ 8 | return `sc ${type} ${state}` 9 | } 10 | 11 | /** 12 | * 未完继续 13 | */ 14 | 15 | continue=()=>{ 16 | return `sc continue` 17 | } 18 | 19 | /** 20 | * 结束 21 | */ 22 | end=(text:string)=>{ 23 | return `sc end ${text}` 24 | } 25 | /** 26 | * 启用/禁用场景音效 27 | */ 28 | } 29 | 30 | const myScener=new Myscene(); 31 | export default myScener; -------------------------------------------------------------------------------- /src/renderer/models/selectcmd.ts: -------------------------------------------------------------------------------- 1 | class Myselect{ 2 | // 直接积木里用select字 3 | } 4 | -------------------------------------------------------------------------------- /src/renderer/models/soundcmd.ts: -------------------------------------------------------------------------------- 1 | class Mysound{ 2 | 3 | /** 4 | * 播放/暂停 5 | * @param nameId 声音名称 6 | * @param type "play"/"pause"/"stop" 7 | */ 8 | play=(nameId:string,type:string)=>{ 9 | return `${nameId} ${type}` 10 | } 11 | 12 | /** 13 | * 音量设置 14 | */ 15 | volume=(nameId:string,value:number)=>{ 16 | return `${nameId} volume ${value}` 17 | } 18 | 19 | /** 20 | * 音量渐变 21 | */ 22 | fade=(nameId:string,value:number,time:number)=>{ 23 | return `${nameId} fade ${value} ${time}` 24 | } 25 | 26 | /** 27 | * 循环/一次 28 | * @param type "loop"/"once" 29 | */ 30 | loop=(nameId:string,type:string)=>{ 31 | return `${nameId} ${type}` 32 | } 33 | 34 | } 35 | const mySounder=new Mysound(); 36 | export default mySounder; -------------------------------------------------------------------------------- /src/renderer/models/specialcmd.ts: -------------------------------------------------------------------------------- 1 | class Myspecial{ 2 | /** 3 | * 注释 4 | */ 5 | spec=(text:string)=>{ 6 | return `//${text}` 7 | } 8 | /** 9 | * 断点 10 | */ 11 | breakpoint=()=>{ 12 | return `==` 13 | } 14 | /** 15 | * 等待 16 | */ 17 | wait=(time:number)=>{ 18 | return `wait ${time}` 19 | } 20 | 21 | /** 22 | * 标记 23 | */ 24 | target=(name:string)=>{ 25 | return `target ${name}` 26 | } 27 | 28 | /** 29 | * 显示所有标记 30 | */ 31 | showtarget=()=>{ 32 | `targets` 33 | } 34 | 35 | /** 36 | * 跳转 37 | */ 38 | jump=(name:string)=>{ 39 | return `jump ${name}` 40 | } 41 | 42 | /** 43 | * 设置自动播放速度 44 | */ 45 | autoplay=(speed:number)=>{ 46 | return `auto ${speed}` 47 | } 48 | 49 | /** 50 | * 切换脚本 51 | */ 52 | switch=(filename:string)=>{ 53 | return `switch ${filename}` 54 | } 55 | } 56 | const mySpecialer=new Myspecial(); 57 | export default mySpecialer; -------------------------------------------------------------------------------- /src/renderer/models/textcmd.ts: -------------------------------------------------------------------------------- 1 | class Mytext{ 2 | /** 3 | * 隐藏文本 4 | */ 5 | hidetext=()=>{ 6 | return `text hide` 7 | } 8 | 9 | /** 10 | * 设置打字机效果时间间隔 11 | */ 12 | textinterval=(time:number)=>{ 13 | return `text interval ${time}` 14 | } 15 | 16 | /** 17 | * 隐藏所有文本框 18 | */ 19 | hidealltext=()=>{ 20 | return `text hide` 21 | } 22 | 23 | /** 24 | * 设置文本内容 25 | * @param iscontinue 是否连续,true时不带断点,false时带断点 26 | */ 27 | text=(name:string,group:string,text:string,iscontinue:boolean)=>{ 28 | if(iscontinue){ 29 | return `tc '${name}' '${group}' '${text}'` 30 | }else{ 31 | return `t '${name}' '${group}' '${text}'` 32 | } 33 | 34 | } 35 | 36 | /** 37 | * 设置文本内容并高亮指定人物 38 | * @param iscontinue 是否连续,true时不带断点,false时带断点 39 | */ 40 | texthighlight=(nameId:string,name:string,group:string,text:string,iscontinue:boolean)=>{ 41 | if(iscontinue){ 42 | return `thc ${nameId} '${name}' '${group}' '${text}'` 43 | }else{ 44 | return `th ${nameId} '${name}' '${group}' '${text}'` 45 | } 46 | 47 | } 48 | 49 | /** 50 | * 文本框 设置文本内容 51 | * @param position middle:画面中间 bottom:底部 52 | * @param iscontinue 是否连续,true时不带断点,false时带断点 53 | * 54 | */ 55 | sidetext=(text:string,position:string,iscontinue:boolean)=>{ 56 | if(position==="middle"){ 57 | if(iscontinue){ 58 | return `mtc '${text}'` 59 | }else{ 60 | return `mt '${text}'` 61 | } 62 | }else{ 63 | if(iscontinue){ 64 | return `btc '${text}'` 65 | }else{ 66 | return `bt '${text}'` 67 | } 68 | } 69 | 70 | } 71 | 72 | /** 73 | * 小标题 74 | */ 75 | label=(text:string)=>{ 76 | return `label '${text}'` 77 | } 78 | 79 | /** 80 | * 一行横幅 81 | */ 82 | banner=(textmain:string)=>{ 83 | return `banner '${textmain}'` 84 | } 85 | 86 | /** 87 | * 两行横幅 88 | */ 89 | banner2=(textmain:string,textside:string)=>{ 90 | return `banner '${textside}' '${textmain}'` 91 | } 92 | 93 | /** 94 | * 三行横幅 95 | */ 96 | banner3=(textmain:string,textside:string,textside2:string)=>{ 97 | return `banner '${textside}' '${textside2}' '${textmain}'` 98 | } 99 | } 100 | const myTexter=new Mytext(); 101 | export default myTexter; -------------------------------------------------------------------------------- /src/renderer/myblocks/01load/Menu01.jsx: -------------------------------------------------------------------------------- 1 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 2 | 3 | import React from 'react' 4 | 5 | export default function Menu01() { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | ) 27 | } 28 | -------------------------------------------------------------------------------- /src/renderer/myblocks/01load/b_load_pic.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myLoader from 'renderer/models/loadcmd' 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_load_pic" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "加载%1图片 昵称 %2 文件名 %3", 11 | "args0": [ 12 | { 13 | "type": "field_dropdown", 14 | "name": "drop1", 15 | "options": [ 16 | ["背景","bg"], 17 | ["中景","mg"], 18 | ["前景","fg"], 19 | ] 20 | }, 21 | { 22 | "type": "input_value", 23 | "name": "val1", 24 | "check": "String" 25 | }, 26 | { 27 | "type": "input_value", 28 | "name": "val2", 29 | "check": "String" 30 | } 31 | ], 32 | "inputsInline": true, 33 | "previousStatement": null, 34 | "nextStatement": null, 35 | "colour": 230, 36 | "tooltip": "前景图片文件需要放在 /data/image/foreground 文件夹中\n中景图片文件需要放在 /data/image/midground 文件夹中\n背景图片文件需要放在 /data/image/background 文件夹中", 37 | "helpUrl": "" 38 | } 39 | 40 | // 注入自定义模块 41 | Blockly.Blocks[blockname] = { 42 | init: function () { 43 | this.jsonInit(jsondesc); 44 | } 45 | } 46 | 47 | // 为自定义块添加js语言生成器 48 | javascriptGenerator[blockname] = function (block) { 49 | const type = block.getFieldValue('drop1'); 50 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 51 | const filename = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 52 | 53 | 54 | return `stagelist.push(\`${myLoader.load(type,wrapStr(nickname),wrapStr(filename))}\`);` 55 | } 56 | 57 | -------------------------------------------------------------------------------- /src/renderer/myblocks/01load/b_load_sound.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myLoader from 'renderer/models/loadcmd' 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_load_sound" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "加载%1声音 昵称 %2 文件名 %3", 11 | "args0": [ 12 | { 13 | "type": "field_dropdown", 14 | "name": "drop1", 15 | "options": [ 16 | ["背景","bgm"], 17 | ["音效","sfx"] 18 | ] 19 | }, 20 | { 21 | "type": "input_value", 22 | "name": "val1", 23 | "check": "String" 24 | }, 25 | { 26 | "type": "input_value", 27 | "name": "val2", 28 | "check": "String" 29 | } 30 | ], 31 | "inputsInline": true, 32 | "previousStatement": null, 33 | "nextStatement": null, 34 | "colour": 230, 35 | "tooltip": "音效文件需要放在 /data/audio/sfx 文件夹中\n背景音乐文件需要放在 /data/audio/bgm 文件夹中\n音效默认播放一次,背景音乐默认循环播放", 36 | "helpUrl": "" 37 | } 38 | 39 | // 注入自定义模块 40 | Blockly.Blocks[blockname] = { 41 | init: function () { 42 | this.jsonInit(jsondesc); 43 | } 44 | } 45 | 46 | // 为自定义块添加js语言生成器 47 | javascriptGenerator[blockname] = function (block) { 48 | const type = block.getFieldValue('drop1'); 49 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 50 | const filename = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 51 | 52 | 53 | return `stagelist.push(\`${myLoader.load(type,wrapStr(nickname),wrapStr(filename))}\`);` 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/renderer/myblocks/01load/b_load_student.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myLoader from 'renderer/models/loadcmd' 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_load_student" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "加载人物 昵称 %1 spr名 %2 %3", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | { 18 | "type": "input_value", 19 | "name": "val2", 20 | "check": "String" 21 | }, 22 | { 23 | "type": "field_dropdown", 24 | "name": "drop1", 25 | "options": [ 26 | ["普通状态","spr"], 27 | ["通讯状态","sprc"], 28 | ] 29 | }, 30 | ], 31 | "inputsInline": true, 32 | "previousStatement": null, 33 | "nextStatement": null, 34 | "colour": 230, 35 | "tooltip": "spine 角色素材需要放在 /data/character/spr 文件夹中", 36 | "helpUrl": "" 37 | } 38 | 39 | // 注入自定义模块 40 | Blockly.Blocks[blockname] = { 41 | init: function () { 42 | this.jsonInit(jsondesc); 43 | } 44 | } 45 | 46 | // 为自定义块添加js语言生成器 47 | javascriptGenerator[blockname] = function (block) { 48 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 49 | const sprname = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 50 | const state = block.getFieldValue('drop1'); 51 | 52 | return `stagelist.push(\`${myLoader.loadspr(state,wrapStr(nickname),wrapStr(sprname))}\`);` 53 | } 54 | 55 | -------------------------------------------------------------------------------- /src/renderer/myblocks/01load/b_load_studentselect.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myLoader from 'renderer/models/loadcmd' 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | import { students_datamap } from 'renderer/datamap'; 6 | // 定义JSON格式自定义模块 7 | let blockname="b_load_studentselect" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "加载人物 昵称 %1 spr名 %2 %3", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": students_datamap 22 | }, 23 | { 24 | "type": "field_dropdown", 25 | "name": "drop2", 26 | "options": [ 27 | ["普通状态","spr"], 28 | ["通讯状态","sprc"], 29 | ] 30 | }, 31 | ], 32 | "inputsInline": true, 33 | "previousStatement": null, 34 | "nextStatement": null, 35 | "colour": 230, 36 | "tooltip": "spine 角色素材需要放在 /data/character/spr 文件夹中", 37 | "helpUrl": "" 38 | } 39 | 40 | // 注入自定义模块 41 | Blockly.Blocks[blockname] = { 42 | init: function () { 43 | this.jsonInit(jsondesc); 44 | } 45 | } 46 | 47 | // 为自定义块添加js语言生成器 48 | javascriptGenerator[blockname] = function (block) { 49 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 50 | const sprname = block.getFieldValue('drop1'); 51 | const state = block.getFieldValue('drop2'); 52 | 53 | return `stagelist.push(\`${myLoader.loadspr(state,wrapStr(nickname),sprname)}\`);` 54 | } 55 | 56 | -------------------------------------------------------------------------------- /src/renderer/myblocks/01load/index.jsx: -------------------------------------------------------------------------------- 1 | import "./b_load_student" 2 | import "./b_load_studentselect" 3 | import "./b_load_pic" 4 | import "./b_load_sound" 5 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/Menu02.jsx: -------------------------------------------------------------------------------- 1 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 2 | 3 | import React from 'react' 4 | 5 | export default function Menu02() { 6 | return ( 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | ) 32 | } 33 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/b_pic_alpha.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myImager from 'renderer/models/imgcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_pic_alpha" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "图片昵称 %1 渐变至透明度 %2, 耗时 %3 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": 0, 22 | "value": 0, 23 | "max": 1, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": 0, 30 | "value": 0, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | ], 35 | "inputsInline": true, 36 | "previousStatement": null, 37 | "nextStatement": null, 38 | "colour": 230, 39 | "tooltip": "", 40 | "helpUrl": "" 41 | } 42 | 43 | // 注入自定义模块 44 | Blockly.Blocks[blockname] = { 45 | init: function () { 46 | this.jsonInit(jsondesc); 47 | } 48 | } 49 | 50 | // 为自定义块添加js语言生成器 51 | javascriptGenerator[blockname] = function (block) { 52 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 53 | const alpha = block.getFieldValue('num1'); 54 | const spendtime = block.getFieldValue('num2'); 55 | 56 | 57 | 58 | return `stagelist.push(\`${myImager.fade(wrapStr(nickname),alpha,spendtime)}\`);` 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/b_pic_display.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myImager from 'renderer/models/imgcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_pic_display" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "图片昵称 %1 %2", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["渐入","show"], 23 | ["渐出","hide"], 24 | ["显示","appear"], 25 | ["隐藏","disappear"], 26 | ] 27 | }, 28 | ], 29 | "inputsInline": true, 30 | "previousStatement": null, 31 | "nextStatement": null, 32 | "colour": 230, 33 | "tooltip": "", 34 | "helpUrl": "" 35 | } 36 | 37 | // 注入自定义模块 38 | Blockly.Blocks[blockname] = { 39 | init: function () { 40 | this.jsonInit(jsondesc); 41 | } 42 | } 43 | 44 | // 为自定义块添加js语言生成器 45 | javascriptGenerator[blockname] = function (block) { 46 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 47 | const action = block.getFieldValue('drop1'); 48 | 49 | return `stagelist.push(\`${myImager.display(wrapStr(nickname),action)}\`);` 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/b_pic_move.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myImager from 'renderer/models/imgcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_pic_move" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "图片昵称 %1 移动至 %2 的 %3, 耗时 %4 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["x轴","xm"], 23 | ["y轴","ym"], 24 | ["z轴","zm"] 25 | ] 26 | }, 27 | { 28 | "type": "field_number", 29 | "name": "num1", 30 | "min": -1000, 31 | "value": 0, 32 | "max": 1000, 33 | "precision": 0.1, 34 | }, 35 | { 36 | "type": "field_number", 37 | "name": "num2", 38 | "min": 0, 39 | "value": 0, 40 | "max": 1000, 41 | "precision": 0.1, 42 | }, 43 | ], 44 | "inputsInline": true, 45 | "previousStatement": null, 46 | "nextStatement": null, 47 | "colour": 230, 48 | "tooltip": "", 49 | "helpUrl": "" 50 | } 51 | 52 | // 注入自定义模块 53 | Blockly.Blocks[blockname] = { 54 | init: function () { 55 | this.jsonInit(jsondesc); 56 | } 57 | } 58 | 59 | // 为自定义块添加js语言生成器 60 | javascriptGenerator[blockname] = function (block) { 61 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 62 | const axis = block.getFieldValue('drop1'); 63 | const distance = block.getFieldValue('num1'); 64 | const spendtime = block.getFieldValue('num2'); 65 | 66 | if(axis==="zm"){ 67 | // z轴移动没有时间参数 68 | return `stagelist.push(\`${myImager.setaxis(wrapStr(nickname),"z",distance)}\`);` 69 | } 70 | 71 | 72 | 73 | return `stagelist.push(\`${myImager.moveaxis(wrapStr(nickname),axis,distance,spendtime)}\`);` 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/b_pic_movexy.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myImager from 'renderer/models/imgcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_pic_movexy" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "图片昵称 %1 移动至横轴: %2 纵轴: %3, 耗时 %4 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": -1000, 22 | "value": 0, 23 | "max": 1000, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": -1000, 30 | "value": 0, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | { 35 | "type": "field_number", 36 | "name": "num3", 37 | "min": 0, 38 | "value": 0, 39 | "max": 100, 40 | "precision": 0.1, 41 | }, 42 | ], 43 | "inputsInline": true, 44 | "previousStatement": null, 45 | "nextStatement": null, 46 | "colour": 230, 47 | "tooltip": "", 48 | "helpUrl": "" 49 | } 50 | 51 | // 注入自定义模块 52 | Blockly.Blocks[blockname] = { 53 | init: function () { 54 | this.jsonInit(jsondesc); 55 | } 56 | } 57 | 58 | // 为自定义块添加js语言生成器 59 | javascriptGenerator[blockname] = function (block) { 60 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 61 | const axis = block.getFieldValue('drop1'); 62 | const xx = block.getFieldValue('num1'); 63 | const yy = block.getFieldValue('num2'); 64 | const spendtime = block.getFieldValue('num3'); 65 | 66 | 67 | return `stagelist.push(\`${myImager.moveposition(wrapStr(nickname),xx,yy,spendtime)}\`);` 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/b_pic_scale.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myImager from 'renderer/models/imgcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_pic_scale" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "图片昵称 %1 缩放至 %2, 耗时 %3 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": 0, 22 | "value": 0.5, 23 | "max": 1, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": 0, 30 | "value": 0, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | ], 35 | "inputsInline": true, 36 | "previousStatement": null, 37 | "nextStatement": null, 38 | "colour": 230, 39 | "tooltip": "", 40 | "helpUrl": "" 41 | } 42 | 43 | // 注入自定义模块 44 | Blockly.Blocks[blockname] = { 45 | init: function () { 46 | this.jsonInit(jsondesc); 47 | } 48 | } 49 | 50 | // 为自定义块添加js语言生成器 51 | javascriptGenerator[blockname] = function (block) { 52 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 53 | const scale = block.getFieldValue('num1'); 54 | const spendtime = block.getFieldValue('num2'); 55 | 56 | 57 | 58 | return `stagelist.push(\`${myImager.scale(wrapStr(nickname),scale,spendtime)}\`);` 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/b_pic_shake.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myImager from 'renderer/models/imgcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_pic_shake" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "图片昵称 %1 %2 抖动%3秒,幅度 %4 频率 %5", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["x轴","xs"], 23 | ["y轴","ys"] 24 | ] 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num1", 29 | "min": 0, 30 | "value": 0.5, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | { 35 | "type": "field_number", 36 | "name": "num2", 37 | "min": -1000, 38 | "value": 20, 39 | "max": 1000, 40 | "precision": 0.1, 41 | }, 42 | { 43 | "type": "field_number", 44 | "name": "num3", 45 | "min": -1000, 46 | "value": 6, 47 | "max": 1000, 48 | "precision": 0.1, 49 | }, 50 | ], 51 | "inputsInline": true, 52 | "previousStatement": null, 53 | "nextStatement": null, 54 | "colour": 230, 55 | "tooltip": "", 56 | "helpUrl": "" 57 | } 58 | 59 | // 注入自定义模块 60 | Blockly.Blocks[blockname] = { 61 | init: function () { 62 | this.jsonInit(jsondesc); 63 | } 64 | } 65 | 66 | // 为自定义块添加js语言生成器 67 | javascriptGenerator[blockname] = function (block) { 68 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 69 | const axis = block.getFieldValue('drop1'); 70 | 71 | const spendtime = block.getFieldValue('num1'); 72 | const distance = block.getFieldValue('num2'); 73 | const frequency = block.getFieldValue('num3'); 74 | 75 | return `stagelist.push(\`${myImager.shakeaxis(wrapStr(nickname),axis,distance,spendtime,frequency)}\`);` 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/b_pic_shakexy.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myImager from 'renderer/models/imgcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_pic_shakexy" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "图片昵称 %1 随机方向 抖动%2秒,幅度 %3 频率 %4", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": 0, 22 | "value": 0.5, 23 | "max": 1000, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": -1000, 30 | "value": 20, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | { 35 | "type": "field_number", 36 | "name": "num3", 37 | "min": -1000, 38 | "value": 6, 39 | "max": 1000, 40 | "precision": 0.1, 41 | }, 42 | ], 43 | "inputsInline": true, 44 | "previousStatement": null, 45 | "nextStatement": null, 46 | "colour": 230, 47 | "tooltip": "", 48 | "helpUrl": "" 49 | } 50 | 51 | // 注入自定义模块 52 | Blockly.Blocks[blockname] = { 53 | init: function () { 54 | this.jsonInit(jsondesc); 55 | } 56 | } 57 | 58 | // 为自定义块添加js语言生成器 59 | javascriptGenerator[blockname] = function (block) { 60 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 61 | 62 | const spendtime = block.getFieldValue('num1'); 63 | const distance = block.getFieldValue('num2'); 64 | const frequency = block.getFieldValue('num3'); 65 | 66 | return `stagelist.push(\`${myImager.shakerandom(wrapStr(nickname),distance,spendtime,frequency)}\`);` 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/renderer/myblocks/02pic/index.jsx: -------------------------------------------------------------------------------- 1 | import "./b_pic_display" 2 | import "./b_pic_alpha" 3 | import "./b_pic_move" 4 | import "./b_pic_movexy" 5 | import "./b_pic_shake" 6 | import "./b_pic_shakexy" 7 | import "./b_pic_scale" 8 | 9 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/Menu03.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 3 | 4 | export default function Menu03() { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | ) 39 | } 40 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_action.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_action" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 动作 %2", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["靠近","close"], 23 | ["远离","back"], 24 | // ["点头","nod"], 25 | // ["小跳","jump"], 26 | // ["跳两下","jump2"], 27 | // ["小颤抖","sshake"], 28 | // ["大颤抖","bshake"] 29 | ] 30 | }, 31 | ], 32 | "inputsInline": true, 33 | "previousStatement": null, 34 | "nextStatement": null, 35 | "colour": 230, 36 | "tooltip": "", 37 | "helpUrl": "" 38 | } 39 | 40 | // 注入自定义模块 41 | Blockly.Blocks[blockname] = { 42 | init: function () { 43 | this.jsonInit(jsondesc); 44 | } 45 | } 46 | 47 | // 为自定义块添加js语言生成器 48 | javascriptGenerator[blockname] = function (block) { 49 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 50 | const action = block.getFieldValue('drop1'); 51 | if(action==="close"||action==="back"){ 52 | return `stagelist.push(\`${myCharer.movein(wrapStr(nickname),action)}\`);` 53 | }else if(action==="nod"){ 54 | return `stagelist.push(\`${myCharer.nod(wrapStr(nickname))}\`);` 55 | }else if(action==="jump"){ 56 | return `stagelist.push(\`${myCharer.jump(wrapStr(nickname))}\`);` 57 | }else if(action==="jump2"){ 58 | return `stagelist.push(\`${myCharer.jump2(wrapStr(nickname))}\`);` 59 | }else if(action==="sshake"){ 60 | return `stagelist.push(\`${myCharer.sshake(wrapStr(nickname))}\`);` 61 | }else if(action==="bshake"){ 62 | return `stagelist.push(\`${myCharer.bshake(wrapStr(nickname))}\`);` 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_display.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_display" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 %2", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["渐入","show"], 23 | ["渐出","hide"], 24 | ["显示","appear"], 25 | ["隐藏","disappear"], 26 | ] 27 | }, 28 | ], 29 | "inputsInline": true, 30 | "previousStatement": null, 31 | "nextStatement": null, 32 | "colour": 230, 33 | "tooltip": "", 34 | "helpUrl": "" 35 | } 36 | 37 | // 注入自定义模块 38 | Blockly.Blocks[blockname] = { 39 | init: function () { 40 | this.jsonInit(jsondesc); 41 | } 42 | } 43 | 44 | // 为自定义块添加js语言生成器 45 | javascriptGenerator[blockname] = function (block) { 46 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 47 | const action = block.getFieldValue('drop1'); 48 | 49 | return `stagelist.push(\`${myCharer.display(wrapStr(nickname),action)}\`);` 50 | } 51 | 52 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_highlight.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_highlight" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 渐变至亮度 %2, 耗时 %3 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": 0, 22 | "value": 0, 23 | "max": 1, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": 0, 30 | "value": 0, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | ], 35 | "inputsInline": true, 36 | "previousStatement": null, 37 | "nextStatement": null, 38 | "colour": 230, 39 | "tooltip": "", 40 | "helpUrl": "" 41 | } 42 | 43 | // 注入自定义模块 44 | Blockly.Blocks[blockname] = { 45 | init: function () { 46 | this.jsonInit(jsondesc); 47 | } 48 | } 49 | 50 | // 为自定义块添加js语言生成器 51 | javascriptGenerator[blockname] = function (block) { 52 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 53 | const light = block.getFieldValue('num1'); 54 | const spendtime = block.getFieldValue('num2'); 55 | 56 | return `stagelist.push(\`${myCharer.highlight(wrapStr(nickname),light,spendtime)}\`);` 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_move.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_move" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 移动至 %2 的 %3, 耗时 %4 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["x轴","xm"], 23 | ["y轴","ym"], 24 | ["z轴","zm"], 25 | ] 26 | }, 27 | { 28 | "type": "field_number", 29 | "name": "num1", 30 | "min": -1000, 31 | "value": 0, 32 | "max": 1000, 33 | "precision": 0.1, 34 | }, 35 | { 36 | "type": "field_number", 37 | "name": "num2", 38 | "min": 0, 39 | "value": 0, 40 | "max": 1000, 41 | "precision": 0.1, 42 | }, 43 | ], 44 | "inputsInline": true, 45 | "previousStatement": null, 46 | "nextStatement": null, 47 | "colour": 230, 48 | "tooltip": "", 49 | "helpUrl": "" 50 | } 51 | 52 | // 注入自定义模块 53 | Blockly.Blocks[blockname] = { 54 | init: function () { 55 | this.jsonInit(jsondesc); 56 | } 57 | } 58 | 59 | // 为自定义块添加js语言生成器 60 | javascriptGenerator[blockname] = function (block) { 61 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 62 | const axis = block.getFieldValue('drop1'); 63 | const distance = block.getFieldValue('num1'); 64 | const spendtime = block.getFieldValue('num2'); 65 | 66 | if(axis==="zm"){ 67 | // z轴移动没有时间参数 68 | return `stagelist.push(\`${myCharer.pos(wrapStr(nickname),"z",distance)}\`);` 69 | } 70 | 71 | return `stagelist.push(\`${myCharer.move(wrapStr(nickname),axis,distance,spendtime)}\`);` 72 | } 73 | 74 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_movexy.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_movexy" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 移动至横轴: %2 纵轴: %3, 耗时 %4 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": -1000, 22 | "value": 0, 23 | "max": 1000, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": -1000, 30 | "value": 0, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | { 35 | "type": "field_number", 36 | "name": "num3", 37 | "min": 0, 38 | "value": 0, 39 | "max": 100, 40 | "precision": 0.1, 41 | }, 42 | ], 43 | "inputsInline": true, 44 | "previousStatement": null, 45 | "nextStatement": null, 46 | "colour": 230, 47 | "tooltip": "", 48 | "helpUrl": "" 49 | } 50 | 51 | // 注入自定义模块 52 | Blockly.Blocks[blockname] = { 53 | init: function () { 54 | this.jsonInit(jsondesc); 55 | } 56 | } 57 | 58 | // 为自定义块添加js语言生成器 59 | javascriptGenerator[blockname] = function (block) { 60 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 61 | const axis = block.getFieldValue('drop1'); 62 | const xx = block.getFieldValue('num1'); 63 | const yy = block.getFieldValue('num2'); 64 | const spendtime = block.getFieldValue('num3'); 65 | 66 | 67 | return `stagelist.push(\`${myCharer.movexy(wrapStr(nickname),xx,yy,spendtime)}\`);` 68 | } 69 | 70 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_scale.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_scale" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 缩放至 %2, 耗时 %3 秒", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": 0, 22 | "value": 0.5, 23 | "max": 1, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": 0, 30 | "value": 0, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | ], 35 | "inputsInline": true, 36 | "previousStatement": null, 37 | "nextStatement": null, 38 | "colour": 230, 39 | "tooltip": "", 40 | "helpUrl": "" 41 | } 42 | 43 | // 注入自定义模块 44 | Blockly.Blocks[blockname] = { 45 | init: function () { 46 | this.jsonInit(jsondesc); 47 | } 48 | } 49 | 50 | // 为自定义块添加js语言生成器 51 | javascriptGenerator[blockname] = function (block) { 52 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 53 | const scale = block.getFieldValue('num1'); 54 | const spendtime = block.getFieldValue('num2'); 55 | 56 | 57 | 58 | return `stagelist.push(\`${myCharer.scale(wrapStr(nickname),scale,spendtime)}\`);` 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_shake.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_shake" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 %2 抖动%3秒,幅度 %4 频率 %5", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["x轴","xs"], 23 | ["y轴","ys"] 24 | ] 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num1", 29 | "min": 0, 30 | "value": 0.5, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | { 35 | "type": "field_number", 36 | "name": "num2", 37 | "min": -1000, 38 | "value": 20, 39 | "max": 1000, 40 | "precision": 0.1, 41 | }, 42 | { 43 | "type": "field_number", 44 | "name": "num3", 45 | "min": -1000, 46 | "value": 6, 47 | "max": 1000, 48 | "precision": 0.1, 49 | }, 50 | ], 51 | "inputsInline": true, 52 | "previousStatement": null, 53 | "nextStatement": null, 54 | "colour": 230, 55 | "tooltip": "", 56 | "helpUrl": "" 57 | } 58 | 59 | // 注入自定义模块 60 | Blockly.Blocks[blockname] = { 61 | init: function () { 62 | this.jsonInit(jsondesc); 63 | } 64 | } 65 | 66 | // 为自定义块添加js语言生成器 67 | javascriptGenerator[blockname] = function (block) { 68 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 69 | const axis = block.getFieldValue('drop1'); 70 | 71 | const spendtime = block.getFieldValue('num1'); 72 | const distance = block.getFieldValue('num2'); 73 | const frequency = block.getFieldValue('num3'); 74 | 75 | return `stagelist.push(\`${myCharer.shake(wrapStr(nickname),axis,distance,spendtime,frequency)}\`);` 76 | } 77 | 78 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_shakexy.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_shakexy" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 随机方向 抖动%2秒,幅度 %3 频率 %4", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_number", 20 | "name": "num1", 21 | "min": 0, 22 | "value": 0.5, 23 | "max": 1000, 24 | "precision": 0.1, 25 | }, 26 | { 27 | "type": "field_number", 28 | "name": "num2", 29 | "min": -1000, 30 | "value": 20, 31 | "max": 1000, 32 | "precision": 0.1, 33 | }, 34 | { 35 | "type": "field_number", 36 | "name": "num3", 37 | "min": -1000, 38 | "value": 6, 39 | "max": 1000, 40 | "precision": 0.1, 41 | }, 42 | ], 43 | "inputsInline": true, 44 | "previousStatement": null, 45 | "nextStatement": null, 46 | "colour": 230, 47 | "tooltip": "", 48 | "helpUrl": "" 49 | } 50 | 51 | // 注入自定义模块 52 | Blockly.Blocks[blockname] = { 53 | init: function () { 54 | this.jsonInit(jsondesc); 55 | } 56 | } 57 | 58 | // 为自定义块添加js语言生成器 59 | javascriptGenerator[blockname] = function (block) { 60 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 61 | 62 | const spendtime = block.getFieldValue('num1'); 63 | const distance = block.getFieldValue('num2'); 64 | const frequency = block.getFieldValue('num3'); 65 | 66 | return `stagelist.push(\`${myCharer.shakerandom(wrapStr(nickname),distance,spendtime,frequency)}\`);` 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/b_char_status.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myCharer from 'renderer/models/charcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_char_status" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "人物昵称 %1 emo表情 %2 脸部状态 %3 皮肤 %4", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "field_dropdown", 20 | "name": "drop1", 21 | "options": [ 22 | ["无","None"], 23 | ["注意","Action"], 24 | ["生气","Aggro"], 25 | ["胡想","Anxiety"], 26 | ["谈话","Chat"], 27 | ["!","E"], 28 | ["?!","EQ"], 29 | ["?","Q"], 30 | ["爱心","Heart"], 31 | ["...","Idea"], 32 | ["哼歌","Note"], 33 | ["害羞","Shy"], 34 | ["流汗","Sweat"], 35 | ["闪亮","Twinkle"], 36 | ["灯泡","Bulb"], 37 | ["伤心","Sad"], 38 | ["叹气","Sigh"], 39 | ["流泪","Tear"], 40 | ["吹气","Steam"], 41 | ] 42 | }, 43 | { 44 | "type": "input_value", 45 | "name": "val2", 46 | "check": "String" 47 | }, 48 | { 49 | "type": "input_value", 50 | "name": "val3", 51 | "check": "String" 52 | }, 53 | ], 54 | "inputsInline": true, 55 | "previousStatement": null, 56 | "nextStatement": null, 57 | "colour": 230, 58 | "tooltip": "", 59 | "helpUrl": "" 60 | } 61 | 62 | // 注入自定义模块 63 | Blockly.Blocks[blockname] = { 64 | init: function () { 65 | this.jsonInit(jsondesc); 66 | } 67 | } 68 | 69 | // 为自定义块添加js语言生成器 70 | javascriptGenerator[blockname] = function (block) { 71 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 72 | const emo = block.getFieldValue('drop1'); 73 | const state = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 74 | const skin = javascriptGenerator.valueToCode(block, 'val3', javascriptGenerator.ORDER_ATOMIC); 75 | 76 | let resstr="" 77 | if(emo!="None"){ 78 | resstr+=`stagelist.push(\`${myCharer.emo(wrapStr(nickname),emo)}\`);` 79 | } 80 | if(state!="''"){ 81 | resstr+=`stagelist.push(\`${myCharer.state(wrapStr(nickname),wrapStr(state))}\`);` 82 | } 83 | if(skin!="''"){ 84 | resstr+=`stagelist.push(\`${myCharer.skin(wrapStr(nickname),wrapStr(skin))}\`);` 85 | } 86 | 87 | return resstr 88 | } 89 | 90 | -------------------------------------------------------------------------------- /src/renderer/myblocks/03char/index.jsx: -------------------------------------------------------------------------------- 1 | import "./b_char_display" 2 | import "./b_char_action" 3 | import "./b_char_highlight" 4 | import "./b_char_status" 5 | import "./b_char_move" 6 | import "./b_char_movexy" 7 | import "./b_char_shake" 8 | import "./b_char_shakexy" 9 | import "./b_char_scale" -------------------------------------------------------------------------------- /src/renderer/myblocks/04sound/Menu04.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 3 | 4 | export default function Menu04() { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /src/renderer/myblocks/04sound/b_sound_loop.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySounder from 'renderer/models/soundcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_sound_loop" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "声音昵称 %1 设置为 %2", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | { 18 | "type": "field_dropdown", 19 | "name": "drop1", 20 | "options": [ 21 | ["循环播放","loop"], 22 | ["播放一次","once"] 23 | ] 24 | }, 25 | ], 26 | "inputsInline": true, 27 | "previousStatement": null, 28 | "nextStatement": null, 29 | "colour": 230, 30 | "tooltip": "音效默认播放一次,背景音乐默认循环播放", 31 | "helpUrl": "" 32 | } 33 | 34 | // 注入自定义模块 35 | Blockly.Blocks[blockname] = { 36 | init: function () { 37 | this.jsonInit(jsondesc); 38 | } 39 | } 40 | 41 | // 为自定义块添加js语言生成器 42 | javascriptGenerator[blockname] = function (block) { 43 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 44 | const type = block.getFieldValue('drop1'); 45 | 46 | 47 | return `stagelist.push(\`${mySounder.loop(wrapStr(nickname),type)}\`);` 48 | } 49 | 50 | -------------------------------------------------------------------------------- /src/renderer/myblocks/04sound/b_sound_play.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySounder from 'renderer/models/soundcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_sound_play" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "声音昵称 %1 %2", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | { 18 | "type": "field_dropdown", 19 | "name": "drop1", 20 | "options": [ 21 | ["播放","play"], 22 | ["暂停","pause"], 23 | ["停止","stop"] 24 | ] 25 | }, 26 | ], 27 | "inputsInline": true, 28 | "previousStatement": null, 29 | "nextStatement": null, 30 | "colour": 230, 31 | "tooltip": "", 32 | "helpUrl": "" 33 | } 34 | 35 | // 注入自定义模块 36 | Blockly.Blocks[blockname] = { 37 | init: function () { 38 | this.jsonInit(jsondesc); 39 | } 40 | } 41 | 42 | // 为自定义块添加js语言生成器 43 | javascriptGenerator[blockname] = function (block) { 44 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 45 | const type = block.getFieldValue('drop1'); 46 | 47 | 48 | return `stagelist.push(\`${mySounder.play(wrapStr(nickname),type)}\`);` 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/renderer/myblocks/04sound/b_sound_volume.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySounder from 'renderer/models/soundcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_sound_volume" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "声音昵称 %1 音量变至 %2, 耗时 %3秒", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | { 18 | "type": "field_number", 19 | "name": "num1", 20 | "min": 0, 21 | "value": 0, 22 | "max": 1, 23 | "precision": 0.1, 24 | }, 25 | { 26 | "type": "field_number", 27 | "name": "num2", 28 | "min": 0, 29 | "value": 1, 30 | "max": 1000, 31 | "precision": 0.1, 32 | }, 33 | ], 34 | "inputsInline": true, 35 | "previousStatement": null, 36 | "nextStatement": null, 37 | "colour": 230, 38 | "tooltip": "", 39 | "helpUrl": "" 40 | } 41 | 42 | // 注入自定义模块 43 | Blockly.Blocks[blockname] = { 44 | init: function () { 45 | this.jsonInit(jsondesc); 46 | } 47 | } 48 | 49 | // 为自定义块添加js语言生成器 50 | javascriptGenerator[blockname] = function (block) { 51 | const nickname = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 52 | const vol = block.getFieldValue('num1'); 53 | const spendtime = block.getFieldValue('num2'); 54 | 55 | 56 | 57 | return `stagelist.push(\`${mySounder.fade(wrapStr(nickname),vol,spendtime)}\`);` 58 | } 59 | 60 | -------------------------------------------------------------------------------- /src/renderer/myblocks/04sound/index.jsx: -------------------------------------------------------------------------------- 1 | import "./b_sound_play" 2 | import "./b_sound_volume" 3 | import "./b_sound_loop" -------------------------------------------------------------------------------- /src/renderer/myblocks/05screen/Menu05.jsx: -------------------------------------------------------------------------------- 1 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 2 | 3 | export default function Menu05() { 4 | return ( 5 | 6 | 7 | 8 | 9 | ) 10 | } 11 | -------------------------------------------------------------------------------- /src/renderer/myblocks/05screen/b_screen_effect.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myScener from 'renderer/models/scenecmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_screen_effect" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "场景效果 %1 %2", 11 | "args0": [ 12 | { 13 | "type": "field_dropdown", 14 | "name": "drop1", 15 | "options": [ 16 | ["注视线","focus"], 17 | ["烟雾","smoke"], 18 | ["雨","rain"], 19 | ["雪","snow"], 20 | ["沙尘","dust"], 21 | ] 22 | }, 23 | { 24 | "type": "field_dropdown", 25 | "name": "drop2", 26 | "options": [ 27 | ["出现","show"], 28 | ["隐藏","hide"], 29 | ] 30 | }, 31 | ], 32 | "inputsInline": true, 33 | "previousStatement": null, 34 | "nextStatement": null, 35 | "colour": 230, 36 | "tooltip": "", 37 | "helpUrl": "" 38 | } 39 | 40 | // 注入自定义模块 41 | Blockly.Blocks[blockname] = { 42 | init: function () { 43 | this.jsonInit(jsondesc); 44 | } 45 | } 46 | 47 | // 为自定义块添加js语言生成器 48 | javascriptGenerator[blockname] = function (block) { 49 | 50 | const type = block.getFieldValue('drop1'); 51 | const status = block.getFieldValue('drop2'); 52 | 53 | 54 | 55 | return `stagelist.push(\`${myScener.scene(type,status)}\`);` 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/renderer/myblocks/05screen/index.jsx: -------------------------------------------------------------------------------- 1 | import "./b_screen_effect" -------------------------------------------------------------------------------- /src/renderer/myblocks/06button/Menu06.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 3 | 4 | export default function Menu06() { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | ) 33 | } 34 | -------------------------------------------------------------------------------- /src/renderer/myblocks/06button/b_one_button.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import { generateTime } from 'renderer/utils/timestamp'; 4 | 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_one_button" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "%1 单个按钮,内容:[ %2 ] 执行 %3", 12 | "args0": [ 13 | { 14 | "type": "field_dropdown", 15 | "name": "drop1", 16 | "options": [ 17 | ["出现按钮","0"], 18 | ["自动选择按钮1","1"], 19 | ] 20 | }, 21 | { 22 | "type": "input_value", 23 | "name": "val1", 24 | "check": "String" 25 | }, 26 | { 27 | "type": "input_statement", 28 | "name": "sta1" 29 | } 30 | ], 31 | "inputsInline": true, 32 | "previousStatement": null, 33 | "nextStatement": null, 34 | "colour": 20, 35 | "tooltip": "", 36 | "helpUrl": "" 37 | } 38 | 39 | // 注入自定义模块 40 | Blockly.Blocks[blockname] = { 41 | init: function () { 42 | this.jsonInit(jsondesc); 43 | } 44 | } 45 | 46 | // 为自定义块添加js语言生成器 47 | javascriptGenerator[blockname] = function (block) { 48 | const value_val1 = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 49 | if(value_val1.length==0){ 50 | // 如果该字符串参数空内没有任何变量,忽略掉本代码块 51 | return ``; 52 | } 53 | const statements_sta1=javascriptGenerator.statementToCode(block,'sta1'); 54 | const dropdown_drop1 = block.getFieldValue('drop1'); 55 | const wordS=dropdown_drop1!=="0"?'':''; 56 | const selnum=wordS?''+dropdown_drop1:''; 57 | 58 | const timestamp=generateTime(); 59 | 60 | 61 | return ` 62 | function buttonfunc${timestamp}(){ 63 | const funcincnum=incnum; 64 | incnum+=1; 65 | 66 | stagelist.push(\`select${wordS}${selnum} \${${value_val1}} \${'${timestamp+"caseA"}'+funcincnum}\`); 67 | stagelist.push(\`target \${'${timestamp+"caseA"}'+funcincnum}\`) 68 | ${statements_sta1.trim()} 69 | } 70 | 71 | buttonfunc${timestamp}() 72 | ` 73 | } 74 | 75 | -------------------------------------------------------------------------------- /src/renderer/myblocks/06button/b_three_button.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import { generateTime } from 'renderer/utils/timestamp'; 4 | 5 | // 定义JSON格式自定义模块 6 | let blockname="b_three_button" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "%1 第一个按钮,内容: [ %2 ] 执行 %3 第二个按钮,内容: [ %4 ] 执行 %5 第三个按钮,内容:[ %6 ] 执行 %7", 11 | "args0": [ 12 | { 13 | "type": "field_dropdown", 14 | "name": "drop1", 15 | "options": [ 16 | ["出现按钮","0"], 17 | ["自动选择按钮1","1"], 18 | ["自动选择按钮2","2"], 19 | ["自动选择按钮3","3"], 20 | ] 21 | }, 22 | { 23 | "type": "input_value", 24 | "name": "val1", 25 | "check": "String" 26 | }, 27 | { 28 | "type": "input_statement", 29 | "name": "sta1" 30 | }, 31 | { 32 | "type": "input_value", 33 | "name": "val2", 34 | "check": "String" 35 | }, 36 | { 37 | "type": "input_statement", 38 | "name": "sta2" 39 | }, 40 | { 41 | "type": "input_value", 42 | "name": "val3", 43 | "check": "String" 44 | }, 45 | { 46 | "type": "input_statement", 47 | "name": "sta3" 48 | } 49 | ], 50 | "inputsInline": true, 51 | "previousStatement": null, 52 | "nextStatement": null, 53 | "colour": 20, 54 | "tooltip": "", 55 | "helpUrl": "" 56 | } 57 | 58 | // 注入自定义模块 59 | Blockly.Blocks[blockname] = { 60 | init: function () { 61 | this.jsonInit(jsondesc); 62 | } 63 | } 64 | 65 | // 为自定义块添加js语言生成器 66 | javascriptGenerator[blockname] = function (block) { 67 | const value_val1 = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 68 | const value_val2 = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 69 | const value_val3 = javascriptGenerator.valueToCode(block, 'val3', javascriptGenerator.ORDER_ATOMIC); 70 | if(value_val1.length==0||value_val2.length==0||value_val3.length==0){ 71 | // 如果该字符串参数空内没有任何变量,忽略掉本代码块 72 | return `` 73 | } 74 | const statements_sta1=javascriptGenerator.statementToCode(block,'sta1'); 75 | const statements_sta2=javascriptGenerator.statementToCode(block,'sta2'); 76 | const statements_sta3=javascriptGenerator.statementToCode(block,'sta3'); 77 | 78 | const dropdown_drop1 = block.getFieldValue('drop1'); 79 | const wordS=dropdown_drop1!=="0"?'':''; 80 | const selnum=wordS?''+dropdown_drop1:''; 81 | 82 | 83 | 84 | const timestamp=generateTime(); 85 | 86 | return ` 87 | function buttonfunc${timestamp}(){ 88 | const funcincnum=incnum; 89 | incnum+=1; 90 | 91 | stagelist.push(\`select${wordS}${selnum} \${${value_val1}} \${'${timestamp+"caseA"}'+funcincnum} \${${value_val2}} \${'${timestamp+"caseB"}'+funcincnum} \${${value_val3}} \${'${timestamp+"caseC"}'+funcincnum}\`); 92 | 93 | stagelist.push(\`target \${'${timestamp+"caseA"}'+funcincnum}\`) 94 | ${statements_sta1.trim()} 95 | stagelist.push(\`jump \${'${timestamp+"IfFinal"}'+funcincnum}\`) 96 | 97 | stagelist.push(\`target \${'${timestamp+"caseB"}'+funcincnum}\`) 98 | ${statements_sta2.trim()} 99 | stagelist.push(\`jump \${'${timestamp+"IfFinal"}'+funcincnum}\`) 100 | 101 | stagelist.push(\`target \${'${timestamp+"caseC"}'+funcincnum}\`) 102 | ${statements_sta3.trim()} 103 | stagelist.push(\`jump \${'${timestamp+"IfFinal"}'+funcincnum}\`) 104 | 105 | stagelist.push(\`target \${'${timestamp+"IfFinal"}'+funcincnum}\`) 106 | } 107 | 108 | buttonfunc${timestamp}() 109 | ` 110 | } 111 | 112 | -------------------------------------------------------------------------------- /src/renderer/myblocks/06button/b_two_button.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import { generateTime } from 'renderer/utils/timestamp'; 4 | 5 | // 定义JSON格式自定义模块 6 | let blockname="b_two_button" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "%1 第一个按钮,内容:[ %2 ] 执行 %3 第二个按钮,内容:[ %4 ] 执行 %5", 11 | "args0": [ 12 | { 13 | "type": "field_dropdown", 14 | "name": "drop1", 15 | "options": [ 16 | ["出现按钮","0"], 17 | ["自动选择按钮1","1"], 18 | ["自动选择按钮2","2"], 19 | ] 20 | }, 21 | { 22 | "type": "input_value", 23 | "name": "val1", 24 | "check": "String" 25 | }, 26 | { 27 | "type": "input_statement", 28 | "name": "sta1" 29 | }, 30 | { 31 | "type": "input_value", 32 | "name": "val2", 33 | "check": "String" 34 | }, 35 | { 36 | "type": "input_statement", 37 | "name": "sta2" 38 | }, 39 | ], 40 | "inputsInline": true, 41 | "previousStatement": null, 42 | "nextStatement": null, 43 | "colour": 20, 44 | "tooltip": "", 45 | "helpUrl": "" 46 | } 47 | 48 | // 注入自定义模块 49 | Blockly.Blocks[blockname] = { 50 | init: function () { 51 | this.jsonInit(jsondesc); 52 | } 53 | } 54 | 55 | // 为自定义块添加js语言生成器 56 | javascriptGenerator[blockname] = function (block) { 57 | const value_val1 = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 58 | const value_val2 = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 59 | if(value_val1.length==0||value_val2.length==0){ 60 | // 如果该字符串参数空内没有任何变量,忽略掉本代码块 61 | return `` 62 | } 63 | const statements_sta1=javascriptGenerator.statementToCode(block,'sta1'); 64 | const statements_sta2=javascriptGenerator.statementToCode(block,'sta2'); 65 | const dropdown_drop1 = block.getFieldValue('drop1'); 66 | const wordS=dropdown_drop1!=="0"?'':''; 67 | const selnum=wordS?''+dropdown_drop1:''; 68 | 69 | 70 | const timestamp=generateTime(); 71 | 72 | return ` 73 | function buttonfunc${timestamp}(){ 74 | const funcincnum=incnum; 75 | incnum+=1; 76 | 77 | stagelist.push(\`select${wordS}${selnum} \${${value_val1}} \${'${timestamp+"caseA"}'+funcincnum} \${${value_val2}} \${'${timestamp+"caseB"}'+funcincnum}\`); 78 | 79 | stagelist.push(\`target \${'${timestamp+"caseA"}'+funcincnum}\`) 80 | ${statements_sta1.trim()} 81 | stagelist.push(\`jump \${'${timestamp+"IfFinal"}'+funcincnum}\`) 82 | 83 | stagelist.push(\`target \${'${timestamp+"caseB"}'+funcincnum}\`) 84 | ${statements_sta2.trim()} 85 | stagelist.push(\`jump \${'${timestamp+"IfFinal"}'+funcincnum}\`) 86 | 87 | stagelist.push(\`target \${'${timestamp+"IfFinal"}'+funcincnum}\`) 88 | } 89 | 90 | buttonfunc${timestamp}() 91 | ` 92 | } 93 | 94 | -------------------------------------------------------------------------------- /src/renderer/myblocks/06button/index.jsx: -------------------------------------------------------------------------------- 1 | import './b_one_button' 2 | import './b_two_button' 3 | import './b_three_button' -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/Menu07.jsx: -------------------------------------------------------------------------------- 1 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 2 | 3 | export default function Menu07() { 4 | return ( 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ) 28 | } 29 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_autotime.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_autotime" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "设置自动播放速度为 %1 秒", 11 | "args0": [ 12 | { 13 | "type": "field_number", 14 | "name": "num1", 15 | "min": 0, 16 | "value": 1, 17 | "max": 1000, 18 | "precision": 0.1, 19 | }, 20 | ], 21 | "inputsInline": true, 22 | "previousStatement": null, 23 | "nextStatement": null, 24 | "colour": 230, 25 | "tooltip": "", 26 | "helpUrl": "" 27 | } 28 | 29 | // 注入自定义模块 30 | Blockly.Blocks[blockname] = { 31 | init: function () { 32 | this.jsonInit(jsondesc); 33 | } 34 | } 35 | 36 | // 为自定义块添加js语言生成器 37 | javascriptGenerator[blockname] = function (block) { 38 | const time = block.getFieldValue('num1'); 39 | 40 | 41 | 42 | return `stagelist.push(\`${mySpecialer.autoplay(time)}\`);` 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_breakpoint.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_breakpoint" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "等待鼠标点击(断点)", 11 | "args0": [ 12 | ], 13 | "inputsInline": true, 14 | "previousStatement": null, 15 | "nextStatement": null, 16 | "colour": 230, 17 | "tooltip": "", 18 | "helpUrl": "" 19 | } 20 | 21 | // 注入自定义模块 22 | Blockly.Blocks[blockname] = { 23 | init: function () { 24 | this.jsonInit(jsondesc); 25 | } 26 | } 27 | 28 | // 为自定义块添加js语言生成器 29 | javascriptGenerator[blockname] = function (block) { 30 | 31 | 32 | 33 | return `stagelist.push(\`${mySpecialer.breakpoint()}\`);` 34 | } 35 | 36 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_command.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_command" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "注释 %1", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | ], 18 | "inputsInline": true, 19 | "previousStatement": null, 20 | "nextStatement": null, 21 | "colour": 230, 22 | "tooltip": "", 23 | "helpUrl": "" 24 | } 25 | 26 | // 注入自定义模块 27 | Blockly.Blocks[blockname] = { 28 | init: function () { 29 | this.jsonInit(jsondesc); 30 | } 31 | } 32 | 33 | // 为自定义块添加js语言生成器 34 | javascriptGenerator[blockname] = function (block) { 35 | const zhushi = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 36 | 37 | 38 | 39 | 40 | return `stagelist.push(\`${mySpecialer.spec(wrapStr(zhushi))}\`);` 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_jump.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_jump" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "跳到标记点 %1", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | ], 18 | "inputsInline": true, 19 | "previousStatement": null, 20 | "nextStatement": null, 21 | "colour": 230, 22 | "tooltip": "", 23 | "helpUrl": "" 24 | } 25 | 26 | // 注入自定义模块 27 | Blockly.Blocks[blockname] = { 28 | init: function () { 29 | this.jsonInit(jsondesc); 30 | } 31 | } 32 | 33 | // 为自定义块添加js语言生成器 34 | javascriptGenerator[blockname] = function (block) { 35 | const name = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 36 | 37 | 38 | 39 | 40 | return `stagelist.push(\`${mySpecialer.jump(wrapStr(name))}\`);` 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_switch.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_switch" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "切换至脚本 %1", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | ], 18 | "inputsInline": true, 19 | "previousStatement": null, 20 | "nextStatement": null, 21 | "colour": 230, 22 | "tooltip": "", 23 | "helpUrl": "" 24 | } 25 | 26 | // 注入自定义模块 27 | Blockly.Blocks[blockname] = { 28 | init: function () { 29 | this.jsonInit(jsondesc); 30 | } 31 | } 32 | 33 | // 为自定义块添加js语言生成器 34 | javascriptGenerator[blockname] = function (block) { 35 | const name = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 36 | 37 | 38 | 39 | 40 | return `stagelist.push(\`${mySpecialer.switch(wrapStr(name))}\`);` 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_target.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_target" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "设为标记点 %1", 11 | "args0": [ 12 | { 13 | "type": "input_value", 14 | "name": "val1", 15 | "check": "String" 16 | }, 17 | ], 18 | "inputsInline": true, 19 | "previousStatement": null, 20 | "nextStatement": null, 21 | "colour": 230, 22 | "tooltip": "", 23 | "helpUrl": "" 24 | } 25 | 26 | // 注入自定义模块 27 | Blockly.Blocks[blockname] = { 28 | init: function () { 29 | this.jsonInit(jsondesc); 30 | } 31 | } 32 | 33 | // 为自定义块添加js语言生成器 34 | javascriptGenerator[blockname] = function (block) { 35 | const name = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 36 | 37 | 38 | 39 | 40 | return `stagelist.push(\`${mySpecialer.target(wrapStr(name))}\`);` 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_targets.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_targets" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "debug所有标记点", 11 | "args0": [ 12 | ], 13 | "inputsInline": true, 14 | "previousStatement": null, 15 | "nextStatement": null, 16 | "colour": 230, 17 | "tooltip": "", 18 | "helpUrl": "" 19 | } 20 | 21 | // 注入自定义模块 22 | Blockly.Blocks[blockname] = { 23 | init: function () { 24 | this.jsonInit(jsondesc); 25 | } 26 | } 27 | 28 | // 为自定义块添加js语言生成器 29 | javascriptGenerator[blockname] = function (block) { 30 | const name = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 31 | 32 | 33 | 34 | 35 | return `stagelist.push(\`${mySpecialer.showtarget()}\`);` 36 | } 37 | 38 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/b_special_wait.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import mySpecialer from 'renderer/models/specialcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_special_wait" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "等待 %1 秒", 11 | "args0": [ 12 | { 13 | "type": "field_number", 14 | "name": "num1", 15 | "min": 0, 16 | "value": 1, 17 | "max": 1000, 18 | "precision": 0.1, 19 | }, 20 | ], 21 | "inputsInline": true, 22 | "previousStatement": null, 23 | "nextStatement": null, 24 | "colour": 230, 25 | "tooltip": "", 26 | "helpUrl": "" 27 | } 28 | 29 | // 注入自定义模块 30 | Blockly.Blocks[blockname] = { 31 | init: function () { 32 | this.jsonInit(jsondesc); 33 | } 34 | } 35 | 36 | // 为自定义块添加js语言生成器 37 | javascriptGenerator[blockname] = function (block) { 38 | const time = block.getFieldValue('num1'); 39 | 40 | 41 | 42 | return `stagelist.push(\`${mySpecialer.wait(time)}\`);` 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/renderer/myblocks/07special/index.jsx: -------------------------------------------------------------------------------- 1 | import "./b_special_autotime" 2 | import "./b_special_breakpoint" 3 | import "./b_special_command" 4 | import "./b_special_jump" 5 | import "./b_special_switch" 6 | import "./b_special_target" 7 | import "./b_special_targets" 8 | import "./b_special_wait" -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/Menu08.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 3 | 4 | export default function Menu08() { 5 | return ( 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | ) 35 | } 36 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/b_text_autotime.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myTexter from 'renderer/models/textcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_text_autotime" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "设置打字机效果间隔 %1 秒", 11 | "args0": [ 12 | { 13 | "type": "field_number", 14 | "name": "num1", 15 | "min": 0, 16 | "value": 0.1, 17 | "max": 1000, 18 | "precision": 0.01, 19 | }, 20 | ], 21 | "inputsInline": true, 22 | "previousStatement": null, 23 | "nextStatement": null, 24 | "colour": 230, 25 | "tooltip": "", 26 | "helpUrl": "" 27 | } 28 | 29 | // 注入自定义模块 30 | Blockly.Blocks[blockname] = { 31 | init: function () { 32 | this.jsonInit(jsondesc); 33 | } 34 | } 35 | 36 | // 为自定义块添加js语言生成器 37 | javascriptGenerator[blockname] = function (block) { 38 | const time = block.getFieldValue('num1'); 39 | 40 | return `stagelist.push(\`${myTexter.textinterval(time)}\`);` 41 | } 42 | 43 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/b_text_banner.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myTexter from 'renderer/models/textcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_text_banner" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "横幅 主标题 %1 副标题 %2 小标题 %3", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "input_value", 20 | "name": "val2", 21 | "check": "String" 22 | }, 23 | { 24 | "type": "input_value", 25 | "name": "val3", 26 | "check": "String" 27 | }, 28 | ], 29 | "inputsInline": true, 30 | "previousStatement": null, 31 | "nextStatement": null, 32 | "colour": 230, 33 | "tooltip": "", 34 | "helpUrl": "" 35 | } 36 | 37 | // 注入自定义模块 38 | Blockly.Blocks[blockname] = { 39 | init: function () { 40 | this.jsonInit(jsondesc); 41 | } 42 | } 43 | 44 | // 为自定义块添加js语言生成器 45 | javascriptGenerator[blockname] = function (block) { 46 | const main = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 47 | const second = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 48 | const third = javascriptGenerator.valueToCode(block, 'val3', javascriptGenerator.ORDER_ATOMIC); 49 | 50 | if(third!="''"){ 51 | return `stagelist.push(\`${myTexter.banner3(wrapStr(main),wrapStr(second),wrapStr(third))}\`);` 52 | } 53 | if(second!="''"){ 54 | return `stagelist.push(\`${myTexter.banner2(wrapStr(main),wrapStr(second))}\`);` 55 | } 56 | return `stagelist.push(\`${myTexter.banner(wrapStr(main))}\`);` 57 | } 58 | 59 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/b_text_hide.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myTexter from 'renderer/models/textcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | // 定义JSON格式自定义模块 6 | let blockname="b_text_hide" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "隐藏所有文本框", 11 | "args0": [ 12 | ], 13 | "inputsInline": true, 14 | "previousStatement": null, 15 | "nextStatement": null, 16 | "colour": 230, 17 | "tooltip": "", 18 | "helpUrl": "" 19 | } 20 | 21 | // 注入自定义模块 22 | Blockly.Blocks[blockname] = { 23 | init: function () { 24 | this.jsonInit(jsondesc); 25 | } 26 | } 27 | 28 | // 为自定义块添加js语言生成器 29 | javascriptGenerator[blockname] = function (block) { 30 | 31 | return `stagelist.push(\`${myTexter.hidealltext()}\`);` 32 | } 33 | 34 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/b_text_highlight.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myTexter from 'renderer/models/textcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_text_highlight" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "对话 高亮人物 %1 人名 %2 部门 %3 内容 %4 %5", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "input_value", 20 | "name": "val2", 21 | "check": "String" 22 | }, 23 | { 24 | "type": "input_value", 25 | "name": "val3", 26 | "check": "String" 27 | }, 28 | { 29 | "type": "input_value", 30 | "name": "val4", 31 | "check": "String" 32 | }, 33 | { 34 | "type": "field_dropdown", 35 | "name": "drop1", 36 | "options": [ 37 | ["有断点","break"], 38 | ["无断点","continue"], 39 | ] 40 | }, 41 | ], 42 | "inputsInline": true, 43 | "previousStatement": null, 44 | "nextStatement": null, 45 | "colour": 230, 46 | "tooltip": "", 47 | "helpUrl": "" 48 | } 49 | 50 | // 注入自定义模块 51 | Blockly.Blocks[blockname] = { 52 | init: function () { 53 | this.jsonInit(jsondesc); 54 | } 55 | } 56 | 57 | // 为自定义块添加js语言生成器 58 | javascriptGenerator[blockname] = function (block) { 59 | const nameId=javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 60 | const name = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 61 | const partment = javascriptGenerator.valueToCode(block, 'val3', javascriptGenerator.ORDER_ATOMIC); 62 | const content = javascriptGenerator.valueToCode(block, 'val4', javascriptGenerator.ORDER_ATOMIC); 63 | 64 | const action = block.getFieldValue('drop1'); 65 | 66 | return `stagelist.push(\`${myTexter.texthighlight(wrapStr(nameId),wrapStr(name),wrapStr(partment),wrapStr(content),action==="continue"?true:false)}\`);` 67 | } 68 | 69 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/b_text_label.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myTexter from 'renderer/models/textcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_text_label" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "左侧小标题 内容 %1", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | ], 19 | "inputsInline": true, 20 | "previousStatement": null, 21 | "nextStatement": null, 22 | "colour": 230, 23 | "tooltip": "", 24 | "helpUrl": "" 25 | } 26 | 27 | // 注入自定义模块 28 | Blockly.Blocks[blockname] = { 29 | init: function () { 30 | this.jsonInit(jsondesc); 31 | } 32 | } 33 | 34 | // 为自定义块添加js语言生成器 35 | javascriptGenerator[blockname] = function (block) { 36 | const content = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 37 | 38 | 39 | return `stagelist.push(\`${myTexter.label(wrapStr(content))}\`);` 40 | } 41 | 42 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/b_text_side.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myTexter from 'renderer/models/textcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_text_side" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "%1 文本框 内容 %2 %3", 12 | "args0": [ 13 | { 14 | "type": "field_dropdown", 15 | "name": "drop1", 16 | "options": [ 17 | ["中部","middle"], 18 | ["底部","bottom"], 19 | ] 20 | }, 21 | { 22 | "type": "input_value", 23 | "name": "val1", 24 | "check": "String" 25 | }, 26 | { 27 | "type": "field_dropdown", 28 | "name": "drop2", 29 | "options": [ 30 | ["有断点","break"], 31 | ["无断点","continue"], 32 | ] 33 | }, 34 | ], 35 | "inputsInline": true, 36 | "previousStatement": null, 37 | "nextStatement": null, 38 | "colour": 230, 39 | "tooltip": "", 40 | "helpUrl": "" 41 | } 42 | 43 | // 注入自定义模块 44 | Blockly.Blocks[blockname] = { 45 | init: function () { 46 | this.jsonInit(jsondesc); 47 | } 48 | } 49 | 50 | // 为自定义块添加js语言生成器 51 | javascriptGenerator[blockname] = function (block) { 52 | const content = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 53 | 54 | const position = block.getFieldValue('drop1'); 55 | const action = block.getFieldValue('drop2'); 56 | 57 | 58 | return `stagelist.push(\`${myTexter.sidetext(wrapStr(content),position,action==="continue"?true:false)}\`);` 59 | } 60 | 61 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/b_text_txt.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import myTexter from 'renderer/models/textcmd'; 4 | import { wrapStr } from 'renderer/utils/DataTool'; 5 | 6 | // 定义JSON格式自定义模块 7 | let blockname="b_text_txt" 8 | // 带有映射的学生名 9 | const jsondesc = { 10 | "type": `${blockname}`, 11 | "message0": "对话 人名 %1 部门 %2 内容 %3 %4", 12 | "args0": [ 13 | { 14 | "type": "input_value", 15 | "name": "val1", 16 | "check": "String" 17 | }, 18 | { 19 | "type": "input_value", 20 | "name": "val2", 21 | "check": "String" 22 | }, 23 | { 24 | "type": "input_value", 25 | "name": "val3", 26 | "check": "String" 27 | }, 28 | { 29 | "type": "field_dropdown", 30 | "name": "drop1", 31 | "options": [ 32 | ["有断点","break"], 33 | ["无断点","continue"], 34 | ] 35 | }, 36 | ], 37 | "inputsInline": true, 38 | "previousStatement": null, 39 | "nextStatement": null, 40 | "colour": 230, 41 | "tooltip": "", 42 | "helpUrl": "" 43 | } 44 | 45 | // 注入自定义模块 46 | Blockly.Blocks[blockname] = { 47 | init: function () { 48 | this.jsonInit(jsondesc); 49 | } 50 | } 51 | 52 | // 为自定义块添加js语言生成器 53 | javascriptGenerator[blockname] = function (block) { 54 | const name = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 55 | const partment = javascriptGenerator.valueToCode(block, 'val2', javascriptGenerator.ORDER_ATOMIC); 56 | const content = javascriptGenerator.valueToCode(block, 'val3', javascriptGenerator.ORDER_ATOMIC); 57 | 58 | const action = block.getFieldValue('drop1'); 59 | 60 | return `stagelist.push(\`${myTexter.text(wrapStr(name),wrapStr(partment),wrapStr(content),action==="continue"?true:false)}\`);` 61 | } 62 | 63 | -------------------------------------------------------------------------------- /src/renderer/myblocks/08text/index.jsx: -------------------------------------------------------------------------------- 1 | import "./b_text_autotime" 2 | import "./b_text_hide" 3 | import "./b_text_txt" 4 | import "./b_text_highlight" 5 | import "./b_text_side" 6 | import "./b_text_label" 7 | import "./b_text_banner" -------------------------------------------------------------------------------- /src/renderer/myblocks/100define/Menu100.jsx: -------------------------------------------------------------------------------- 1 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../../components/PlayGround'; 2 | 3 | import React from 'react' 4 | 5 | export default function Menu100() { 6 | return ( 7 | 8 | 9 | 10 | 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /src/renderer/myblocks/100define/b_case.jsx: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | 4 | /** 5 | * 定义了一个阶段,阶段数字越小,阶段越早进行 6 | */ 7 | 8 | // 定义JSON格式自定义模块 9 | const jsondesc = { 10 | "type": "b_case", 11 | "message0": "定义代码块(唯一) %1 %2", 12 | "args0": [ 13 | { 14 | "type": "field_number", 15 | "name": "num1", 16 | "value": 201, 17 | "min": 201, 18 | "max": 300, 19 | "precision": 1, 20 | }, 21 | { 22 | "type": "input_statement", 23 | "name": "sta1" 24 | } 25 | ], 26 | "colour": 290, 27 | "tooltip": "", 28 | "helpUrl": "" 29 | } 30 | 31 | // 注入自定义模块 32 | Blockly.Blocks['b_case'] = { 33 | init: function () { 34 | this.jsonInit(jsondesc); 35 | } 36 | } 37 | 38 | // 为自定义块添加js语言生成器 39 | javascriptGenerator['b_case'] = function (block) { 40 | // 阶段数字 41 | const number_val1 = block.getFieldValue('num1'); 42 | // 阶段右侧代码忽略 43 | // var value_valeinput = javascriptGenerator.valueToCode(block, 'stageinput', javascriptGenerator.ORDER_ATOMIC); 44 | // 内部包裹的代码 45 | const statements_steps = javascriptGenerator.statementToCode(block, 'sta1'); 46 | return ` 47 | // 支线${number_val1}代码 48 | function bcasefunc${number_val1}(){ 49 | ${statements_steps.trim()} 50 | } 51 | if(resmap.has(${number_val1})){ 52 | errorset.add(${number_val1}); 53 | }else{ 54 | resmap.set(${number_val1},"\\n"); 55 | } 56 | // 支线${number_val1}代码结束 57 | ` 58 | } -------------------------------------------------------------------------------- /src/renderer/myblocks/100define/b_case_jump.jsx: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import { generateTime } from 'renderer/utils/timestamp'; 4 | 5 | // 定义JSON格式自定义模块 6 | let blockname="b_case_jump" 7 | // 带有映射的学生名 8 | const jsondesc = { 9 | "type": `${blockname}`, 10 | "message0": "运行代码块 %1", 11 | "args0": [ 12 | { 13 | "type": "field_number", 14 | "name": "num1", 15 | "min": 201, 16 | "value": 201, 17 | "max": 300, 18 | "precision": 1, 19 | }, 20 | ], 21 | "inputsInline": true, 22 | "previousStatement": null, 23 | "nextStatement": null, 24 | "colour": 290, 25 | "tooltip": "", 26 | "helpUrl": "" 27 | } 28 | 29 | // 注入自定义模块 30 | Blockly.Blocks[blockname] = { 31 | init: function () { 32 | this.jsonInit(jsondesc); 33 | } 34 | } 35 | 36 | // 为自定义块添加js语言生成器 37 | javascriptGenerator[blockname] = function (block) { 38 | const number_num1 = block.getFieldValue('num1');//id 39 | const timestamp=generateTime(); 40 | 41 | return ` 42 | // 把 支线块被哪个时间戳的跳转使用 push到case_jump_dict的该id的value(一个列表)里 43 | if(typeof bcasefunc${number_num1}==="undefined"){ 44 | throw new Error("代码块${number_num1}未定义") 45 | }else{ 46 | bcasefunc${number_num1}(); 47 | } 48 | ` 49 | } 50 | 51 | -------------------------------------------------------------------------------- /src/renderer/myblocks/100define/b_stage.jsx: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | 4 | /** 5 | * 定义了一个阶段,阶段数字越小,阶段越早进行 6 | */ 7 | 8 | // 定义JSON格式自定义模块 9 | const jsondesc = { 10 | "type": "b_stage", 11 | "message0": "主线块(唯一) %1 %2", 12 | "args0": [ 13 | { 14 | "type": "field_number", 15 | "name": "num1", 16 | "value": 1, 17 | "min": 1, 18 | "max": 100 19 | }, 20 | { 21 | "type": "input_statement", 22 | "name": "sta1" 23 | } 24 | ], 25 | "colour": 230, 26 | "tooltip": "", 27 | "helpUrl": "" 28 | } 29 | 30 | // 注入自定义模块 31 | Blockly.Blocks['b_stage'] = { 32 | init: function () { 33 | this.jsonInit(jsondesc); 34 | } 35 | } 36 | 37 | // 为自定义块添加js语言生成器 38 | javascriptGenerator['b_stage'] = function (block) { 39 | // 阶段数字 40 | const number_val1 = block.getFieldValue('num1'); 41 | // 阶段右侧代码忽略 42 | // var value_valeinput = javascriptGenerator.valueToCode(block, 'stageinput', javascriptGenerator.ORDER_ATOMIC); 43 | // 内部包裹的代码 44 | const statements_steps = javascriptGenerator.statementToCode(block, 'sta1'); 45 | return ` 46 | // 阶段${number_val1}代码 47 | stagelist=[]; 48 | ${statements_steps.trim()} 49 | if(resmap.has(${number_val1})){ 50 | errorset.add(${number_val1}); 51 | }else{ 52 | resmap.set(${number_val1},stagelist.join("\\n")+"\\n"); 53 | } 54 | // 阶段${number_val1}代码结束 55 | ` 56 | } -------------------------------------------------------------------------------- /src/renderer/myblocks/100define/b_user_write.jsx: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | 4 | // 定义JSON格式自定义模块 5 | let blockname="b_user_write" 6 | // 带有映射的学生名 7 | const jsondesc = { 8 | "type": `${blockname}`, 9 | "message0": "脚本 %1", 10 | "args0": [ 11 | { 12 | "type": "field_multilinetext", 13 | "name": "val1", 14 | "text":"//可以是多行\n//文字脚本", 15 | "spellcheck": false 16 | }, 17 | ], 18 | "inputsInline": true, 19 | "previousStatement": null, 20 | "nextStatement": null, 21 | "colour": 230, 22 | "tooltip": "这里你可以填多行文字脚本", 23 | "helpUrl": "" 24 | } 25 | 26 | // 注入自定义模块 27 | Blockly.Blocks[blockname] = { 28 | init: function () { 29 | this.jsonInit(jsondesc); 30 | } 31 | } 32 | 33 | // 为自定义块添加js语言生成器 34 | javascriptGenerator[blockname] = function (block) { 35 | const value_val1 = block.getFieldValue('val1') 36 | if(value_val1.length==0){ 37 | // 如果该字符串参数空内没有任何变量,忽略掉本代码块 38 | return `` 39 | } 40 | 41 | 42 | return `stagelist.push(\`${value_val1}\`);` 43 | } 44 | 45 | -------------------------------------------------------------------------------- /src/renderer/myblocks/100define/index.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 自定定义的用于完善功能的块 3 | */ 4 | import './b_stage.jsx' 5 | import './b_case.jsx' 6 | import './b_case_jump.jsx' 7 | import './b_user_write.jsx' -------------------------------------------------------------------------------- /src/renderer/myblocks/Toolbox.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import PlayGround, { Block, Value, Field, Shadow, Category } from '../components/PlayGround'; 3 | 4 | import Menu01 from './01load/Menu01'; 5 | import Menu02 from './02pic/Menu02'; 6 | import Menu03 from './03char/Menu03'; 7 | import Menu04 from './04sound/Menu04'; 8 | import Menu05 from './05screen/Menu05'; 9 | import Menu06 from './06button/Menu06'; 10 | import Menu07 from './07special/Menu07'; 11 | import Menu08 from './08text/Menu08' 12 | import Menu100 from './100define/Menu100'; 13 | 14 | 15 | export default function Toolbox() { 16 | return ( 17 | <> 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | ) 31 | } 32 | -------------------------------------------------------------------------------- /src/renderer/myblocks/index.js: -------------------------------------------------------------------------------- 1 | // import使其被运行 2 | import "./01load" 3 | import "./02pic" 4 | import "./03char" 5 | import "./04sound" 6 | import "./05screen" 7 | import "./06button" 8 | import "./07special" 9 | import "./08text" 10 | import "./100define" 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/renderer/myblocks/temp.js: -------------------------------------------------------------------------------- 1 | import * as Blockly from 'blockly/core'; 2 | import { javascriptGenerator } from 'blockly/javascript'; 3 | import { wrapStr } from 'renderer/utils/DataTool'; 4 | // 定义JSON格式自定义模块 5 | let blockname="b_temp" 6 | // 带有映射的学生名 7 | const jsondesc = { 8 | "type": `${blockname}`, 9 | "message0": "文字 变量 %1 下拉框 %2 数字 %3", 10 | "args0": [ 11 | { 12 | "type": "input_value", 13 | "name": "val1", 14 | "check": "String" 15 | }, 16 | { 17 | "type": "field_dropdown", 18 | "name": "drop1", 19 | "options": [ 20 | ["",""], 21 | ["",""], 22 | ] 23 | }, 24 | { 25 | "type": "field_number", 26 | "name": "num1", 27 | "min": 0, 28 | "value": 1, 29 | "max": 1000, 30 | "precision": 0.1, 31 | }, 32 | ], 33 | "inputsInline": true, 34 | "previousStatement": null, 35 | "nextStatement": null, 36 | "colour": 230, 37 | "tooltip": "", 38 | "helpUrl": "" 39 | } 40 | 41 | // 注入自定义模块 42 | Blockly.Blocks[blockname] = { 43 | init: function () { 44 | this.jsonInit(jsondesc); 45 | } 46 | } 47 | 48 | // 为自定义块添加js语言生成器 49 | javascriptGenerator[blockname] = function (block) { 50 | const value_val1 = javascriptGenerator.valueToCode(block, 'val1', javascriptGenerator.ORDER_ATOMIC); 51 | const dropdown_drop1 = block.getFieldValue('drop1'); 52 | const number_num1 = block.getFieldValue('num1'); 53 | 54 | 55 | return `stagelist.push(\`变量\${${value_val1}} 下拉${dropdown_drop1} 数字${number_num1}\`);` 56 | } 57 | 58 | -------------------------------------------------------------------------------- /src/renderer/preload.d.ts: -------------------------------------------------------------------------------- 1 | import { ElectronHandler } from 'main/preload'; 2 | 3 | declare global { 4 | // eslint-disable-next-line no-unused-vars 5 | interface Window { 6 | electron: ElectronHandler; 7 | } 8 | } 9 | 10 | export {}; 11 | -------------------------------------------------------------------------------- /src/renderer/utils/DataTool.jsx: -------------------------------------------------------------------------------- 1 | // Utility function to remove base64 URL prefix and store base64-encoded string in a Uint8Array 2 | // Courtesy: https://gist.github.com/borismus/1032746 3 | export function convertDataURIToBinary(dataURI) { 4 | let BASE64_MARKER = ';base64,'; 5 | let base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length; 6 | let base64 = dataURI.substring(base64Index); 7 | let raw = window.atob(base64); 8 | let rawLength = raw.length; 9 | let array = new Uint8Array(new ArrayBuffer(rawLength)); 10 | 11 | for (let i = 0; i < rawLength; i++) { 12 | array[i] = raw.charCodeAt(i); 13 | } 14 | return array; 15 | } 16 | 17 | 18 | 19 | /** 20 | * 从已上传的文件中根据文件名找到所需要的那个文件 21 | */ 22 | export const findneededFile=(list,fname)=>{ 23 | try { 24 | for(let fitem of list){ 25 | if(fitem.name===fname){ 26 | // console.log(fitem) 27 | return fitem 28 | } 29 | } 30 | } catch (error) { 31 | // console.log(error) 32 | return null 33 | } 34 | 35 | return null 36 | } 37 | 38 | /** 39 | * 从blockly字符串块传来的字符串套一个\`${}\` 40 | */ 41 | export const wrapStr=(str)=>{ 42 | return `\${${str}}` 43 | } -------------------------------------------------------------------------------- /src/renderer/utils/IOdata.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * 保存到localStorage,data为Object 3 | */ 4 | export function saveToLocalStorage(keyname,data){ 5 | const workspaceString=JSON.stringify(data) 6 | localStorage.setItem(keyname,workspaceString) 7 | } 8 | 9 | /** 10 | * 带后缀名称 11 | */ 12 | export function saveTxt(name,txt,recall=()=>{}){ 13 | // 要保存的字符串 14 | const stringData = txt 15 | // dada 表示要转换的字符串数据,type 表示要转换的数据格式 16 | const blob = new Blob([stringData], { 17 | type: "text/plain;charset=utf-8" 18 | }) 19 | // 根据 blob生成 url链接 20 | const objectURL = URL.createObjectURL(blob) 21 | 22 | // 创建一个 a 标签Tag 23 | const aTag = document.createElement('a') 24 | // 设置文件的下载地址 25 | aTag.href = objectURL 26 | // 设置保存后的文件名称 27 | aTag.download = name 28 | // 给 a 标签触发点击事件 29 | aTag.click() 30 | // 释放一个之前已经存在的、通过调用 URL.createObjectURL() 创建的 URL 对象。 31 | // 当你结束使用某个 URL 对象之后,应该通过调用这个方法来让浏览器知道不用在内存中继续保留对这个文件的引用了。 32 | URL.revokeObjectURL(objectURL) 33 | recall() 34 | } 35 | 36 | /** 37 | * 获取用户上传txt 38 | */ 39 | export function uploadTxt(file,resolve){ 40 | const reader = new FileReader(); 41 | reader.addEventListener('load', (event) => { 42 | resolve(event.target.result + "") 43 | }); 44 | reader.readAsText(file,"UTF-8") 45 | } -------------------------------------------------------------------------------- /src/renderer/utils/codetool.jsx: -------------------------------------------------------------------------------- 1 | export function generatefinalCodes(code){ 2 | let resultcode=` 3 | try { 4 | function makecodetxt(){ 5 | let importArea=false; 6 | let stagelist=[]; 7 | const errorset=new Set(); 8 | const resmap=new Map(); 9 | let incnum=0; 10 | 11 | let met200=false; 12 | 13 | const case_jump_dict=new Map(); 14 | 15 | // 所有阶段代码开始 16 | ${code} 17 | // 所有阶段代码结束 18 | let rescode="" 19 | if(errorset.size!=0){ 20 | 21 | rescode="以下主线块或定义支线块的id重复: "+Array.from(errorset.values()).join(","); 22 | return rescode; 23 | }else{ 24 | // 排序 25 | const sortMap = new Map([...resmap].sort((a, b) => a[0] - b[0])); 26 | rescode=""; 27 | for(let thiskey of sortMap.keys()){ 28 | if(thiskey>200 && !met200){ 29 | met200=true; 30 | rescode+="jump wholeProjectTail\\n" 31 | } 32 | if(thiskey>200){//key就是id 33 | // 支线块副本 34 | let thisvaluecode=sortMap.get(thiskey); 35 | // 如果有 跳转到该支线块 的跳转块 36 | if(case_jump_dict.has(thiskey)){ 37 | for(let timestamp of case_jump_dict.get(thiskey)){ 38 | rescode+="target "+thiskey+timestamp+"PathStart\\n" 39 | rescode+=thisvaluecode; 40 | rescode+="jump "+thiskey+timestamp+"PathBack\\n" 41 | } 42 | } 43 | 44 | }else{ 45 | // 主线块 46 | let thisvaluecode=sortMap.get(thiskey); 47 | rescode+=thisvaluecode; 48 | } 49 | 50 | } 51 | if(met200){//如果有支线 52 | rescode+="target wholeProjectTail\\n" 53 | } 54 | // 调试用 55 | window.errorset=errorset; 56 | window.resmap=resmap; 57 | window.case_jump_dict=case_jump_dict; 58 | // 去除换行后多余空格 59 | rescode=rescode.replace(/ *\\n */g,"\\n"); 60 | return rescode; 61 | } 62 | 63 | return rescode; 64 | } 65 | // React里提取txtcode 66 | txtcode=makecodetxt() 67 | } catch (error) { 68 | txtcode="生成脚本时出错啦!你可以反馈该问题:"+error.message 69 | } 70 | 71 | ` 72 | return resultcode 73 | } -------------------------------------------------------------------------------- /src/renderer/utils/hashtool.jsx: -------------------------------------------------------------------------------- 1 | const I64BIT_TABLE = 2 | 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-'.split(''); 3 | 4 | export function gethash(input){ 5 | let hash = 5381; 6 | let i = input.length - 1; 7 | 8 | if(typeof input == 'string'){ 9 | for (; i > -1; i--) 10 | hash += (hash << 5) + input.charCodeAt(i); 11 | }else{ 12 | for (; i > -1; i--) 13 | hash += (hash << 5) + input[i]; 14 | } 15 | let value = hash & 0x7FFFFFFF; 16 | 17 | let retValue = ''; 18 | do{ 19 | retValue += I64BIT_TABLE[value & 0x3F]; 20 | } 21 | while(value >>= 6); 22 | 23 | return retValue; 24 | } 25 | 26 | // console.log(gethash("阿露")) -------------------------------------------------------------------------------- /src/renderer/utils/imagetool.jsx: -------------------------------------------------------------------------------- 1 | export const getBase64 = (file) =>{ 2 | const promise=new Promise((resolve, reject) => { 3 | const reader = new FileReader(); 4 | reader.readAsDataURL(file); 5 | reader.onload = () => resolve(reader.result); 6 | reader.onerror = (error) => reject(error); 7 | }) 8 | return promise 9 | } 10 | 11 | export const getText=(file)=>{ 12 | const promise=new Promise((resolve, reject) => { 13 | const reader = new FileReader(); 14 | reader.readAsText(file) 15 | reader.onload = () => resolve(reader.result); 16 | reader.onerror = (error) => reject(error); 17 | }) 18 | return promise 19 | } 20 | 21 | export const getArrayBuffer=(file)=>{ 22 | const promise=new Promise((resolve, reject) => { 23 | const reader = new FileReader(); 24 | reader.readAsArrayBuffer(file) 25 | reader.onload = () => resolve(reader.result); 26 | reader.onerror = (error) => reject(error); 27 | }) 28 | return promise 29 | } -------------------------------------------------------------------------------- /src/renderer/utils/timestamp.jsx: -------------------------------------------------------------------------------- 1 | // 根据时间生成yyyymmddhhmmss,用来下载图片命名 2 | // 最多2000个不同的数 3 | function bigfunc(){ 4 | if(!window.numinbigfunc){ 5 | window.numinbigfunc=0 6 | } 7 | function smallfunc(){ 8 | window.numinbigfunc+=1 9 | return "tstamp"+window.numinbigfunc 10 | } 11 | 12 | return smallfunc 13 | } 14 | 15 | 16 | 17 | 18 | 19 | 20 | export const generateTime=bigfunc() 21 | 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "incremental": true, 4 | "target": "es2021", 5 | "module": "commonjs", 6 | "lib": ["dom", "es2021"], 7 | "jsx": "react-jsx", 8 | "strict": true, 9 | "sourceMap": true, 10 | "baseUrl": "./src", 11 | "moduleResolution": "node", 12 | "esModuleInterop": true, 13 | "allowSyntheticDefaultImports": true, 14 | "resolveJsonModule": true, 15 | "allowJs": true, 16 | "outDir": ".erb/dll" 17 | }, 18 | "exclude": ["test", "release/build", "release/app/dist", ".erb/dll"] 19 | } 20 | --------------------------------------------------------------------------------