├── .babelrc.js ├── .changeset ├── README.md └── config.json ├── .editorconfig ├── .eslintignore ├── .eslintrc ├── .gitignore ├── .npmignore ├── .npmrc ├── .npmrc.template ├── .prettierrc ├── .travis.yml ├── .vsce.template ├── LICENSE ├── README.md ├── README.zh-CN.md ├── _config.yml ├── demo ├── .babelrc.js ├── index.html ├── src │ ├── 2d │ │ └── index.tsx │ ├── 3d │ │ ├── box.tsx │ │ ├── index.tsx │ │ └── wireframe.tsx │ ├── benchmark.ts │ ├── data-flow │ │ ├── Collection.tsx │ │ ├── DisposerTest.tsx │ │ ├── Line.tsx │ │ ├── NormalPoint.tsx │ │ ├── Point.tsx │ │ ├── domain │ │ │ ├── countertop.ts │ │ │ ├── countertops.ts │ │ │ ├── line.ts │ │ │ └── point.ts │ │ ├── index.tsx │ │ ├── math │ │ │ └── Point2d.ts │ │ └── types │ │ │ └── enum.ts │ ├── image-builder │ │ ├── commands │ │ │ ├── default │ │ │ │ ├── index.ts │ │ │ │ └── move │ │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── shared │ │ │ │ ├── adjust │ │ │ │ └── index.ts │ │ │ │ ├── entity │ │ │ │ └── index.ts │ │ │ │ └── index.ts │ │ ├── common │ │ │ ├── consts │ │ │ │ ├── action.ts │ │ │ │ ├── color.ts │ │ │ │ ├── scene.ts │ │ │ │ └── view-entity.ts │ │ │ ├── imgs │ │ │ │ └── eden.png │ │ │ ├── styles │ │ │ │ ├── base.less │ │ │ │ └── theme.less │ │ │ └── utils │ │ │ │ ├── image.ts │ │ │ │ └── text.ts │ │ ├── hooks │ │ │ └── index.ts │ │ ├── index.less │ │ ├── index.tsx │ │ ├── models │ │ │ ├── domain │ │ │ │ ├── document.ts │ │ │ │ └── scene.ts │ │ │ ├── entity │ │ │ │ ├── frame.ts │ │ │ │ └── item.ts │ │ │ └── index.ts │ │ ├── types │ │ │ ├── README.md │ │ │ ├── assetsDefinition.d.ts │ │ │ ├── global.d.ts │ │ │ └── types.ts │ │ └── views │ │ │ ├── bottomBar │ │ │ ├── index.less │ │ │ └── index.tsx │ │ │ ├── leftPanel │ │ │ ├── index.less │ │ │ └── index.tsx │ │ │ ├── rightPanel │ │ │ ├── attribute.tsx │ │ │ ├── index.less │ │ │ └── index.tsx │ │ │ ├── topBar │ │ │ ├── index.less │ │ │ └── index.tsx │ │ │ └── world │ │ │ ├── entity │ │ │ ├── frame │ │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ └── item │ │ │ │ └── index.ts │ │ │ ├── gizmo │ │ │ └── index.ts │ │ │ ├── grid │ │ │ └── index.ts │ │ │ ├── hintLine │ │ │ └── index.ts │ │ │ ├── rangeLine │ │ │ └── index.ts │ │ │ └── snapLine │ │ │ └── index.ts │ ├── index.tsx │ └── lite-design │ │ ├── commands │ │ ├── clip │ │ │ └── index.ts │ │ ├── default │ │ │ ├── index.ts │ │ │ ├── move │ │ │ │ └── index.ts │ │ │ ├── rotate │ │ │ │ └── index.ts │ │ │ └── scale │ │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── measure │ │ │ ├── domain.ts │ │ │ └── index.ts │ │ └── skew │ │ │ └── index.ts │ │ ├── common │ │ ├── consts │ │ │ └── scene.ts │ │ ├── fonts │ │ │ ├── ionicons.eot │ │ │ ├── ionicons.svg │ │ │ ├── ionicons.ttf │ │ │ └── ionicons.woff │ │ ├── imgs │ │ │ └── eden.png │ │ ├── styles │ │ │ ├── base.less │ │ │ └── theme.less │ │ └── utils │ │ │ └── .gitkeep │ │ ├── hooks │ │ └── index.ts │ │ ├── index.tsx │ │ ├── models │ │ ├── domain │ │ │ ├── actions.ts │ │ │ ├── controls.ts │ │ │ ├── document.ts │ │ │ └── scene.ts │ │ ├── entity │ │ │ ├── adjustPoint.ts │ │ │ ├── assembly.ts │ │ │ ├── background.ts │ │ │ ├── clipPoint.ts │ │ │ ├── cube.ts │ │ │ ├── deletePoint.ts │ │ │ ├── product.ts │ │ │ ├── rotatePoint.ts │ │ │ ├── scalePoint.ts │ │ │ ├── skewPoint.ts │ │ │ └── skyBox.ts │ │ └── index.ts │ │ ├── tests │ │ └── index.test.ts │ │ ├── types │ │ ├── README.md │ │ ├── assetsDefinition.d.ts │ │ ├── global.d.ts │ │ └── types.ts │ │ ├── utils │ │ ├── category.ts │ │ ├── color.ts │ │ ├── common.ts │ │ └── image.ts │ │ └── views │ │ ├── leftPanel │ │ ├── index.less │ │ └── index.tsx │ │ └── scene │ │ ├── animation3d │ │ └── index.ts │ │ ├── camera │ │ └── index.tsx │ │ ├── helper │ │ └── index.tsx │ │ ├── index.less │ │ ├── index.tsx │ │ ├── light │ │ └── index.tsx │ │ ├── modelsWorld │ │ ├── AdjustPoint.ts │ │ ├── Assembly.ts │ │ ├── Background.ts │ │ ├── ClipBorder.ts │ │ ├── ClipPoint.ts │ │ ├── Cube.ts │ │ ├── DeletePoint.ts │ │ ├── Product.ts │ │ ├── RotatePoint.ts │ │ ├── ScalePoint.ts │ │ ├── SkewPoint.ts │ │ └── index.ts │ │ ├── skyBox │ │ └── index.ts │ │ └── tempWorld │ │ ├── Product2D.ts │ │ └── index.ts ├── tsconfig.json └── webpack.config.js ├── docs ├── .nojekyll ├── CHANGELOG.md ├── _navbar.md ├── en-us │ └── README.md ├── index.html ├── turbox-zhihu.md └── zh-cn │ ├── README.md │ ├── cli.md │ ├── dev-tool.md │ └── turbox.md ├── gen.js ├── jest.config.js ├── package.json ├── packages ├── command-manager │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── demo │ │ ├── CommandDemo.ts │ │ └── interactors │ │ │ ├── demo │ │ │ └── index.ts │ │ │ ├── index.ts │ │ │ ├── ioc │ │ │ ├── index.ts │ │ │ └── test.ts │ │ │ └── structure │ │ │ ├── CommandUnit.ts │ │ │ ├── DistributeCommandUnit.ts │ │ │ ├── Manager.ts │ │ │ ├── SequenceCommandUnit.ts │ │ │ ├── index.ts │ │ │ └── type.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── Command.ts │ │ ├── CommandManager.ts │ │ ├── Interaction.ts │ │ ├── compose.ts │ │ ├── create.ts │ │ ├── index.ts │ │ ├── install.ts │ │ ├── manager.ts │ │ ├── type.ts │ │ └── util.ts │ ├── tsconfig.json │ └── webpack.config.js ├── design-engine │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── assembly-entity-object │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── collision-engine │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── document-system │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── entity-object │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── env-system │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── free-draw-command │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── hint-command │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── inference-engine │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── load-system │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── material-brush-command │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── material-drag-system │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── measure-command │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── mount-system │ │ │ ├── README.md │ │ │ ├── ViewMounter.tsx │ │ │ ├── index.ts │ │ │ └── renderPluginView.tsx │ │ ├── placement-engine │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── rect-selection-command │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── selection-command │ │ │ ├── README.md │ │ │ ├── command.ts │ │ │ ├── domain.ts │ │ │ └── index.ts │ │ ├── space-engine │ │ │ ├── README.md │ │ │ └── index.ts │ │ └── unit-system │ │ │ ├── README.md │ │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── event-manager │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── index.ts │ │ ├── interactive │ │ │ ├── coordinate.ts │ │ │ ├── index.ts │ │ │ ├── listener │ │ │ │ ├── index.ts │ │ │ │ ├── type.ts │ │ │ │ └── utils.ts │ │ │ ├── sceneEvent.ts │ │ │ └── type.ts │ │ └── keyboard │ │ │ ├── index.ts │ │ │ ├── keyCode.ts │ │ │ ├── listener │ │ │ ├── index.ts │ │ │ └── util.ts │ │ │ └── type.ts │ ├── tsconfig.json │ └── webpack.config.js ├── graphic-component-pixi │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── _utils │ │ │ ├── README.md │ │ │ └── utils.ts │ │ ├── angle-dimension │ │ │ └── index.ts │ │ ├── arrow2d │ │ │ └── index.ts │ │ ├── axis2d │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── circle2d │ │ │ └── index.ts │ │ ├── dimension │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── draw-utils │ │ │ ├── README.md │ │ │ ├── drawCircle.ts │ │ │ ├── drawLine.ts │ │ │ ├── drawPath.ts │ │ │ ├── drawPolygon.ts │ │ │ ├── drawRect.ts │ │ │ ├── index.ts │ │ │ └── option.ts │ │ ├── gizmo2d │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── grid2d │ │ │ ├── grid-helper.ts │ │ │ └── index.ts │ │ ├── image2d │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── line2d │ │ │ └── index.ts │ │ ├── placement │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── polygon │ │ │ └── index.ts │ │ ├── radius-dimension │ │ │ └── index.ts │ │ ├── rect2d │ │ │ └── index.ts │ │ └── text2d │ │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── graphic-component-three │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── _utils │ │ │ ├── README.md │ │ │ └── utils.ts │ │ ├── animation3d │ │ │ └── index.ts │ │ ├── arrow3d │ │ │ └── index.ts │ │ ├── axis3d │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── circle3d │ │ │ └── index.ts │ │ ├── cube │ │ │ └── index.ts │ │ ├── fat-line │ │ │ └── index.ts │ │ ├── gizmo3d │ │ │ ├── README.md │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── rect3d │ │ │ └── index.ts │ │ └── wireframe │ │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── math │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── MathUtils.ts │ │ ├── base │ │ │ ├── Box2.ts │ │ │ ├── Box3.ts │ │ │ ├── Euler.ts │ │ │ ├── Interval.ts │ │ │ ├── Line3.ts │ │ │ ├── Matrix3.ts │ │ │ ├── Matrix4.ts │ │ │ ├── Quaternion.ts │ │ │ ├── Ray.ts │ │ │ ├── Tolerance.ts │ │ │ ├── Vector2.ts │ │ │ ├── Vector3.ts │ │ │ └── Vector4.ts │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── reactivity-react │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── components │ │ │ ├── ErrorBoundary.tsx │ │ │ └── Reactive.tsx │ │ ├── index.ts │ │ └── utils │ │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── reactivity │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── const │ │ │ ├── config.ts │ │ │ ├── enums.ts │ │ │ └── symbol.ts │ │ ├── core │ │ │ ├── action.ts │ │ │ ├── collector.ts │ │ │ ├── domain.ts │ │ │ ├── init.ts │ │ │ ├── reactive.ts │ │ │ ├── store.ts │ │ │ ├── time-travel.ts │ │ │ └── use.ts │ │ ├── decorators │ │ │ ├── action.ts │ │ │ ├── computed.ts │ │ │ ├── effect.ts │ │ │ ├── mutation.ts │ │ │ └── reactor.ts │ │ ├── index.ts │ │ ├── interfaces.ts │ │ ├── middlewares │ │ │ ├── common.ts │ │ │ ├── effect.ts │ │ │ ├── logger.ts │ │ │ ├── mutation.ts │ │ │ └── perf.ts │ │ └── utils │ │ │ ├── common.ts │ │ │ ├── event.ts │ │ │ └── materialCallStack.ts │ ├── tsconfig.json │ └── webpack.config.js ├── renderer-core │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── __tests__ │ │ │ └── render.test.ts │ │ ├── common.ts │ │ ├── component.ts │ │ ├── index.ts │ │ ├── mesh.ts │ │ ├── reactive.ts │ │ ├── render.ts │ │ ├── scene.ts │ │ └── utils.ts │ ├── tsconfig.json │ └── webpack.config.js ├── renderer-pixi │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── Mesh2D │ │ │ └── Mesh2D.ts │ │ ├── Scene2D │ │ │ └── index.ts │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── renderer-three │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── Mesh3D │ │ │ └── Mesh3D.ts │ │ ├── Scene3D │ │ │ └── index.ts │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── shared │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── __tests__ │ │ │ ├── common.test.ts │ │ │ ├── compose.test.ts │ │ │ └── lang.test.ts │ │ ├── common.ts │ │ ├── compose.ts │ │ ├── debounce.ts │ │ ├── decorator.ts │ │ ├── deep-merge.ts │ │ ├── error.ts │ │ ├── event.ts │ │ ├── graphic.ts │ │ ├── image.ts │ │ ├── index.ts │ │ ├── lang.ts │ │ ├── rafTask.ts │ │ ├── task.ts │ │ ├── type.ts │ │ └── uuid.ts │ ├── tsconfig.json │ └── webpack.config.js ├── turbox │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── __tests__ │ │ │ └── index.test.ts │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── turbox2d │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── __tests__ │ │ │ └── index.test.ts │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js └── turbox3d │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── jest.config.js │ ├── package.json │ ├── src │ ├── __tests__ │ │ └── index.test.ts │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── plugins ├── turbox-dev-tool │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── fps-monitor │ │ │ ├── fps.ts │ │ │ └── index.tsx │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js ├── turbox-hot-loader │ ├── .babelrc.js │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── components │ │ │ └── hot.tsx │ │ ├── hot.ts │ │ ├── index.ts │ │ └── utils │ │ │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.js └── turbox-snippets │ ├── .vscodeignore │ ├── CHANGELOG.md │ ├── README.md │ ├── images │ └── turbox.png │ ├── package.json │ └── snippets │ └── snippets.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── sync.js ├── tsconfig.json ├── typedoc.json └── webpack.config.js /.babelrc.js: -------------------------------------------------------------------------------- 1 | const cjs = process.env.BABEL_ENV === 'commonjs' ? 'commonjs' : false; 2 | 3 | const presets = [ 4 | [ 5 | '@babel/env', 6 | { 7 | modules: cjs, 8 | }, 9 | ], 10 | ]; 11 | const plugins = [ 12 | [ 13 | '@babel/plugin-transform-runtime', 14 | { 15 | useESModules: !cjs, 16 | // corejs: 2, 17 | }, 18 | ], 19 | ]; 20 | 21 | if (cjs) { 22 | plugins.push('@babel/plugin-transform-modules-commonjs'); 23 | } 24 | 25 | module.exports = (api) => { 26 | api && api.cache(true); 27 | return { 28 | presets, 29 | plugins, 30 | }; 31 | } 32 | -------------------------------------------------------------------------------- /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": true, 5 | "fixed": [], 6 | "linked": [], 7 | "access": "public", 8 | "baseBranch": "master", 9 | "updateInternalDependencies": "patch", 10 | "ignore": [] 11 | } 12 | -------------------------------------------------------------------------------- /.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 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | plugins/ 2 | node_modules/ 3 | demo/ 4 | *.js 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode 2 | .DS_Store 3 | .difflintfiles 4 | .idea 5 | lerna-debug.log* 6 | npm-debug.log* 7 | node_modules 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lib 11 | dist 12 | es 13 | coverage 14 | ts 15 | typings 16 | .history 17 | pluginA 18 | pluginB 19 | packages/atom 20 | build 21 | typedocs 22 | pnpm-publish-summary.json 23 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Mac 10 | .DS_Store 11 | 12 | # git 13 | .git 14 | 15 | # Editor directories and files 16 | .idea 17 | .vscode 18 | .history 19 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=true 2 | # enable-pre-post-scripts=true 3 | # link-workspace-packages=false 4 | # prefer-workspace-packages=true 5 | # save-workspace-protocol=true 6 | -------------------------------------------------------------------------------- /.npmrc.template: -------------------------------------------------------------------------------- 1 | always-auth=true 2 | //registry.npmjs.org/:_authToken=${NPM_AUTH_TOKEN} 3 | registry=https://registry.npmjs.org/ 4 | sass_binary_site=https://npm.taobao.org/mirrors/node-sass 5 | lockfile=false 6 | link-workspace-packages=false 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 120, 3 | "singleQuote": true, 4 | "arrowParens": "avoid" 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | cache: 3 | npm: false 4 | directories: 5 | - "~/.pnpm-store" 6 | node_js: 7 | - 12.16.2 8 | before_install: 9 | - corepack enable 10 | - corepack prepare pnpm@latest-8 --activate 11 | - pnpm config set store-dir ~/.pnpm-store 12 | install: 13 | - pnpm install 14 | 15 | stages: 16 | - test 17 | - name: deploy 18 | if: (tag =~ ^@turbox3d) OR (tag =~ ^turbox) 19 | - name: deploy-plugin 20 | if: tag =~ ^@plugin 21 | 22 | jobs: 23 | include: 24 | - stage: test 25 | script: 26 | - pnpm --filter './packages/**' run build:ts 27 | - pnpm --filter './packages/**' run test 28 | - stage: deploy 29 | script: 30 | - cp .npmrc.template $HOME/.npmrc 31 | - pnpm run publish 32 | - stage: deploy-plugin 33 | script: 34 | - cp .vsce.template $HOME/.vsce 35 | - cd ./plugins/turbox-snippets 36 | - pnpm exec vsce publish 37 | -------------------------------------------------------------------------------- /.vsce.template: -------------------------------------------------------------------------------- 1 | { 2 | "publishers":[{ 3 | "name": "feifan-gff", 4 | "pat": "${AZURE_ACCESS_TOKEN}" 5 | }] 6 | } 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-present, Felix Koo 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.md: -------------------------------------------------------------------------------- 1 | English | [简体中文](./README.zh-CN.md) 2 | 3 |

4 | turbox Logo 5 |

6 | 7 | [![build status](https://img.shields.io/travis/com/turbox3d/turbox/master.svg?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 8 | [![license](https://img.shields.io/github/license/turbox3d/turbox?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 9 | [![npm version](https://img.shields.io/npm/v/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 10 | [![npm downloads](https://img.shields.io/npm/dm/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 11 | [![install size](https://img.shields.io/bundlephobia/minzip/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 12 | 13 |

Turbox

14 | 15 | **Turbox** is a large-scale productivity application front-end framework. 16 | 17 | ## Ecosystem 18 | 19 | | Project | Status | Description | 20 | |---------|--------|-------------| 21 | | turbox-cli | - | Project cli tool, include scaffolding | 22 | | turbox-dev-tool | - | Browser DevTools extension | 23 | | turbox-loader | - | Turbox loader for webpack | 24 | | turbox-snippets | [see marketplace](https://marketplace.visualstudio.com/items?itemName=feifan-gff.turbox-snippets) | Vscode snippet extension | 25 | 26 | ## Documentation 27 | 28 | [中文文档](https://turbox3d.github.io/turbox/#/zh-cn/turbox) 29 | 30 | Visit [turbox official website](https://turbox3d.github.io/turbox/#/en-us/). 31 | 32 | ## Feedback 33 | 34 | | Github Issue | Wechat | 35 | | --- | --- | 36 | | [turbox3d/turbox/issues](https://github.com/turbox3d/turbox/issues) | | 37 | 38 | ## License 39 | 40 | [MIT](http://opensource.org/licenses/MIT) 41 | 42 | Copyright (c) 2020-present, Felix Koo 43 | -------------------------------------------------------------------------------- /README.zh-CN.md: -------------------------------------------------------------------------------- 1 | [English](./README.md) | 简体中文 2 | 3 |

4 | turbox Logo 5 |

6 | 7 | [![build status](https://img.shields.io/travis/com/turbox3d/turbox/master.svg?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 8 | [![license](https://img.shields.io/github/license/turbox3d/turbox?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 9 | [![npm version](https://img.shields.io/npm/v/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 10 | [![npm downloads](https://img.shields.io/npm/dm/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 11 | [![install size](https://img.shields.io/bundlephobia/minzip/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 12 | 13 |

Turbox

14 | 15 | **Turbox**(涡轮)是适合大型生产力软件应用的前端框架,场景来源于复杂大型 3D 业务 16 | 17 | ## 生态系统 18 | 19 | | Project | Status | Description | 20 | |---------|--------|-------------| 21 | | turbox-cli | - | Project cli tool, include scaffolding | 22 | | turbox-dev-tool | - | Browser DevTools extension | 23 | | turbox-loader | - | Turbox loader for webpack | 24 | | turbox-snippets | [see marketplace](https://marketplace.visualstudio.com/items?itemName=feifan-gff.turbox-snippets) | Vscode snippet extension | 25 | 26 | ## 文档 27 | 28 | [中文文档](https://turbox3d.github.io/turbox/#/zh-cn/turbox) 29 | 30 | Visit [turbox official website](https://turbox3d.github.io/turbox/#/en-us/). 31 | 32 | ## 反馈 33 | 34 | | Github Issue | 微信群 | 35 | | --- | --- | 36 | | [turbox3d/turbox/issues](https://github.com/turbox3d/turbox/issues) | | 37 | 38 | ## 许可证 39 | 40 | [MIT](http://opensource.org/licenses/MIT) 41 | 42 | Copyright (c) 2020-present, Felix Koo 43 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /demo/.babelrc.js: -------------------------------------------------------------------------------- 1 | const cjs = process.env.BABEL_ENV === 'commonjs' ? 'commonjs' : false; 2 | 3 | const presets = [ 4 | [ 5 | '@babel/env', 6 | { 7 | modules: cjs, 8 | }, 9 | ], 10 | '@babel/react', 11 | ]; 12 | const plugins = [ 13 | [ 14 | '@babel/plugin-transform-runtime', 15 | { 16 | useESModules: !cjs, 17 | // corejs: 2, 18 | }, 19 | ], 20 | ]; 21 | 22 | if (cjs) { 23 | plugins.push('@babel/plugin-transform-modules-commonjs'); 24 | } 25 | 26 | module.exports = (api) => { 27 | api && api.cache(true); 28 | return { 29 | presets, 30 | plugins, 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Turbox Demo 6 | 7 | 8 | 9 | 13 | 14 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /demo/src/2d/index.tsx: -------------------------------------------------------------------------------- 1 | // import * as React from 'react'; 2 | // import * as PIXI from 'pixi.js'; 3 | // import { Mesh2D, Scene2D } from '@turbox3d/graphic-view-2d'; 4 | 5 | // const Width = 600; 6 | // const Height = 600; 7 | 8 | // export class Scene2DFront extends React.Component { 9 | // render() { 10 | // return ( 11 | // 16 | // 17 | // 18 | // ); 19 | // } 20 | // } 21 | // class Box extends Mesh2D { 22 | // protected view = new PIXI.Graphics(); 23 | // draw() { 24 | // this.view.beginFill(0x00eeee); 25 | // this.view.drawCircle(150, -300, 200); 26 | // this.view.endFill(); 27 | 28 | // this.view.beginFill(0xee1100); 29 | // this.view.drawRect(350, -200, 200, 200); 30 | // this.view.endFill(); 31 | // } 32 | // } 33 | -------------------------------------------------------------------------------- /demo/src/3d/wireframe.tsx: -------------------------------------------------------------------------------- 1 | // import { EntityObject, Mesh3D } from '@turbox3d/turbox'; 2 | // import * as THREE from 'three'; 3 | // import { color16 } from './box'; 4 | 5 | // interface IProps { 6 | // model: EntityObject; 7 | // } 8 | 9 | // export class WireFrame extends Mesh3D { 10 | // protected reactivePipeLine = [ 11 | // this.updateGeometry, 12 | // ]; 13 | // protected view = new THREE.Mesh(); 14 | 15 | // updateGeometry() { 16 | // const { model } = this.props; 17 | // const box = model.getBox3(); 18 | // const p0 = box[0]; 19 | // const p1 = box[1]; 20 | // const p3 = box[3]; 21 | // const p7 = box[7]; 22 | // const width = p3.x - p0.x; 23 | // const height = p7.y - p0.y; 24 | // const depth = p1.z - p0.z; 25 | // const geometry = new THREE.BoxGeometry(width, height, depth); 26 | // const material = new THREE.MeshBasicMaterial({ color: color16() }); 27 | // const wireframe = new THREE.WireframeGeometry(geometry); 28 | // const line = new THREE.LineSegments(wireframe); 29 | // line.material = material; 30 | // this.view.position.set(0, 0, 0); 31 | // this.view.add(line); 32 | // } 33 | // } 34 | -------------------------------------------------------------------------------- /demo/src/data-flow/Collection.tsx: -------------------------------------------------------------------------------- 1 | import { Reactive } from '@turbox3d/reactivity-react'; 2 | import React from 'react'; 3 | import { cts } from './index'; 4 | 5 | const Collection: React.FC<{}> = () => { 6 | console.log('Collection'); 7 | for (const [key, value] of cts.countertops[0].myMap) { 8 | console.log(key, value); 9 | } 10 | return ( 11 |
12 |
13 | test Map: 14 | {cts.countertops[0].myMap.size}
15 | {Array.from(cts.countertops[0].myMap).join()}
16 | {/* {cts.countertops[0].myMap.get(0)}
*/} 17 | {/* {cts.countertops[0].myMap.has(0) ? 'true' : 'false'}
*/} 18 | {cts.countertops[0].myMap.get(1)}
19 | {cts.countertops[0].myMap.has(1) ? 'true' : 'false'}
20 | {/* {cts.countertops[0].myMap.forEach((value, key) => { 21 | console.log(value, '...', key); 22 | })}
*/} 23 | {/* {cts.countertops[0].myMap.entries()}
*/} 24 | {/* {cts.countertops[0].myMap.keys()}
*/} 25 | {/* {cts.countertops[0].myMap.values()}
*/} 26 |
27 |
28 | test Set: 29 | {cts.countertops[0].mySet.size}
30 | {Array.from(cts.countertops[0].mySet).join()}
31 | {/* {cts.countertops[0].mySet.has(0) ? 'true' : 'false'}
*/} 32 | {/* {cts.countertops[0].mySet.has(1) ? 'true' : 'false'}
*/} 33 | {cts.countertops[0].mySet.has(1000) ? 'true' : 'false'}
34 | {/* {cts.countertops[0].mySet.forEach((value) => { 35 | console.log(value, '@@@'); 36 | })}
*/} 37 | {/* {cts.countertops[0].mySet.entries()}
*/} 38 | {/* {cts.countertops[0].mySet.keys()}
*/} 39 | {/* {cts.countertops[0].mySet.values()}
*/} 40 |
41 |
42 | ); 43 | }; 44 | 45 | export default Reactive(Collection); 46 | -------------------------------------------------------------------------------- /demo/src/data-flow/DisposerTest.tsx: -------------------------------------------------------------------------------- 1 | import { Reactive, reactive } from '@turbox3d/reactivity-react'; 2 | import React from 'react'; 3 | import { cts } from './index'; 4 | 5 | const r = reactive(() => { 6 | console.log('^^^^^'); 7 | }); 8 | 9 | const Disposer: React.FC<{}> = () => { 10 | console.log('Disposer'); 11 | // console.log(p.position); 12 | console.log(cts.countertops[0].points[0] && cts.countertops[0].points[0].position); 13 | return ( 14 |
hello disposer
15 | ) 16 | }; 17 | 18 | export default Reactive(Disposer); 19 | -------------------------------------------------------------------------------- /demo/src/data-flow/Line.tsx: -------------------------------------------------------------------------------- 1 | import { Reactive } from '@turbox3d/reactivity-react'; 2 | import React from 'react'; 3 | import { Line } from './domain/line'; 4 | 5 | interface IProps { 6 | data: Line; 7 | } 8 | 9 | const LineComp: React.FC = ({ data }) => { 10 | console.log('***childLine'); 11 | React.useEffect(() => { 12 | console.log('line didMount'); 13 | }, []); 14 | // React.useCallback(() => { 15 | 16 | // }, []); 17 | return ( 18 | 19 | line: 20 | lineLength: {data.length} 21 | lineStart: ({data.start.position.x},{data.start.position.y}) 22 | lineEnd: ({data.end.position.x},{data.end.position.y}) 23 | 24 | 25 | 26 | ); 27 | }; 28 | 29 | export default Reactive(LineComp); 30 | -------------------------------------------------------------------------------- /demo/src/data-flow/NormalPoint.tsx: -------------------------------------------------------------------------------- 1 | 2 | import React from 'react'; 3 | import { Reactive } from '@turbox3d/reactivity-react'; 4 | import { cts } from './index'; 5 | 6 | interface IProps { 7 | index: number; 8 | np: object; 9 | } 10 | 11 | const NormalPoint: React.FC = Reactive(({ index, np }) => { 12 | console.log(index, np, '&(*(&(*&(&'); 13 | const updateFirstPointPosition = (index) => () => { 14 | cts.countertops[0].updatePointByIndex(index, false); 15 | } 16 | 17 | return ( 18 |
19 | np position: { (np as any).position.isActive ? 'true' : 'false' } 20 | 21 |
22 | ); 23 | }); 24 | 25 | export default NormalPoint; 26 | -------------------------------------------------------------------------------- /demo/src/data-flow/domain/countertops.ts: -------------------------------------------------------------------------------- 1 | import { Domain, mutation, reactor } from '@turbox3d/reactivity-react'; 2 | import { Countertop } from './countertop'; 3 | 4 | export class Countertops extends Domain { 5 | @reactor countertops: Countertop[]; 6 | 7 | @mutation('更新Countertops') 8 | updateCountertops(countertops: Countertop[]) { 9 | this.countertops = countertops; 10 | } 11 | 12 | constructor({ 13 | countertops, 14 | }: { 15 | countertops: Countertop[], 16 | }) { 17 | super(); 18 | this.countertops = countertops; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /demo/src/data-flow/domain/line.ts: -------------------------------------------------------------------------------- 1 | import { Domain, reactor } from '@turbox3d/reactivity-react'; 2 | import { Countertop } from './countertop'; 3 | import { Point } from './point'; 4 | 5 | export class Line extends Domain { 6 | @reactor start: Point; 7 | @reactor end: Point; 8 | @reactor length: number; 9 | @reactor countertop?: Countertop; 10 | 11 | constructor({ 12 | start, 13 | end, 14 | countertop, 15 | }: { 16 | start: Point, 17 | end: Point, 18 | countertop?: Countertop; 19 | }) { 20 | super(); 21 | this.start = start; 22 | this.end = end; 23 | this.countertop = countertop; 24 | this.length = 10; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/data-flow/domain/point.ts: -------------------------------------------------------------------------------- 1 | import Point2d from '../math/Point2d'; 2 | import { Domain, mutation, reactor } from '@turbox3d/reactivity-react'; 3 | import { Countertop } from './countertop'; 4 | import { Line } from './line'; 5 | import { EPointType } from '../types/enum'; 6 | 7 | export class Point extends Domain { 8 | @reactor(true, true, function(target, property) { 9 | // console.log('$$$$$', target, property); 10 | // console.log(this); 11 | }) position: Point2d; 12 | @reactor type: EPointType; 13 | @reactor prevLine?: Line; 14 | @reactor nextLine?: Line; 15 | @reactor countertop?: Countertop; 16 | 17 | @mutation('更新点位置') 18 | updatePosition = (p: Point2d) => { 19 | this.position = p; 20 | } 21 | 22 | @mutation('更新点x位置') 23 | updatePositionX = () => { 24 | this.position.x = 1000; 25 | } 26 | 27 | constructor({ 28 | position, 29 | type, 30 | }: { 31 | position: Point2d, 32 | type: EPointType, 33 | prevLine?: Line; 34 | nextLine?: Line; 35 | countertop?: Countertop; 36 | }) { 37 | super(); 38 | this.position = position; 39 | this.type = type; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /demo/src/data-flow/math/Point2d.ts: -------------------------------------------------------------------------------- 1 | export default class Point2d { 2 | x: number; 3 | y: number; 4 | 5 | constructor(x: number, y: number) { 6 | this.x = x; 7 | this.y = y; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /demo/src/data-flow/types/enum.ts: -------------------------------------------------------------------------------- 1 | export enum EPointType { 2 | NONE = 0, 3 | CIRCLE = 1, 4 | LINE = 2, 5 | CUT_CIRCLE = 3, 6 | } 7 | -------------------------------------------------------------------------------- /demo/src/image-builder/commands/default/index.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager, SelectionCommand, HintCommand, SceneEvent, SceneTool, ViewEntity } from '@turbox3d/turbox'; 2 | 3 | import { MoveCommand } from './move'; 4 | import { imageBuilderStore } from '../../models'; 5 | 6 | /** 7 | * 画布默认激活的全局事件指令集 8 | */ 9 | class DefaultCommand extends CommandManager.compose({ 10 | hint: HintCommand, 11 | select: SelectionCommand, 12 | move: MoveCommand, 13 | }) { 14 | active() { 15 | this.select.active({ 16 | hint: this.hint, 17 | }); 18 | this.hint.active(this.select); 19 | this.move.active(); 20 | } 21 | 22 | protected onWheel(entity: ViewEntity, event: SceneEvent, tools: SceneTool): void { 23 | const sceneTool = imageBuilderStore.scene.sceneTools; 24 | if (!sceneTool) { 25 | return; 26 | } 27 | const rootView = sceneTool.getRootView(); 28 | imageBuilderStore.scene.$update({ 29 | canvasZoom: rootView.scale.x, 30 | }); 31 | } 32 | } 33 | 34 | export { DefaultCommand }; 35 | -------------------------------------------------------------------------------- /demo/src/image-builder/commands/index.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager } from '@turbox3d/turbox'; 2 | 3 | import { SharedCommand } from './shared'; 4 | import { DefaultCommand } from './default'; 5 | 6 | /** 7 | * 除公共函数指令集,其他顶层全局事件指令集之间是互斥的,即一次只能激活一组指令集,非当前指令集的事件会被自动禁用 8 | */ 9 | class AppCommandManager extends CommandManager.install({ 10 | default: DefaultCommand, 11 | _shared: SharedCommand, 12 | }) { 13 | installed() { 14 | this.default.apply(); // 激活默认指令集 15 | } 16 | 17 | disposeAll() { 18 | this.default.select.clearAllSelected(); 19 | this.default.dispose(); 20 | this._shared.dispose(); 21 | } 22 | } 23 | 24 | export const appCommandManager = new AppCommandManager(); 25 | -------------------------------------------------------------------------------- /demo/src/image-builder/commands/shared/index.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager } from '@turbox3d/turbox'; 2 | import { AdjustCommand } from './adjust'; 3 | import { EntityCommand } from './entity'; 4 | 5 | /** 6 | * 公共函数指令集(不存在全局事件,以函数收敛通用交互逻辑,可随时调用) 7 | */ 8 | class SharedCommand extends CommandManager.compose({ 9 | adjust: AdjustCommand, 10 | entity: EntityCommand, 11 | }) { 12 | active() { 13 | this.adjust.active(); 14 | this.entity.active(); 15 | } 16 | } 17 | 18 | export { SharedCommand }; 19 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/consts/action.ts: -------------------------------------------------------------------------------- 1 | export enum Z_INDEX_ACTION { 2 | /** 置顶 */ 3 | TOP = 'top', 4 | /** 置底 */ 5 | BOTTOM = 'bottom', 6 | /** 下移 */ 7 | DECREASE = 'decrease', 8 | /** 上移 */ 9 | INCREASE = 'increase', 10 | } 11 | 12 | export enum MIRROR_ACTION { 13 | /** 左右镜像 */ 14 | LEFT_RIGHT = 'left_right', 15 | /** 上下镜像 */ 16 | TOP_BOTTOM = 'top_bottom', 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/consts/color.ts: -------------------------------------------------------------------------------- 1 | export const PRIMARY_COLOR = 0xFE2C55; 2 | export const RED = 0xff0000; 3 | export const GREEN = 0x00ff00; 4 | export const YELLOW = 0xffff00; 5 | export const BLUE = 0x0000ff; 6 | export const WHITE = 0xffffff; 7 | export const GRAY = 0xdddddd; 8 | export const BLACK = 0x000000; 9 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/consts/scene.ts: -------------------------------------------------------------------------------- 1 | export enum Z_INDEX_ACTION { 2 | /** 置顶 */ 3 | TOP = 'top', 4 | /** 置底 */ 5 | BOTTOM = 'bottom', 6 | /** 下移 */ 7 | DECREASE = 'decrease', 8 | /** 上移 */ 9 | INCREASE = 'increase', 10 | } 11 | 12 | export enum RenderOrder { 13 | GRID = -9999, 14 | BACKGROUND = -1, 15 | SNAP_LINE = 9000, 16 | GIZMO = 9999, 17 | } 18 | 19 | export enum ItemType { 20 | /** 图片 */ 21 | IMAGE = 'image', 22 | /** 文本 */ 23 | TEXT = 'text', 24 | /** 按钮 */ 25 | BUTTON = 'button', 26 | } 27 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/consts/view-entity.ts: -------------------------------------------------------------------------------- 1 | export const ItemSymbol = Symbol('item'); 2 | export const FrameSymbol = Symbol('frame'); 3 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/imgs/eden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/demo/src/image-builder/common/imgs/eden.png -------------------------------------------------------------------------------- /demo/src/image-builder/common/styles/base.less: -------------------------------------------------------------------------------- 1 | // @import "normalize.css"; 2 | @import "./theme.less"; 3 | 4 | .body { 5 | font-size: 12px; 6 | } 7 | 8 | * { 9 | box-sizing: border-box; 10 | } 11 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/styles/theme.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: rgb(247, 245, 245); 3 | } 4 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/utils/image.ts: -------------------------------------------------------------------------------- 1 | export function updateQueryStringParameter(url: string, key: string, value: string) { 2 | if (!value) { 3 | return url; 4 | } 5 | const re = new RegExp(`([?&])${key}=.*?(&|$)`, 'i'); 6 | const separator = url.indexOf('?') !== -1 ? '&' : '?'; 7 | if (url.match(re)) { 8 | return url.replace(re, `$1${key}=${value}$2`); 9 | } 10 | return `${url}${separator}${key}=${value}`; 11 | } 12 | 13 | function convertUrl(url: string, key = 'turbox') { 14 | if (url.includes(';base64,') || !url) { 15 | return url; 16 | } 17 | return updateQueryStringParameter(url, key, 'true'); 18 | } 19 | 20 | export async function loadImageElement(url: string | Blob) { 21 | const img = new Image(); 22 | img.setAttribute('crossOrigin', 'anonymous'); 23 | img.src = url instanceof Blob ? URL.createObjectURL(url) : convertUrl(url); 24 | return new Promise<{ 25 | element: HTMLImageElement; 26 | width: number; 27 | height: number; 28 | }>(resolve => { 29 | img.onload = () => { 30 | url instanceof Blob && URL.revokeObjectURL(img.src); 31 | resolve({ 32 | element: img, 33 | width: img.width, 34 | height: img.height, 35 | }); 36 | }; 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /demo/src/image-builder/common/utils/text.ts: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js'; 2 | import { ItemEntity } from '../../models/entity/item'; 3 | 4 | export const getMaxWidthWord = (target: ItemEntity) => { 5 | const style = new PIXI.TextStyle(target.fontStyles); 6 | const words = target.text.trim().split(/\s+/); 7 | const maxWidthWord = words.reduce((prev, cur) => { 8 | const prevWidth = new PIXI.Text(prev, style).width; 9 | const curWidth = new PIXI.Text(cur, style).width; 10 | if (prevWidth > curWidth) { 11 | return prev; 12 | } 13 | return cur; 14 | }); 15 | const width = new PIXI.Text(maxWidthWord, style).width; 16 | return width; 17 | }; 18 | 19 | export const getTextBounds = (target: ItemEntity) => { 20 | const style = new PIXI.TextStyle(target.fontStyles); 21 | const text = target.text.trim(); 22 | const { width, height } = new PIXI.Text(text, style); 23 | return { 24 | width, 25 | height, 26 | }; 27 | }; 28 | -------------------------------------------------------------------------------- /demo/src/image-builder/index.less: -------------------------------------------------------------------------------- 1 | .fps-monitor { 2 | position: absolute; 3 | z-index: 100; 4 | top: 0; 5 | left: 0; 6 | background: rgba(0, 0, 0, .7); 7 | color: #fff; 8 | width: 70px; 9 | height: 20px; 10 | pointer-events: none; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | } 15 | 16 | body { 17 | margin: 0; 18 | padding: 0; 19 | overflow: hidden; 20 | } 21 | -------------------------------------------------------------------------------- /demo/src/image-builder/models/entity/frame.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | import { GRAY } from '../../common/consts/color'; 3 | 4 | export class FrameEntity extends EntityObject { 5 | @reactor imageData?: HTMLImageElement; 6 | @reactor resourceUrl = ''; 7 | @reactor bgColor = GRAY; 8 | } 9 | -------------------------------------------------------------------------------- /demo/src/image-builder/models/index.ts: -------------------------------------------------------------------------------- 1 | import { DocumentDomain } from './domain/document'; 2 | import { SceneDomain } from './domain/scene'; 3 | 4 | export const imageBuilderStore = { 5 | document: new DocumentDomain(), 6 | scene: new SceneDomain(), 7 | }; 8 | -------------------------------------------------------------------------------- /demo/src/image-builder/types/README.md: -------------------------------------------------------------------------------- 1 | # 全局类型文件 2 | -------------------------------------------------------------------------------- /demo/src/image-builder/types/assetsDefinition.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png'; 2 | declare module '*.jpg'; 3 | declare module '*.svg'; 4 | declare module '*.jpeg'; 5 | declare module '*.gif'; 6 | declare module '*.webp'; 7 | declare module '*.ttf'; 8 | declare module '*.woff'; 9 | declare module '*.woff2'; 10 | declare module '*.scss'; 11 | declare module '*.less'; 12 | declare module '*.css'; 13 | declare module '*?__inline'; 14 | declare module '*?__inline=true'; 15 | declare module '*?__inline=false'; 16 | -------------------------------------------------------------------------------- /demo/src/image-builder/types/global.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | // eslint-disable-next-line @typescript-eslint/naming-convention 3 | $$DEBUG: any; 4 | ColorThief: any; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/image-builder/types/types.ts: -------------------------------------------------------------------------------- 1 | export interface IConstructorOf { 2 | new(...args: any[]): T; 3 | } 4 | 5 | export interface IMapOf { 6 | [key: string]: T; 7 | } 8 | 9 | export type Nullable = { [K in keyof T]?: T[K] | null }; 10 | 11 | export function getValue(obj: T, key: K): T[K] { 12 | return obj[key]; 13 | } 14 | 15 | export interface IDictionary { 16 | [index: string]: T; 17 | } 18 | 19 | export interface INumericDictionary { 20 | [index: number]: T; 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/bottomBar/index.less: -------------------------------------------------------------------------------- 1 | .bottom-bar { 2 | position: absolute; 3 | bottom: 10px; 4 | left: 330px; 5 | padding: 0 10px; 6 | background: #fff; 7 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1); 8 | border-radius: 5px; 9 | font-size: 16px; 10 | line-height: 14px; 11 | color: #4E5969; 12 | z-index: 1000; 13 | display: flex; 14 | align-items: center; 15 | 16 | .slider { 17 | width: 120px; 18 | margin: 12px; 19 | } 20 | 21 | .action-item { 22 | display: flex; 23 | align-items: center; 24 | margin-right: 10px; 25 | 26 | &:last-child { 27 | margin-right: 0; 28 | } 29 | 30 | &.reset { 31 | cursor: pointer; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/bottomBar/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Slider, Tooltip } from 'antd'; 3 | import { ReactiveReact } from '@turbox3d/turbox'; 4 | import { SyncOutlined, ZoomInOutlined, ZoomOutOutlined } from '@ant-design/icons'; 5 | import './index.less'; 6 | import { imageBuilderStore } from '../../models'; 7 | 8 | export const BottomBar = ReactiveReact(() => { 9 | const [min, max] = imageBuilderStore.scene.canvasZoomRange; 10 | const sceneTool = imageBuilderStore.scene.sceneTools; 11 | if (!sceneTool) { 12 | return null; 13 | } 14 | const scaleScene = (ratio: number) => { 15 | const rootView = sceneTool.getRootView(); 16 | rootView.scale.x = ratio; 17 | rootView.scale.y = ratio; 18 | imageBuilderStore.scene.$update({ 19 | canvasZoom: ratio, 20 | }); 21 | }; 22 | const resetView = () => { 23 | const rootView = sceneTool.getRootView(); 24 | rootView.position.x = 0; 25 | rootView.position.y = 0; 26 | rootView.scale.x = 1; 27 | rootView.scale.y = 1; 28 | imageBuilderStore.scene.$update({ 29 | canvasZoom: 1, 30 | }); 31 | }; 32 | 33 | return ( 34 |
35 |
36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 |
44 |
45 | 46 | 47 | 48 |
49 |
50 | ); 51 | }); 52 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/rightPanel/attribute.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export function Attribute({ attribute }: { attribute: string }) { 4 | return ( 5 |

13 | {attribute} 14 |

15 | ); 16 | } 17 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/rightPanel/index.less: -------------------------------------------------------------------------------- 1 | .right-panel { 2 | position: absolute; 3 | right: 0; 4 | top: 75px; 5 | bottom: 0; 6 | width: 260px; 7 | display: flex; 8 | flex-direction: column; 9 | background: #fff; 10 | padding: 20px; 11 | z-index: 10; 12 | overflow: scroll; 13 | box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.1); 14 | } 15 | .flex-horizontal { 16 | display: flex; 17 | justify-content: space-between; 18 | align-items: center; 19 | } 20 | .mirror-group { 21 | display: flex; 22 | align-items: center; 23 | color: #4E5969; 24 | font-size: 14px; 25 | 26 | & > div { 27 | margin-right: 10px; 28 | } 29 | 30 | span { 31 | margin-right: 10px; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/topBar/index.less: -------------------------------------------------------------------------------- 1 | .action { 2 | gap: 15px; 3 | display: flex; 4 | align-items: center; 5 | } 6 | .button { 7 | height: 30px; 8 | } 9 | .top-bar { 10 | position: absolute; 11 | left: 0; 12 | right: 0; 13 | top: 0; 14 | background: #fff; 15 | padding: 16px; 16 | border-bottom: 1px solid #e5e6eb; 17 | display: flex; 18 | align-items: center; 19 | justify-content: space-between; 20 | } 21 | 22 | .global-msg { 23 | position: absolute; 24 | top: 60px; 25 | left: 50%; 26 | transform: translateX(-50%); 27 | } 28 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/world/entity/frame/index.ts: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js'; 2 | 3 | import { Mesh2D, DrawUtils } from '@turbox3d/turbox'; 4 | 5 | import { FrameEntity } from '../../../../models/entity/frame'; 6 | 7 | export interface IFrameViewEntityProps { 8 | model: FrameEntity; 9 | } 10 | 11 | export class FrameViewEntity extends Mesh2D { 12 | protected view = new PIXI.Graphics(); 13 | protected reactivePipeLine = [this.updateGeometry, this.updateMaterial]; 14 | 15 | updateGeometry() { 16 | const { model } = this.props; 17 | this.view.clear(); 18 | this.view.zIndex = model.renderOrder; 19 | DrawUtils.drawRect(this.view, { 20 | x: model.position.x, 21 | y: model.position.y, 22 | width: model.size.x, 23 | height: model.size.y, 24 | central: true, 25 | fillColor: model.bgColor, 26 | fillAlpha: 1, 27 | }); 28 | } 29 | 30 | updateMaterial() { 31 | const { model } = this.props; 32 | if (model.imageData) { 33 | this.view.clear(); 34 | DrawUtils.drawRect(this.view, { 35 | x: model.position.x, 36 | y: model.position.y, 37 | width: model.size.x, 38 | height: model.size.y, 39 | central: true, 40 | backgroundImage: model.imageData.src, 41 | }); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/world/entity/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Component, g } from '@turbox3d/turbox'; 2 | import { imageBuilderStore } from '../../../models'; 3 | import { FrameViewEntity } from './frame'; 4 | import { ItemViewEntity } from './item'; 5 | import { FrameEntity } from '../../../models/entity/frame'; 6 | import { ItemEntity } from '../../../models/entity/item'; 7 | import { FrameSymbol, ItemSymbol } from '../../../common/consts/view-entity'; 8 | 9 | @Reactive 10 | export class ViewEntity extends Component { 11 | render() { 12 | const frames = imageBuilderStore.document.getFrameEntities(); 13 | const items = imageBuilderStore.document.getItemEntities(); 14 | return [ 15 | ...frames.map(m => g(FrameViewEntity, { 16 | key: m.id, 17 | model: m as FrameEntity, 18 | id: m.id, 19 | type: FrameSymbol, 20 | })), 21 | ...items.map(m => g(ItemViewEntity, { 22 | key: m.id, 23 | model: m as ItemEntity, 24 | id: m.id, 25 | type: ItemSymbol, 26 | clickable: true, 27 | draggable: true, 28 | hoverable: true, 29 | })), 30 | ]; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/world/hintLine/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Component, g, Rect2d, MathUtils } from '@turbox3d/turbox'; 2 | import { RenderOrder } from '../../../common/consts/scene'; 3 | import { appCommandManager } from '../../../commands'; 4 | import { BLUE } from '../../../common/consts/color'; 5 | 6 | @Reactive 7 | export class HintLine extends Component { 8 | render() { 9 | const hinted = appCommandManager.default.hint.getHintedEntity(); 10 | return [ 11 | hinted && 12 | g(Rect2d, { 13 | key: 'wireframe', 14 | x: hinted.position.x, 15 | y: hinted.position.y, 16 | width: hinted.size.x, 17 | height: hinted.size.y, 18 | central: true, 19 | lineWidth: 1, 20 | lineColor: BLUE, 21 | fillAlpha: 0, 22 | alignment: 1, 23 | rotation: hinted.rotation.z * MathUtils.DEG2RAD, 24 | zIndex: RenderOrder.GIZMO, 25 | }), 26 | ]; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/world/rangeLine/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Component, g, Rect2d, MathUtils } from '@turbox3d/turbox'; 2 | import { imageBuilderStore } from '../../../models'; 3 | import { RED } from '../../../common/consts/color'; 4 | import { RenderOrder } from '../../../common/consts/scene'; 5 | 6 | @Reactive 7 | export class RangeLine extends Component { 8 | render() { 9 | const showInvalidRangeFrame = imageBuilderStore.scene.isShowInvalidRangeFrame(); 10 | const frames = imageBuilderStore.document.getFrameEntities(); 11 | return [ 12 | showInvalidRangeFrame && 13 | g(Rect2d, { 14 | key: 'range-wireframe', 15 | width: frames[0].size.x, 16 | height: frames[0].size.y, 17 | x: frames[0].position.x, 18 | y: frames[0].position.y, 19 | rotation: frames[0].rotation.z * MathUtils.DEG2RAD, 20 | zIndex: RenderOrder.GIZMO, 21 | central: true, 22 | lineWidth: 1, 23 | lineColor: RED, 24 | fillAlpha: 0, 25 | alignment: 1, 26 | }), 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /demo/src/image-builder/views/world/snapLine/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Component, g, Line2d } from '@turbox3d/turbox'; 2 | import { imageBuilderStore } from '../../../models'; 3 | import { RED } from '../../../common/consts/color'; 4 | 5 | @Reactive 6 | export class SnapLine extends Component { 7 | render() { 8 | return [ 9 | ...imageBuilderStore.scene.snapLines.map((sl, index) => g(Line2d, { 10 | key: `snapLine-${index}`, 11 | start: sl[0], 12 | end: sl[1], 13 | lineWidth: 1, 14 | lineColor: RED, 15 | })), 16 | ]; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /demo/src/lite-design/commands/default/index.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager, SelectionCommand, HintCommand } from '@turbox3d/turbox'; 2 | 3 | import { MoveCommand } from './move/index'; 4 | import { RotateCommand } from './rotate/index'; 5 | import { ScaleCommand } from './scale/index'; 6 | 7 | class DefaultCommand extends CommandManager.compose({ 8 | hint: HintCommand, 9 | select: SelectionCommand, 10 | move: MoveCommand, 11 | scale: ScaleCommand, 12 | rotate: RotateCommand, 13 | }) { 14 | active() { 15 | this.select.active({ 16 | hint: this.hint, 17 | }); 18 | this.hint.active(this.select); 19 | this.move.active(); 20 | this.rotate.active(); 21 | this.scale.active(); 22 | } 23 | } 24 | 25 | export { DefaultCommand }; 26 | -------------------------------------------------------------------------------- /demo/src/lite-design/commands/index.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager } from '@turbox3d/turbox'; 2 | 3 | import { ClipCommand } from './clip/index'; 4 | import { DefaultCommand } from './default'; 5 | import { MeasureCommand } from './measure/index'; 6 | import { SkewCommand } from './skew/index'; 7 | 8 | class AppCommandManager extends CommandManager { 9 | defaultCommand = new DefaultCommand(this); 10 | clipCommand = new ClipCommand(this); 11 | skewCommand = new SkewCommand(this); 12 | measureCommand = new MeasureCommand(this); 13 | 14 | constructor() { 15 | super(); 16 | this.defaultCommand.apply(); 17 | } 18 | 19 | disposeAll() { 20 | this.defaultCommand.select.clearAllSelected(); 21 | this.defaultCommand.dispose(); 22 | this.clipCommand.dispose(); 23 | this.skewCommand.dispose(); 24 | } 25 | } 26 | 27 | export const appCommandManager = new AppCommandManager(); 28 | -------------------------------------------------------------------------------- /demo/src/lite-design/commands/measure/domain.ts: -------------------------------------------------------------------------------- 1 | import { Domain, Vector3, reactor } from '@turbox3d/turbox'; 2 | 3 | export class MeasureDomain extends Domain { 4 | @reactor() start?: Vector3; 5 | @reactor() end?: Vector3; 6 | 7 | getLength() { 8 | if (this.end && this.start) { 9 | return this.end.subtracted(this.start).length; 10 | } 11 | return 0; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /demo/src/lite-design/commands/measure/index.ts: -------------------------------------------------------------------------------- 1 | import { Command, ViewEntity, SceneEvent, SceneTool, Action, Vec3, Vector3 } from '@turbox3d/turbox'; 2 | 3 | import { MeasureDomain } from './domain'; 4 | 5 | export class MeasureCommand extends Command { 6 | private action = Action.create('measure'); 7 | measure = new MeasureDomain(); 8 | 9 | protected onDragStart(viewEntity: ViewEntity, event: SceneEvent, tools: SceneTool) { 10 | const scenePosition = event.getScenePosition(0) as Vec3; 11 | this.action.execute(() => { 12 | this.measure.$update({ 13 | start: new Vector3(scenePosition.x, scenePosition.y, scenePosition.z), 14 | }); 15 | }); 16 | } 17 | 18 | protected onDragMove(viewEntity: ViewEntity, event: SceneEvent, tools: SceneTool) { 19 | const scenePosition = event.getScenePosition(0) as Vec3; 20 | this.action.execute(() => { 21 | this.measure.$update({ 22 | end: new Vector3(scenePosition.x, scenePosition.y, scenePosition.z), 23 | }); 24 | }); 25 | } 26 | 27 | protected onDragEnd() { 28 | this.action.complete(); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/lite-design/common/consts/scene.ts: -------------------------------------------------------------------------------- 1 | export enum CameraDistance { 2 | CAMERA = 1000, 3 | } 4 | 5 | export enum RenderOrder { 6 | EMPTY_BACKGROUND = -2, 7 | BACKGROUND = -1, 8 | SKY_BOX = 20, 9 | Cube = 30, 10 | CONTROL_POINT = 9999, 11 | } 12 | 13 | export enum Z_INDEX_ACTION { 14 | /** 置顶 */ 15 | TOP = 'top', 16 | /** 置底 */ 17 | BOTTOM = 'bottom', 18 | /** 下移 */ 19 | DECREASE = 'decrease', 20 | /** 上移 */ 21 | INCREASE = 'increase', 22 | } 23 | 24 | export enum MIRROR_ACTION { 25 | /** 左右镜像 */ 26 | LEFT_RIGHT = 'left_right', 27 | /** 上下镜像 */ 28 | TOP_BOTTOM = 'top_bottom', 29 | } 30 | 31 | export const ProductSymbol = Symbol('product'); 32 | export const CubeSymbol = Symbol('cube'); 33 | export const AssemblySymbol = Symbol('assembly'); 34 | export const BackgroundSymbol = Symbol('background'); 35 | export const ScalePointSymbol = Symbol('scale-point'); 36 | export const RotatePointSymbol = Symbol('rotate-point'); 37 | export const Product2DSymbol = Symbol('product-2d'); 38 | export const SkewPointSymbol = Symbol('skew-point'); 39 | export const ClipPointSymbol = Symbol('clip-point'); 40 | export const ClipBorderSymbol = Symbol('clip-border'); 41 | export const AdjustPointSymbol = Symbol('adjust-point'); 42 | export const DeletePointSymbol = Symbol('delete-point'); 43 | export const SkyBoxSymbol = Symbol('sky-box'); 44 | -------------------------------------------------------------------------------- /demo/src/lite-design/common/fonts/ionicons.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/demo/src/lite-design/common/fonts/ionicons.eot -------------------------------------------------------------------------------- /demo/src/lite-design/common/fonts/ionicons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/demo/src/lite-design/common/fonts/ionicons.ttf -------------------------------------------------------------------------------- /demo/src/lite-design/common/fonts/ionicons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/demo/src/lite-design/common/fonts/ionicons.woff -------------------------------------------------------------------------------- /demo/src/lite-design/common/imgs/eden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/demo/src/lite-design/common/imgs/eden.png -------------------------------------------------------------------------------- /demo/src/lite-design/common/styles/base.less: -------------------------------------------------------------------------------- 1 | // @import "normalize.css"; 2 | @import "./theme.less"; 3 | 4 | .body { 5 | font-size: 12px; 6 | } 7 | -------------------------------------------------------------------------------- /demo/src/lite-design/common/styles/theme.less: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: rgb(247, 245, 245); 3 | } 4 | -------------------------------------------------------------------------------- /demo/src/lite-design/common/utils/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/demo/src/lite-design/common/utils/.gitkeep -------------------------------------------------------------------------------- /demo/src/lite-design/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { depCollector } from '@turbox3d/turbox'; 4 | 5 | import { appCommandManager } from './commands/index'; 6 | import { ldeStore } from './models/index'; 7 | import { LeftPanel } from './views/leftPanel/index'; 8 | import { MainScene } from './views/scene'; 9 | import './common/styles/base.less'; 10 | import { SceneUtil } from './views/scene/modelsWorld/index'; 11 | 12 | window.$$DEMO_DEBUG = { 13 | appCommandManager, 14 | ldeStore, 15 | SceneUtil, 16 | depCollector, 17 | }; 18 | 19 | ldeStore.document.createTimeTravel('lite-design', 20); 20 | ldeStore.document.applyTimeTravel(); 21 | 22 | export const Demo = () => ( 23 | <> 24 | 34 | 35 | 36 | ); 37 | 38 | export default Demo; 39 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/domain/scene.ts: -------------------------------------------------------------------------------- 1 | import { Domain, reactor, Vector3, mutation } from '@turbox3d/turbox'; 2 | 3 | import { CameraDistance } from '../../common/consts/scene'; 4 | 5 | export class SceneDomain extends Domain { 6 | /** 设备类型 */ 7 | @reactor deviceType: 'iPad' | 'PC' = 'PC'; 8 | @reactor cameraPosition = new Vector3(0, 0, CameraDistance.CAMERA); 9 | @reactor cameraTarget = new Vector3(0, 0, 0); 10 | @reactor cameraControlsEnabled = false; 11 | /** 中间阴影部分画布区域的缩放 */ 12 | @reactor canvasZoom = 1; 13 | /** 画布缩放的限制范围 */ 14 | @reactor canvasZoomRange = [0.1, 2]; 15 | /** 中间阴影部分画布区域的位置 */ 16 | @reactor canvasPosition = { x: 0, y: 0 }; 17 | /** 中间阴影部分画布区域的尺寸比例 */ 18 | @reactor canvasRatio = 16 / 9; 19 | /** 中间阴影部分画布区域的边距比例 */ 20 | @reactor canvasMarginRatio = 0.95; 21 | @reactor isSkewMode = false; 22 | @reactor isClipMode = false; 23 | @reactor isPdfMode = false; 24 | @reactor hideSkewPoint = false; 25 | /** 场景的宽度 */ 26 | @reactor sceneWidth = 0; 27 | /** 场景的高度 */ 28 | @reactor sceneHeight = 0; 29 | @reactor hideClipPoint = false; 30 | @reactor resolution = window.devicePixelRatio; 31 | @reactor renderFlag2d = false; 32 | @reactor renderFlag3d = true; 33 | 34 | @mutation 35 | setResolution(res = window.devicePixelRatio) { 36 | this.resolution = res; 37 | } 38 | 39 | @mutation('', true) 40 | setRenderFlag2d(flag: boolean) { 41 | this.renderFlag2d = flag; 42 | } 43 | 44 | @mutation('', true) 45 | setRenderFlag3d(flag: boolean) { 46 | this.renderFlag3d = flag; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/adjustPoint.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | 3 | export class AdjustPointEntity extends EntityObject { 4 | @reactor radius = 10; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/assembly.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject } from '@turbox3d/turbox'; 2 | 3 | export class AssemblyEntity extends EntityObject { 4 | name = 'assembly'; 5 | 6 | setPosition(position: { x?: number; y?: number; z?: number }) { 7 | super.setPosition(position); 8 | if (position.z !== undefined) { 9 | this.children.forEach(child => 10 | child.setPosition({ 11 | z: 0, 12 | }) 13 | ); 14 | } 15 | return this; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/background.ts: -------------------------------------------------------------------------------- 1 | import { ProductEntity } from './product'; 2 | 3 | export class BackgroundEntity extends ProductEntity { 4 | name = 'background'; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/clipPoint.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | 3 | export class ClipPointEntity extends EntityObject { 4 | @reactor radius = 10; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/cube.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject } from '@turbox3d/turbox'; 2 | 3 | export class CubeEntity extends EntityObject {} 4 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/deletePoint.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | 3 | export class DeletePointEntity extends EntityObject { 4 | @reactor radius = 10; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/rotatePoint.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | 3 | export class RotatePointEntity extends EntityObject { 4 | @reactor radius = 10; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/scalePoint.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | 3 | export class ScalePointEntity extends EntityObject { 4 | @reactor radius = 10; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/skewPoint.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | 3 | export class SkewPointEntity extends EntityObject { 4 | @reactor radius = 10; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/entity/skyBox.ts: -------------------------------------------------------------------------------- 1 | import { EntityObject, reactor } from '@turbox3d/turbox'; 2 | 3 | export class SkyBoxEntity extends EntityObject { 4 | @reactor isShowAllFace = false; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/models/index.ts: -------------------------------------------------------------------------------- 1 | import { ActionsDomain } from './domain/actions'; 2 | import { DocumentDomain } from './domain/document'; 3 | import { SceneDomain } from './domain/scene'; 4 | 5 | export const ldeStore = { 6 | document: new DocumentDomain(), 7 | actions: new ActionsDomain(), 8 | scene: new SceneDomain(), 9 | }; 10 | -------------------------------------------------------------------------------- /demo/src/lite-design/tests/index.test.ts: -------------------------------------------------------------------------------- 1 | test('adds 1 + 2 to equal 3', () => { 2 | expect((1 + 2)).toBe(3); 3 | }); 4 | -------------------------------------------------------------------------------- /demo/src/lite-design/types/README.md: -------------------------------------------------------------------------------- 1 | # 全局类型文件 2 | -------------------------------------------------------------------------------- /demo/src/lite-design/types/assetsDefinition.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png'; 2 | declare module '*.jpg'; 3 | declare module '*.svg'; 4 | declare module '*.jpeg'; 5 | declare module '*.gif'; 6 | declare module '*.webp'; 7 | declare module '*.ttf'; 8 | declare module '*.woff'; 9 | declare module '*.woff2'; 10 | declare module '*.scss'; 11 | declare module '*.less'; 12 | declare module '*.css'; 13 | declare module '*?__inline'; 14 | declare module '*?__inline=true'; 15 | declare module '*?__inline=false'; 16 | -------------------------------------------------------------------------------- /demo/src/lite-design/types/global.d.ts: -------------------------------------------------------------------------------- 1 | interface Window { 2 | // eslint-disable-next-line @typescript-eslint/naming-convention 3 | $$DEMO_DEBUG: any; 4 | ColorThief: any; 5 | } 6 | -------------------------------------------------------------------------------- /demo/src/lite-design/types/types.ts: -------------------------------------------------------------------------------- 1 | export interface IConstructorOf { 2 | new(...args: any[]): T; 3 | } 4 | 5 | export interface IMapOf { 6 | [key: string]: T; 7 | } 8 | 9 | export type Nullable = { [K in keyof T]?: T[K] | null }; 10 | 11 | export function getValue(obj: T, key: K): T[K] { 12 | return obj[key]; 13 | } 14 | 15 | export interface IDictionary { 16 | [index: string]: T; 17 | } 18 | 19 | export interface INumericDictionary { 20 | [index: number]: T; 21 | } 22 | -------------------------------------------------------------------------------- /demo/src/lite-design/utils/color.ts: -------------------------------------------------------------------------------- 1 | function randomColor() { 2 | let c = Math.floor(Math.random() * 256); 3 | while (c === 0 || c > 255) { 4 | c = Math.floor(Math.random() * 256); 5 | } 6 | return c; 7 | } 8 | function prefix(num: number, val: string) { 9 | return (new Array(num).join('0') + val).slice(-num); 10 | } 11 | export function color16() { 12 | const r = randomColor().toString(16); 13 | const g = randomColor().toString(16); 14 | const b = randomColor().toString(16); 15 | const color = `#${prefix(2, r)}${prefix(2, g)}${prefix(2, b)}`; 16 | return color; 17 | } 18 | -------------------------------------------------------------------------------- /demo/src/lite-design/utils/common.ts: -------------------------------------------------------------------------------- 1 | export const coordinateStringToArray = (txt: string) => 2 | txt 3 | .slice(1, -1) 4 | .split(',') 5 | // eslint-disable-next-line @typescript-eslint/no-shadow 6 | .map(txt => parseFloat(txt.replace('{', '').replace('}', ''))); 7 | 8 | export async function wait(ms: number) { 9 | await new Promise(resolve => { 10 | setTimeout(() => { 11 | resolve(); 12 | }, ms); 13 | }); 14 | } 15 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/leftPanel/index.less: -------------------------------------------------------------------------------- 1 | .left-panel { 2 | width: 25%; 3 | display: flex; 4 | flex-direction: column; 5 | position: absolute; 6 | top: 0; 7 | bottom: 0; 8 | background: #e9ebf0; 9 | padding: 20px; 10 | z-index: 10; 11 | touch-action: none; 12 | } 13 | 14 | .material { 15 | display: flex; 16 | justify-content: space-between; 17 | flex-wrap: wrap; 18 | width: 200px; 19 | } 20 | 21 | .img-list { 22 | display: flex; 23 | flex-direction: column; 24 | } 25 | 26 | .op { 27 | margin-bottom: 10px; 28 | } 29 | 30 | * { 31 | -webkit-touch-callout: none; 32 | -webkit-user-select: none; 33 | -khtml-user-select: none; 34 | -moz-user-select: none; 35 | -ms-user-select: none; 36 | user-select: none; 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/camera/index.tsx: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three'; 2 | 3 | import { Mesh3D } from '@turbox3d/turbox'; 4 | 5 | import { CameraDistance } from '../../../common/consts/scene'; 6 | import { ldeStore } from '../../../models/index'; 7 | 8 | const NEAR_RATIO = 0.0001; 9 | 10 | export class OrthographicCamera extends Mesh3D { 11 | protected view = new THREE.OrthographicCamera( 12 | -ldeStore.scene.sceneWidth / 2, 13 | ldeStore.scene.sceneWidth / 2, 14 | ldeStore.scene.sceneHeight / 2, 15 | -ldeStore.scene.sceneHeight / 2, 16 | 1, 17 | 30000 18 | ); 19 | protected viewType: 'camera' | 'light' | 'model' = 'camera'; 20 | } 21 | 22 | export class PerspectiveCamera extends Mesh3D { 23 | protected view = new THREE.PerspectiveCamera( 24 | 50, 25 | ldeStore.scene.sceneWidth / ldeStore.scene.sceneHeight, 26 | CameraDistance.CAMERA * NEAR_RATIO, 27 | CameraDistance.CAMERA * (2 - NEAR_RATIO) 28 | ); 29 | protected viewType: 'camera' | 'light' | 'model' = 'camera'; 30 | } 31 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/index.less: -------------------------------------------------------------------------------- 1 | .fps-monitor { 2 | position: absolute; 3 | z-index: 100; 4 | top: 0; 5 | left: 0; 6 | background: rgba(0, 0, 0, 0.7); 7 | color: white; 8 | width: 70px; 9 | height: 20px; 10 | pointer-events: none; 11 | display: flex; 12 | justify-content: center; 13 | align-items: center; 14 | } 15 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/AdjustPoint.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, MathUtils, g, Mesh3D } from '@turbox3d/turbox'; 2 | 3 | import { RenderOrder } from '../../../common/consts/scene'; 4 | import { AdjustPointEntity } from '../../../models/entity/adjustPoint'; 5 | import { Circle, Rect3d, IRect3dProps, ICircleProps } from '../helper/index'; 6 | 7 | interface IAdjustPointProps { 8 | model: AdjustPointEntity; 9 | } 10 | 11 | @Reactive 12 | export class AdjustPointViewEntity extends Mesh3D { 13 | protected reactivePipeLine = [this.updatePosition, this.updateRotation, this.updateScale]; 14 | 15 | render() { 16 | const hotArea = Math.min( 17 | this.props.model.radius * 6, 18 | Math.min(this.props.model.parent!.size.x / 3, this.props.model.parent!.size.y / 3) 19 | ); 20 | return [ 21 | g(Rect3d, { 22 | width: hotArea, 23 | height: hotArea, 24 | opacity: 0, 25 | renderOrder: RenderOrder.CONTROL_POINT + 1, 26 | }), 27 | g(Circle, { 28 | radius: this.props.model.radius, 29 | imgUrl: 'https://sf16-va.tiktokcdn.com/obj/eden-va2/uhmplmeh7uhmplmbn/edm/adjust.svg', 30 | imgScale: { x: this.props.model.radius * 3 - 8, y: this.props.model.radius * 3 - 8, z: 1 }, 31 | renderOrder: RenderOrder.CONTROL_POINT, 32 | }), 33 | ]; 34 | } 35 | 36 | private updatePosition() { 37 | const { model } = this.props; 38 | this.view.position.set(model.position.x, model.position.y, model.position.z); 39 | } 40 | 41 | private updateRotation() { 42 | const { model } = this.props; 43 | this.view.rotation.set( 44 | model.rotation.x * MathUtils.DEG2RAD, 45 | model.rotation.y * MathUtils.DEG2RAD, 46 | model.rotation.z * MathUtils.DEG2RAD 47 | ); 48 | } 49 | 50 | private updateScale() { 51 | const { model } = this.props; 52 | this.view.scale.set(model.scale.x, model.scale.y, model.scale.z); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/Assembly.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Mesh3D, MathUtils, EntityObject, Element, g } from '@turbox3d/turbox'; 2 | 3 | import { appCommandManager } from '../../../commands/index'; 4 | import { AssemblyEntity } from '../../../models/entity/assembly'; 5 | import { WireFrame } from '../helper/index'; 6 | 7 | interface IAssemblyProps { 8 | model: AssemblyEntity; 9 | renderEntityViews: (entities: IterableIterator) => Element[]; 10 | } 11 | 12 | @Reactive 13 | export class AssemblyViewEntity extends Mesh3D { 14 | protected reactivePipeLine = [this.updatePosition, this.updateRotation, this.updateScale]; 15 | 16 | render() { 17 | const { model } = this.props; 18 | const isSelected = appCommandManager.defaultCommand.select.getSelectedEntities().includes(model); 19 | const views = this.props.renderEntityViews(model.children.values()); 20 | if (isSelected) { 21 | return [ 22 | ...views, 23 | g(WireFrame, { 24 | model, 25 | }), 26 | ]; 27 | } 28 | return views; 29 | } 30 | 31 | private updatePosition() { 32 | const { model } = this.props; 33 | this.view.position.set(model.position.x, model.position.y, model.position.z); 34 | } 35 | 36 | private updateRotation() { 37 | const { model } = this.props; 38 | this.view.rotation.set( 39 | model.rotation.x * MathUtils.DEG2RAD, 40 | model.rotation.y * MathUtils.DEG2RAD, 41 | model.rotation.z * MathUtils.DEG2RAD 42 | ); 43 | } 44 | 45 | private updateScale() { 46 | const { model } = this.props; 47 | this.view.scale.set(model.scale.x, model.scale.y, model.scale.z); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/ClipBorder.ts: -------------------------------------------------------------------------------- 1 | import { BufferGeometry, LineDashedMaterial, LineSegments, Vector3 } from 'three'; 2 | 3 | import { Reactive, Mesh3D } from '@turbox3d/turbox'; 4 | 5 | import { ClipPointEntity } from '../../../models/entity/clipPoint'; 6 | 7 | @Reactive 8 | export class ClipBorder extends Mesh3D<{ clipPoints: ClipPointEntity[] }> { 9 | protected reactivePipeLine = [this.updateGeometry]; 10 | protected view = new LineSegments( 11 | new BufferGeometry(), 12 | new LineDashedMaterial({ color: 0xffffff, dashSize: 10, gapSize: 5 }) 13 | ); 14 | 15 | private updateGeometry() { 16 | const { clipPoints } = this.props; 17 | const points: Vector3[] = []; 18 | const xs = clipPoints.map(p => p.position.x); 19 | const ys = clipPoints.map(p => p.position.y); 20 | const { z } = clipPoints[0].position; 21 | 22 | points.push(new Vector3(Math.min(...xs), Math.max(...ys), z)); 23 | points.push(new Vector3(Math.max(...xs), Math.max(...ys), z)); 24 | 25 | points.push(new Vector3(Math.max(...xs), Math.max(...ys), z)); 26 | points.push(new Vector3(Math.max(...xs), Math.min(...ys), z)); 27 | 28 | points.push(new Vector3(Math.max(...xs), Math.min(...ys), z)); 29 | points.push(new Vector3(Math.min(...xs), Math.min(...ys), z)); 30 | 31 | points.push(new Vector3(Math.min(...xs), Math.min(...ys), z)); 32 | points.push(new Vector3(Math.min(...xs), Math.max(...ys), z)); 33 | 34 | this.view.geometry = new BufferGeometry().setFromPoints(points); 35 | this.view.computeLineDistances(); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/ClipPoint.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Mesh3D, MathUtils, g } from '@turbox3d/turbox'; 2 | 3 | import { RenderOrder } from '../../../common/consts/scene'; 4 | import { ClipPointEntity } from '../../../models/entity/clipPoint'; 5 | import { ldeStore } from '../../../models/index'; 6 | import { Circle, Rect3d } from '../helper/index'; 7 | 8 | interface IClipPointProps { 9 | model: ClipPointEntity; 10 | } 11 | 12 | @Reactive 13 | export class ClipPointViewEntity extends Mesh3D { 14 | protected reactivePipeLine = [this.updatePosition, this.updateRotation, this.updateScale]; 15 | 16 | render() { 17 | const hotArea = ldeStore.scene.deviceType === 'iPad' ? this.props.model.radius * 6 : this.props.model.radius * 3; 18 | return [ 19 | g(Rect3d, { 20 | width: hotArea, 21 | height: hotArea, 22 | opacity: 0, 23 | renderOrder: RenderOrder.CONTROL_POINT + 1, 24 | }), 25 | g(Circle, { 26 | radius: this.props.model.radius - 5, 27 | color: 0xffffff, 28 | renderOrder: RenderOrder.CONTROL_POINT, 29 | key: 1, 30 | }), 31 | g(Circle, { 32 | radius: this.props.model.radius, 33 | color: 0xbf975b, 34 | renderOrder: RenderOrder.CONTROL_POINT, 35 | key: 2, 36 | }), 37 | ]; 38 | } 39 | 40 | private updatePosition() { 41 | const { model } = this.props; 42 | this.view.position.set(model.position.x, model.position.y, model.position.z); 43 | } 44 | 45 | private updateRotation() { 46 | const { model } = this.props; 47 | this.view.rotation.set( 48 | model.rotation.x * MathUtils.DEG2RAD, 49 | model.rotation.y * MathUtils.DEG2RAD, 50 | model.rotation.z * MathUtils.DEG2RAD 51 | ); 52 | } 53 | 54 | private updateScale() { 55 | const { model } = this.props; 56 | this.view.scale.set(model.scale.x, model.scale.y, model.scale.z); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/Cube.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Mesh3D, MathUtils, Element, g } from '@turbox3d/turbox'; 2 | 3 | import { appCommandManager } from '../../../commands/index'; 4 | import { RenderOrder } from '../../../common/consts/scene'; 5 | import { CubeEntity } from '../../../models/entity/cube'; 6 | import { Cube, WireFrame } from '../helper/index'; 7 | 8 | interface IProps { 9 | model: CubeEntity; 10 | } 11 | 12 | @Reactive 13 | export class CubeViewEntity extends Mesh3D { 14 | protected reactivePipeLine = [this.updatePosition, this.updateRotation, this.updateScale]; 15 | 16 | render() { 17 | this.view.renderOrder = RenderOrder.Cube; 18 | const { model } = this.props; 19 | const isSelected = appCommandManager.defaultCommand.select.getSelectedEntities().includes(model); 20 | const views: Element[] = []; 21 | if (isSelected) { 22 | views.push( 23 | g(WireFrame, { 24 | model, 25 | }) 26 | ); 27 | } 28 | views.push( 29 | g(Cube, { 30 | model, 31 | }) 32 | ); 33 | return views; 34 | } 35 | 36 | private updatePosition() { 37 | const { model } = this.props; 38 | this.view.position.set(model.position.x, model.position.y, model.position.z); 39 | } 40 | 41 | private updateRotation() { 42 | const { model } = this.props; 43 | this.view.rotation.set( 44 | model.rotation.x * MathUtils.DEG2RAD, 45 | model.rotation.y * MathUtils.DEG2RAD, 46 | model.rotation.z * MathUtils.DEG2RAD 47 | ); 48 | } 49 | 50 | private updateScale() { 51 | const { model } = this.props; 52 | this.view.scale.set(model.scale.x, model.scale.y, model.scale.z); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/RotatePoint.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Mesh3D, MathUtils, g } from '@turbox3d/turbox'; 2 | 3 | import { RenderOrder } from '../../../common/consts/scene'; 4 | import { RotatePointEntity } from '../../../models/entity/rotatePoint'; 5 | import { Circle } from '../helper/index'; 6 | 7 | interface IRotatePointProps { 8 | model: RotatePointEntity; 9 | } 10 | 11 | @Reactive 12 | export class RotatePointViewEntity extends Mesh3D { 13 | protected reactivePipeLine = [this.updatePosition, this.updateRotation, this.updateScale]; 14 | 15 | render() { 16 | return [ 17 | g(Circle, { 18 | radius: this.props.model.radius, 19 | imgUrl: 'https://sf16-va.tiktokcdn.com/obj/eden-va2/uhmplmeh7uhmplmbn/edm/rotate.png', 20 | renderOrder: RenderOrder.CONTROL_POINT, 21 | }), 22 | ]; 23 | } 24 | 25 | private updatePosition() { 26 | const { model } = this.props; 27 | this.view.position.set(model.position.x, model.position.y, model.position.z); 28 | } 29 | 30 | private updateRotation() { 31 | const { model } = this.props; 32 | this.view.rotation.set( 33 | model.rotation.x * MathUtils.DEG2RAD, 34 | model.rotation.y * MathUtils.DEG2RAD, 35 | model.rotation.z * MathUtils.DEG2RAD 36 | ); 37 | } 38 | 39 | private updateScale() { 40 | const { model } = this.props; 41 | this.view.scale.set(model.scale.x, model.scale.y, model.scale.z); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/ScalePoint.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Mesh3D, MathUtils, g } from '@turbox3d/turbox'; 2 | 3 | import { RenderOrder } from '../../../common/consts/scene'; 4 | import { ScalePointEntity } from '../../../models/entity/scalePoint'; 5 | import { Rect3d } from '../helper/index'; 6 | 7 | interface IScalePointProps { 8 | model: ScalePointEntity; 9 | } 10 | 11 | @Reactive 12 | export class ScalePointViewEntity extends Mesh3D { 13 | protected reactivePipeLine = [this.updatePosition, this.updateRotation, this.updateScale]; 14 | 15 | render() { 16 | return [ 17 | g(Rect3d, { 18 | width: this.props.model.radius * 1.5, 19 | height: this.props.model.radius * 1.5, 20 | renderOrder: RenderOrder.CONTROL_POINT, 21 | }), 22 | ]; 23 | } 24 | 25 | private updatePosition() { 26 | const { model } = this.props; 27 | this.view.position.set(model.position.x, model.position.y, model.position.z); 28 | } 29 | 30 | private updateRotation() { 31 | const { model } = this.props; 32 | this.view.rotation.set( 33 | model.rotation.x * MathUtils.DEG2RAD, 34 | model.rotation.y * MathUtils.DEG2RAD, 35 | model.rotation.z * MathUtils.DEG2RAD 36 | ); 37 | } 38 | 39 | private updateScale() { 40 | const { model } = this.props; 41 | this.view.scale.set(model.scale.x, model.scale.y, model.scale.z); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/modelsWorld/SkewPoint.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Mesh3D, MathUtils, g } from '@turbox3d/turbox'; 2 | 3 | import { RenderOrder } from '../../../common/consts/scene'; 4 | import { SkewPointEntity } from '../../../models/entity/skewPoint'; 5 | import { Circle } from '../helper/index'; 6 | 7 | interface ISkewPointProps { 8 | model: SkewPointEntity; 9 | } 10 | 11 | @Reactive 12 | export class SkewPointViewEntity extends Mesh3D { 13 | protected reactivePipeLine = [this.updatePosition, this.updateRotation, this.updateScale]; 14 | 15 | render() { 16 | return [ 17 | g(Circle, { 18 | radius: this.props.model.radius, 19 | color: 0xbf975b, 20 | renderOrder: RenderOrder.CONTROL_POINT, 21 | }), 22 | ]; 23 | } 24 | 25 | private updatePosition() { 26 | const { model } = this.props; 27 | this.view.position.set(model.position.x, model.position.y, model.position.z); 28 | } 29 | 30 | private updateRotation() { 31 | const { model } = this.props; 32 | this.view.rotation.set( 33 | model.rotation.x * MathUtils.DEG2RAD, 34 | model.rotation.y * MathUtils.DEG2RAD, 35 | model.rotation.z * MathUtils.DEG2RAD 36 | ); 37 | } 38 | 39 | private updateScale() { 40 | const { model } = this.props; 41 | this.view.scale.set(model.scale.x, model.scale.y, model.scale.z); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /demo/src/lite-design/views/scene/tempWorld/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive, Component, g } from '@turbox3d/turbox'; 2 | 3 | import { Product2DSymbol } from '../../../common/consts/scene'; 4 | import { ProductEntity } from '../../../models/entity/product'; 5 | import { ldeStore } from '../../../models/index'; 6 | import { SceneUtil } from '../modelsWorld/index'; 7 | 8 | // import { Product2DViewEntity } from './Product2D'; 9 | 10 | @Reactive 11 | export class TempWorld extends Component { 12 | render() { 13 | SceneUtil.get2DScreenShot = this.context.getSceneTools().getScreenShot; 14 | SceneUtil.get2DApp = this.context.getSceneTools().getApp; 15 | SceneUtil.get2DRootView = this.context.getSceneTools().getRootView; 16 | // if (ldeStore.document.skewModel) { 17 | // return [ 18 | // g(Product2DViewEntity, { 19 | // model: ldeStore.document.skewModel as ProductEntity, 20 | // id: ldeStore.document.skewModel.id, 21 | // type: Product2DSymbol, 22 | // }), 23 | // ]; 24 | // } 25 | return null; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /demo/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "module": "esnext", 5 | "noImplicitAny": false, 6 | "declaration": false, 7 | "strictNullChecks": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "removeComments": false, 13 | "preserveConstEnums": true, 14 | "experimentalDecorators": true, 15 | "sourceMap": false, 16 | "downlevelIteration": true, 17 | "target": "ES2018", 18 | "moduleResolution": "node", 19 | "lib": [ 20 | "DOM", 21 | "ESNext", 22 | ], 23 | "types": [ 24 | "node", 25 | "jest", 26 | "webpack-env" 27 | ], 28 | "skipLibCheck": true 29 | }, 30 | "include": [ 31 | "src/**/*" 32 | ], 33 | "exclude": [ 34 | "node_modules", 35 | "**/node_modules/**/*", 36 | "**/__tests__/**/*" 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /docs/.nojekyll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/docs/.nojekyll -------------------------------------------------------------------------------- /docs/_navbar.md: -------------------------------------------------------------------------------- 1 | * Translations 2 | * [English](/en-us/) 3 | * [中文](/zh-cn/) 4 | 5 | * [Changelog](CHANGELOG.md) 6 | 7 | * [API List](https://turbox3d.github.io/turbox-type-doc/) 8 | 9 | * [Online Demo](https://codesandbox.io/s/turbox-demo-forked-48s2t) 10 | -------------------------------------------------------------------------------- /docs/en-us/README.md: -------------------------------------------------------------------------------- 1 | # Turbox 2 | 3 | [![build status](https://img.shields.io/travis/com/turbox3d/turbox/master.svg?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 4 | [![license](https://img.shields.io/github/license/turbox3d/turbox?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 5 | [![npm version](https://img.shields.io/npm/v/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 6 | [![npm downloads](https://img.shields.io/npm/dm/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 7 | [![install size](https://img.shields.io/bundlephobia/minzip/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 8 | 9 | ## Introduction 10 | 11 | **Turbox** is a large-scale productivity application front-end framework. 12 | 13 | ## Documentation 14 | 15 | WIP... 16 | 17 | ## Ecosystem 18 | 19 | | Project | Status | Description | 20 | |---------|--------|-------------| 21 | | turbox-cli | - | Project cli tool, include scaffolding | 22 | | turbox-dev-tool | - | Browser DevTools extension | 23 | | turbox-loader | - | Turbox loader for webpack | 24 | | turbox-snippets | [see marketplace](https://marketplace.visualstudio.com/items?itemName=feifan-gff.turbox-snippets) | Vscode snippet extension | 25 | 26 | ## Feedback 27 | 28 | | Github Issue | Wechat | 29 | | --- | --- | 30 | | [turbox3d/turbox/issues](https://github.com/turbox3d/turbox/issues) | | 31 | 32 | ## License 33 | 34 | [MIT](http://opensource.org/licenses/MIT) 35 | 36 | Copyright (c) 2020-present, Felix Koo 37 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | turbox 6 | 7 | 8 | 9 | 10 | 16 | 17 | 18 |
19 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /docs/zh-cn/README.md: -------------------------------------------------------------------------------- 1 | # Turbox 2 | 3 | [![build status](https://img.shields.io/travis/com/turbox3d/turbox/master.svg?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 4 | [![license](https://img.shields.io/github/license/turbox3d/turbox?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 5 | [![npm version](https://img.shields.io/npm/v/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 6 | [![npm downloads](https://img.shields.io/npm/dm/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 7 | [![install size](https://img.shields.io/bundlephobia/minzip/@turbox3d/turbox?style=flat-square)](https://www.npmjs.com/package/@turbox3d/turbox) 8 | 9 | ## 介绍 10 | 11 | **Turbox**(涡轮)是适合大型生产力软件应用的前端框架,场景来源于复杂大型 3D 业务 12 | 13 | ## 文档列表 14 | 15 | * turbox 16 | * turbox-cli 17 | * turbox-dev-tool 18 | 19 | ## 生态系统 20 | 21 | | Project | Status | Description | 22 | |---------|--------|-------------| 23 | | turbox-cli | - | Project cli tool, include scaffolding | 24 | | turbox-dev-tool | - | Browser DevTools extension | 25 | | turbox-loader | - | Turbox loader for webpack | 26 | | turbox-snippets | [see marketplace](https://marketplace.visualstudio.com/items?itemName=feifan-gff.turbox-snippets) | Vscode snippet extension | 27 | 28 | ## 反馈 29 | 30 | | Github Issue | 微信群 | 31 | | --- | --- | 32 | | [turbox3d/turbox/issues](https://github.com/turbox3d/turbox/issues) | | 33 | 34 | ## 许可证 35 | 36 | [MIT](http://opensource.org/licenses/MIT) 37 | 38 | Copyright (c) 2020-present, Felix Koo 39 | -------------------------------------------------------------------------------- /docs/zh-cn/cli.md: -------------------------------------------------------------------------------- 1 | # turbox-cli 2 | [![pipeline status](https://img.shields.io/travis/com/turbox3d/turbox/master.svg?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 3 | 4 | ## 介绍 5 | turbox 的命令行工具 6 | -------------------------------------------------------------------------------- /docs/zh-cn/dev-tool.md: -------------------------------------------------------------------------------- 1 | # turbox-dev-tool 2 | [![pipeline status](https://img.shields.io/travis/com/turbox3d/turbox/master.svg?style=flat-square)](https://travis-ci.com/github/turbox3d/turbox) 3 | 4 | ## 介绍 5 | turbox 的浏览器辅助开发工具 6 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | roots: ['src/'], 3 | transform: { 4 | '^.+\\.(t|j)sx?$': 'ts-jest' 5 | }, 6 | testEnvironment: 'node', 7 | testMatch: [ 8 | '**/__tests__/**/*.(spec|test).(js|ts)' 9 | ], 10 | moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], 11 | collectCoverage: true, 12 | coverageDirectory: 'coverage', 13 | coverageReporters: ['json', 'lcov', 'text', 'text-summary'], 14 | globals: { 15 | window: {} 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/command-manager/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/command-manager/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/command-manager/demo/CommandDemo.ts: -------------------------------------------------------------------------------- 1 | import { Command } from '../src/Command'; 2 | import { CommandManager } from '../src/CommandManager'; 3 | import { manager } from '../src/manager'; 4 | import { compose } from '../src/compose'; 5 | import { create } from '../src/create'; 6 | 7 | class ACommand extends Command {} 8 | 9 | class BCommand extends Command { 10 | constructor(holder: CommandManager, parent?: Command) { 11 | super(holder, parent); 12 | } 13 | } 14 | 15 | class DCommand extends Command {} 16 | 17 | class ECommand extends Command {} 18 | 19 | // 组合单个Command 20 | class ABCommand extends compose({ 21 | aCommand: ACommand, 22 | bCommand: BCommand, 23 | }) { 24 | active(name: string, age: number) { 25 | this.aCommand.active(name); 26 | } 27 | } 28 | 29 | // 组合以后的 Command 依然可以被组合 30 | // 不等同于 compose([ACommand, BCommand, DCommand]) 31 | class ABDCommand extends compose({ 32 | abCommand: ABCommand, 33 | dCommand: DCommand, 34 | }) {} 35 | 36 | class WCommand extends create<{ a: string }>() { 37 | active(param: { a: '10' }) {} 38 | } 39 | 40 | const w = new WCommand(); 41 | // w.apply() 42 | 43 | // 创建应用唯一的 Box 44 | class DemoCommandBox extends CommandManager { 45 | // 使用独立的 Command 46 | aCommand = new ACommand(this); 47 | 48 | eCommand = new ECommand(this); 49 | 50 | // 使用合成的 Command 51 | abdCommand = new ABDCommand(this); 52 | } 53 | 54 | const demoCommandBox = new DemoCommandBox(); 55 | 56 | class AWCommand extends compose({ 57 | a: ACommand, 58 | w: WCommand, 59 | }) {} 60 | 61 | const awCommand = new AWCommand(); 62 | // awCommand.w.active(); 63 | 64 | class Demo2 extends manager({ 65 | a: ACommand, 66 | w: WCommand, 67 | }) {} 68 | 69 | const a: CommandManager = new Demo2(); 70 | 71 | const demo2 = new Demo2(); 72 | // demo2.w.apply() 73 | 74 | class View { 75 | onClick() { 76 | demoCommandBox.aCommand.active(); 77 | 78 | demoCommandBox.abdCommand.abCommand.active('', 18); 79 | } 80 | } 81 | 82 | export { demoCommandBox }; 83 | -------------------------------------------------------------------------------- /packages/command-manager/demo/interactors/index.ts: -------------------------------------------------------------------------------- 1 | // export * from './ioc'; 2 | export * from './structure'; 3 | -------------------------------------------------------------------------------- /packages/command-manager/demo/interactors/ioc/test.ts: -------------------------------------------------------------------------------- 1 | // import { Inject, Injectable } from './index'; 2 | 3 | // @Injectable() 4 | // class A { 5 | // log(str: string) { 6 | // console.log(str); 7 | // } 8 | // } 9 | 10 | // class B { 11 | // @Inject() a: A; 12 | 13 | // log() { 14 | // this.a.log('quan'); 15 | // } 16 | // } 17 | 18 | // const b = new B(); 19 | // b.log(); 20 | -------------------------------------------------------------------------------- /packages/command-manager/demo/interactors/structure/CommandUnit.ts: -------------------------------------------------------------------------------- 1 | import { CommandUnitManager } from './Manager'; 2 | 3 | /** 4 | * 业务处理模块 5 | */ 6 | abstract class CommandUnit { 7 | constructor(private holder: CommandUnitManager) {} 8 | 9 | /** 10 | * 激活当前 CommandUnit 11 | * 12 | * 激活的 CommandUnit 将会收到场景视图中的交互事件 13 | * 14 | * 派生类重写该方法时,需调用 super.active() 15 | */ 16 | active(...args: any[]) { 17 | this.holder.addActivatedCommand(this); 18 | } 19 | 20 | /** 21 | * 注销当前 CommandUnit 22 | * 23 | * CommandUnit 将不会响应场景视图中的交互事件 24 | * 25 | * 派生类重写该方法时,需调用 super.dispose() 26 | */ 27 | dispose(result?: any) { 28 | this.holder.removeActivatedCommand(this, result); 29 | } 30 | 31 | // 场景交互回调 32 | 33 | onClick(entity: T) {} 34 | 35 | // onSelected(entity: T) {} 36 | 37 | onHoverIn(entity: T) {} 38 | 39 | onHoverOut(entity: T) {} 40 | 41 | beforeDrag(entity: T) {} 42 | 43 | onDrag(entity: T) {} 44 | 45 | afterDrag(entity: T) {} 46 | 47 | onMouseUp(entity: T) {} 48 | 49 | onMouseDown(entity: T) {} 50 | 51 | onMouseMove(entity: T) {} 52 | 53 | onThrottledDrag(entity: T) {} 54 | 55 | onThrottledMouseMove(entity: T) {} 56 | 57 | // TODO 考虑对视图能力的支持 58 | } 59 | 60 | export { CommandUnit }; 61 | -------------------------------------------------------------------------------- /packages/command-manager/demo/interactors/structure/DistributeCommandUnit.ts: -------------------------------------------------------------------------------- 1 | import { CommandUnit } from './CommandUnit'; 2 | import { CommandUnitManager } from './Manager'; 3 | 4 | interface Item { 5 | unit: CommandUnit; 6 | transformParam?: (...args: any[]) => any; 7 | } 8 | 9 | /** 10 | * 具有分发能力的 CommandUnit 11 | * 12 | * 根据参数筛选要激活的 CommandUnit 13 | */ 14 | abstract class DistributeCommandUnit extends CommandUnit { 15 | private activeCommand: CommandUnit; 16 | 17 | active(...args: any[]) { 18 | // 如果存在未销毁的 CommandUnit , 请先销毁 19 | // this.dispose(); 20 | 21 | const { unit, transformParam } = this.onActive(...args); 22 | 23 | const param = transformParam ? transformParam(...args) : args; 24 | this.activeCommand = unit; 25 | if (Array.isArray(param)) { 26 | this.activeCommand.active(...param); 27 | } else { 28 | this.activeCommand.active(param); 29 | } 30 | } 31 | 32 | dispose() { 33 | if (this.activeCommand) { 34 | this.activeCommand.dispose(); 35 | } 36 | } 37 | 38 | /** 39 | * 用户需在该方法中实现分发逻辑 40 | * 41 | * @param args active 方法的入参 42 | */ 43 | abstract onActive(...args: any[]): Item; 44 | } 45 | 46 | export { DistributeCommandUnit }; 47 | -------------------------------------------------------------------------------- /packages/command-manager/demo/interactors/structure/index.ts: -------------------------------------------------------------------------------- 1 | export * from './CommandUnit'; 2 | export * from './Manager'; 3 | export * from './DistributeCommandUnit'; 4 | export * from './SequenceCommandUnit'; 5 | -------------------------------------------------------------------------------- /packages/command-manager/demo/interactors/structure/type.ts: -------------------------------------------------------------------------------- 1 | // 同步 DisplayControll 的事件 2 | const eventsType = [ 3 | 'click', 4 | 'dblclick', 5 | 'wheel', 6 | 'touchstart', 7 | 'touchend', 8 | 'touchmove', 9 | 'mouseup', 10 | 'mousedown', 11 | 'mousemove', 12 | 'mouseover', 13 | 'mouseout', 14 | 'keydown', 15 | 'keyup', 16 | 'dragstart', 17 | 'dragmove', 18 | 'dragend', 19 | ]; 20 | 21 | export enum EventType { 22 | CLICK = 'click', 23 | MOUSEOVER = 'mouseover', 24 | MOUSEOUT = 'mouseout', 25 | MOUSEMOVE = 'mousemove', 26 | MOUSEUP = 'mouseup', 27 | MOUSEDOWN = 'mousedown', 28 | DRAGSTART = 'dragstart', 29 | DRAGMOVE = 'dragmove', 30 | DRAGEND = 'dragend', 31 | } 32 | -------------------------------------------------------------------------------- /packages/command-manager/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/command-manager/src/CommandManager.ts: -------------------------------------------------------------------------------- 1 | import { ViewEntity, SceneEvent, EventType } from '@turbox3d/event-manager'; 2 | import { Command } from './Command'; 3 | import { create } from './create'; 4 | import { compose } from './compose'; 5 | import { manager } from './manager'; 6 | import { SceneTool } from './type'; 7 | import { install } from './install'; 8 | 9 | export abstract class CommandManager { 10 | /** 11 | * 构建一个 Command 基类 12 | * 13 | * 范型类型为激活时的函数参数 14 | */ 15 | static create = create; 16 | /** 17 | * 构建一个组合了其他 Command 的结构(本质依然是一个 Command) 18 | */ 19 | static compose = compose; 20 | /** 21 | * 构建一个 CommandManager 基类 22 | */ 23 | static manager = manager; 24 | /** 25 | * 安装声明一系列指令集 26 | */ 27 | static install = install; 28 | /** 29 | * 当前激活的 Command 30 | */ 31 | protected activeCommand?: Command; 32 | 33 | installed() { 34 | // 35 | } 36 | 37 | toggleCommand(command?: Command) { 38 | this.activeCommand = command; 39 | } 40 | 41 | clearCommand() { 42 | this.activeCommand = undefined; 43 | } 44 | 45 | /** 46 | * 判断当前激活的 Command 是否为入参 command 47 | * @param command 48 | */ 49 | isCommandActive(command: Command) { 50 | return this.activeCommand === command; 51 | } 52 | 53 | distributeEvent(eventType: EventType, ev: ViewEntity, event: SceneEvent, tools: SceneTool) { 54 | if (this.activeCommand) { 55 | this.activeCommand.distributeEvent(eventType, ev, event, tools); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /packages/command-manager/src/compose.ts: -------------------------------------------------------------------------------- 1 | import { Command } from './Command'; 2 | import { CommandManager } from './CommandManager'; 3 | import { CommandType } from './create'; 4 | import { ComposedCommand, IDeclaredMap } from './type'; 5 | 6 | /** 7 | * 构建一个组合了其他 Command 的结构(本质依然是一个 Command) 8 | */ 9 | function compose = IDeclaredMap>(declaredMap: M) { 10 | return class extends Command { 11 | constructor(holer: CommandManager, parent?: Command) { 12 | super(holer, parent); 13 | 14 | // 构建 $children 15 | Object.keys(declaredMap).forEach((key) => { 16 | const command = new declaredMap[key](this.holder, this); 17 | this[key] = command; 18 | this.$children[key] = command as Command; 19 | }); 20 | } 21 | } as any as ComposedCommand; 22 | } 23 | 24 | export { compose }; 25 | -------------------------------------------------------------------------------- /packages/command-manager/src/create.ts: -------------------------------------------------------------------------------- 1 | import { IConstructorOf } from '@turbox3d/shared'; 2 | import { Command } from './Command'; 3 | 4 | // 仅作为类型标示无参数的 Command 生命周期函数 5 | class INoParamCommand { 6 | apply() { 7 | // 8 | } 9 | 10 | active() { 11 | // 12 | } 13 | } 14 | 15 | // 仅作为类型标示有参数的 Command 生命周期函数 16 | class IParamCommand

{ 17 | apply(param: P) { 18 | // 19 | } 20 | 21 | active(param: P) { 22 | // 23 | } 24 | } 25 | 26 | type LifeCircleClass

= P extends {} ? IParamCommand

: INoParamCommand; 27 | 28 | export type CommandType = Omit; 29 | 30 | // type E = keyof Command; 31 | 32 | // type P = Pick; 33 | 34 | /** 35 | * 构建一个 Command 基类 36 | * 37 | * 范型类型为激活时的函数参数 38 | */ 39 | function create

() { 40 | return Command as any as IConstructorOf & CommandType>; 41 | } 42 | 43 | export { create }; 44 | -------------------------------------------------------------------------------- /packages/command-manager/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Command } from './Command'; 2 | import { CommandManager } from './CommandManager'; 3 | import { isCommandManager } from './util'; 4 | import { SceneTool } from './type'; 5 | 6 | export { 7 | Command, 8 | CommandManager, 9 | isCommandManager, 10 | SceneTool, 11 | }; 12 | -------------------------------------------------------------------------------- /packages/command-manager/src/install.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager } from './CommandManager'; 2 | import { CommandType } from './create'; 3 | import { ComposedCommand, IDeclaredMap } from './type'; 4 | 5 | function install = IDeclaredMap>(declaredMap: M) { 6 | return class extends CommandManager { 7 | constructor() { 8 | super(); 9 | Object.keys(declaredMap).forEach(key => { 10 | const command = new declaredMap[key](this); 11 | this[key] = command; 12 | }); 13 | this.installed(); 14 | } 15 | } as any as ComposedCommand; 16 | } 17 | 18 | export { install }; 19 | -------------------------------------------------------------------------------- /packages/command-manager/src/manager.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager } from './CommandManager'; 2 | import { CommandType } from './create'; 3 | import { ComposedCommand, IDeclaredMap } from './type'; 4 | 5 | /** 6 | * 构建一个 CommandManager 基类 7 | */ 8 | function manager = IDeclaredMap>(declaredMap: M) { 9 | return class extends CommandManager { 10 | constructor() { 11 | super(); 12 | 13 | Object.keys(declaredMap).forEach((key) => { 14 | const command = new declaredMap[key](this); 15 | this[key] = command; 16 | }); 17 | } 18 | } as any as ComposedCommand; 19 | } 20 | 21 | export { manager }; 22 | -------------------------------------------------------------------------------- /packages/command-manager/src/type.ts: -------------------------------------------------------------------------------- 1 | import { IConstructorOf, Vec2, Vec3 } from '@turbox3d/shared'; 2 | import { InteractiveConfig, ViewEntity, CoordinateType } from '@turbox3d/event-manager'; 3 | 4 | export interface IDeclaredMap { 5 | [key: string]: IConstructorOf; 6 | } 7 | 8 | export type IInstanceMap> = { 9 | [K in keyof M]: InstanceType; 10 | }; 11 | 12 | export type ComposedCommand> = IConstructorOf>; 13 | 14 | export interface SceneTool { 15 | updateInteractiveObject: (view: any, config?: InteractiveConfig) => void; 16 | updateCursor: (cursor?: string) => void; 17 | hitTarget: (point: { x: number; y: number }) => Partial | undefined; 18 | coordinateTransform: (point: Vec2 | Vec3, type: CoordinateType, z?: number) => Vec2 | Vec3; 19 | getCamera: () => any; 20 | getRaycaster: () => any; 21 | getScene: () => any; 22 | getRootView: () => any; 23 | getScreenShot: ( 24 | sx?: number, 25 | sy?: number, 26 | w?: number, 27 | h?: number, 28 | fileType?: string, 29 | quality?: number, 30 | isBase64?: boolean 31 | ) => Promise; 32 | getApp: () => any; 33 | addTicker: (ticker: (deltaTime: number) => void) => void; 34 | removeTicker: (ticker: (deltaTime: number) => void) => void; 35 | } 36 | -------------------------------------------------------------------------------- /packages/command-manager/src/util.ts: -------------------------------------------------------------------------------- 1 | import { CommandManager } from './CommandManager'; 2 | 3 | export function isCommandManager(mgr: any): mgr is CommandManager { 4 | return mgr instanceof CommandManager; 5 | } 6 | -------------------------------------------------------------------------------- /packages/command-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/command-manager/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/design-engine/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/design-engine/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/design-engine/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/design-engine/src/assembly-entity-object/README.md: -------------------------------------------------------------------------------- 1 | # 组合实体模型 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/assembly-entity-object/index.ts: -------------------------------------------------------------------------------- 1 | import EntityObject from '../entity-object/index'; 2 | 3 | export default class AssemblyEntityObject extends EntityObject { 4 | } 5 | -------------------------------------------------------------------------------- /packages/design-engine/src/collision-engine/README.md: -------------------------------------------------------------------------------- 1 | # 碰撞引擎 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/collision-engine/index.ts: -------------------------------------------------------------------------------- 1 | export default class CollisionEngine { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/document-system/README.md: -------------------------------------------------------------------------------- 1 | # 文档系统 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/entity-object/README.md: -------------------------------------------------------------------------------- 1 | # 通用实体模型 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/env-system/README.md: -------------------------------------------------------------------------------- 1 | # 环境系统 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/env-system/index.ts: -------------------------------------------------------------------------------- 1 | import { Domain, reactor, mutation } from '@turbox3d/reactivity'; 2 | 3 | /** 应用环境变量 */ 4 | enum EAppEnv { 5 | /** 定制商品素材主插件 */ 6 | CUSTOMIZE_PRODUCTS = 'customize-products', 7 | /** 定制铝合金门窗自由绘制插件 */ 8 | CUSTOMIZE_DOOR_WINDOW = 'customize-door-window', 9 | } 10 | 11 | class AppEnvironmentManager extends Domain { 12 | /** 当前应用环境变量 */ 13 | @reactor() appEnv = ''; 14 | 15 | /** 切换应用环境 */ 16 | @mutation('切换应用环境', true) 17 | switchAppEnv(appEnvId: string) { 18 | this.appEnv = appEnvId; 19 | } 20 | } 21 | 22 | /** 应用环境管理器 */ 23 | const EnvSystem = { 24 | EAppEnv, 25 | AppEnvMgr: new AppEnvironmentManager(), 26 | }; 27 | 28 | export default EnvSystem; 29 | -------------------------------------------------------------------------------- /packages/design-engine/src/free-draw-command/README.md: -------------------------------------------------------------------------------- 1 | # 自由绘制指令 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/free-draw-command/index.ts: -------------------------------------------------------------------------------- 1 | export default class FreeDrawCommand { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/hint-command/README.md: -------------------------------------------------------------------------------- 1 | # 实体提示指令 2 | 3 | 实体的 hover 效果 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/index.ts: -------------------------------------------------------------------------------- 1 | const ENV = process.env.NODE_ENV; 2 | if ( 3 | ENV !== 'production' && 4 | ENV !== 'test' && 5 | typeof console !== 'undefined' && 6 | console.warn && // eslint-disable-line no-console 7 | typeof window !== 'undefined' 8 | ) { 9 | // eslint-disable-next-line no-console 10 | console.warn( 11 | 'You are using a whole package of design engine, ' + 12 | 'please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.', 13 | ); 14 | } 15 | 16 | export { default as AssemblyEntityObject } from './assembly-entity-object/index'; 17 | export { default as CollisionEngine } from './collision-engine/index'; 18 | export { default as DocumentSystem } from './document-system/index'; 19 | export { default as EntityObject } from './entity-object/index'; 20 | export { default as EnvSystem } from './env-system/index'; 21 | export { default as FreeDrawCommand } from './free-draw-command/index'; 22 | export { default as HintCommand } from './hint-command/index'; 23 | export { default as InferenceEngine } from './inference-engine/index'; 24 | export { default as LoadSystem } from './load-system/index'; 25 | export { default as MaterialBrushCommand } from './material-brush-command/index'; 26 | export { default as MaterialDragSystem } from './material-drag-system/index'; 27 | export { default as MeasureCommand } from './measure-command/index'; 28 | export { default as MountSystem } from './mount-system/index'; 29 | export { default as PlacementEngine } from './placement-engine/index'; 30 | export { default as RectSelectionCommand } from './rect-selection-command/index'; 31 | export { default as SelectionCommand } from './selection-command/index'; 32 | export { default as SpaceEngine } from './space-engine/index'; 33 | export { default as UnitSystem } from './unit-system/index'; 34 | -------------------------------------------------------------------------------- /packages/design-engine/src/inference-engine/README.md: -------------------------------------------------------------------------------- 1 | # 吸附引擎 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/load-system/README.md: -------------------------------------------------------------------------------- 1 | # 资源加载系统 2 | 3 | 贴图、二进制文件、JSON 文件等 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/load-system/index.ts: -------------------------------------------------------------------------------- 1 | import { loadJSON } from '@turbox3d/shared'; 2 | 3 | const LoadSystem = { 4 | loadJSON, 5 | }; 6 | 7 | export default LoadSystem; 8 | -------------------------------------------------------------------------------- /packages/design-engine/src/material-brush-command/README.md: -------------------------------------------------------------------------------- 1 | # 材质刷指令 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/material-brush-command/index.ts: -------------------------------------------------------------------------------- 1 | export default class MaterialBrushCommand { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/material-drag-system/README.md: -------------------------------------------------------------------------------- 1 | # 素材拖拽系统(for web 面板) 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/measure-command/README.md: -------------------------------------------------------------------------------- 1 | # 测量指令 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/measure-command/index.ts: -------------------------------------------------------------------------------- 1 | export default class MeasureCommand { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/mount-system/README.md: -------------------------------------------------------------------------------- 1 | # 挂载容器系统 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/mount-system/ViewMounter.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { Reactive } from '@turbox3d/reactivity-react'; 3 | import EnvSystem from '../env-system/index'; 4 | 5 | interface IProps extends React.PropsWithChildren { 6 | /** 挂载点 */ 7 | mountPointId?: string; 8 | /** 容器节点样式 */ 9 | className?: string; 10 | /** 只在当前支持的环境下渲染,离开环境自动卸载 */ 11 | environments?: string[]; 12 | /** style */ 13 | style?: React.CSSProperties; 14 | /** 切换环境时是否需要卸载 dom */ 15 | unmountDom?: boolean; 16 | } 17 | 18 | @Reactive 19 | export class EnvViewMounter extends React.Component { 20 | static defaultProps = { 21 | className: '', 22 | mountPointId: '', 23 | environments: [], 24 | style: {}, 25 | unmountDom: true, 26 | }; 27 | 28 | render() { 29 | const { environments, className, mountPointId, style, unmountDom } = this.props; 30 | const matched = environments!.includes(EnvSystem.AppEnvMgr.appEnv); 31 | let styles = style; 32 | if (!matched) { 33 | if (unmountDom) { 34 | return null; 35 | } 36 | styles = { 37 | ...style, 38 | display: 'none', 39 | }; 40 | } 41 | return ( 42 |

47 | {this.props.children} 48 |
49 | ); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/design-engine/src/mount-system/index.ts: -------------------------------------------------------------------------------- 1 | import { EnvViewMounter } from './ViewMounter'; 2 | import { renderPluginView } from './renderPluginView'; 3 | 4 | const MountSystem = { 5 | EnvViewMounter, 6 | renderPluginView, 7 | }; 8 | 9 | export default MountSystem; 10 | -------------------------------------------------------------------------------- /packages/design-engine/src/mount-system/renderPluginView.tsx: -------------------------------------------------------------------------------- 1 | import * as ReactDOM from 'react-dom/client'; 2 | import * as ReactDOMLegacy from 'react-dom'; 3 | import * as React from 'react'; 4 | 5 | /** 渲染插件应用视图 */ 6 | export function renderPluginView(Target: React.ComponentType, pluginId: string) { 7 | const el = document.getElementById(`turbox-plugin-${pluginId}`); 8 | let containerNode: HTMLElement; 9 | if (el) { 10 | containerNode = el; 11 | } else { 12 | containerNode = document.createElement('div'); 13 | containerNode.id = `turbox-plugin-${pluginId}`; 14 | containerNode.className = `turbox-plugin-${pluginId}-class`; 15 | document.body.appendChild(containerNode); 16 | } 17 | if (React.version.startsWith('18')) { 18 | const root = ReactDOM.createRoot(containerNode); 19 | root.render(React.createElement(Target)); 20 | } else { 21 | ReactDOMLegacy.render(React.createElement(Target), containerNode); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/design-engine/src/placement-engine/README.md: -------------------------------------------------------------------------------- 1 | # 摆放引擎 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/placement-engine/index.ts: -------------------------------------------------------------------------------- 1 | class PlacementEngine { 2 | 3 | } 4 | 5 | export default PlacementEngine; 6 | -------------------------------------------------------------------------------- /packages/design-engine/src/rect-selection-command/README.md: -------------------------------------------------------------------------------- 1 | # 框选指令 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/rect-selection-command/index.ts: -------------------------------------------------------------------------------- 1 | export default class RectSelectionCommand { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/selection-command/README.md: -------------------------------------------------------------------------------- 1 | # 实体选择指令 2 | 3 | 包括整体选择、部件选择、多级选择、多选 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/selection-command/domain.ts: -------------------------------------------------------------------------------- 1 | import { Domain, mutation, reactor } from '@turbox3d/reactivity'; 2 | import { batchRemove } from '@turbox3d/shared'; 3 | import EntityObject from '../entity-object'; 4 | import { ESelectMode } from './command'; 5 | 6 | export class Selection extends Domain { 7 | @reactor() selectedEntities: EntityObject[] = []; 8 | /** 选择层级深度,多选时取最大值 */ 9 | @reactor() layerDepth = 1; 10 | @reactor() selectMode = ESelectMode.OVERALL; 11 | @reactor() selectEntityTypes?: symbol[]; 12 | @reactor() isMultiSelectMode = false; 13 | 14 | @mutation 15 | setMultiSelect(isMultiple: boolean) { 16 | this.isMultiSelectMode = isMultiple; 17 | } 18 | 19 | @mutation() 20 | switchSelectMode(selectMode: ESelectMode) { 21 | this.selectMode = selectMode; 22 | } 23 | 24 | @mutation 25 | setLayerDepth(layerDepth: number) { 26 | this.layerDepth = layerDepth; 27 | } 28 | 29 | @mutation() 30 | select(models: EntityObject[], onSelectHandler?: (models: EntityObject[]) => void) { 31 | if (models.length === 0) { 32 | return; 33 | } 34 | this.selectedEntities.push(...models); 35 | const layerDepths = models.map((m) => m.getParentPathChain().indexOf(m) + 1); 36 | this.setLayerDepth(Math.max(...layerDepths)); 37 | onSelectHandler && onSelectHandler(models); 38 | } 39 | 40 | @mutation() 41 | unselect(models: EntityObject[], onUnselectHandler?: (models: EntityObject[]) => void) { 42 | batchRemove(this.selectedEntities, models); 43 | onUnselectHandler && onUnselectHandler(models); 44 | } 45 | 46 | @mutation() 47 | clearAllSelected(onUnselectHandler?: (models: EntityObject[]) => void) { 48 | const selected = this.selectedEntities.slice(); 49 | batchRemove(this.selectedEntities, selected); 50 | onUnselectHandler && onUnselectHandler(selected); 51 | } 52 | 53 | @mutation() 54 | setSelectEntityTypes(types?: symbol[]) { 55 | this.selectEntityTypes = types; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/design-engine/src/selection-command/index.ts: -------------------------------------------------------------------------------- 1 | import { SelectionCommand } from './command'; 2 | 3 | export default SelectionCommand; 4 | -------------------------------------------------------------------------------- /packages/design-engine/src/space-engine/README.md: -------------------------------------------------------------------------------- 1 | # 内空引擎 2 | 3 | * 2d 内空 4 | * 3d 内空 5 | -------------------------------------------------------------------------------- /packages/design-engine/src/space-engine/index.ts: -------------------------------------------------------------------------------- 1 | class SpaceEngine { 2 | 3 | } 4 | 5 | export default SpaceEngine; 6 | -------------------------------------------------------------------------------- /packages/design-engine/src/unit-system/README.md: -------------------------------------------------------------------------------- 1 | # 单位系统 2 | -------------------------------------------------------------------------------- /packages/design-engine/src/unit-system/index.ts: -------------------------------------------------------------------------------- 1 | class UnitSystem { 2 | 3 | } 4 | 5 | export default UnitSystem; 6 | -------------------------------------------------------------------------------- /packages/design-engine/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/design-engine/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/event-manager/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/event-manager/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/event-manager/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/event-manager/src/index.ts: -------------------------------------------------------------------------------- 1 | export { 2 | throttleInAFrame, 3 | TaskPriority, 4 | } from '@turbox3d/shared'; 5 | export { Key } from './keyboard/keyCode'; 6 | export { 7 | HotKey, 8 | HotKeyController, 9 | HotKeyConfig, 10 | HotKeyData, 11 | } from './keyboard'; 12 | export { SceneEvent } from './interactive/sceneEvent'; 13 | export { CoordinateController } from './interactive/coordinate'; 14 | export { 15 | InteractiveEvent, 16 | EventType, 17 | GesturesExtra, 18 | Extra, 19 | } from './interactive/listener/type'; 20 | export { InteractiveListener } from './interactive/listener/index'; 21 | export { InteractiveController } from './interactive/index'; 22 | export { 23 | InteractiveType, 24 | InteractiveConfig, 25 | CoordinateType, 26 | ViewEntity, 27 | } from './interactive/type'; 28 | export { HotKeyEventType } from './keyboard/listener/util'; 29 | -------------------------------------------------------------------------------- /packages/event-manager/src/interactive/listener/type.ts: -------------------------------------------------------------------------------- 1 | import { Vec2 } from '@turbox3d/shared'; 2 | import { NativeEventSet } from '../type'; 3 | 4 | /** 标示拖拽阶段 */ 5 | export enum DragStatus { 6 | Ready = 'ready', 7 | Dragging = 'dragging', 8 | End = 'end', 9 | } 10 | 11 | /** 12 | * 当次鼠标事件(down -> move -> up)的处理类型 13 | */ 14 | export enum MouseDealType { 15 | /** 16 | * 作为一次 Drag 事件处理 17 | */ 18 | Drag = 'drag', 19 | /** 20 | * 作为一次 Click 事件处理 21 | */ 22 | Click = 'click', 23 | /** 多点触控事件 */ 24 | MultiTouch = 'multi-touch', 25 | /** 按压 */ 26 | Press = 'press', 27 | } 28 | 29 | /** 30 | * 可监听的交互事件类型 31 | */ 32 | export enum InteractiveEvent { 33 | Click = 1, // 涵盖移动端的 tap 34 | DBClick, 35 | RightClick, 36 | DragStart, // 涵盖移动端的 pan 37 | DragMove, // 涵盖移动端的 pan 38 | DragEnd, // 涵盖移动端的 pan 39 | CarriageMove, 40 | CarriageEnd, 41 | Hover, 42 | Wheel, 43 | PinchStart, 44 | Pinch, 45 | PinchEnd, 46 | RotateStart, 47 | Rotate, 48 | RotateEnd, 49 | Press, 50 | PressUp, 51 | } 52 | 53 | export enum EventType { 54 | onClick, 55 | onDBClick, 56 | onRightClick, 57 | onDragStart, 58 | onDragMove, 59 | onDragEnd, 60 | onCarriageMove, 61 | onCarriageEnd, 62 | onHoverIn, 63 | onHoverOut, 64 | onWheel, 65 | onPinchStart, 66 | onPinch, 67 | onPinchEnd, 68 | onRotateStart, 69 | onRotate, 70 | onRotateEnd, 71 | onPress, 72 | onPressUp, 73 | } 74 | 75 | export type ICallBack = { 76 | (event: NativeEventSet, extra?: GesturesExtra | Extra): void; 77 | }; 78 | 79 | export interface GesturesExtra { 80 | scale?: number; 81 | deltaScale?: number; 82 | rotate?: number; 83 | deltaRotate?: number; 84 | eventCache?: NativeEventSet[]; 85 | } 86 | 87 | export interface Extra { 88 | mouseDownInfo?: Vec2; 89 | } 90 | 91 | export interface IFunc { 92 | (event: NativeEventSet, extra?: GesturesExtra | Extra): void; 93 | } 94 | -------------------------------------------------------------------------------- /packages/event-manager/src/interactive/listener/utils.ts: -------------------------------------------------------------------------------- 1 | import { Vec2 } from '@turbox3d/shared'; 2 | import { NativeEventSet } from '../type'; 3 | 4 | export function isMouseMoved(mouseDownInfo: Vec2, moveEvent: NativeEventSet, tolerance: number) { 5 | const dx = mouseDownInfo.x - moveEvent.clientX; 6 | const dy = mouseDownInfo.y - moveEvent.clientY; 7 | return dx * dx + dy * dy > tolerance * tolerance; 8 | } 9 | -------------------------------------------------------------------------------- /packages/event-manager/src/keyboard/type.ts: -------------------------------------------------------------------------------- 1 | import { HotKeyEventType } from './listener/util'; 2 | 3 | export type Key = string | string[]; 4 | 5 | export type Handler = (keyEventType: HotKeyEventType) => void; 6 | export type Condition = () => boolean; 7 | 8 | export interface HotKeyConfig { 9 | /** 10 | * 快捷键字符 11 | * 12 | * 单个:'ctrl+a' 13 | * 14 | * 多个:['ctrl+a', 'ctrl+b', 'meta+a'] 15 | */ 16 | key: Key; 17 | /** 18 | * 快捷功能名称 19 | */ 20 | name?: string; 21 | /** 22 | * 快捷键功能描述 23 | */ 24 | description?: string; 25 | /** 26 | * 快捷键是否露出 27 | * 28 | * @default false 29 | */ 30 | show?: boolean; 31 | /** 32 | * 快捷键的额外信息(当快捷键冲突时会提示该信息) 33 | */ 34 | info?: string; 35 | /** 36 | * 快捷键回调函数 37 | */ 38 | handler: Handler; 39 | /** 40 | * 快捷键触发回调的条件函数 41 | * 42 | * @default () => true 43 | */ 44 | condition?: Condition; 45 | } 46 | 47 | export interface HotKeyData { 48 | key: string; 49 | name?: string; 50 | description?: string; 51 | } 52 | -------------------------------------------------------------------------------- /packages/event-manager/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/event-manager/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/_utils/README.md: -------------------------------------------------------------------------------- 1 | # 公共工具函数 2 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/angle-dimension/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh2D } from '@turbox3d/renderer-pixi'; 2 | import * as PIXI from 'pixi.js'; 3 | import { Vec2 } from '@turbox3d/shared'; 4 | import { drawText } from '../_utils/utils'; 5 | 6 | interface IXY { 7 | x: number; 8 | y: number; 9 | } 10 | 11 | interface IAngleDimensionProps { 12 | center: IXY; 13 | rotation?: number; 14 | scale?: Vec2; 15 | radius: number; 16 | startAngle: number; 17 | endAngle: number; 18 | anticlockwise: boolean; 19 | } 20 | 21 | /** 22 | * @description: 半径尺寸线 23 | */ 24 | export default class AngleDimension extends Mesh2D { 25 | protected view = new PIXI.Graphics(); 26 | 27 | public draw() { 28 | const graphics = this.view; 29 | graphics.clear(); 30 | 31 | graphics.lineStyle(1, 0x131313); 32 | graphics.line.native = true; 33 | 34 | graphics.arc(this.props.center.x, this.props.center.y, this.props.radius, this.props.startAngle, this.props.endAngle, !this.props.anticlockwise); 35 | 36 | // calculate number text 37 | let k = -1; 38 | if (this.props.anticlockwise) k *= -1; 39 | if (this.props.endAngle % (Math.PI * 2) < this.props.startAngle % (Math.PI * 2)) k *= -1; 40 | 41 | let text = Math.abs(this.props.endAngle - this.props.startAngle) % (Math.PI * 2) * 180 / Math.PI; 42 | if (k < 0) text = 360 - text; 43 | 44 | const bisectorAngle = (this.props.startAngle + this.props.endAngle) / 2; 45 | const bisectorDir = { x: Math.cos(bisectorAngle), y: Math.sin(bisectorAngle) }; 46 | drawText(graphics, text.toFixed(0), { offset: { x: this.props.center.x + 1.3 * k * this.props.radius * bisectorDir.x, y: this.props.center.y + 1.2 * k * this.props.radius * bisectorDir.y }, size: this.props.radius / 2, rotation: Math.PI / 2 + bisectorAngle }); 47 | 48 | this.view.rotation = this.props.rotation ?? 0; 49 | this.view.scale.set(this.props.scale?.x ?? 1, this.props.scale?.y ?? 1); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/arrow2d/index.ts: -------------------------------------------------------------------------------- 1 | export default class Arrow2d { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/axis2d/README.md: -------------------------------------------------------------------------------- 1 | # 坐标轴 2d 控件 2 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/axis2d/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh2D } from '@turbox3d/renderer-pixi'; 2 | import * as PIXI from 'pixi.js'; 3 | import DrawUtils from '../draw-utils/index'; 4 | 5 | interface IAxis2dProps { 6 | type?: 'front' | 'top' | 'left'; 7 | } 8 | 9 | /** 坐标轴 2d 控件 */ 10 | export default class Axis2d extends Mesh2D { 11 | protected view = new PIXI.Graphics(); 12 | 13 | draw() { 14 | this.view.clear(); 15 | this.view.zIndex = Number.MAX_SAFE_INTEGER; 16 | const red = 0xff0000; // x轴 17 | const green = 0x09ff00; // y轴 18 | const blue = 0x005cfc; // z轴 19 | let lineColors: number[] = [red, green]; 20 | if (this.props.type === 'front') { 21 | lineColors = [red, green]; 22 | } else if (this.props.type === 'top') { 23 | lineColors = [red, blue]; 24 | } else if (this.props.type === 'left') { 25 | lineColors = [blue, green]; 26 | } 27 | DrawUtils.drawLine(this.view, { 28 | x0: 0, 29 | y0: 0, 30 | x1: Number.MAX_SAFE_INTEGER, 31 | y1: 0, 32 | lineWidth: 5, 33 | lineColor: lineColors[0], 34 | alignment: 0.5, 35 | }); 36 | DrawUtils.drawLine(this.view, { 37 | x0: 0, 38 | y0: 0, 39 | x1: 0, 40 | y1: Number.MAX_SAFE_INTEGER, 41 | lineWidth: 5, 42 | lineColor: lineColors[1], 43 | alignment: 0.5, 44 | }); 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/circle2d/index.ts: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js'; 2 | import { Mesh2D } from '@turbox3d/renderer-pixi'; 3 | import { Vec2 } from '@turbox3d/shared'; 4 | import DrawUtils from '../draw-utils/index'; 5 | 6 | interface ICircle2DProps { 7 | center: Vec2; 8 | radius: number; 9 | rotation?: number; 10 | scale?: Vec2; 11 | lineWidth?: number; 12 | lineColor?: number; 13 | lineAlpha?: number; 14 | fillColor?: number; 15 | fillAlpha?: number; 16 | alpha?: number; 17 | alignment?: number; 18 | native?: boolean; 19 | zIndex?: number; 20 | } 21 | 22 | /** 正方形 */ 23 | export default class Circle2d extends Mesh2D { 24 | protected view = new PIXI.Graphics(); 25 | protected reactivePipeLine = [ 26 | this.updateGeometry, 27 | this.updateMaterial, 28 | this.updatePosition, 29 | this.updateRotation, 30 | this.updateScale, 31 | ]; 32 | 33 | updateGeometry() { 34 | this.view.clear(); 35 | const { 36 | radius, 37 | lineWidth, 38 | lineColor, 39 | lineAlpha, 40 | fillColor, 41 | fillAlpha, 42 | alpha, 43 | alignment, 44 | native, 45 | } = this.props; 46 | DrawUtils.drawCircle(this.view, { 47 | cx: 0, 48 | cy: 0, 49 | radius, 50 | lineWidth, 51 | lineColor, 52 | lineAlpha, 53 | fillColor, 54 | fillAlpha, 55 | alpha, 56 | alignment, 57 | native, 58 | }); 59 | } 60 | 61 | updateMaterial() { 62 | const { zIndex = 0 } = this.props; 63 | this.view.zIndex = zIndex; 64 | } 65 | 66 | updatePosition() { 67 | const { center } = this.props; 68 | this.view.position.set(center.x, center.y); 69 | } 70 | 71 | updateRotation() { 72 | this.view.rotation = this.props.rotation ?? 0; 73 | } 74 | 75 | updateScale() { 76 | const { scale = { x: 1, y: 1 } } = this.props; 77 | this.view.scale.set(scale.x, scale.y); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/dimension/README.md: -------------------------------------------------------------------------------- 1 | # 尺寸线的图形控件 2 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/draw-utils/README.md: -------------------------------------------------------------------------------- 1 | # 图形绘制工具方法 2 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/draw-utils/drawCircle.ts: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js'; 2 | import { IGraphicOption, setCommonOption } from './option'; 3 | 4 | interface ICircleParam { 5 | cx: number; 6 | cy: number; 7 | radius: number; 8 | } 9 | 10 | export function drawCircle(graphic: PIXI.Graphics, param: ICircleParam & IGraphicOption) { 11 | // 样式配置 12 | setCommonOption(graphic, param); 13 | 14 | const { cx, cy, radius } = param; 15 | graphic.drawCircle(cx, cy, radius); 16 | graphic.endFill(); 17 | } 18 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/draw-utils/drawLine.ts: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js'; 2 | import { IGraphicOption, parseGraphicOption } from './option'; 3 | 4 | interface ILineParam { 5 | x0: number; 6 | y0: number; 7 | x1: number; 8 | y1: number; 9 | } 10 | 11 | interface ILinesParam { 12 | points: number[]; 13 | } 14 | 15 | /** 16 | * 绘制一条从 (x0, y0) 到 (x1, y1) 的线 17 | */ 18 | export function drawLine(graphic: PIXI.Graphics, param: ILineParam & IGraphicOption) { 19 | // 样式配置 20 | const { lineWidth, lineColor, lineAlpha, alignment, native } = parseGraphicOption(param); 21 | graphic.lineStyle(lineWidth, lineColor, lineAlpha, alignment, native); 22 | // 坐标配置 23 | const { x0, y0, x1, y1 } = param; 24 | graphic.moveTo(x0, y0); 25 | graphic.lineTo(x1, y1); 26 | return graphic; 27 | } 28 | 29 | export function drawLines(graphic: PIXI.Graphics, param: ILinesParam & IGraphicOption) { 30 | // 样式配置 31 | const { lineWidth, lineColor, lineAlpha, alignment, native } = parseGraphicOption(param); 32 | graphic.lineStyle(lineWidth, lineColor, lineAlpha, alignment, native); 33 | // 坐标配置 34 | const [x0, y0] = param.points; 35 | graphic.moveTo(x0, y0); 36 | for (let index = 2; index < param.points.length; index += 2) { 37 | graphic.lineTo(param.points[index], param.points[index + 1]); 38 | } 39 | return graphic; 40 | } 41 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/draw-utils/drawPath.ts: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js'; 2 | import { drawLine } from './drawLine'; 3 | import { IGraphicOption, parseGraphicOption } from './option'; 4 | 5 | interface IPathParam { 6 | path: Array<{ x: number; y: number }>; 7 | /** 8 | * 绘制的路径是否闭合 9 | * 10 | * 默认:false,不闭合 11 | */ 12 | closed?: boolean; 13 | } 14 | 15 | /** 16 | * 绘制一条路径 17 | */ 18 | export function drawPath(graphic: PIXI.Graphics, param: IPathParam & IGraphicOption) { 19 | const { path, closed = false } = param; 20 | const length = path.length - 1; 21 | 22 | if (length < 1) { 23 | return; 24 | } 25 | 26 | // 样式配置 27 | const { lineWidth, lineColor, lineAlpha, alignment, native } = parseGraphicOption(param); 28 | graphic.lineStyle(lineWidth, lineColor, lineAlpha, alignment, native); 29 | 30 | for (let i = 0; i < length; i++) { 31 | drawLine(graphic, { 32 | x0: path[i].x, 33 | y0: path[i].y, 34 | x1: path[i + 1].x, 35 | y1: path[i + 1].y, 36 | lineWidth, 37 | lineColor, 38 | lineAlpha, 39 | alignment, 40 | native, 41 | }); 42 | } 43 | 44 | if (closed) { 45 | drawLine(graphic, { 46 | x0: path[length].x, 47 | y0: path[length].y, 48 | x1: path[0].x, 49 | y1: path[0].y, 50 | lineWidth, 51 | lineColor, 52 | lineAlpha, 53 | alignment, 54 | native, 55 | }); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/draw-utils/drawPolygon.ts: -------------------------------------------------------------------------------- 1 | import * as PIXI from 'pixi.js'; 2 | import { IGraphicOption, setCommonOption } from './option'; 3 | 4 | interface IPolygonParam { 5 | path: Array<{ x: number; y: number }>; 6 | } 7 | 8 | export function drawPolygon(graphic: PIXI.Graphics, param: IPolygonParam & IGraphicOption) { 9 | // 样式配置 10 | setCommonOption(graphic, param); 11 | 12 | const points = param.path.map(p => new PIXI.Point(p.x, p.y)); 13 | graphic.drawPolygon(points); 14 | graphic.endFill(); 15 | } 16 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/draw-utils/index.ts: -------------------------------------------------------------------------------- 1 | import { drawCircle } from './drawCircle'; 2 | import { drawLine, drawLines } from './drawLine'; 3 | import { drawPath } from './drawPath'; 4 | import { drawPolygon } from './drawPolygon'; 5 | import { drawRect } from './drawRect'; 6 | 7 | const DrawUtils = { 8 | drawCircle, 9 | drawLine, 10 | drawLines, 11 | drawPath, 12 | drawPolygon, 13 | drawRect, 14 | }; 15 | 16 | export default DrawUtils; 17 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/gizmo2d/README.md: -------------------------------------------------------------------------------- 1 | # gizmo 对象旋转、平移、缩放控件 2 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/grid2d/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh2D } from '@turbox3d/renderer-pixi'; 2 | import { GridHelper } from './grid-helper'; 3 | 4 | interface IGrid2dProps { 5 | gridWidth: number; 6 | cellSize?: number; 7 | lineWidth?: number; 8 | lineColor?: number; 9 | drawBoundaries?: boolean; 10 | zIndex?: number; 11 | } 12 | 13 | export default class Grid2d extends Mesh2D { 14 | protected view!: GridHelper; 15 | 16 | draw() { 17 | const { lineWidth = 2, lineColor = 0xffffff, drawBoundaries = true, gridWidth, cellSize = 0, zIndex = 0 } = this.props; 18 | this.view = new GridHelper(gridWidth, cellSize); 19 | this.view.lineStyle({ width: lineWidth, color: lineColor }); 20 | this.view.drawBoundaries = drawBoundaries; 21 | this.view.drawGrid(); 22 | this.view.position.set(-gridWidth / 2 + window.innerWidth / 2, -gridWidth / 2 + window.innerHeight / 2); 23 | this.view.zIndex = zIndex; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/index.ts: -------------------------------------------------------------------------------- 1 | const ENV = process.env.NODE_ENV; 2 | if ( 3 | ENV !== 'production' && 4 | ENV !== 'test' && 5 | typeof console !== 'undefined' && 6 | console.warn && // eslint-disable-line no-console 7 | typeof window !== 'undefined' 8 | ) { 9 | // eslint-disable-next-line no-console 10 | console.warn( 11 | 'You are using a whole package of graphic component pixi, ' + 12 | 'please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.', 13 | ); 14 | } 15 | 16 | export { default as Rect2d } from './rect2d/index'; 17 | export { default as Circle2d } from './circle2d/index'; 18 | export { default as Polygon } from './polygon/index'; 19 | export { default as Placement } from './placement/index'; 20 | export { default as DrawUtils } from './draw-utils/index'; 21 | export { default as Dimension } from './dimension/index'; 22 | export { default as RadiusDimension } from './radius-dimension/index'; 23 | export { default as AngleDimension } from './angle-dimension/index'; 24 | export { default as Axis2d } from './axis2d/index'; 25 | export { default as Arrow2d } from './arrow2d/index'; 26 | export { default as Gizmo2d } from './gizmo2d/index'; 27 | export { default as Text2d } from './text2d/index'; 28 | export { default as Image2d } from './image2d/index'; 29 | export { default as Line2d } from './line2d/index'; 30 | export { default as Grid2d } from './grid2d/index'; 31 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/line2d/index.ts: -------------------------------------------------------------------------------- 1 | import { Vec2 } from '@turbox3d/shared'; 2 | import { Mesh2D } from '@turbox3d/renderer-pixi'; 3 | import * as PIXI from 'pixi.js'; 4 | import DrawUtils from '../draw-utils'; 5 | 6 | interface ILine2dProps { 7 | lineWidth?: number; 8 | lineColor?: number; 9 | alignment?: number; 10 | start: Vec2; 11 | end: Vec2; 12 | rotation?: number; 13 | scale?: Vec2; 14 | zIndex?: number; 15 | } 16 | 17 | export default class Line2d extends Mesh2D { 18 | protected view = new PIXI.Graphics(); 19 | 20 | draw() { 21 | const { lineWidth = 2, lineColor = 0xffffff, start, end, alignment = 0.5, zIndex = 0 } = this.props; 22 | this.view.clear(); 23 | this.view.zIndex = zIndex; 24 | DrawUtils.drawLine(this.view, { 25 | x0: start.x, 26 | y0: start.y, 27 | x1: end.x, 28 | y1: end.y, 29 | lineWidth, 30 | lineColor, 31 | alignment, 32 | }); 33 | this.view.rotation = this.props.rotation ?? 0; 34 | this.view.scale.set(this.props.scale?.x ?? 1, this.props.scale?.y ?? 1); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/placement/README.md: -------------------------------------------------------------------------------- 1 | # 六面、四角摆放的控件 2 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/placement/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh2D } from '@turbox3d/renderer-pixi'; 2 | import * as PIXI from 'pixi.js'; 3 | 4 | export default class Placement extends Mesh2D { 5 | protected view = new PIXI.Graphics(); 6 | protected reactivePipeLine = [ 7 | this.updateGeometry, 8 | this.updateMaterial, 9 | this.updatePosition, 10 | this.updateRotation, 11 | this.updateScale, 12 | ]; 13 | 14 | updateGeometry() { 15 | this.view.clear(); 16 | } 17 | 18 | updateMaterial() { 19 | // 20 | } 21 | 22 | updatePosition() { 23 | // const { position } = this.props; 24 | // this.view.position.set(position!.x, position!.y); 25 | } 26 | 27 | updateRotation() { 28 | // this.view.rotation = this.props.rotation!; 29 | } 30 | 31 | updateScale() { 32 | // const { scale } = this.props; 33 | // this.view.scale.set(scale!.x, scale!.y); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/src/polygon/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh2D } from '@turbox3d/renderer-pixi'; 2 | import { Vec2 } from '@turbox3d/shared'; 3 | import * as PIXI from 'pixi.js'; 4 | import DrawUtils from '../draw-utils/index'; 5 | 6 | interface IPolygonProps { 7 | path: Vec2[]; 8 | rotation?: number; 9 | scale?: Vec2; 10 | lineWidth?: number; 11 | lineColor?: number; 12 | lineAlpha?: number; 13 | fillColor?: number; 14 | fillAlpha?: number; 15 | alpha?: number; 16 | zIndex?: number; 17 | alignment?: number; 18 | native?: boolean; 19 | } 20 | 21 | /** 多边形 */ 22 | export default class Polygon extends Mesh2D { 23 | protected view = new PIXI.Graphics(); 24 | protected reactivePipeLine = [ 25 | this.updateGeometry, 26 | this.updateMaterial, 27 | this.updatePosition, 28 | this.updateRotation, 29 | this.updateScale, 30 | ]; 31 | 32 | updateGeometry() { 33 | this.view.clear(); 34 | const { 35 | path, 36 | lineWidth, 37 | lineColor, 38 | lineAlpha, 39 | fillColor, 40 | fillAlpha, 41 | alpha, 42 | zIndex, 43 | alignment, 44 | native, 45 | } = this.props; 46 | zIndex && (this.view.zIndex = zIndex); 47 | DrawUtils.drawPolygon(this.view, { 48 | path: path.map(p => ({ x: p.x, y: p.y })), 49 | lineWidth, 50 | lineColor, 51 | lineAlpha, 52 | fillColor, 53 | fillAlpha, 54 | alpha, 55 | alignment, 56 | native, 57 | }); 58 | } 59 | 60 | updateMaterial() { 61 | // 62 | } 63 | 64 | updatePosition() { 65 | // const { position } = this.props; 66 | // this.view.position.set(position!.x, position!.y); 67 | } 68 | 69 | updateRotation() { 70 | this.view.rotation = this.props.rotation ?? 0; 71 | } 72 | 73 | updateScale() { 74 | this.view.scale.set(this.props.scale?.x ?? 1, this.props.scale?.y ?? 1); 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/graphic-component-pixi/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/graphic-component-three/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/graphic-component-three/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/graphic-component-three/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/_utils/README.md: -------------------------------------------------------------------------------- 1 | # 公共工具函数 2 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/_utils/utils.ts: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/packages/graphic-component-three/src/_utils/utils.ts -------------------------------------------------------------------------------- /packages/graphic-component-three/src/arrow3d/index.ts: -------------------------------------------------------------------------------- 1 | export default class Arrow3d { 2 | 3 | } 4 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/axis3d/README.md: -------------------------------------------------------------------------------- 1 | # 坐标轴 3d 控件 2 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/axis3d/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from '@turbox3d/renderer-three'; 2 | import * as THREE from 'three'; 3 | 4 | /** 坐标轴 3d 控件 */ 5 | export default class Axis3d extends Mesh3D { 6 | protected view = new THREE.AxesHelper(5000); 7 | } 8 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/circle3d/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from '@turbox3d/renderer-three'; 2 | import * as THREE from 'three'; 3 | import { Vec3 } from '@turbox3d/shared'; 4 | 5 | interface ICircleProps { 6 | radius: number; 7 | color?: number; 8 | imgUrl?: string; 9 | imgScale?: Vec3; 10 | scale?: Vec3; 11 | opacity?: number; 12 | } 13 | 14 | export default class Circle3d extends Mesh3D { 15 | sprite = new THREE.Sprite(); 16 | protected view = new THREE.Mesh(); 17 | protected reactivePipeLine = [this.updateGeometry, this.updateImage]; 18 | 19 | async updateGeometry() { 20 | const { scale = { x: 1, y: 1, z: 1 }, radius, color, opacity = 1 } = this.props; 21 | const geometry = new THREE.CircleGeometry(radius, 32); 22 | const material = new THREE.MeshBasicMaterial({ color: color || 0xBF975B, opacity, transparent: true }); 23 | (this.view as THREE.Mesh).geometry = geometry; 24 | (this.view as THREE.Mesh).material = material; 25 | this.view.scale.set(scale.x, scale.y, scale.z); 26 | } 27 | 28 | async updateImage() { 29 | const { imgScale, radius, imgUrl } = this.props; 30 | if (imgUrl) { 31 | const spriteMaterial = new THREE.SpriteMaterial(); 32 | const loader = new THREE.TextureLoader(); 33 | loader.setWithCredentials(true); 34 | const map = await loader.loadAsync(imgUrl).catch((err) => { 35 | console.error(err); 36 | }); 37 | if (!map) { 38 | return; 39 | } 40 | spriteMaterial.map = map; 41 | spriteMaterial.map.minFilter = THREE.LinearFilter; 42 | this.sprite.scale.set(imgScale?.x || radius * 2 - 5, imgScale?.y || radius * 2 - 5, imgScale?.z || 1); 43 | this.sprite.material = spriteMaterial; 44 | this.view.add(this.sprite); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/cube/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from '@turbox3d/renderer-three'; 2 | import { Vec3 } from '@turbox3d/shared'; 3 | import * as THREE from 'three'; 4 | 5 | interface ICubeProps { 6 | size: Vec3; 7 | color?: number; 8 | } 9 | 10 | export default class Cube extends Mesh3D { 11 | protected reactivePipeLine = [this.updateGeometry]; 12 | protected view = new THREE.Mesh(); 13 | 14 | updateGeometry() { 15 | const geometry = new THREE.BoxGeometry( 16 | this.props.size.x, 17 | this.props.size.y, 18 | this.props.size.z 19 | ); 20 | const material = new THREE.MeshPhongMaterial({ color: this.props.color || 0x00D000 }); 21 | this.view.geometry = geometry; 22 | this.view.material = material; 23 | this.view.position.set(0, 0, 0); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/fat-line/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from '@turbox3d/renderer-three'; 2 | import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'; 3 | import { Line2 } from 'three/examples/jsm/lines/Line2.js'; 4 | import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js'; 5 | import { Vec3 } from '@turbox3d/shared'; 6 | 7 | interface IFatLineProps { 8 | position: Vec3; 9 | rotation: Vec3; 10 | linePositions: number[]; 11 | dashed?: boolean; 12 | linewidth?: number; 13 | color?: number; 14 | dashScale?: number; 15 | dashSize?: number; 16 | gapSize?: number; 17 | looped?: boolean; 18 | } 19 | 20 | export default class FatLine extends Mesh3D { 21 | protected reactivePipeLine = [this.updateGeometry]; 22 | protected view = new Line2(); 23 | 24 | private updateGeometry() { 25 | const { position, rotation, linePositions, dashed = false, linewidth = 0.002, color = 0xFFE802, dashScale = 0.4, dashSize = 1, gapSize = 1, looped = false } = this.props; 26 | const geometry = new LineGeometry(); 27 | geometry.setPositions(looped ? [...linePositions, linePositions[0], linePositions[1], linePositions[2]] : linePositions); 28 | const material = new LineMaterial({ 29 | color, 30 | linewidth, 31 | dashed, 32 | dashScale, 33 | dashSize, 34 | gapSize, 35 | alphaToCoverage: true, 36 | }); 37 | this.view.geometry = geometry; 38 | this.view.material = material; 39 | this.view.position.set(position.x, position.y, position.z); 40 | this.view.rotation.set(rotation.x, rotation.y, rotation.z); 41 | this.view.computeLineDistances(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/gizmo3d/README.md: -------------------------------------------------------------------------------- 1 | # gizmo 对象旋转、平移、缩放控件 2 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/gizmo3d/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from '@turbox3d/renderer-three'; 2 | 3 | export default class Gizmo3d extends Mesh3D { 4 | protected reactivePipeLine = [ 5 | this.updateGeometry, 6 | this.updateMaterial, 7 | this.updatePosition, 8 | this.updateRotation, 9 | this.updateScale, 10 | ]; 11 | 12 | updateGeometry() { 13 | this.view.clear(); 14 | } 15 | 16 | updateMaterial() { 17 | // 18 | } 19 | 20 | updatePosition() { 21 | // const { position } = this.props; 22 | // this.view.position.set(position!.x, position!.y); 23 | } 24 | 25 | updateRotation() { 26 | // this.view.rotation = this.props.rotation!; 27 | } 28 | 29 | updateScale() { 30 | // const { scale } = this.props; 31 | // this.view.scale.set(scale!.x, scale!.y); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/index.ts: -------------------------------------------------------------------------------- 1 | const ENV = process.env.NODE_ENV; 2 | if ( 3 | ENV !== 'production' && 4 | ENV !== 'test' && 5 | typeof console !== 'undefined' && 6 | console.warn && // eslint-disable-line no-console 7 | typeof window !== 'undefined' 8 | ) { 9 | // eslint-disable-next-line no-console 10 | console.warn( 11 | 'You are using a whole package of graphic component three, ' + 12 | 'please use https://www.npmjs.com/package/babel-plugin-import to reduce app bundle size.', 13 | ); 14 | } 15 | 16 | export { default as Arrow3d } from './arrow3d/index'; 17 | export { default as Axis3d } from './axis3d/index'; 18 | export { default as Circle3d } from './circle3d/index'; 19 | export { default as Cube } from './cube/index'; 20 | export { default as FatLine } from './fat-line/index'; 21 | export { default as Gizmo3d } from './gizmo3d/index'; 22 | export { default as Rect3d } from './rect3d/index'; 23 | export { default as Wireframe } from './wireframe/index'; 24 | export { default as Animation3d } from './animation3d/index'; 25 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/rect3d/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from '@turbox3d/renderer-three'; 2 | import * as THREE from 'three'; 3 | 4 | interface IRect3dProps { 5 | width: number; 6 | height: number; 7 | color?: number; 8 | side?: THREE.Side; 9 | opacity?: number; 10 | } 11 | 12 | export default class Rect3d extends Mesh3D { 13 | protected reactivePipeLine = [this.updateGeometry]; 14 | protected view = new THREE.Mesh(); 15 | 16 | updateGeometry() { 17 | const { width, height, color, side, opacity = 1 } = this.props; 18 | const geometry = new THREE.PlaneGeometry(width, height); 19 | const material = new THREE.MeshBasicMaterial({ color: color || 0xFFE802, opacity, transparent: true, side: side || THREE.DoubleSide }); 20 | this.view.geometry = geometry; 21 | this.view.material = material; 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/graphic-component-three/src/wireframe/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from '@turbox3d/renderer-three'; 2 | import { Vec3 } from '@turbox3d/shared'; 3 | import * as THREE from 'three'; 4 | import { LineSegmentsGeometry } from 'three/examples/jsm/lines/LineSegmentsGeometry.js'; 5 | import { Wireframe as WireFrame } from 'three/examples/jsm/lines/Wireframe.js'; 6 | import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'; 7 | 8 | interface IProps { 9 | size: Vec3; 10 | color?: number; 11 | lineWidth?: number; 12 | } 13 | 14 | export default class Wireframe extends Mesh3D { 15 | protected reactivePipeLine = [this.updateGeometry]; 16 | protected view = new WireFrame(); 17 | 18 | private updateGeometry() { 19 | const { size, color, lineWidth } = this.props; 20 | const geometry = new THREE.BoxGeometry(size.x, size.y, size.z); 21 | const wireframe = new THREE.EdgesGeometry(geometry); 22 | const material = new LineMaterial({ color: color || 0xFFE802, linewidth: lineWidth || 0.002 }); 23 | const lineGeo = new LineSegmentsGeometry().fromEdgesGeometry(wireframe); 24 | this.view.geometry = lineGeo; 25 | this.view.material = material; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/graphic-component-three/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/graphic-component-three/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/math/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/math/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/math/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @turbox3d/math 2 | 3 | ## 1.1.21 4 | 5 | ### Patch Changes 6 | 7 | - fix: enhance gizmo2d&text2d 8 | 9 | ## 1.1.20 10 | 11 | ### Patch Changes 12 | 13 | - fix: fix issue 14 | 15 | ## 1.1.19 16 | 17 | ### Patch Changes 18 | 19 | - fix: fix dep version 20 | 21 | ## 1.1.18 22 | 23 | ### Patch Changes 24 | 25 | - refactor: enhance code 26 | 27 | ## 1.1.17 28 | 29 | ### Patch Changes 30 | 31 | - fix: fix 32 | 33 | ## 1.1.16 34 | 35 | ### Patch Changes 36 | 37 | - feat: add grid2d&gizmo2d component 38 | 39 | ## 1.1.15 40 | 41 | ### Patch Changes 42 | 43 | - feat: add inference engine&fix rect2d&add line2d&add keyup hot key feature 44 | 45 | ## 1.1.14 46 | 47 | ### Patch Changes 48 | 49 | - fix: fix build issue 50 | 51 | ## 1.1.13 52 | 53 | ### Patch Changes 54 | 55 | - fix: update version 56 | 57 | ## 1.1.12 58 | 59 | ### Patch Changes 60 | 61 | - f188584: Fix build script 62 | 63 | ## 1.1.11 64 | 65 | ### Patch Changes 66 | 67 | - Sync code 68 | 69 | ## 1.1.10 70 | 71 | ### Patch Changes 72 | 73 | - Fix changeset issue 74 | 75 | ## 1.1.9 76 | 77 | ### Patch Changes 78 | 79 | - Upgrade deps: pixi.js->v7,three->v0.159,react->v18,react-dom->v18,typescript->v5 80 | 81 | ## 1.1.8 82 | 83 | ### Patch Changes 84 | 85 | - Move dts file to dist 86 | 87 | ## 1.1.7 88 | 89 | ### Patch Changes 90 | 91 | - Update build script&config file 92 | 93 | ## 1.1.6 94 | 95 | ### Patch Changes 96 | 97 | - Add doc gen building process 98 | 99 | ## 1.1.5 100 | 101 | ### Patch Changes 102 | 103 | - Upgrade react version 104 | 105 | ## 1.1.4 106 | 107 | ### Patch Changes 108 | 109 | - Lint change 110 | 111 | ## 1.1.3 112 | 113 | ### Patch Changes 114 | 115 | - Replace pnpm from lerna 116 | -------------------------------------------------------------------------------- /packages/math/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/math/src/base/Tolerance.ts: -------------------------------------------------------------------------------- 1 | export const TOLERANCE = 1E-6; 2 | export const TOLERANCE_HALF = TOLERANCE * 0.5; 3 | export const TOLERANCE_SQUARE = TOLERANCE * TOLERANCE; 4 | export const TOLERANCE_SAGITTA = 1; 5 | 6 | export class Tolerance { 7 | static COS_TOL = 1e-6; 8 | static DIST_TOL = 1e-6; 9 | static NUM_TOL = 1e-6; 10 | static global = new Tolerance(); 11 | static setGlobal(cosTol: number, distTol: number, numTol: number) { 12 | Tolerance.global = new Tolerance(cosTol, distTol, numTol); 13 | } 14 | 15 | cosTol: number; 16 | distTol: number; 17 | numTol: number; 18 | 19 | constructor(cosTol?: number, distTol?: number, numTol?: number) { 20 | this.cosTol = cosTol || Tolerance.COS_TOL; 21 | this.distTol = distTol || Tolerance.DIST_TOL; 22 | this.numTol = numTol || Tolerance.NUM_TOL; 23 | } 24 | 25 | /** 26 | * set cosTol by given angle 27 | * @param angle 28 | * @param isRadian true means the angle is radian, false means the angle is degree 29 | */ 30 | setCosTolByAngle(angle: number, isRadian: boolean) { 31 | const flag: number = isRadian ? 1 : Math.PI / 180; 32 | this.cosTol = 1 - Math.cos(angle * flag); 33 | } 34 | 35 | clone() { 36 | return new Tolerance(this.cosTol, this.distTol, this.numTol); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/math/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Box2 } from './base/Box2'; 2 | import { Box3 } from './base/Box3'; 3 | import { Euler } from './base/Euler'; 4 | import { Interval } from './base/Interval'; 5 | import { Line3 } from './base/Line3'; 6 | import { MathUtils } from './MathUtils'; 7 | import { Matrix3 } from './base/Matrix3'; 8 | import { Matrix4 } from './base/Matrix4'; 9 | import { Quaternion } from './base/Quaternion'; 10 | import { Ray } from './base/Ray'; 11 | import { Tolerance } from './base/Tolerance'; 12 | import { Vector2 } from './base/Vector2'; 13 | import { Vector3 } from './base/Vector3'; 14 | import { Vector4 } from './base/Vector4'; 15 | 16 | export interface Vec2 { 17 | x: number; 18 | y: number; 19 | } 20 | 21 | export interface Vec3 { 22 | x: number; 23 | y: number; 24 | z: number; 25 | } 26 | 27 | export { 28 | Box2, 29 | Box3, 30 | Euler, 31 | Interval, 32 | Line3, 33 | MathUtils, 34 | Matrix3, 35 | Matrix4, 36 | Quaternion, 37 | Ray, 38 | Tolerance, 39 | Vector2, 40 | Vector3, 41 | Vector4, 42 | }; 43 | -------------------------------------------------------------------------------- /packages/math/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/math/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/reactivity-react/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/reactivity-react/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/reactivity-react/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/reactivity-react/src/components/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | export default class ErrorBoundary extends React.Component { 4 | state = { 5 | hasError: false, 6 | error: { 7 | message: '', 8 | }, 9 | }; 10 | 11 | componentDidCatch(error: Error) { 12 | this.setState({ 13 | hasError: true, 14 | error, 15 | }); 16 | } 17 | 18 | render() { 19 | const { message } = this.state.error; 20 | if (this.state.hasError) { 21 | return

Something went wrong. Error: {message}

; 22 | } 23 | return this.props.children; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/reactivity-react/src/index.ts: -------------------------------------------------------------------------------- 1 | import * as ReactDOM from 'react-dom'; 2 | import { registerExternalBatchUpdate, init } from '@turbox3d/reactivity'; 3 | import { Reactive } from './components/Reactive'; 4 | import { IdCustomType } from './utils/index'; 5 | 6 | init(); 7 | registerExternalBatchUpdate({ 8 | handler: ReactDOM.unstable_batchedUpdates, 9 | idCustomType: IdCustomType, 10 | }); 11 | 12 | export * from '@turbox3d/reactivity'; 13 | export { Reactive }; 14 | -------------------------------------------------------------------------------- /packages/reactivity-react/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // based on https://github.com/mridgway/hoist-non-react-statics/blob/master/src/index.js 2 | const hoistBlackList = { 3 | $$typeof: true, 4 | render: true, 5 | compare: true, 6 | type: true, 7 | }; 8 | 9 | export function copyStaticProperties(base, target) { 10 | const keys = Object.keys(base); 11 | for (let index = 0; index < keys.length; index++) { 12 | const key = keys[index]; 13 | if (hoistBlackList[key] === void 0) { 14 | Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(base, key)!); 15 | } 16 | } 17 | } 18 | 19 | export const IdCustomType = 'react'; 20 | -------------------------------------------------------------------------------- /packages/reactivity-react/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/reactivity-react/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/reactivity/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/reactivity/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/reactivity/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/reactivity/src/const/config.ts: -------------------------------------------------------------------------------- 1 | import { deepMerge } from '@turbox3d/shared'; 2 | import { ConfigCtx } from '../interfaces'; 3 | 4 | const isDev = process.env.NODE_ENV !== 'production'; 5 | 6 | export let ctx: ConfigCtx = { 7 | middleware: { 8 | logger: isDev, 9 | diffLogger: true, 10 | effect: false, 11 | perf: isDev, 12 | skipNestLog: true, 13 | skipNestPerfLog: true, 14 | }, 15 | timeTravel: { 16 | isActive: false, 17 | isNeedRecord: false, 18 | maxStepNumber: 20, 19 | keepActionChain: isDev, 20 | }, 21 | disableReactive: false, 22 | strictMode: isDev, 23 | devTool: false, 24 | batchUpdateOnFinish: undefined, 25 | }; 26 | 27 | /** 28 | * framework global config method. 29 | */ 30 | export function config(conf: Partial) { 31 | ctx = deepMerge(ctx, conf); 32 | } 33 | -------------------------------------------------------------------------------- /packages/reactivity/src/const/enums.ts: -------------------------------------------------------------------------------- 1 | export enum EDepState { 2 | NOT_OBSERVED = 'notObserved', 3 | OBSERVED = 'observed', 4 | LATEST = 'latest', 5 | } 6 | 7 | export enum ESpecialReservedKey { 8 | ARRAY_LENGTH = 'length', 9 | ITERATE = 'iterate', 10 | COMPUTED = 'computed', 11 | } 12 | 13 | export enum ECollectType { 14 | SET = 'set', 15 | MAP_SET = 'map-set', 16 | ADD = 'add', 17 | SET_ADD = 'set-add', 18 | DELETE = 'delete', 19 | MAP_DELETE = 'map-delete', 20 | SET_DELETE = 'set-delete', 21 | } 22 | 23 | export enum EMaterialType { 24 | DEFAULT = 'default', 25 | MUTATION = 'mutation', 26 | ACTION = 'action', 27 | UPDATE = 'update', 28 | EFFECT = 'effect', 29 | UNDO = 'undo', 30 | REDO = 'redo', 31 | } 32 | 33 | export enum ActionStatus { 34 | WORKING = 'working', 35 | COMPLETED = 'completed', 36 | ABORT = 'abort', 37 | } 38 | -------------------------------------------------------------------------------- /packages/reactivity/src/const/symbol.ts: -------------------------------------------------------------------------------- 1 | import { isSupportSymbol } from '@turbox3d/shared'; 2 | 3 | export const TURBOX_PREFIX = '@@TURBOX__'; 4 | 5 | export function compatibleSymbol(key: string) { 6 | return isSupportSymbol() ? Symbol(key) : `${TURBOX_PREFIX}${key}`; 7 | } 8 | 9 | export const NAMESPACE = compatibleSymbol('namespace'); 10 | export const REACTIVE_COMPONENT_NAME = compatibleSymbol('reactive-component-name'); 11 | export const UNSUBSCRIBE_HANDLER = compatibleSymbol('unsubscribe-handler'); 12 | export const MATERIAL_TYPE = `${TURBOX_PREFIX}materialType`; 13 | export const EMPTY_ACTION_NAME = `${TURBOX_PREFIX}empty`; 14 | export const DEFAULT_FIELD_NAME = `${TURBOX_PREFIX}field`; 15 | -------------------------------------------------------------------------------- /packages/reactivity/src/core/use.ts: -------------------------------------------------------------------------------- 1 | import { compose, fail } from '@turbox3d/shared'; 2 | import { Middleware, Store } from '../interfaces'; 3 | import { Action } from './action'; 4 | import { actionTypeChain } from './store'; 5 | import { depCollector } from './collector'; 6 | 7 | export const middlewares: Array = []; 8 | 9 | /** 10 | * Add middleware. 11 | */ 12 | export function use(middleware: Middleware | Array, inner = true) { 13 | const arr = Array.isArray(middleware) ? middleware : [middleware]; 14 | if (inner) { 15 | middlewares.unshift(...arr); 16 | } else { 17 | middlewares.push(...arr); 18 | } 19 | } 20 | 21 | export function applyMiddleware() { 22 | return (createStore: any): Store => { 23 | const store = createStore(); 24 | let dispatch: any = () => { 25 | fail('Dispatching while constructing your middleware is not allowed. ' + 26 | 'Other middleware would not be applied to this dispatch.'); 27 | }; 28 | const exposedMethod = { 29 | getActionChain: () => { 30 | if (Action.context) { 31 | return Action.context.historyNode.actionChain.slice(); 32 | } 33 | return actionTypeChain.slice(); 34 | }, 35 | getDependencyGraph: () => new Map(depCollector.dependencyGraph), 36 | dispatch: (...args: any[]) => dispatch(...args), 37 | }; 38 | const runnerChain = middlewares.map(middleware => middleware(exposedMethod)); 39 | 40 | dispatch = compose(...runnerChain)(store.dispatch); 41 | 42 | return { 43 | ...store, 44 | dispatch, 45 | }; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /packages/reactivity/src/index.ts: -------------------------------------------------------------------------------- 1 | import { use } from './core/use'; 2 | import { config } from './const/config'; 3 | import { mutation } from './decorators/mutation'; 4 | // import { effect } from './decorators/effect'; 5 | import { reactor } from './decorators/reactor'; 6 | import { computed } from './decorators/computed'; 7 | import { Domain, createDomain } from './core/domain'; 8 | import { init } from './core/init'; 9 | import { reactive, Reaction } from './core/reactive'; 10 | import { TimeTravel } from './core/time-travel'; 11 | import { ActionStatus } from './const/enums'; 12 | import { Action } from './core/action'; 13 | import { action } from './decorators/action'; 14 | import { depCollector } from './core/collector'; 15 | import { store, registerExternalBatchUpdate } from './core/store'; 16 | import { REACTIVE_COMPONENT_NAME, UNSUBSCRIBE_HANDLER } from './const/symbol'; 17 | 18 | export * from './utils/event'; 19 | export * from './interfaces'; 20 | 21 | init(); 22 | 23 | export { 24 | reactive, 25 | // effect, 26 | mutation, 27 | computed, 28 | use, 29 | config, 30 | reactor, 31 | init, 32 | Domain, 33 | createDomain, 34 | TimeTravel, 35 | Action, 36 | ActionStatus, 37 | action, 38 | depCollector, 39 | Reaction, 40 | store, 41 | REACTIVE_COMPONENT_NAME, 42 | UNSUBSCRIBE_HANDLER, 43 | registerExternalBatchUpdate, 44 | }; 45 | -------------------------------------------------------------------------------- /packages/reactivity/src/middlewares/common.ts: -------------------------------------------------------------------------------- 1 | import { isPromise } from '@turbox3d/shared'; 2 | import { DispatchedAction, Dispatch } from '../interfaces'; 3 | 4 | export function normalNextReturn(next: Dispatch, dispatchedAction: DispatchedAction, callback?: () => void, errorCallback?: (error: string) => void) { 5 | const result = next(dispatchedAction); 6 | if (isPromise(result)) { 7 | return new Promise((resolve, reject) => { 8 | (result as Promise).then((res) => { 9 | callback && callback(); 10 | resolve(res); 11 | }).catch((error: Error) => { 12 | errorCallback && errorCallback(error.stack || error.message); 13 | reject(error); 14 | }); 15 | }); 16 | } 17 | if (result && result instanceof Error) { 18 | errorCallback && errorCallback(result.stack || result.message); 19 | } else { 20 | callback && callback(); 21 | } 22 | return result; 23 | } 24 | -------------------------------------------------------------------------------- /packages/reactivity/src/middlewares/effect.ts: -------------------------------------------------------------------------------- 1 | // import { Effect, Middleware } from '../interfaces'; 2 | // import { actionTypeChain } from '../core/store'; 3 | // import { invariant } from '../utils/error'; 4 | // import { EMaterialType } from '../const/enums'; 5 | // import { Action } from '../core/action'; 6 | // import { materialCallStack } from '../core/domain'; 7 | // import { normalNextReturn } from './common'; 8 | 9 | // function createEffectMiddleware(): Middleware { 10 | // return () => (next) => (dispatchedAction) => { 11 | // const { name, displayName, payload, type, original, action } = dispatchedAction; 12 | 13 | // if (type === EMaterialType.EFFECT) { 14 | // const length = materialCallStack.length; 15 | // if (length > 1) { 16 | // invariant(materialCallStack[length - 2] !== EMaterialType.MUTATION, 'Cannot trigger other effect while the current mutation is executing.'); 17 | // } 18 | 19 | // const effect = original as Effect; 20 | // actionTypeChain.push({ 21 | // name, 22 | // displayName, 23 | // }); 24 | 25 | // return new Promise((resolve) => { 26 | // effect(action as Action, ...payload).then(() => { 27 | // resolve(); 28 | // }); 29 | // }); 30 | // } 31 | 32 | // return normalNextReturn(next, dispatchedAction); 33 | // } 34 | // } 35 | 36 | // export default createEffectMiddleware(); 37 | -------------------------------------------------------------------------------- /packages/reactivity/src/middlewares/mutation.ts: -------------------------------------------------------------------------------- 1 | import { Middleware } from '../interfaces'; 2 | import { actionTypeChain } from '../core/store'; 3 | import { EMaterialType } from '../const/enums'; 4 | import { Action } from '../core/action'; 5 | import { normalNextReturn } from './common'; 6 | 7 | function createMutationMiddleware(): Middleware { 8 | return () => next => (dispatchedAction) => { 9 | const { name, displayName, type, isInner } = dispatchedAction; 10 | if (isInner || (type !== EMaterialType.MUTATION && type !== EMaterialType.UPDATE)) { 11 | return normalNextReturn(next, dispatchedAction); 12 | } 13 | 14 | if (Action.context) { 15 | Action.context.historyNode.actionChain.push({ 16 | name, 17 | displayName, 18 | }); 19 | } else { 20 | actionTypeChain.push({ 21 | name, 22 | displayName, 23 | }); 24 | } 25 | 26 | return normalNextReturn(next, dispatchedAction); 27 | }; 28 | } 29 | 30 | export default createMutationMiddleware(); 31 | -------------------------------------------------------------------------------- /packages/reactivity/src/middlewares/perf.ts: -------------------------------------------------------------------------------- 1 | import { Middleware } from '../interfaces'; 2 | import { normalNextReturn } from './common'; 3 | import { EMPTY_ACTION_NAME } from '../const/symbol'; 4 | import { ctx } from '../const/config'; 5 | import { materialCallStack } from '../utils/materialCallStack'; 6 | 7 | function createPerfMiddleware(): Middleware { 8 | return () => next => (dispatchedAction) => { 9 | if (!ctx.middleware.perf) { 10 | return normalNextReturn(next, dispatchedAction); 11 | } 12 | const { name, displayName } = dispatchedAction; 13 | const start = performance.now(); 14 | 15 | const length = materialCallStack.stack.length; 16 | if (ctx.middleware.skipNestPerfLog && length !== 1) { 17 | return normalNextReturn(next, dispatchedAction); 18 | } 19 | 20 | return normalNextReturn(next, dispatchedAction, () => { 21 | const end = performance.now(); 22 | console.log( 23 | `%c[TURBOX PERF]: ${name} ${displayName !== EMPTY_ACTION_NAME ? displayName : ''} ${(end - start).toFixed(3)}ms`, 24 | 'background: #FA54FF; color: #fff; font-weight: bold; padding: 3px 5px;', 25 | ); 26 | }); 27 | }; 28 | } 29 | 30 | export default createPerfMiddleware(); 31 | -------------------------------------------------------------------------------- /packages/reactivity/src/utils/common.ts: -------------------------------------------------------------------------------- 1 | import { Domain } from '../core/domain'; 2 | 3 | export function isDomain(value: any): boolean { 4 | return value instanceof Domain; 5 | } 6 | -------------------------------------------------------------------------------- /packages/reactivity/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/reactivity/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-core/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-core/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/renderer-core/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-core/src/__tests__/render.test.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '../component'; 2 | 3 | describe('render', () => { 4 | it('render', () => { 5 | class A extends Component { 6 | render() { 7 | return []; 8 | } 9 | } 10 | class B extends Component { 11 | render() { 12 | return []; 13 | } 14 | } 15 | class Root extends Component { 16 | render() { 17 | return [ 18 | { 19 | component: A, 20 | props: {}, 21 | }, 22 | { 23 | component: B, 24 | props: {}, 25 | }, 26 | ]; 27 | } 28 | } 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /packages/renderer-core/src/common.ts: -------------------------------------------------------------------------------- 1 | export const IdCustomType = 'renderer'; 2 | 3 | export enum NodeStatus { 4 | READY = 1, 5 | UPDATE = 2, 6 | UPDATE_INTERACTIVE = 4, 7 | UPDATE_CUSTOM_PROPS = 8, 8 | FAKE_UPDATE = 16, 9 | REMOVE = 32, 10 | CREATE = 64, 11 | } 12 | 13 | export enum NodeTag { 14 | COMPONENT = 1, 15 | SCENE = 2, 16 | MESH = 3, 17 | } 18 | -------------------------------------------------------------------------------- /packages/renderer-core/src/index.ts: -------------------------------------------------------------------------------- 1 | import { init, registerExternalBatchUpdate } from '@turbox3d/reactivity'; 2 | import { Component, PureComponent, ComponentProps } from './component'; 3 | import { Element, VirtualNode, render, batchUpdate, ElementSchema, g } from './render'; 4 | import { IdCustomType } from './common'; 5 | import { Reactive } from './reactive'; 6 | import { BaseMesh } from './mesh'; 7 | import { BaseScene, SceneContext, BaseSceneProps, ViewportInfo, ViewInfo, SceneType } from './scene'; 8 | 9 | init(); 10 | registerExternalBatchUpdate({ 11 | handler: batchUpdate, 12 | idCustomType: IdCustomType, 13 | }); 14 | 15 | export { 16 | Component, 17 | PureComponent, 18 | Element, 19 | ElementSchema, 20 | VirtualNode, 21 | render, 22 | g, 23 | batchUpdate, 24 | Reactive, 25 | BaseMesh, 26 | SceneContext, 27 | BaseScene, 28 | BaseSceneProps, 29 | ViewportInfo, 30 | ViewInfo, 31 | SceneType, 32 | ComponentProps, 33 | }; 34 | -------------------------------------------------------------------------------- /packages/renderer-core/src/utils.ts: -------------------------------------------------------------------------------- 1 | import { Component } from './component'; 2 | import { NodeTag } from './common'; 3 | 4 | /** 5 | * 找寻类型为 BaseMesh | BaseScene 的上层组件 6 | * @param component 7 | */ 8 | export function getMeshParent(component: Component) { 9 | const vNode = component._vNode; 10 | 11 | if (!vNode) { 12 | return; 13 | } 14 | 15 | let parent = vNode.parent; 16 | 17 | while (parent) { 18 | if (parent && (parent.tag === NodeTag.SCENE || parent.tag === NodeTag.MESH)) { 19 | return parent.instance; 20 | } 21 | 22 | parent = parent.parent; 23 | } 24 | } 25 | 26 | export function getSceneParent(component: Component) { 27 | const vNode = component._vNode; 28 | 29 | if (!vNode) { 30 | return; 31 | } 32 | 33 | let parent = vNode.parent; 34 | 35 | while (parent) { 36 | if (parent && parent.tag === NodeTag.SCENE) { 37 | return parent.instance; 38 | } 39 | 40 | parent = parent.parent; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/renderer-core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/renderer-core/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-pixi/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-pixi/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/renderer-pixi/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-pixi/src/Mesh2D/Mesh2D.ts: -------------------------------------------------------------------------------- 1 | import { BaseMesh, ComponentProps } from '@turbox3d/renderer-core'; 2 | import { Vec2, warn } from '@turbox3d/shared'; 3 | import * as PIXI from 'pixi.js'; 4 | 5 | export abstract class Mesh2D extends BaseMesh { 6 | constructor(props = {} as ComponentProps) { 7 | super(props); 8 | if (this.view instanceof PIXI.Container) { 9 | this.view.sortableChildren = true; 10 | } 11 | } 12 | 13 | createDefaultView() { 14 | return new PIXI.Container(); 15 | } 16 | 17 | addChildView(view: PIXI.DisplayObject) { 18 | if (this.view instanceof PIXI.Container) { 19 | this.view.addChild(view); 20 | } 21 | } 22 | 23 | clearView() { 24 | if (this.view instanceof PIXI.Graphics) { 25 | this.view.clear(); 26 | } 27 | } 28 | 29 | removeFromWorld() { 30 | // 这里有可能因为父节点中主动触发了子节点的 destroy 方法,而导致无需在调用 destroy .(重复调用会报错) 31 | try { 32 | if (this.view instanceof PIXI.Container) { 33 | this.view.destroy({ children: false }); 34 | } else { 35 | this.view.destroy(); 36 | } 37 | } catch (e) { 38 | // 如果异常,也是该节点已经被卸载了,无需理会 39 | warn('destroy error'); 40 | } 41 | } 42 | 43 | setViewInteractive(interactive: boolean) { 44 | this.view.eventMode = interactive ? 'static' : 'auto'; 45 | } 46 | 47 | addViewToScene() { 48 | // 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /packages/renderer-pixi/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh2D } from './Mesh2D/Mesh2D'; 2 | import { Scene2D, Scene2DSymbol } from './Scene2D/index'; 3 | 4 | export * from '@turbox3d/renderer-core'; 5 | export { 6 | Mesh2D, 7 | Scene2D, 8 | Scene2DSymbol, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/renderer-pixi/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/renderer-pixi/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-three/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-three/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/renderer-three/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/renderer-three/src/Mesh3D/Mesh3D.ts: -------------------------------------------------------------------------------- 1 | import * as THREE from 'three'; 2 | import { BaseMesh, ComponentProps } from '@turbox3d/renderer-core'; 3 | import { Vec2 } from '@turbox3d/shared'; 4 | import { Scene3D } from '../Scene3D/index'; 5 | 6 | export abstract class Mesh3D extends BaseMesh { 7 | constructor(props = {} as ComponentProps) { 8 | super(props); 9 | } 10 | 11 | createDefaultView() { 12 | return new THREE.Group(); 13 | } 14 | 15 | addChildView(view: THREE.Object3D) { 16 | this.view.add(view); 17 | } 18 | 19 | clearView() { 20 | // if (this.view instanceof THREE.Mesh) { 21 | // this.view.clear(); 22 | // } 23 | } 24 | 25 | removeFromWorld() { 26 | this.view.removeFromParent(); 27 | } 28 | 29 | setViewInteractive(interactive: boolean) { 30 | this.view.userData.interactive = interactive; 31 | } 32 | 33 | addViewToScene(scene3d: Scene3D, view: THREE.Object3D) { 34 | scene3d.scene!.add(view); 35 | const isCamera = this.viewType === 'camera'; 36 | if (isCamera) { 37 | scene3d.camera = view as THREE.Camera; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/renderer-three/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Mesh3D } from './Mesh3D/Mesh3D'; 2 | import { Scene3D, Scene3DSymbol } from './Scene3D/index'; 3 | 4 | export * from '@turbox3d/renderer-core'; 5 | export { 6 | Mesh3D, 7 | Scene3D, 8 | Scene3DSymbol, 9 | }; 10 | -------------------------------------------------------------------------------- /packages/renderer-three/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/renderer-three/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/shared/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/shared/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/shared/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/shared/src/__tests__/compose.test.ts: -------------------------------------------------------------------------------- 1 | import { compose } from '../compose'; 2 | 3 | describe('utils -> compose', () => { 4 | it('compose', () => { 5 | const original = param => `original${param}`; 6 | const middlewares = [(next) => (param) => { 7 | console.log('111'); 8 | return next(param); 9 | }, (next) => (param) => { 10 | console.log('222'); 11 | return next(param); 12 | }, (next) => (param) => { 13 | console.log('333'); 14 | return next(param); 15 | }]; 16 | const enhanced = compose(...middlewares)(original); 17 | expect(enhanced('test')).toBe('originaltest'); 18 | }); 19 | 20 | it('compose one middleware', () => { 21 | const original = param => `original${param}`; 22 | const middlewares = [(next) => (param) => { 23 | console.log('111'); 24 | return next(param); 25 | }]; 26 | const enhanced = compose(...middlewares)(original); 27 | expect(enhanced('test')).toBe('originaltest'); 28 | }); 29 | 30 | it('compose no middleware', () => { 31 | const original = param => `original${param}`; 32 | const middlewares = []; 33 | const enhanced = compose(...middlewares)(original); 34 | expect(enhanced('test')).toBe('originaltest'); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /packages/shared/src/__tests__/lang.test.ts: -------------------------------------------------------------------------------- 1 | import { isReserved, isSymbol } from '../lang'; 2 | 3 | describe('utils -> lang', () => { 4 | it('isReserved', () => { 5 | expect(isReserved('$global')).toBeTruthy(); 6 | }); 7 | 8 | it('isSymbol', () => { 9 | expect(isSymbol(Symbol('sss'))).toBeTruthy(); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /packages/shared/src/compose.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * from redux compose 3 | */ 4 | export function compose(...funcs: any[]) { 5 | if (funcs.length === 0) { 6 | return arg => arg; 7 | } 8 | 9 | if (funcs.length === 1) { 10 | return funcs[0]; 11 | } 12 | 13 | return funcs.reduce((a, b) => (...args) => a(b(...args))); 14 | } 15 | -------------------------------------------------------------------------------- /packages/shared/src/decorator.ts: -------------------------------------------------------------------------------- 1 | import { toObjectTypeString, stateDecoRegExp } from './lang'; 2 | 3 | export function quacksLikeADecorator(args: any[]): boolean { 4 | return (args.length === 2 || args.length === 3) && typeof args[1] === 'string'; 5 | } 6 | 7 | // prop could be decorated by @reactor 8 | export const canObserve = (value: any): boolean => stateDecoRegExp.test(toObjectTypeString(value)); 9 | -------------------------------------------------------------------------------- /packages/shared/src/error.ts: -------------------------------------------------------------------------------- 1 | export const OBFUSCATED_ERROR = 2 | 'An invariant failed, however the error is obfuscated because this is an production build.'; 3 | 4 | export function invariant(check: boolean, message?: string | boolean) { 5 | if (!check) throw new Error(`[turbox]: ${message || OBFUSCATED_ERROR}`); 6 | } 7 | 8 | export function fail(message: string | boolean): never { 9 | invariant(false, message); 10 | // eslint-disable-next-line no-throw-literal 11 | throw 'X'; 12 | } 13 | 14 | export function warn(message: string | boolean) { 15 | console.warn(`[turbox]: ${message}`); 16 | } 17 | -------------------------------------------------------------------------------- /packages/shared/src/event.ts: -------------------------------------------------------------------------------- 1 | class Emitter { 2 | private listeners = {}; 3 | 4 | on(eventName: string, callback: (...args: any[]) => void) { 5 | const listeners = this.listeners[eventName] || []; 6 | listeners.push(callback); 7 | this.listeners[eventName] = listeners; 8 | } 9 | 10 | emit(eventName: string, ...args: any[]) { 11 | const listeners = this.listeners[eventName]; 12 | if (!Array.isArray(listeners)) return; 13 | listeners.forEach((callback) => { 14 | try { 15 | callback.apply(this, args); 16 | } catch (e) { 17 | console.error(e); 18 | } 19 | }); 20 | } 21 | 22 | off(eventName: string) { 23 | if (!this.listeners[eventName]) { 24 | return; 25 | } 26 | this.listeners[eventName] = []; 27 | } 28 | } 29 | 30 | export const emitter = new Emitter(); 31 | -------------------------------------------------------------------------------- /packages/shared/src/graphic.ts: -------------------------------------------------------------------------------- 1 | export interface Vec2 { 2 | x: number; 3 | y: number; 4 | } 5 | 6 | export interface Vec3 { 7 | x: number; 8 | y: number; 9 | z: number; 10 | } 11 | 12 | /** 判断点是否在矩形内 */ 13 | export function pointInRect(p: Vec2, rect: Vec2[]) { 14 | const [r1, r2] = rect; 15 | const c1 = (p.x - r1.x) * (p.x - r2.x); 16 | const c2 = (p.y - r1.y) * (p.y - r2.y); 17 | return c1 <= 0 && c2 <= 0; 18 | } 19 | 20 | interface ICanvasRect { 21 | width: number; 22 | height: number; 23 | x: number; 24 | y: number; 25 | } 26 | 27 | /** 28 | * 获得点击位置相对于 canvas 的坐标 29 | * 如果输入参数不合法,或点击位置超出 canvas 的 clientRect 则返回 undefined 30 | * @param vec 事件坐标 31 | * @param canvas 要接受的 canvas 对象 32 | */ 33 | export function getRelativePositionFromEvent(vec: Vec2, rect: ICanvasRect) { 34 | const point = { 35 | x: vec.x - rect.x, 36 | y: vec.y - rect.y, 37 | }; 38 | if (point.x <= 0 || point.y <= 0 || point.x > rect.width || point.y > rect.height) { 39 | return undefined; 40 | } 41 | return point; 42 | } 43 | -------------------------------------------------------------------------------- /packages/shared/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from './uuid'; 2 | export * from './type'; 3 | export * from './task'; 4 | export * from './rafTask'; 5 | export * from './lang'; 6 | export * from './image'; 7 | export * from './graphic'; 8 | export * from './event'; 9 | export * from './error'; 10 | export * from './deep-merge'; 11 | export * from './decorator'; 12 | export * from './debounce'; 13 | export * from './compose'; 14 | export * from './common'; 15 | -------------------------------------------------------------------------------- /packages/shared/src/lang.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Check if a string starts with $ or _ 3 | */ 4 | export function isReserved(str: string): boolean { 5 | const c = (`${str}`).charCodeAt(0); 6 | return c === 0x24 || c === 0x5F; 7 | } 8 | 9 | export function isSupportProxy(): boolean { 10 | return typeof Proxy !== 'undefined'; 11 | } 12 | 13 | export function isSymbol(symbol: any): boolean { 14 | return typeof symbol === 'symbol'; 15 | } 16 | 17 | export function isSupportSymbol(): boolean { 18 | return typeof Symbol !== 'undefined'; 19 | } 20 | 21 | export const toObjectTypeString = (value: any): string => Object.prototype.toString.call(value); 22 | 23 | export const stateDecoRegExp = /^\[object (?:Object|Array|Map|Set|WeakMap|WeakSet)\]$/; 24 | -------------------------------------------------------------------------------- /packages/shared/src/task.ts: -------------------------------------------------------------------------------- 1 | class Task { 2 | static createTask(fn: Function, priority: number) { 3 | return new Task(fn, priority); 4 | } 5 | 6 | fn: Function; 7 | priority: number; 8 | 9 | constructor(fn: Function, priority: number) { 10 | this.fn = fn; 11 | this.priority = priority; 12 | } 13 | } 14 | 15 | export { Task }; 16 | -------------------------------------------------------------------------------- /packages/shared/src/type.ts: -------------------------------------------------------------------------------- 1 | export interface IConstructorOf { 2 | new(...args: any[]): T; 3 | } 4 | 5 | export interface IMapOf { 6 | [key: string]: T; 7 | } 8 | 9 | export type Nullable = { [K in keyof T]?: T[K] | null }; 10 | 11 | export function getValue(obj: T, key: K): T[K] { 12 | return obj[key]; 13 | } 14 | 15 | export interface IDictionary { 16 | [index: string]: T; 17 | } 18 | 19 | export interface INumericDictionary { 20 | [index: number]: T; 21 | } 22 | -------------------------------------------------------------------------------- /packages/shared/src/uuid.ts: -------------------------------------------------------------------------------- 1 | const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split(''); 2 | const uuid = new Array(36); 3 | 4 | /** 5 | * Generates uuid 6 | */ 7 | export function generateUUID(): string { 8 | let rnd = 0; 9 | for (let i = 0; i < 36; i++) { 10 | if (i === 8 || i === 13 || i === 18 || i === 23) { 11 | uuid[i] = '-'; 12 | } else if (i === 14) { 13 | uuid[i] = '7'; 14 | } else { 15 | if (rnd <= 0x02) { 16 | rnd = 0x2000000 + (Math.random() * 0x1000000) | 0; 17 | } 18 | const r = rnd & 0xf; 19 | rnd >>= 4; 20 | uuid[i] = chars[(i === 19) ? (r & 0x3) | 0x8 : r]; 21 | } 22 | } 23 | return uuid.join(''); 24 | } 25 | -------------------------------------------------------------------------------- /packages/shared/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/shared/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/turbox/README.md: -------------------------------------------------------------------------------- 1 | # 标准化通用项目 2 | -------------------------------------------------------------------------------- /packages/turbox/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox/src/__tests__/index.test.ts: -------------------------------------------------------------------------------- 1 | describe('test', () => { 2 | it('test', () => { 3 | expect(true).toBeTruthy(); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/turbox/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive as ReactiveReact } from '@turbox3d/reactivity-react'; 2 | 3 | export * from '@turbox3d/command-manager'; 4 | export * from '@turbox3d/design-engine'; 5 | export * from '@turbox3d/event-manager'; 6 | export * from '@turbox3d/graphic-component-pixi'; 7 | export * from '@turbox3d/graphic-component-three'; 8 | export * from '@turbox3d/math'; 9 | export * from '@turbox3d/reactivity'; 10 | export { ReactiveReact }; 11 | export * from '@turbox3d/renderer-core'; 12 | export * from '@turbox3d/renderer-pixi'; 13 | export * from '@turbox3d/renderer-three'; 14 | -------------------------------------------------------------------------------- /packages/turbox/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/turbox/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox2d/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox2d/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/turbox2d/README.md: -------------------------------------------------------------------------------- 1 | # 标准化通用项目 2 | -------------------------------------------------------------------------------- /packages/turbox2d/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox2d/src/__tests__/index.test.ts: -------------------------------------------------------------------------------- 1 | describe('test', () => { 2 | it('test', () => { 3 | expect(true).toBeTruthy(); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/turbox2d/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive as ReactiveReact } from '@turbox3d/reactivity-react'; 2 | 3 | export * from '@turbox3d/command-manager'; 4 | export * from '@turbox3d/design-engine'; 5 | export * from '@turbox3d/event-manager'; 6 | export * from '@turbox3d/graphic-component-pixi'; 7 | export * from '@turbox3d/math'; 8 | export * from '@turbox3d/reactivity'; 9 | export { ReactiveReact }; 10 | export * from '@turbox3d/renderer-core'; 11 | export * from '@turbox3d/renderer-pixi'; 12 | -------------------------------------------------------------------------------- /packages/turbox2d/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/turbox2d/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox3d/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox3d/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /packages/turbox3d/README.md: -------------------------------------------------------------------------------- 1 | # 标准化通用项目 2 | -------------------------------------------------------------------------------- /packages/turbox3d/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /packages/turbox3d/src/__tests__/index.test.ts: -------------------------------------------------------------------------------- 1 | describe('test', () => { 2 | it('test', () => { 3 | expect(true).toBeTruthy(); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /packages/turbox3d/src/index.ts: -------------------------------------------------------------------------------- 1 | import { Reactive as ReactiveReact } from '@turbox3d/reactivity-react'; 2 | 3 | export * from '@turbox3d/command-manager'; 4 | export * from '@turbox3d/design-engine'; 5 | export * from '@turbox3d/event-manager'; 6 | export * from '@turbox3d/graphic-component-three'; 7 | export * from '@turbox3d/math'; 8 | export * from '@turbox3d/reactivity'; 9 | export { ReactiveReact }; 10 | export * from '@turbox3d/renderer-core'; 11 | export * from '@turbox3d/renderer-three'; 12 | -------------------------------------------------------------------------------- /packages/turbox3d/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /packages/turbox3d/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @turbox3d/turbox-dev-tool 2 | 3 | ## 1.0.22 4 | 5 | ### Patch Changes 6 | 7 | - fix: enhance gizmo2d&text2d 8 | 9 | ## 1.0.21 10 | 11 | ### Patch Changes 12 | 13 | - fix: fix issue 14 | 15 | ## 1.0.20 16 | 17 | ### Patch Changes 18 | 19 | - fix: fix dep version 20 | 21 | ## 1.0.19 22 | 23 | ### Patch Changes 24 | 25 | - feat: add inference engine&fix rect2d&add line2d&add keyup hot key feature 26 | 27 | ## 1.0.18 28 | 29 | ### Patch Changes 30 | 31 | - fix: fix build issue 32 | 33 | ## 1.0.17 34 | 35 | ### Patch Changes 36 | 37 | - fix: update version 38 | 39 | ## 1.0.16 40 | 41 | ### Patch Changes 42 | 43 | - f188584: Fix build script 44 | 45 | ## 1.0.15 46 | 47 | ### Patch Changes 48 | 49 | - Sync code 50 | 51 | ## 1.0.14 52 | 53 | ### Patch Changes 54 | 55 | - Upgrade deps: pixi.js->v7,three->v0.159,react->v18,react-dom->v18,typescript->v5 56 | 57 | ## 1.0.13 58 | 59 | ### Patch Changes 60 | 61 | - Move dts file to dist 62 | 63 | ## 1.0.12 64 | 65 | ### Patch Changes 66 | 67 | - Update build script&config file 68 | 69 | ## 1.0.11 70 | 71 | ### Patch Changes 72 | 73 | - Add doc gen building process 74 | 75 | ## 1.0.10 76 | 77 | ### Patch Changes 78 | 79 | - Upgrade react version 80 | 81 | ## 1.0.9 82 | 83 | ### Patch Changes 84 | 85 | - Lint change 86 | 87 | ## 1.0.8 88 | 89 | ### Patch Changes 90 | 91 | - Replace pnpm from lerna 92 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/src/fps-monitor/fps.ts: -------------------------------------------------------------------------------- 1 | export class FPSMonitor { 2 | costTimes: number[] = []; 3 | prevTime?: number; 4 | raf?: number; 5 | maxFPS = 120; 6 | 7 | getAverageCostTimePerFrame() { 8 | const length = this.costTimes.length; 9 | if (!length) { 10 | return 0; 11 | } 12 | return this.costTimes.reduce((prev, current) => prev + current, 0) / length; 13 | } 14 | 15 | record(costTime: number) { 16 | this.costTimes.push(costTime); 17 | if (this.costTimes.length > this.maxFPS) { 18 | this.costTimes.shift(); 19 | } 20 | } 21 | 22 | start(maxFPS = 120) { 23 | this.maxFPS = maxFPS; 24 | this.end(); 25 | if (this.maxFPS === 60) { 26 | this.raf = requestAnimationFrame(this.monitor); 27 | } else { 28 | this.raf = window.setTimeout(this.monitor, 1000 / this.maxFPS); 29 | } 30 | } 31 | 32 | end() { 33 | if (this.maxFPS === 60) { 34 | this.raf && cancelAnimationFrame(this.raf); 35 | } else { 36 | this.raf && window.clearTimeout(this.raf); 37 | } 38 | this.costTimes = []; 39 | this.prevTime = void 0; 40 | this.maxFPS = 120; 41 | } 42 | 43 | monitor = () => { 44 | const now = performance.now(); 45 | if (this.prevTime !== void 0) { 46 | this.record(now - this.prevTime); 47 | } 48 | this.prevTime = now; 49 | if (this.maxFPS === 60) { 50 | this.raf = requestAnimationFrame(this.monitor); 51 | } else { 52 | this.raf = window.setTimeout(this.monitor, 1000 / this.maxFPS); 53 | } 54 | } 55 | 56 | getFPS() { 57 | return Math.ceil(1000 / this.getAverageCostTimePerFrame()); 58 | } 59 | } 60 | 61 | export const fpsMonitor = new FPSMonitor(); 62 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/src/fps-monitor/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import { fpsMonitor } from './fps'; 3 | 4 | interface IProp { 5 | className?: string; 6 | } 7 | 8 | interface IState { 9 | fps: number; 10 | } 11 | 12 | export class FPSMonitorComponent extends React.Component { 13 | state = { 14 | fps: 0, 15 | }; 16 | private interval?: number; 17 | 18 | componentDidMount() { 19 | fpsMonitor.start(); 20 | this.interval = window.setInterval(() => { 21 | this.setState({ 22 | fps: fpsMonitor.getFPS(), 23 | }); 24 | }, 1000); 25 | } 26 | 27 | componentWillUnmount() { 28 | fpsMonitor.end(); 29 | this.interval && window.clearInterval(this.interval); 30 | } 31 | 32 | render() { 33 | const { className } = this.props; 34 | let color: string; 35 | if (this.state.fps >= 40) { 36 | color = '#00cc00'; 37 | } else if (this.state.fps >= 20) { 38 | color = '#fdea42'; 39 | } else { 40 | color = '#ff0000'; 41 | } 42 | 43 | return ( 44 |
45 | FPS:{this.state.fps} 46 |
47 | ); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/src/index.ts: -------------------------------------------------------------------------------- 1 | import { FPSMonitorComponent } from './fps-monitor/index'; 2 | import { FPSMonitor } from './fps-monitor/fps'; 3 | 4 | export { 5 | FPSMonitorComponent, 6 | FPSMonitor 7 | }; 8 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /plugins/turbox-dev-tool/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/turbox-hot-loader/.babelrc.js: -------------------------------------------------------------------------------- 1 | const config = require('../../.babelrc.js'); 2 | 3 | module.exports = { 4 | ...config(), 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/turbox-hot-loader/.npmignore: -------------------------------------------------------------------------------- 1 | # npm and yarn 2 | npm-debug.log* 3 | node_modules 4 | .npmrc 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Mac 9 | .DS_Store 10 | 11 | # git 12 | .git 13 | 14 | # Editor directories and files 15 | .idea 16 | .vscode 17 | -------------------------------------------------------------------------------- /plugins/turbox-hot-loader/jest.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../jest.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/turbox-hot-loader/src/index.ts: -------------------------------------------------------------------------------- 1 | // @ts-nocheck 2 | import { fail } from './utils'; 3 | import { hot as reactComponentHot } from './components/hot'; 4 | import { hot as domainHot } from './hot'; 5 | 6 | declare global { 7 | interface NodeModule { 8 | i?: string; 9 | parents?: string[]; 10 | } 11 | interface Window { 12 | $$turbox_hot: boolean; 13 | } 14 | } 15 | 16 | export let hot; 17 | export let hotDomain: (stores: T) => T; 18 | 19 | if (module.hot) { 20 | const cache = require.cache; 21 | if (!module.parents || module.parents.length === 0) { 22 | fail('`hot` is not supported on your system.'); 23 | } 24 | const parent = cache[module.parents[0]]; 25 | if (!parent) { 26 | fail('`hot` is not supported on your system.'); 27 | } 28 | // remove from cache, trigger create new hot module and update ref 29 | delete cache[module.id]; 30 | hot = reactComponentHot(parent); 31 | hotDomain = domainHot(parent); 32 | } 33 | -------------------------------------------------------------------------------- /plugins/turbox-hot-loader/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | // based on https://github.com/mridgway/hoist-non-react-statics/blob/master/src/index.js 2 | const hoistBlackList = { 3 | $$typeof: true, 4 | render: true, 5 | compare: true, 6 | type: true, 7 | }; 8 | 9 | export function copyStaticProperties(base, target) { 10 | const keys = Object.keys(base); 11 | for (let index = 0; index < keys.length; index++) { 12 | const key = keys[index]; 13 | if (hoistBlackList[key] === void 0) { 14 | Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(base, key)!); 15 | } 16 | } 17 | } 18 | 19 | export const OBFUSCATED_ERROR = 20 | 'An invariant failed, however the error is obfuscated because this is an production build.'; 21 | 22 | export function invariant(check: boolean, message?: string | boolean) { 23 | if (!check) throw new Error(`[turbox]: ${message || OBFUSCATED_ERROR}`); 24 | } 25 | 26 | export function fail(message: string | boolean): never { 27 | invariant(false, message); 28 | // eslint-disable-next-line no-throw-literal 29 | throw 'X'; 30 | } 31 | 32 | export function warn(message: string | boolean) { 33 | console.warn(`[turbox]: ${message}`); 34 | } 35 | 36 | export function bind(fn, ctx) { 37 | function boundFn(a?: any) { 38 | const l: number = arguments.length; 39 | // eslint-disable-next-line no-nested-ternary 40 | return l 41 | ? l > 1 42 | // eslint-disable-next-line prefer-rest-params 43 | ? fn.apply(ctx, arguments) 44 | : fn.call(ctx, a) 45 | : fn.call(ctx); 46 | } 47 | return boundFn; 48 | } 49 | -------------------------------------------------------------------------------- /plugins/turbox-hot-loader/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "compilerOptions": { 4 | "declarationDir": "./typings", 5 | "outDir": "./ts" 6 | }, 7 | "include": ["src"] 8 | } 9 | -------------------------------------------------------------------------------- /plugins/turbox-hot-loader/webpack.config.js: -------------------------------------------------------------------------------- 1 | const config = require('../../webpack.config.js'); 2 | 3 | module.exports = { 4 | ...config, 5 | }; 6 | -------------------------------------------------------------------------------- /plugins/turbox-snippets/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | .gitignore 4 | -------------------------------------------------------------------------------- /plugins/turbox-snippets/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | 3 | ## 1.0.17 4 | 5 | ### Patch Changes 6 | 7 | - fix: fix build issue 8 | 9 | ## 1.0.16 10 | 11 | ### Patch Changes 12 | 13 | - fix: update version 14 | 15 | ## 1.0.15 16 | 17 | ### Patch Changes 18 | 19 | - Update build script&config file 20 | 21 | All notable changes to the "turbox-snippets" extension will be documented in this file. 22 | 23 | Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. 24 | -------------------------------------------------------------------------------- /plugins/turbox-snippets/images/turbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/turbox3d/turbox/417d21098c01894dd7403c3e486acf4512c26b40/plugins/turbox-snippets/images/turbox.png -------------------------------------------------------------------------------- /plugins/turbox-snippets/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "turbox-snippets", 3 | "displayName": "Turbox Snippets", 4 | "version": "1.0.17", 5 | "description": "Code snippets for Turbox", 6 | "author": "feifan ", 7 | "license": "MIT", 8 | "repository": { 9 | "type": "git", 10 | "url": "git+https://github.com/turbox3d/turbox.git" 11 | }, 12 | "scripts": { 13 | "deploy": "pnpm exec vsce publish" 14 | }, 15 | "publisher": "feifan-gff", 16 | "engines": { 17 | "vscode": "^1.28.0" 18 | }, 19 | "categories": [ 20 | "Snippets" 21 | ], 22 | "icon": "images/turbox.png", 23 | "contributes": { 24 | "snippets": [ 25 | { 26 | "language": "javascript", 27 | "path": "./snippets/snippets.json" 28 | }, 29 | { 30 | "language": "javascriptreact", 31 | "path": "./snippets/snippets.json" 32 | }, 33 | { 34 | "language": "typescript", 35 | "path": "./snippets/snippets.json" 36 | }, 37 | { 38 | "language": "typescriptreact", 39 | "path": "./snippets/snippets.json" 40 | } 41 | ] 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'plugins/*' 4 | link-workspace-packages: false 5 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "module": "es6", 5 | "noImplicitAny": false, 6 | "declaration": true, 7 | "strictNullChecks": true, 8 | "allowJs": false, 9 | "jsx": "react", 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "removeComments": false, 13 | "preserveConstEnums": true, 14 | "experimentalDecorators": true, 15 | "sourceMap": false, 16 | "downlevelIteration": true, 17 | "target": "ES2018", 18 | "moduleResolution": "node", 19 | "resolveJsonModule": true, 20 | "lib": [ 21 | "DOM", 22 | "ESNext" 23 | ], 24 | "types": [ 25 | "node", 26 | "jest", 27 | "webpack-env" 28 | ], 29 | "skipLibCheck": true 30 | }, 31 | "include": [ 32 | "packages/**/src/**/*", 33 | "plugins/**/src/**/*" 34 | ], 35 | "exclude": [ 36 | "node_modules", 37 | "**/node_modules/**/*", 38 | "**/__tests__/**/*" 39 | ] 40 | } 41 | -------------------------------------------------------------------------------- /typedoc.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://typedoc.org/schema.json", 3 | "includeVersion": true, 4 | "out": "./typedocs" 5 | } 6 | --------------------------------------------------------------------------------