├── .dependabot └── config.yml ├── .editorconfig ├── .github ├── FUNDING.yml ├── PULL_REQUEST_TEMPLATE.md └── workflows │ └── main.yml ├── .gitignore ├── .node-version ├── .prettierrc ├── .sasslintrc ├── .travis.yml ├── .vscode └── settings.json ├── .yarnclean ├── CONTRIBUTING-ja.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── assets └── screenshot.png ├── build-assets └── icon.png ├── gulpfile.ts ├── jest.config.js ├── package.json ├── packages ├── contrib-posteffect │ ├── index.spec.ts │ ├── jest.config.js │ ├── tsconfig.json │ └── tsconfig.test.json ├── core-test-helper │ ├── index.ts │ └── package.json ├── core │ ├── .gitignore │ ├── .npmignore │ ├── CHANGELOG.md │ ├── README.md │ ├── SCHEMA_CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── plugin-example.zip │ ├── plugin-example │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── src │ │ │ └── index.ts │ │ ├── tsconfig.json │ │ ├── webpack.config.js │ │ └── yarn.lock │ ├── spec │ │ └── fixture │ │ │ └── project │ │ │ ├── 2017091401.delir.json │ │ │ └── 2019052601.delir.json │ ├── src │ │ ├── Editor │ │ │ └── Editor.tsx │ │ ├── Engine │ │ │ ├── AssetProxy.ts │ │ │ ├── DependencyResolver.ts │ │ │ ├── Engine.ts │ │ │ ├── ExpressionSupport │ │ │ │ ├── EffectProxy.ts │ │ │ │ ├── ExpressionCompiler.ts │ │ │ │ ├── ExpressionContext.ts │ │ │ │ ├── ExpressionVM.ts │ │ │ │ └── createExpressionContext.ts │ │ │ ├── IRenderingStreamObserver.ts │ │ │ ├── KeyframeCalcurator.spec.ts │ │ │ ├── KeyframeCalcurator.ts │ │ │ ├── ParamType.ts │ │ │ ├── ParametersTable.spec.ts │ │ │ ├── ParametersTable.ts │ │ │ ├── RenderContext │ │ │ │ ├── ClipPreRenderContext.ts │ │ │ │ ├── ClipRenderContext.ts │ │ │ │ ├── EffectPreRenderContext.ts │ │ │ │ ├── EffectRenderContext.ts │ │ │ │ ├── IRenderContextBase.ts │ │ │ │ └── RenderContextBase.ts │ │ │ ├── Renderer │ │ │ │ ├── Adjustment │ │ │ │ │ └── Adjustment.ts │ │ │ │ ├── Audio │ │ │ │ │ └── Audio.ts │ │ │ │ ├── Image │ │ │ │ │ └── Image.ts │ │ │ │ ├── P5js │ │ │ │ │ ├── P5Hooks.ts │ │ │ │ │ ├── P5js.spec.ts │ │ │ │ │ ├── P5js.ts │ │ │ │ │ ├── P5jsContextTypeDefinition.ts │ │ │ │ │ └── specFixtures │ │ │ │ │ │ └── globals.js │ │ │ │ ├── RendererBase.ts │ │ │ │ ├── Solid │ │ │ │ │ └── Solid.ts │ │ │ │ ├── Text │ │ │ │ │ └── Text.ts │ │ │ │ ├── Video │ │ │ │ │ └── Video.ts │ │ │ │ └── index.ts │ │ │ ├── Task │ │ │ │ ├── ClipRenderTask.ts │ │ │ │ ├── EffectRenderTask.spec.ts │ │ │ │ ├── EffectRenderTask.ts │ │ │ │ └── LayerRenderTask.ts │ │ │ ├── WebGL │ │ │ │ └── WebGLContext.ts │ │ │ └── index.ts │ │ ├── Entity │ │ │ ├── Animatable.ts │ │ │ ├── Asset.ts │ │ │ ├── Clip.ts │ │ │ ├── Composition.ts │ │ │ ├── Effect.ts │ │ │ ├── Keyframe.ts │ │ │ ├── Layer.ts │ │ │ ├── Project.ts │ │ │ └── index.ts │ │ ├── Exceptions │ │ │ ├── DelirException.ts │ │ │ ├── EffectPluginMissingException.ts │ │ │ ├── PlugiinAssertionFailedException.ts │ │ │ ├── PluginLoadFailException.ts │ │ │ ├── RenderingAbortedException.ts │ │ │ ├── RenderingFailedException.ts │ │ │ ├── UnknownPluginReferenceException.ts │ │ │ ├── UserCodeException.ts │ │ │ └── index.ts │ │ ├── Exporter.spec.ts │ │ ├── Exporter.ts │ │ ├── Migration │ │ │ ├── MigrationHelper.ts │ │ │ ├── ProjectMigrator.spec.ts │ │ │ ├── ProjectMigrator.ts │ │ │ └── __snapshots__ │ │ │ │ └── ProjectMigrator.spec.ts.snap │ │ ├── PluginSupport │ │ │ ├── PluginBase.ts │ │ │ ├── PluginRegistry.spec.ts │ │ │ ├── PluginRegistry.ts │ │ │ ├── PostEffectBase.ts │ │ │ ├── TypeDescriptor.ts │ │ │ ├── index.ts │ │ │ └── types.ts │ │ ├── Values │ │ │ ├── AssetPointer.ts │ │ │ ├── ColorRGB.ts │ │ │ ├── ColorRGBA.ts │ │ │ ├── Expression.ts │ │ │ ├── index.ts │ │ │ ├── point-2d.ts │ │ │ ├── point-3d.ts │ │ │ ├── size-2d.ts │ │ │ └── size-3d.ts │ │ ├── __snapshots__ │ │ │ └── Exporter.spec.ts.snap │ │ ├── declarations.d.ts │ │ ├── helper │ │ │ ├── Audio.ts │ │ │ ├── Branded.ts │ │ │ ├── FPSCounter.ts │ │ │ ├── defaults.ts │ │ │ ├── neverCheck.ts │ │ │ ├── progress-promise.ts │ │ │ ├── proxyFreeze.ts │ │ │ └── safeAssign.ts │ │ └── index.ts │ ├── tsconfig.json │ └── tsconfig.test.json ├── delir │ ├── .storybook │ │ ├── addons.ts │ │ ├── config.tsx │ │ ├── patch.sass │ │ └── webpack.config.ts │ ├── __spec__ │ │ ├── __bootstrap__.js │ │ └── fixtures │ │ │ └── Project.ts │ ├── jest.config.js │ ├── package.json │ ├── src │ │ ├── assets │ │ │ ├── fonts │ │ │ │ ├── FontAwesome.otf │ │ │ │ ├── fontawesome-webfont.eot │ │ │ │ ├── fontawesome-webfont.svg │ │ │ │ ├── fontawesome-webfont.ttf │ │ │ │ ├── fontawesome-webfont.woff │ │ │ │ └── fontawesome-webfont.woff2 │ │ │ ├── images │ │ │ │ ├── .gitkeep │ │ │ │ ├── delir.svg │ │ │ │ ├── empty.png │ │ │ │ └── twemoji-svg │ │ │ │ │ ├── 1f004.svg │ │ │ │ │ ├── 1f0cf.svg │ │ │ │ │ ├── 1f170.svg │ │ │ │ │ ├── 1f171.svg │ │ │ │ │ ├── 1f17e.svg │ │ │ │ │ ├── 1f17f.svg │ │ │ │ │ ├── 1f18e.svg │ │ │ │ │ ├── 1f191.svg │ │ │ │ │ ├── 1f192.svg │ │ │ │ │ ├── 1f193.svg │ │ │ │ │ ├── 1f194.svg │ │ │ │ │ ├── 1f195.svg │ │ │ │ │ ├── 1f196.svg │ │ │ │ │ ├── 1f197.svg │ │ │ │ │ ├── 1f198.svg │ │ │ │ │ ├── 1f199.svg │ │ │ │ │ ├── 1f19a.svg │ │ │ │ │ ├── 1f1e6-1f1e8.svg │ │ │ │ │ ├── 1f1e6-1f1e9.svg │ │ │ │ │ ├── 1f1e6-1f1ea.svg │ │ │ │ │ ├── 1f1e6-1f1eb.svg │ │ │ │ │ ├── 1f1e6-1f1ec.svg │ │ │ │ │ ├── 1f1e6-1f1ee.svg │ │ │ │ │ ├── 1f1e6-1f1f1.svg │ │ │ │ │ ├── 1f1e6-1f1f2.svg │ │ │ │ │ ├── 1f1e6-1f1f4.svg │ │ │ │ │ ├── 1f1e6-1f1f6.svg │ │ │ │ │ ├── 1f1e6-1f1f7.svg │ │ │ │ │ ├── 1f1e6-1f1f8.svg │ │ │ │ │ ├── 1f1e6-1f1f9.svg │ │ │ │ │ ├── 1f1e6-1f1fa.svg │ │ │ │ │ ├── 1f1e6-1f1fc.svg │ │ │ │ │ ├── 1f1e6-1f1fd.svg │ │ │ │ │ ├── 1f1e6-1f1ff.svg │ │ │ │ │ ├── 1f1e6.svg │ │ │ │ │ ├── 1f1e7-1f1e6.svg │ │ │ │ │ ├── 1f1e7-1f1e7.svg │ │ │ │ │ ├── 1f1e7-1f1e9.svg │ │ │ │ │ ├── 1f1e7-1f1ea.svg │ │ │ │ │ ├── 1f1e7-1f1eb.svg │ │ │ │ │ ├── 1f1e7-1f1ec.svg │ │ │ │ │ ├── 1f1e7-1f1ed.svg │ │ │ │ │ ├── 1f1e7-1f1ee.svg │ │ │ │ │ ├── 1f1e7-1f1ef.svg │ │ │ │ │ ├── 1f1e7-1f1f1.svg │ │ │ │ │ ├── 1f1e7-1f1f2.svg │ │ │ │ │ ├── 1f1e7-1f1f3.svg │ │ │ │ │ ├── 1f1e7-1f1f4.svg │ │ │ │ │ ├── 1f1e7-1f1f6.svg │ │ │ │ │ ├── 1f1e7-1f1f7.svg │ │ │ │ │ ├── 1f1e7-1f1f8.svg │ │ │ │ │ ├── 1f1e7-1f1f9.svg │ │ │ │ │ ├── 1f1e7-1f1fb.svg │ │ │ │ │ ├── 1f1e7-1f1fc.svg │ │ │ │ │ ├── 1f1e7-1f1fe.svg │ │ │ │ │ ├── 1f1e7-1f1ff.svg │ │ │ │ │ ├── 1f1e7.svg │ │ │ │ │ ├── 1f1e8-1f1e6.svg │ │ │ │ │ ├── 1f1e8-1f1e8.svg │ │ │ │ │ ├── 1f1e8-1f1e9.svg │ │ │ │ │ ├── 1f1e8-1f1eb.svg │ │ │ │ │ ├── 1f1e8-1f1ec.svg │ │ │ │ │ ├── 1f1e8-1f1ed.svg │ │ │ │ │ ├── 1f1e8-1f1ee.svg │ │ │ │ │ ├── 1f1e8-1f1f0.svg │ │ │ │ │ ├── 1f1e8-1f1f1.svg │ │ │ │ │ ├── 1f1e8-1f1f2.svg │ │ │ │ │ ├── 1f1e8-1f1f3.svg │ │ │ │ │ ├── 1f1e8-1f1f4.svg │ │ │ │ │ ├── 1f1e8-1f1f5.svg │ │ │ │ │ ├── 1f1e8-1f1f7.svg │ │ │ │ │ ├── 1f1e8-1f1fa.svg │ │ │ │ │ ├── 1f1e8-1f1fb.svg │ │ │ │ │ ├── 1f1e8-1f1fc.svg │ │ │ │ │ ├── 1f1e8-1f1fd.svg │ │ │ │ │ ├── 1f1e8-1f1fe.svg │ │ │ │ │ ├── 1f1e8-1f1ff.svg │ │ │ │ │ ├── 1f1e8.svg │ │ │ │ │ ├── 1f1e9-1f1ea.svg │ │ │ │ │ ├── 1f1e9-1f1ec.svg │ │ │ │ │ ├── 1f1e9-1f1ef.svg │ │ │ │ │ ├── 1f1e9-1f1f0.svg │ │ │ │ │ ├── 1f1e9-1f1f2.svg │ │ │ │ │ ├── 1f1e9-1f1f4.svg │ │ │ │ │ ├── 1f1e9-1f1ff.svg │ │ │ │ │ ├── 1f1e9.svg │ │ │ │ │ ├── 1f1ea-1f1e6.svg │ │ │ │ │ ├── 1f1ea-1f1e8.svg │ │ │ │ │ ├── 1f1ea-1f1ea.svg │ │ │ │ │ ├── 1f1ea-1f1ec.svg │ │ │ │ │ ├── 1f1ea-1f1ed.svg │ │ │ │ │ ├── 1f1ea-1f1f7.svg │ │ │ │ │ ├── 1f1ea-1f1f8.svg │ │ │ │ │ ├── 1f1ea-1f1f9.svg │ │ │ │ │ ├── 1f1ea-1f1fa.svg │ │ │ │ │ ├── 1f1ea.svg │ │ │ │ │ ├── 1f1eb-1f1ee.svg │ │ │ │ │ ├── 1f1eb-1f1ef.svg │ │ │ │ │ ├── 1f1eb-1f1f0.svg │ │ │ │ │ ├── 1f1eb-1f1f2.svg │ │ │ │ │ ├── 1f1eb-1f1f4.svg │ │ │ │ │ ├── 1f1eb-1f1f7.svg │ │ │ │ │ ├── 1f1eb.svg │ │ │ │ │ ├── 1f1ec-1f1e6.svg │ │ │ │ │ ├── 1f1ec-1f1e7.svg │ │ │ │ │ ├── 1f1ec-1f1e9.svg │ │ │ │ │ ├── 1f1ec-1f1ea.svg │ │ │ │ │ ├── 1f1ec-1f1eb.svg │ │ │ │ │ ├── 1f1ec-1f1ec.svg │ │ │ │ │ ├── 1f1ec-1f1ed.svg │ │ │ │ │ ├── 1f1ec-1f1ee.svg │ │ │ │ │ ├── 1f1ec-1f1f1.svg │ │ │ │ │ ├── 1f1ec-1f1f2.svg │ │ │ │ │ ├── 1f1ec-1f1f3.svg │ │ │ │ │ ├── 1f1ec-1f1f5.svg │ │ │ │ │ ├── 1f1ec-1f1f6.svg │ │ │ │ │ ├── 1f1ec-1f1f7.svg │ │ │ │ │ ├── 1f1ec-1f1f8.svg │ │ │ │ │ ├── 1f1ec-1f1f9.svg │ │ │ │ │ ├── 1f1ec-1f1fa.svg │ │ │ │ │ ├── 1f1ec-1f1fc.svg │ │ │ │ │ ├── 1f1ec-1f1fe.svg │ │ │ │ │ ├── 1f1ec.svg │ │ │ │ │ ├── 1f1ed-1f1f0.svg │ │ │ │ │ ├── 1f1ed-1f1f2.svg │ │ │ │ │ ├── 1f1ed-1f1f3.svg │ │ │ │ │ ├── 1f1ed-1f1f7.svg │ │ │ │ │ ├── 1f1ed-1f1f9.svg │ │ │ │ │ ├── 1f1ed-1f1fa.svg │ │ │ │ │ ├── 1f1ed.svg │ │ │ │ │ ├── 1f1ee-1f1e8.svg │ │ │ │ │ ├── 1f1ee-1f1e9.svg │ │ │ │ │ ├── 1f1ee-1f1ea.svg │ │ │ │ │ ├── 1f1ee-1f1f1.svg │ │ │ │ │ ├── 1f1ee-1f1f2.svg │ │ │ │ │ ├── 1f1ee-1f1f3.svg │ │ │ │ │ ├── 1f1ee-1f1f4.svg │ │ │ │ │ ├── 1f1ee-1f1f6.svg │ │ │ │ │ ├── 1f1ee-1f1f7.svg │ │ │ │ │ ├── 1f1ee-1f1f8.svg │ │ │ │ │ ├── 1f1ee-1f1f9.svg │ │ │ │ │ ├── 1f1ee.svg │ │ │ │ │ ├── 1f1ef-1f1ea.svg │ │ │ │ │ ├── 1f1ef-1f1f2.svg │ │ │ │ │ ├── 1f1ef-1f1f4.svg │ │ │ │ │ ├── 1f1ef-1f1f5.svg │ │ │ │ │ ├── 1f1ef.svg │ │ │ │ │ ├── 1f1f0-1f1ea.svg │ │ │ │ │ ├── 1f1f0-1f1ec.svg │ │ │ │ │ ├── 1f1f0-1f1ed.svg │ │ │ │ │ ├── 1f1f0-1f1ee.svg │ │ │ │ │ ├── 1f1f0-1f1f2.svg │ │ │ │ │ ├── 1f1f0-1f1f3.svg │ │ │ │ │ ├── 1f1f0-1f1f5.svg │ │ │ │ │ ├── 1f1f0-1f1f7.svg │ │ │ │ │ ├── 1f1f0-1f1fc.svg │ │ │ │ │ ├── 1f1f0-1f1fe.svg │ │ │ │ │ ├── 1f1f0-1f1ff.svg │ │ │ │ │ ├── 1f1f0.svg │ │ │ │ │ ├── 1f1f1-1f1e6.svg │ │ │ │ │ ├── 1f1f1-1f1e7.svg │ │ │ │ │ ├── 1f1f1-1f1e8.svg │ │ │ │ │ ├── 1f1f1-1f1ee.svg │ │ │ │ │ ├── 1f1f1-1f1f0.svg │ │ │ │ │ ├── 1f1f1-1f1f7.svg │ │ │ │ │ ├── 1f1f1-1f1f8.svg │ │ │ │ │ ├── 1f1f1-1f1f9.svg │ │ │ │ │ ├── 1f1f1-1f1fa.svg │ │ │ │ │ ├── 1f1f1-1f1fb.svg │ │ │ │ │ ├── 1f1f1-1f1fe.svg │ │ │ │ │ ├── 1f1f1.svg │ │ │ │ │ ├── 1f1f2-1f1e6.svg │ │ │ │ │ ├── 1f1f2-1f1e8.svg │ │ │ │ │ ├── 1f1f2-1f1e9.svg │ │ │ │ │ ├── 1f1f2-1f1ea.svg │ │ │ │ │ ├── 1f1f2-1f1eb.svg │ │ │ │ │ ├── 1f1f2-1f1ec.svg │ │ │ │ │ ├── 1f1f2-1f1ed.svg │ │ │ │ │ ├── 1f1f2-1f1f0.svg │ │ │ │ │ ├── 1f1f2-1f1f1.svg │ │ │ │ │ ├── 1f1f2-1f1f2.svg │ │ │ │ │ ├── 1f1f2-1f1f3.svg │ │ │ │ │ ├── 1f1f2-1f1f4.svg │ │ │ │ │ ├── 1f1f2-1f1f5.svg │ │ │ │ │ ├── 1f1f2-1f1f6.svg │ │ │ │ │ ├── 1f1f2-1f1f7.svg │ │ │ │ │ ├── 1f1f2-1f1f8.svg │ │ │ │ │ ├── 1f1f2-1f1f9.svg │ │ │ │ │ ├── 1f1f2-1f1fa.svg │ │ │ │ │ ├── 1f1f2-1f1fb.svg │ │ │ │ │ ├── 1f1f2-1f1fc.svg │ │ │ │ │ ├── 1f1f2-1f1fd.svg │ │ │ │ │ ├── 1f1f2-1f1fe.svg │ │ │ │ │ ├── 1f1f2-1f1ff.svg │ │ │ │ │ ├── 1f1f2.svg │ │ │ │ │ ├── 1f1f3-1f1e6.svg │ │ │ │ │ ├── 1f1f3-1f1e8.svg │ │ │ │ │ ├── 1f1f3-1f1ea.svg │ │ │ │ │ ├── 1f1f3-1f1eb.svg │ │ │ │ │ ├── 1f1f3-1f1ec.svg │ │ │ │ │ ├── 1f1f3-1f1ee.svg │ │ │ │ │ ├── 1f1f3-1f1f1.svg │ │ │ │ │ ├── 1f1f3-1f1f4.svg │ │ │ │ │ ├── 1f1f3-1f1f5.svg │ │ │ │ │ ├── 1f1f3-1f1f7.svg │ │ │ │ │ ├── 1f1f3-1f1fa.svg │ │ │ │ │ ├── 1f1f3-1f1ff.svg │ │ │ │ │ ├── 1f1f3.svg │ │ │ │ │ ├── 1f1f4-1f1f2.svg │ │ │ │ │ ├── 1f1f4.svg │ │ │ │ │ ├── 1f1f5-1f1e6.svg │ │ │ │ │ ├── 1f1f5-1f1ea.svg │ │ │ │ │ ├── 1f1f5-1f1eb.svg │ │ │ │ │ ├── 1f1f5-1f1ec.svg │ │ │ │ │ ├── 1f1f5-1f1ed.svg │ │ │ │ │ ├── 1f1f5-1f1f0.svg │ │ │ │ │ ├── 1f1f5-1f1f1.svg │ │ │ │ │ ├── 1f1f5-1f1f2.svg │ │ │ │ │ ├── 1f1f5-1f1f3.svg │ │ │ │ │ ├── 1f1f5-1f1f7.svg │ │ │ │ │ ├── 1f1f5-1f1f8.svg │ │ │ │ │ ├── 1f1f5-1f1f9.svg │ │ │ │ │ ├── 1f1f5-1f1fc.svg │ │ │ │ │ ├── 1f1f5-1f1fe.svg │ │ │ │ │ ├── 1f1f5.svg │ │ │ │ │ ├── 1f1f6-1f1e6.svg │ │ │ │ │ ├── 1f1f6.svg │ │ │ │ │ ├── 1f1f7-1f1ea.svg │ │ │ │ │ ├── 1f1f7-1f1f4.svg │ │ │ │ │ ├── 1f1f7-1f1f8.svg │ │ │ │ │ ├── 1f1f7-1f1fa.svg │ │ │ │ │ ├── 1f1f7-1f1fc.svg │ │ │ │ │ ├── 1f1f7.svg │ │ │ │ │ ├── 1f1f8-1f1e6.svg │ │ │ │ │ ├── 1f1f8-1f1e7.svg │ │ │ │ │ ├── 1f1f8-1f1e8.svg │ │ │ │ │ ├── 1f1f8-1f1e9.svg │ │ │ │ │ ├── 1f1f8-1f1ea.svg │ │ │ │ │ ├── 1f1f8-1f1ec.svg │ │ │ │ │ ├── 1f1f8-1f1ed.svg │ │ │ │ │ ├── 1f1f8-1f1ee.svg │ │ │ │ │ ├── 1f1f8-1f1ef.svg │ │ │ │ │ ├── 1f1f8-1f1f0.svg │ │ │ │ │ ├── 1f1f8-1f1f1.svg │ │ │ │ │ ├── 1f1f8-1f1f2.svg │ │ │ │ │ ├── 1f1f8-1f1f3.svg │ │ │ │ │ ├── 1f1f8-1f1f4.svg │ │ │ │ │ ├── 1f1f8-1f1f7.svg │ │ │ │ │ ├── 1f1f8-1f1f8.svg │ │ │ │ │ ├── 1f1f8-1f1f9.svg │ │ │ │ │ ├── 1f1f8-1f1fb.svg │ │ │ │ │ ├── 1f1f8-1f1fd.svg │ │ │ │ │ ├── 1f1f8-1f1fe.svg │ │ │ │ │ ├── 1f1f8-1f1ff.svg │ │ │ │ │ ├── 1f1f8.svg │ │ │ │ │ ├── 1f1f9-1f1e6.svg │ │ │ │ │ ├── 1f1f9-1f1e8.svg │ │ │ │ │ ├── 1f1f9-1f1e9.svg │ │ │ │ │ ├── 1f1f9-1f1eb.svg │ │ │ │ │ ├── 1f1f9-1f1ec.svg │ │ │ │ │ ├── 1f1f9-1f1ed.svg │ │ │ │ │ ├── 1f1f9-1f1ef.svg │ │ │ │ │ ├── 1f1f9-1f1f0.svg │ │ │ │ │ ├── 1f1f9-1f1f1.svg │ │ │ │ │ ├── 1f1f9-1f1f2.svg │ │ │ │ │ ├── 1f1f9-1f1f3.svg │ │ │ │ │ ├── 1f1f9-1f1f4.svg │ │ │ │ │ ├── 1f1f9-1f1f7.svg │ │ │ │ │ ├── 1f1f9-1f1f9.svg │ │ │ │ │ ├── 1f1f9-1f1fb.svg │ │ │ │ │ ├── 1f1f9-1f1fc.svg │ │ │ │ │ ├── 1f1f9-1f1ff.svg │ │ │ │ │ ├── 1f1f9.svg │ │ │ │ │ ├── 1f1fa-1f1e6.svg │ │ │ │ │ ├── 1f1fa-1f1ec.svg │ │ │ │ │ ├── 1f1fa-1f1f2.svg │ │ │ │ │ ├── 1f1fa-1f1f3.svg │ │ │ │ │ ├── 1f1fa-1f1f8.svg │ │ │ │ │ ├── 1f1fa-1f1fe.svg │ │ │ │ │ ├── 1f1fa-1f1ff.svg │ │ │ │ │ ├── 1f1fa.svg │ │ │ │ │ ├── 1f1fb-1f1e6.svg │ │ │ │ │ ├── 1f1fb-1f1e8.svg │ │ │ │ │ ├── 1f1fb-1f1ea.svg │ │ │ │ │ ├── 1f1fb-1f1ec.svg │ │ │ │ │ ├── 1f1fb-1f1ee.svg │ │ │ │ │ ├── 1f1fb-1f1f3.svg │ │ │ │ │ ├── 1f1fb-1f1fa.svg │ │ │ │ │ ├── 1f1fb.svg │ │ │ │ │ ├── 1f1fc-1f1eb.svg │ │ │ │ │ ├── 1f1fc-1f1f8.svg │ │ │ │ │ ├── 1f1fc.svg │ │ │ │ │ ├── 1f1fd-1f1f0.svg │ │ │ │ │ ├── 1f1fd.svg │ │ │ │ │ ├── 1f1fe-1f1ea.svg │ │ │ │ │ ├── 1f1fe-1f1f9.svg │ │ │ │ │ ├── 1f1fe.svg │ │ │ │ │ ├── 1f1ff-1f1e6.svg │ │ │ │ │ ├── 1f1ff-1f1f2.svg │ │ │ │ │ ├── 1f1ff-1f1fc.svg │ │ │ │ │ ├── 1f1ff.svg │ │ │ │ │ ├── 1f201.svg │ │ │ │ │ ├── 1f202.svg │ │ │ │ │ ├── 1f21a.svg │ │ │ │ │ ├── 1f22f.svg │ │ │ │ │ ├── 1f232.svg │ │ │ │ │ ├── 1f233.svg │ │ │ │ │ ├── 1f234.svg │ │ │ │ │ ├── 1f235.svg │ │ │ │ │ ├── 1f236.svg │ │ │ │ │ ├── 1f237.svg │ │ │ │ │ ├── 1f238.svg │ │ │ │ │ ├── 1f239.svg │ │ │ │ │ ├── 1f23a.svg │ │ │ │ │ ├── 1f250.svg │ │ │ │ │ ├── 1f251.svg │ │ │ │ │ ├── 1f300.svg │ │ │ │ │ ├── 1f301.svg │ │ │ │ │ ├── 1f302.svg │ │ │ │ │ ├── 1f303.svg │ │ │ │ │ ├── 1f304.svg │ │ │ │ │ ├── 1f305.svg │ │ │ │ │ ├── 1f306.svg │ │ │ │ │ ├── 1f307.svg │ │ │ │ │ ├── 1f308.svg │ │ │ │ │ ├── 1f309.svg │ │ │ │ │ ├── 1f30a.svg │ │ │ │ │ ├── 1f30b.svg │ │ │ │ │ ├── 1f30c.svg │ │ │ │ │ ├── 1f30d.svg │ │ │ │ │ ├── 1f30e.svg │ │ │ │ │ ├── 1f30f.svg │ │ │ │ │ ├── 1f310.svg │ │ │ │ │ ├── 1f311.svg │ │ │ │ │ ├── 1f312.svg │ │ │ │ │ ├── 1f313.svg │ │ │ │ │ ├── 1f314.svg │ │ │ │ │ ├── 1f315.svg │ │ │ │ │ ├── 1f316.svg │ │ │ │ │ ├── 1f317.svg │ │ │ │ │ ├── 1f318.svg │ │ │ │ │ ├── 1f319.svg │ │ │ │ │ ├── 1f31a.svg │ │ │ │ │ ├── 1f31b.svg │ │ │ │ │ ├── 1f31c.svg │ │ │ │ │ ├── 1f31d.svg │ │ │ │ │ ├── 1f31e.svg │ │ │ │ │ ├── 1f31f.svg │ │ │ │ │ ├── 1f320.svg │ │ │ │ │ ├── 1f321.svg │ │ │ │ │ ├── 1f324.svg │ │ │ │ │ ├── 1f325.svg │ │ │ │ │ ├── 1f326.svg │ │ │ │ │ ├── 1f327.svg │ │ │ │ │ ├── 1f328.svg │ │ │ │ │ ├── 1f329.svg │ │ │ │ │ ├── 1f32a.svg │ │ │ │ │ ├── 1f32b.svg │ │ │ │ │ ├── 1f32c.svg │ │ │ │ │ ├── 1f32d.svg │ │ │ │ │ ├── 1f32e.svg │ │ │ │ │ ├── 1f32f.svg │ │ │ │ │ ├── 1f330.svg │ │ │ │ │ ├── 1f331.svg │ │ │ │ │ ├── 1f332.svg │ │ │ │ │ ├── 1f333.svg │ │ │ │ │ ├── 1f334.svg │ │ │ │ │ ├── 1f335.svg │ │ │ │ │ ├── 1f336.svg │ │ │ │ │ ├── 1f337.svg │ │ │ │ │ ├── 1f338.svg │ │ │ │ │ ├── 1f339.svg │ │ │ │ │ ├── 1f33a.svg │ │ │ │ │ ├── 1f33b.svg │ │ │ │ │ ├── 1f33c.svg │ │ │ │ │ ├── 1f33d.svg │ │ │ │ │ ├── 1f33e.svg │ │ │ │ │ ├── 1f33f.svg │ │ │ │ │ ├── 1f340.svg │ │ │ │ │ ├── 1f341.svg │ │ │ │ │ ├── 1f342.svg │ │ │ │ │ ├── 1f343.svg │ │ │ │ │ ├── 1f344.svg │ │ │ │ │ ├── 1f345.svg │ │ │ │ │ ├── 1f346.svg │ │ │ │ │ ├── 1f347.svg │ │ │ │ │ ├── 1f348.svg │ │ │ │ │ ├── 1f349.svg │ │ │ │ │ ├── 1f34a.svg │ │ │ │ │ ├── 1f34b.svg │ │ │ │ │ ├── 1f34c.svg │ │ │ │ │ ├── 1f34d.svg │ │ │ │ │ ├── 1f34e.svg │ │ │ │ │ ├── 1f34f.svg │ │ │ │ │ ├── 1f350.svg │ │ │ │ │ ├── 1f351.svg │ │ │ │ │ ├── 1f352.svg │ │ │ │ │ ├── 1f353.svg │ │ │ │ │ ├── 1f354.svg │ │ │ │ │ ├── 1f355.svg │ │ │ │ │ ├── 1f356.svg │ │ │ │ │ ├── 1f357.svg │ │ │ │ │ ├── 1f358.svg │ │ │ │ │ ├── 1f359.svg │ │ │ │ │ ├── 1f35a.svg │ │ │ │ │ ├── 1f35b.svg │ │ │ │ │ ├── 1f35c.svg │ │ │ │ │ ├── 1f35d.svg │ │ │ │ │ ├── 1f35e.svg │ │ │ │ │ ├── 1f35f.svg │ │ │ │ │ ├── 1f360.svg │ │ │ │ │ ├── 1f361.svg │ │ │ │ │ ├── 1f362.svg │ │ │ │ │ ├── 1f363.svg │ │ │ │ │ ├── 1f364.svg │ │ │ │ │ ├── 1f365.svg │ │ │ │ │ ├── 1f366.svg │ │ │ │ │ ├── 1f367.svg │ │ │ │ │ ├── 1f368.svg │ │ │ │ │ ├── 1f369.svg │ │ │ │ │ ├── 1f36a.svg │ │ │ │ │ ├── 1f36b.svg │ │ │ │ │ ├── 1f36c.svg │ │ │ │ │ ├── 1f36d.svg │ │ │ │ │ ├── 1f36e.svg │ │ │ │ │ ├── 1f36f.svg │ │ │ │ │ ├── 1f370.svg │ │ │ │ │ ├── 1f371.svg │ │ │ │ │ ├── 1f372.svg │ │ │ │ │ ├── 1f373.svg │ │ │ │ │ ├── 1f374.svg │ │ │ │ │ ├── 1f375.svg │ │ │ │ │ ├── 1f376.svg │ │ │ │ │ ├── 1f377.svg │ │ │ │ │ ├── 1f378.svg │ │ │ │ │ ├── 1f379.svg │ │ │ │ │ ├── 1f37a.svg │ │ │ │ │ ├── 1f37b.svg │ │ │ │ │ ├── 1f37c.svg │ │ │ │ │ ├── 1f37d.svg │ │ │ │ │ ├── 1f37e.svg │ │ │ │ │ ├── 1f37f.svg │ │ │ │ │ ├── 1f380.svg │ │ │ │ │ ├── 1f381.svg │ │ │ │ │ ├── 1f382.svg │ │ │ │ │ ├── 1f383.svg │ │ │ │ │ ├── 1f384.svg │ │ │ │ │ ├── 1f385-1f3fb.svg │ │ │ │ │ ├── 1f385-1f3fc.svg │ │ │ │ │ ├── 1f385-1f3fd.svg │ │ │ │ │ ├── 1f385-1f3fe.svg │ │ │ │ │ ├── 1f385-1f3ff.svg │ │ │ │ │ ├── 1f385.svg │ │ │ │ │ ├── 1f386.svg │ │ │ │ │ ├── 1f387.svg │ │ │ │ │ ├── 1f388.svg │ │ │ │ │ ├── 1f389.svg │ │ │ │ │ ├── 1f38a.svg │ │ │ │ │ ├── 1f38b.svg │ │ │ │ │ ├── 1f38c.svg │ │ │ │ │ ├── 1f38d.svg │ │ │ │ │ ├── 1f38e.svg │ │ │ │ │ ├── 1f38f.svg │ │ │ │ │ ├── 1f390.svg │ │ │ │ │ ├── 1f391.svg │ │ │ │ │ ├── 1f392.svg │ │ │ │ │ ├── 1f393.svg │ │ │ │ │ ├── 1f396.svg │ │ │ │ │ ├── 1f397.svg │ │ │ │ │ ├── 1f399.svg │ │ │ │ │ ├── 1f39a.svg │ │ │ │ │ ├── 1f39b.svg │ │ │ │ │ ├── 1f39e.svg │ │ │ │ │ ├── 1f39f.svg │ │ │ │ │ ├── 1f3a0.svg │ │ │ │ │ ├── 1f3a1.svg │ │ │ │ │ ├── 1f3a2.svg │ │ │ │ │ ├── 1f3a3.svg │ │ │ │ │ ├── 1f3a4.svg │ │ │ │ │ ├── 1f3a5.svg │ │ │ │ │ ├── 1f3a6.svg │ │ │ │ │ ├── 1f3a7.svg │ │ │ │ │ ├── 1f3a8.svg │ │ │ │ │ ├── 1f3a9.svg │ │ │ │ │ ├── 1f3aa.svg │ │ │ │ │ ├── 1f3ab.svg │ │ │ │ │ ├── 1f3ac.svg │ │ │ │ │ ├── 1f3ad.svg │ │ │ │ │ ├── 1f3ae.svg │ │ │ │ │ ├── 1f3af.svg │ │ │ │ │ ├── 1f3b0.svg │ │ │ │ │ ├── 1f3b1.svg │ │ │ │ │ ├── 1f3b2.svg │ │ │ │ │ ├── 1f3b3.svg │ │ │ │ │ ├── 1f3b4.svg │ │ │ │ │ ├── 1f3b5.svg │ │ │ │ │ ├── 1f3b6.svg │ │ │ │ │ ├── 1f3b7.svg │ │ │ │ │ ├── 1f3b8.svg │ │ │ │ │ ├── 1f3b9.svg │ │ │ │ │ ├── 1f3ba.svg │ │ │ │ │ ├── 1f3bb.svg │ │ │ │ │ ├── 1f3bc.svg │ │ │ │ │ ├── 1f3bd.svg │ │ │ │ │ ├── 1f3be.svg │ │ │ │ │ ├── 1f3bf.svg │ │ │ │ │ ├── 1f3c0.svg │ │ │ │ │ ├── 1f3c1.svg │ │ │ │ │ ├── 1f3c2-1f3fb.svg │ │ │ │ │ ├── 1f3c2-1f3fc.svg │ │ │ │ │ ├── 1f3c2-1f3fd.svg │ │ │ │ │ ├── 1f3c2-1f3fe.svg │ │ │ │ │ ├── 1f3c2-1f3ff.svg │ │ │ │ │ ├── 1f3c2.svg │ │ │ │ │ ├── 1f3c3-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fb.svg │ │ │ │ │ ├── 1f3c3-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fc.svg │ │ │ │ │ ├── 1f3c3-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fd.svg │ │ │ │ │ ├── 1f3c3-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3fe.svg │ │ │ │ │ ├── 1f3c3-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c3-1f3ff.svg │ │ │ │ │ ├── 1f3c3-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c3-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c3.svg │ │ │ │ │ ├── 1f3c4-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fb.svg │ │ │ │ │ ├── 1f3c4-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fc.svg │ │ │ │ │ ├── 1f3c4-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fd.svg │ │ │ │ │ ├── 1f3c4-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3fe.svg │ │ │ │ │ ├── 1f3c4-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c4-1f3ff.svg │ │ │ │ │ ├── 1f3c4-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3c4-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3c4.svg │ │ │ │ │ ├── 1f3c5.svg │ │ │ │ │ ├── 1f3c6.svg │ │ │ │ │ ├── 1f3c7-1f3fb.svg │ │ │ │ │ ├── 1f3c7-1f3fc.svg │ │ │ │ │ ├── 1f3c7-1f3fd.svg │ │ │ │ │ ├── 1f3c7-1f3fe.svg │ │ │ │ │ ├── 1f3c7-1f3ff.svg │ │ │ │ │ ├── 1f3c7.svg │ │ │ │ │ ├── 1f3c8.svg │ │ │ │ │ ├── 1f3c9.svg │ │ │ │ │ ├── 1f3ca-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fb.svg │ │ │ │ │ ├── 1f3ca-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fc.svg │ │ │ │ │ ├── 1f3ca-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fd.svg │ │ │ │ │ ├── 1f3ca-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3fe.svg │ │ │ │ │ ├── 1f3ca-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3ca-1f3ff.svg │ │ │ │ │ ├── 1f3ca-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3ca-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3ca.svg │ │ │ │ │ ├── 1f3cb-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fb.svg │ │ │ │ │ ├── 1f3cb-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fc.svg │ │ │ │ │ ├── 1f3cb-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fd.svg │ │ │ │ │ ├── 1f3cb-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3fe.svg │ │ │ │ │ ├── 1f3cb-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cb-1f3ff.svg │ │ │ │ │ ├── 1f3cb-fe0f-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cb-fe0f-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cb.svg │ │ │ │ │ ├── 1f3cc-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fb.svg │ │ │ │ │ ├── 1f3cc-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fc.svg │ │ │ │ │ ├── 1f3cc-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fd.svg │ │ │ │ │ ├── 1f3cc-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3fe.svg │ │ │ │ │ ├── 1f3cc-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cc-1f3ff.svg │ │ │ │ │ ├── 1f3cc-fe0f-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f3cc-fe0f-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f3cc.svg │ │ │ │ │ ├── 1f3cd.svg │ │ │ │ │ ├── 1f3ce.svg │ │ │ │ │ ├── 1f3cf.svg │ │ │ │ │ ├── 1f3d0.svg │ │ │ │ │ ├── 1f3d1.svg │ │ │ │ │ ├── 1f3d2.svg │ │ │ │ │ ├── 1f3d3.svg │ │ │ │ │ ├── 1f3d4.svg │ │ │ │ │ ├── 1f3d5.svg │ │ │ │ │ ├── 1f3d6.svg │ │ │ │ │ ├── 1f3d7.svg │ │ │ │ │ ├── 1f3d8.svg │ │ │ │ │ ├── 1f3d9.svg │ │ │ │ │ ├── 1f3da.svg │ │ │ │ │ ├── 1f3db.svg │ │ │ │ │ ├── 1f3dc.svg │ │ │ │ │ ├── 1f3dd.svg │ │ │ │ │ ├── 1f3de.svg │ │ │ │ │ ├── 1f3df.svg │ │ │ │ │ ├── 1f3e0.svg │ │ │ │ │ ├── 1f3e1.svg │ │ │ │ │ ├── 1f3e2.svg │ │ │ │ │ ├── 1f3e3.svg │ │ │ │ │ ├── 1f3e4.svg │ │ │ │ │ ├── 1f3e5.svg │ │ │ │ │ ├── 1f3e6.svg │ │ │ │ │ ├── 1f3e7.svg │ │ │ │ │ ├── 1f3e8.svg │ │ │ │ │ ├── 1f3e9.svg │ │ │ │ │ ├── 1f3ea.svg │ │ │ │ │ ├── 1f3eb.svg │ │ │ │ │ ├── 1f3ec.svg │ │ │ │ │ ├── 1f3ed.svg │ │ │ │ │ ├── 1f3ee.svg │ │ │ │ │ ├── 1f3ef.svg │ │ │ │ │ ├── 1f3f0.svg │ │ │ │ │ ├── 1f3f3-fe0f-200d-1f308.svg │ │ │ │ │ ├── 1f3f3.svg │ │ │ │ │ ├── 1f3f4-200d-2620-fe0f.svg │ │ │ │ │ ├── 1f3f4.svg │ │ │ │ │ ├── 1f3f5.svg │ │ │ │ │ ├── 1f3f7.svg │ │ │ │ │ ├── 1f3f8.svg │ │ │ │ │ ├── 1f3f9.svg │ │ │ │ │ ├── 1f3fa.svg │ │ │ │ │ ├── 1f3fb.svg │ │ │ │ │ ├── 1f3fc.svg │ │ │ │ │ ├── 1f3fd.svg │ │ │ │ │ ├── 1f3fe.svg │ │ │ │ │ ├── 1f3ff.svg │ │ │ │ │ ├── 1f400.svg │ │ │ │ │ ├── 1f401.svg │ │ │ │ │ ├── 1f402.svg │ │ │ │ │ ├── 1f403.svg │ │ │ │ │ ├── 1f404.svg │ │ │ │ │ ├── 1f405.svg │ │ │ │ │ ├── 1f406.svg │ │ │ │ │ ├── 1f407.svg │ │ │ │ │ ├── 1f408.svg │ │ │ │ │ ├── 1f409.svg │ │ │ │ │ ├── 1f40a.svg │ │ │ │ │ ├── 1f40b.svg │ │ │ │ │ ├── 1f40c.svg │ │ │ │ │ ├── 1f40d.svg │ │ │ │ │ ├── 1f40e.svg │ │ │ │ │ ├── 1f40f.svg │ │ │ │ │ ├── 1f410.svg │ │ │ │ │ ├── 1f411.svg │ │ │ │ │ ├── 1f412.svg │ │ │ │ │ ├── 1f413.svg │ │ │ │ │ ├── 1f414.svg │ │ │ │ │ ├── 1f415.svg │ │ │ │ │ ├── 1f416.svg │ │ │ │ │ ├── 1f417.svg │ │ │ │ │ ├── 1f418.svg │ │ │ │ │ ├── 1f419.svg │ │ │ │ │ ├── 1f41a.svg │ │ │ │ │ ├── 1f41b.svg │ │ │ │ │ ├── 1f41c.svg │ │ │ │ │ ├── 1f41d.svg │ │ │ │ │ ├── 1f41e.svg │ │ │ │ │ ├── 1f41f.svg │ │ │ │ │ ├── 1f420.svg │ │ │ │ │ ├── 1f421.svg │ │ │ │ │ ├── 1f422.svg │ │ │ │ │ ├── 1f423.svg │ │ │ │ │ ├── 1f424.svg │ │ │ │ │ ├── 1f425.svg │ │ │ │ │ ├── 1f426.svg │ │ │ │ │ ├── 1f427.svg │ │ │ │ │ ├── 1f428.svg │ │ │ │ │ ├── 1f429.svg │ │ │ │ │ ├── 1f42a.svg │ │ │ │ │ ├── 1f42b.svg │ │ │ │ │ ├── 1f42c.svg │ │ │ │ │ ├── 1f42d.svg │ │ │ │ │ ├── 1f42e.svg │ │ │ │ │ ├── 1f42f.svg │ │ │ │ │ ├── 1f430.svg │ │ │ │ │ ├── 1f431.svg │ │ │ │ │ ├── 1f432.svg │ │ │ │ │ ├── 1f433.svg │ │ │ │ │ ├── 1f434.svg │ │ │ │ │ ├── 1f435.svg │ │ │ │ │ ├── 1f436.svg │ │ │ │ │ ├── 1f437.svg │ │ │ │ │ ├── 1f438.svg │ │ │ │ │ ├── 1f439.svg │ │ │ │ │ ├── 1f43a.svg │ │ │ │ │ ├── 1f43b.svg │ │ │ │ │ ├── 1f43c.svg │ │ │ │ │ ├── 1f43d.svg │ │ │ │ │ ├── 1f43e.svg │ │ │ │ │ ├── 1f43f.svg │ │ │ │ │ ├── 1f440.svg │ │ │ │ │ ├── 1f441-200d-1f5e8.svg │ │ │ │ │ ├── 1f441.svg │ │ │ │ │ ├── 1f442-1f3fb.svg │ │ │ │ │ ├── 1f442-1f3fc.svg │ │ │ │ │ ├── 1f442-1f3fd.svg │ │ │ │ │ ├── 1f442-1f3fe.svg │ │ │ │ │ ├── 1f442-1f3ff.svg │ │ │ │ │ ├── 1f442.svg │ │ │ │ │ ├── 1f443-1f3fb.svg │ │ │ │ │ ├── 1f443-1f3fc.svg │ │ │ │ │ ├── 1f443-1f3fd.svg │ │ │ │ │ ├── 1f443-1f3fe.svg │ │ │ │ │ ├── 1f443-1f3ff.svg │ │ │ │ │ ├── 1f443.svg │ │ │ │ │ ├── 1f444.svg │ │ │ │ │ ├── 1f445.svg │ │ │ │ │ ├── 1f446-1f3fb.svg │ │ │ │ │ ├── 1f446-1f3fc.svg │ │ │ │ │ ├── 1f446-1f3fd.svg │ │ │ │ │ ├── 1f446-1f3fe.svg │ │ │ │ │ ├── 1f446-1f3ff.svg │ │ │ │ │ ├── 1f446.svg │ │ │ │ │ ├── 1f447-1f3fb.svg │ │ │ │ │ ├── 1f447-1f3fc.svg │ │ │ │ │ ├── 1f447-1f3fd.svg │ │ │ │ │ ├── 1f447-1f3fe.svg │ │ │ │ │ ├── 1f447-1f3ff.svg │ │ │ │ │ ├── 1f447.svg │ │ │ │ │ ├── 1f448-1f3fb.svg │ │ │ │ │ ├── 1f448-1f3fc.svg │ │ │ │ │ ├── 1f448-1f3fd.svg │ │ │ │ │ ├── 1f448-1f3fe.svg │ │ │ │ │ ├── 1f448-1f3ff.svg │ │ │ │ │ ├── 1f448.svg │ │ │ │ │ ├── 1f449-1f3fb.svg │ │ │ │ │ ├── 1f449-1f3fc.svg │ │ │ │ │ ├── 1f449-1f3fd.svg │ │ │ │ │ ├── 1f449-1f3fe.svg │ │ │ │ │ ├── 1f449-1f3ff.svg │ │ │ │ │ ├── 1f449.svg │ │ │ │ │ ├── 1f44a-1f3fb.svg │ │ │ │ │ ├── 1f44a-1f3fc.svg │ │ │ │ │ ├── 1f44a-1f3fd.svg │ │ │ │ │ ├── 1f44a-1f3fe.svg │ │ │ │ │ ├── 1f44a-1f3ff.svg │ │ │ │ │ ├── 1f44a.svg │ │ │ │ │ ├── 1f44b-1f3fb.svg │ │ │ │ │ ├── 1f44b-1f3fc.svg │ │ │ │ │ ├── 1f44b-1f3fd.svg │ │ │ │ │ ├── 1f44b-1f3fe.svg │ │ │ │ │ ├── 1f44b-1f3ff.svg │ │ │ │ │ ├── 1f44b.svg │ │ │ │ │ ├── 1f44c-1f3fb.svg │ │ │ │ │ ├── 1f44c-1f3fc.svg │ │ │ │ │ ├── 1f44c-1f3fd.svg │ │ │ │ │ ├── 1f44c-1f3fe.svg │ │ │ │ │ ├── 1f44c-1f3ff.svg │ │ │ │ │ ├── 1f44c.svg │ │ │ │ │ ├── 1f44d-1f3fb.svg │ │ │ │ │ ├── 1f44d-1f3fc.svg │ │ │ │ │ ├── 1f44d-1f3fd.svg │ │ │ │ │ ├── 1f44d-1f3fe.svg │ │ │ │ │ ├── 1f44d-1f3ff.svg │ │ │ │ │ ├── 1f44d.svg │ │ │ │ │ ├── 1f44e-1f3fb.svg │ │ │ │ │ ├── 1f44e-1f3fc.svg │ │ │ │ │ ├── 1f44e-1f3fd.svg │ │ │ │ │ ├── 1f44e-1f3fe.svg │ │ │ │ │ ├── 1f44e-1f3ff.svg │ │ │ │ │ ├── 1f44e.svg │ │ │ │ │ ├── 1f44f-1f3fb.svg │ │ │ │ │ ├── 1f44f-1f3fc.svg │ │ │ │ │ ├── 1f44f-1f3fd.svg │ │ │ │ │ ├── 1f44f-1f3fe.svg │ │ │ │ │ ├── 1f44f-1f3ff.svg │ │ │ │ │ ├── 1f44f.svg │ │ │ │ │ ├── 1f450-1f3fb.svg │ │ │ │ │ ├── 1f450-1f3fc.svg │ │ │ │ │ ├── 1f450-1f3fd.svg │ │ │ │ │ ├── 1f450-1f3fe.svg │ │ │ │ │ ├── 1f450-1f3ff.svg │ │ │ │ │ ├── 1f450.svg │ │ │ │ │ ├── 1f451.svg │ │ │ │ │ ├── 1f452.svg │ │ │ │ │ ├── 1f453.svg │ │ │ │ │ ├── 1f454.svg │ │ │ │ │ ├── 1f455.svg │ │ │ │ │ ├── 1f456.svg │ │ │ │ │ ├── 1f457.svg │ │ │ │ │ ├── 1f458.svg │ │ │ │ │ ├── 1f459.svg │ │ │ │ │ ├── 1f45a.svg │ │ │ │ │ ├── 1f45b.svg │ │ │ │ │ ├── 1f45c.svg │ │ │ │ │ ├── 1f45d.svg │ │ │ │ │ ├── 1f45e.svg │ │ │ │ │ ├── 1f45f.svg │ │ │ │ │ ├── 1f460.svg │ │ │ │ │ ├── 1f461.svg │ │ │ │ │ ├── 1f462.svg │ │ │ │ │ ├── 1f463.svg │ │ │ │ │ ├── 1f464.svg │ │ │ │ │ ├── 1f465.svg │ │ │ │ │ ├── 1f466-1f3fb.svg │ │ │ │ │ ├── 1f466-1f3fc.svg │ │ │ │ │ ├── 1f466-1f3fd.svg │ │ │ │ │ ├── 1f466-1f3fe.svg │ │ │ │ │ ├── 1f466-1f3ff.svg │ │ │ │ │ ├── 1f466.svg │ │ │ │ │ ├── 1f467-1f3fb.svg │ │ │ │ │ ├── 1f467-1f3fc.svg │ │ │ │ │ ├── 1f467-1f3fd.svg │ │ │ │ │ ├── 1f467-1f3fe.svg │ │ │ │ │ ├── 1f467-1f3ff.svg │ │ │ │ │ ├── 1f467.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f33e.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f373.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f393.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f3a4.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f3a8.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f3eb.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f3ed.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f4bb.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f4bc.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f527.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f52c.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f680.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-1f692.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fb-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fb.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f33e.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f373.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f393.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f3a4.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f3a8.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f3eb.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f3ed.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f4bb.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f4bc.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f527.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f52c.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f680.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-1f692.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fc-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fc.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f33e.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f373.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f393.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f3a4.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f3a8.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f3eb.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f3ed.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f4bb.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f4bc.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f527.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f52c.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f680.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-1f692.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fd-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fd.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f33e.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f373.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f393.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f3a4.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f3a8.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f3eb.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f3ed.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f4bb.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f4bc.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f527.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f52c.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f680.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-1f692.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fe-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f468-1f3fe.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f33e.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f373.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f393.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f3a4.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f3a8.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f3eb.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f3ed.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f4bb.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f4bc.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f527.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f52c.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f680.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-1f692.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f468-1f3ff-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f468-1f3ff.svg │ │ │ │ │ ├── 1f468-200d-1f33e.svg │ │ │ │ │ ├── 1f468-200d-1f373.svg │ │ │ │ │ ├── 1f468-200d-1f393.svg │ │ │ │ │ ├── 1f468-200d-1f3a4.svg │ │ │ │ │ ├── 1f468-200d-1f3a8.svg │ │ │ │ │ ├── 1f468-200d-1f3eb.svg │ │ │ │ │ ├── 1f468-200d-1f3ed.svg │ │ │ │ │ ├── 1f468-200d-1f466-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f467-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f467-200d-1f467.svg │ │ │ │ │ ├── 1f468-200d-1f467.svg │ │ │ │ │ ├── 1f468-200d-1f468-200d-1f466-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f468-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f468-200d-1f467-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f468-200d-1f467-200d-1f467.svg │ │ │ │ │ ├── 1f468-200d-1f468-200d-1f467.svg │ │ │ │ │ ├── 1f468-200d-1f469-200d-1f466-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f469-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f469-200d-1f467-200d-1f466.svg │ │ │ │ │ ├── 1f468-200d-1f469-200d-1f467-200d-1f467.svg │ │ │ │ │ ├── 1f468-200d-1f469-200d-1f467.svg │ │ │ │ │ ├── 1f468-200d-1f4bb.svg │ │ │ │ │ ├── 1f468-200d-1f4bc.svg │ │ │ │ │ ├── 1f468-200d-1f527.svg │ │ │ │ │ ├── 1f468-200d-1f52c.svg │ │ │ │ │ ├── 1f468-200d-1f680.svg │ │ │ │ │ ├── 1f468-200d-1f692.svg │ │ │ │ │ ├── 1f468-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f468-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f468-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f468-200d-2764-fe0f-200d-1f468.svg │ │ │ │ │ ├── 1f468-200d-2764-fe0f-200d-1f48b-200d-1f468.svg │ │ │ │ │ ├── 1f468.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f33e.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f373.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f393.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f3a4.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f3a8.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f3eb.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f3ed.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f4bb.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f4bc.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f527.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f52c.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f680.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-1f692.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fb-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fb.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f33e.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f373.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f393.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f3a4.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f3a8.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f3eb.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f3ed.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f4bb.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f4bc.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f527.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f52c.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f680.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-1f692.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fc-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fc.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f33e.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f373.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f393.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f3a4.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f3a8.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f3eb.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f3ed.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f4bb.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f4bc.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f527.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f52c.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f680.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-1f692.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fd-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fd.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f33e.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f373.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f393.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f3a4.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f3a8.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f3eb.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f3ed.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f4bb.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f4bc.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f527.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f52c.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f680.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-1f692.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fe-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f469-1f3fe.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f33e.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f373.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f393.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f3a4.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f3a8.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f3eb.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f3ed.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f4bb.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f4bc.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f527.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f52c.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f680.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-1f692.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f469-1f3ff-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f469-1f3ff.svg │ │ │ │ │ ├── 1f469-200d-1f33e.svg │ │ │ │ │ ├── 1f469-200d-1f373.svg │ │ │ │ │ ├── 1f469-200d-1f393.svg │ │ │ │ │ ├── 1f469-200d-1f3a4.svg │ │ │ │ │ ├── 1f469-200d-1f3a8.svg │ │ │ │ │ ├── 1f469-200d-1f3eb.svg │ │ │ │ │ ├── 1f469-200d-1f3ed.svg │ │ │ │ │ ├── 1f469-200d-1f466-200d-1f466.svg │ │ │ │ │ ├── 1f469-200d-1f466.svg │ │ │ │ │ ├── 1f469-200d-1f467-200d-1f466.svg │ │ │ │ │ ├── 1f469-200d-1f467-200d-1f467.svg │ │ │ │ │ ├── 1f469-200d-1f467.svg │ │ │ │ │ ├── 1f469-200d-1f469-200d-1f466-200d-1f466.svg │ │ │ │ │ ├── 1f469-200d-1f469-200d-1f466.svg │ │ │ │ │ ├── 1f469-200d-1f469-200d-1f467-200d-1f466.svg │ │ │ │ │ ├── 1f469-200d-1f469-200d-1f467-200d-1f467.svg │ │ │ │ │ ├── 1f469-200d-1f469-200d-1f467.svg │ │ │ │ │ ├── 1f469-200d-1f4bb.svg │ │ │ │ │ ├── 1f469-200d-1f4bc.svg │ │ │ │ │ ├── 1f469-200d-1f527.svg │ │ │ │ │ ├── 1f469-200d-1f52c.svg │ │ │ │ │ ├── 1f469-200d-1f680.svg │ │ │ │ │ ├── 1f469-200d-1f692.svg │ │ │ │ │ ├── 1f469-200d-2695-fe0f.svg │ │ │ │ │ ├── 1f469-200d-2696-fe0f.svg │ │ │ │ │ ├── 1f469-200d-2708-fe0f.svg │ │ │ │ │ ├── 1f469-200d-2764-fe0f-200d-1f468.svg │ │ │ │ │ ├── 1f469-200d-2764-fe0f-200d-1f469.svg │ │ │ │ │ ├── 1f469-200d-2764-fe0f-200d-1f48b-200d-1f468.svg │ │ │ │ │ ├── 1f469-200d-2764-fe0f-200d-1f48b-200d-1f469.svg │ │ │ │ │ ├── 1f469.svg │ │ │ │ │ ├── 1f46a.svg │ │ │ │ │ ├── 1f46b.svg │ │ │ │ │ ├── 1f46c.svg │ │ │ │ │ ├── 1f46d.svg │ │ │ │ │ ├── 1f46e-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fb.svg │ │ │ │ │ ├── 1f46e-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fc.svg │ │ │ │ │ ├── 1f46e-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fd.svg │ │ │ │ │ ├── 1f46e-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3fe.svg │ │ │ │ │ ├── 1f46e-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f46e-1f3ff.svg │ │ │ │ │ ├── 1f46e-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f46e-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f46e.svg │ │ │ │ │ ├── 1f46f-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f46f-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f46f.svg │ │ │ │ │ ├── 1f470-1f3fb.svg │ │ │ │ │ ├── 1f470-1f3fc.svg │ │ │ │ │ ├── 1f470-1f3fd.svg │ │ │ │ │ ├── 1f470-1f3fe.svg │ │ │ │ │ ├── 1f470-1f3ff.svg │ │ │ │ │ ├── 1f470.svg │ │ │ │ │ ├── 1f471-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fb.svg │ │ │ │ │ ├── 1f471-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fc.svg │ │ │ │ │ ├── 1f471-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fd.svg │ │ │ │ │ ├── 1f471-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f471-1f3fe.svg │ │ │ │ │ ├── 1f471-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f471-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f471-1f3ff.svg │ │ │ │ │ ├── 1f471-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f471-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f471.svg │ │ │ │ │ ├── 1f472-1f3fb.svg │ │ │ │ │ ├── 1f472-1f3fc.svg │ │ │ │ │ ├── 1f472-1f3fd.svg │ │ │ │ │ ├── 1f472-1f3fe.svg │ │ │ │ │ ├── 1f472-1f3ff.svg │ │ │ │ │ ├── 1f472.svg │ │ │ │ │ ├── 1f473-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fb.svg │ │ │ │ │ ├── 1f473-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fc.svg │ │ │ │ │ ├── 1f473-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fd.svg │ │ │ │ │ ├── 1f473-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f473-1f3fe.svg │ │ │ │ │ ├── 1f473-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f473-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f473-1f3ff.svg │ │ │ │ │ ├── 1f473-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f473-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f473.svg │ │ │ │ │ ├── 1f474-1f3fb.svg │ │ │ │ │ ├── 1f474-1f3fc.svg │ │ │ │ │ ├── 1f474-1f3fd.svg │ │ │ │ │ ├── 1f474-1f3fe.svg │ │ │ │ │ ├── 1f474-1f3ff.svg │ │ │ │ │ ├── 1f474.svg │ │ │ │ │ ├── 1f475-1f3fb.svg │ │ │ │ │ ├── 1f475-1f3fc.svg │ │ │ │ │ ├── 1f475-1f3fd.svg │ │ │ │ │ ├── 1f475-1f3fe.svg │ │ │ │ │ ├── 1f475-1f3ff.svg │ │ │ │ │ ├── 1f475.svg │ │ │ │ │ ├── 1f476-1f3fb.svg │ │ │ │ │ ├── 1f476-1f3fc.svg │ │ │ │ │ ├── 1f476-1f3fd.svg │ │ │ │ │ ├── 1f476-1f3fe.svg │ │ │ │ │ ├── 1f476-1f3ff.svg │ │ │ │ │ ├── 1f476.svg │ │ │ │ │ ├── 1f477-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fb.svg │ │ │ │ │ ├── 1f477-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fc.svg │ │ │ │ │ ├── 1f477-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fd.svg │ │ │ │ │ ├── 1f477-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f477-1f3fe.svg │ │ │ │ │ ├── 1f477-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f477-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f477-1f3ff.svg │ │ │ │ │ ├── 1f477-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f477-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f477.svg │ │ │ │ │ ├── 1f478-1f3fb.svg │ │ │ │ │ ├── 1f478-1f3fc.svg │ │ │ │ │ ├── 1f478-1f3fd.svg │ │ │ │ │ ├── 1f478-1f3fe.svg │ │ │ │ │ ├── 1f478-1f3ff.svg │ │ │ │ │ ├── 1f478.svg │ │ │ │ │ ├── 1f479.svg │ │ │ │ │ ├── 1f47a.svg │ │ │ │ │ ├── 1f47b.svg │ │ │ │ │ ├── 1f47c-1f3fb.svg │ │ │ │ │ ├── 1f47c-1f3fc.svg │ │ │ │ │ ├── 1f47c-1f3fd.svg │ │ │ │ │ ├── 1f47c-1f3fe.svg │ │ │ │ │ ├── 1f47c-1f3ff.svg │ │ │ │ │ ├── 1f47c.svg │ │ │ │ │ ├── 1f47d.svg │ │ │ │ │ ├── 1f47e.svg │ │ │ │ │ ├── 1f47f.svg │ │ │ │ │ ├── 1f480.svg │ │ │ │ │ ├── 1f481-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fb.svg │ │ │ │ │ ├── 1f481-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fc.svg │ │ │ │ │ ├── 1f481-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fd.svg │ │ │ │ │ ├── 1f481-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f481-1f3fe.svg │ │ │ │ │ ├── 1f481-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f481-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f481-1f3ff.svg │ │ │ │ │ ├── 1f481-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f481-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f481.svg │ │ │ │ │ ├── 1f482-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fb.svg │ │ │ │ │ ├── 1f482-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fc.svg │ │ │ │ │ ├── 1f482-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fd.svg │ │ │ │ │ ├── 1f482-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f482-1f3fe.svg │ │ │ │ │ ├── 1f482-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f482-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f482-1f3ff.svg │ │ │ │ │ ├── 1f482-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f482-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f482.svg │ │ │ │ │ ├── 1f483-1f3fb.svg │ │ │ │ │ ├── 1f483-1f3fc.svg │ │ │ │ │ ├── 1f483-1f3fd.svg │ │ │ │ │ ├── 1f483-1f3fe.svg │ │ │ │ │ ├── 1f483-1f3ff.svg │ │ │ │ │ ├── 1f483.svg │ │ │ │ │ ├── 1f484.svg │ │ │ │ │ ├── 1f485-1f3fb.svg │ │ │ │ │ ├── 1f485-1f3fc.svg │ │ │ │ │ ├── 1f485-1f3fd.svg │ │ │ │ │ ├── 1f485-1f3fe.svg │ │ │ │ │ ├── 1f485-1f3ff.svg │ │ │ │ │ ├── 1f485.svg │ │ │ │ │ ├── 1f486-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fb.svg │ │ │ │ │ ├── 1f486-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fc.svg │ │ │ │ │ ├── 1f486-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fd.svg │ │ │ │ │ ├── 1f486-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f486-1f3fe.svg │ │ │ │ │ ├── 1f486-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f486-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f486-1f3ff.svg │ │ │ │ │ ├── 1f486-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f486-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f486.svg │ │ │ │ │ ├── 1f487-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fb.svg │ │ │ │ │ ├── 1f487-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fc.svg │ │ │ │ │ ├── 1f487-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fd.svg │ │ │ │ │ ├── 1f487-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f487-1f3fe.svg │ │ │ │ │ ├── 1f487-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f487-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f487-1f3ff.svg │ │ │ │ │ ├── 1f487-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f487-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f487.svg │ │ │ │ │ ├── 1f488.svg │ │ │ │ │ ├── 1f489.svg │ │ │ │ │ ├── 1f48a.svg │ │ │ │ │ ├── 1f48b.svg │ │ │ │ │ ├── 1f48c.svg │ │ │ │ │ ├── 1f48d.svg │ │ │ │ │ ├── 1f48e.svg │ │ │ │ │ ├── 1f48f.svg │ │ │ │ │ ├── 1f490.svg │ │ │ │ │ ├── 1f491.svg │ │ │ │ │ ├── 1f492.svg │ │ │ │ │ ├── 1f493.svg │ │ │ │ │ ├── 1f494.svg │ │ │ │ │ ├── 1f495.svg │ │ │ │ │ ├── 1f496.svg │ │ │ │ │ ├── 1f497.svg │ │ │ │ │ ├── 1f498.svg │ │ │ │ │ ├── 1f499.svg │ │ │ │ │ ├── 1f49a.svg │ │ │ │ │ ├── 1f49b.svg │ │ │ │ │ ├── 1f49c.svg │ │ │ │ │ ├── 1f49d.svg │ │ │ │ │ ├── 1f49e.svg │ │ │ │ │ ├── 1f49f.svg │ │ │ │ │ ├── 1f4a0.svg │ │ │ │ │ ├── 1f4a1.svg │ │ │ │ │ ├── 1f4a2.svg │ │ │ │ │ ├── 1f4a3.svg │ │ │ │ │ ├── 1f4a4.svg │ │ │ │ │ ├── 1f4a5.svg │ │ │ │ │ ├── 1f4a6.svg │ │ │ │ │ ├── 1f4a7.svg │ │ │ │ │ ├── 1f4a8.svg │ │ │ │ │ ├── 1f4a9.svg │ │ │ │ │ ├── 1f4aa-1f3fb.svg │ │ │ │ │ ├── 1f4aa-1f3fc.svg │ │ │ │ │ ├── 1f4aa-1f3fd.svg │ │ │ │ │ ├── 1f4aa-1f3fe.svg │ │ │ │ │ ├── 1f4aa-1f3ff.svg │ │ │ │ │ ├── 1f4aa.svg │ │ │ │ │ ├── 1f4ab.svg │ │ │ │ │ ├── 1f4ac.svg │ │ │ │ │ ├── 1f4ad.svg │ │ │ │ │ ├── 1f4ae.svg │ │ │ │ │ ├── 1f4af.svg │ │ │ │ │ ├── 1f4b0.svg │ │ │ │ │ ├── 1f4b1.svg │ │ │ │ │ ├── 1f4b2.svg │ │ │ │ │ ├── 1f4b3.svg │ │ │ │ │ ├── 1f4b4.svg │ │ │ │ │ ├── 1f4b5.svg │ │ │ │ │ ├── 1f4b6.svg │ │ │ │ │ ├── 1f4b7.svg │ │ │ │ │ ├── 1f4b8.svg │ │ │ │ │ ├── 1f4b9.svg │ │ │ │ │ ├── 1f4ba.svg │ │ │ │ │ ├── 1f4bb.svg │ │ │ │ │ ├── 1f4bc.svg │ │ │ │ │ ├── 1f4bd.svg │ │ │ │ │ ├── 1f4be.svg │ │ │ │ │ ├── 1f4bf.svg │ │ │ │ │ ├── 1f4c0.svg │ │ │ │ │ ├── 1f4c1.svg │ │ │ │ │ ├── 1f4c2.svg │ │ │ │ │ ├── 1f4c3.svg │ │ │ │ │ ├── 1f4c4.svg │ │ │ │ │ ├── 1f4c5.svg │ │ │ │ │ ├── 1f4c6.svg │ │ │ │ │ ├── 1f4c7.svg │ │ │ │ │ ├── 1f4c8.svg │ │ │ │ │ ├── 1f4c9.svg │ │ │ │ │ ├── 1f4ca.svg │ │ │ │ │ ├── 1f4cb.svg │ │ │ │ │ ├── 1f4cc.svg │ │ │ │ │ ├── 1f4cd.svg │ │ │ │ │ ├── 1f4ce.svg │ │ │ │ │ ├── 1f4cf.svg │ │ │ │ │ ├── 1f4d0.svg │ │ │ │ │ ├── 1f4d1.svg │ │ │ │ │ ├── 1f4d2.svg │ │ │ │ │ ├── 1f4d3.svg │ │ │ │ │ ├── 1f4d4.svg │ │ │ │ │ ├── 1f4d5.svg │ │ │ │ │ ├── 1f4d6.svg │ │ │ │ │ ├── 1f4d7.svg │ │ │ │ │ ├── 1f4d8.svg │ │ │ │ │ ├── 1f4d9.svg │ │ │ │ │ ├── 1f4da.svg │ │ │ │ │ ├── 1f4db.svg │ │ │ │ │ ├── 1f4dc.svg │ │ │ │ │ ├── 1f4dd.svg │ │ │ │ │ ├── 1f4de.svg │ │ │ │ │ ├── 1f4df.svg │ │ │ │ │ ├── 1f4e0.svg │ │ │ │ │ ├── 1f4e1.svg │ │ │ │ │ ├── 1f4e2.svg │ │ │ │ │ ├── 1f4e3.svg │ │ │ │ │ ├── 1f4e4.svg │ │ │ │ │ ├── 1f4e5.svg │ │ │ │ │ ├── 1f4e6.svg │ │ │ │ │ ├── 1f4e7.svg │ │ │ │ │ ├── 1f4e8.svg │ │ │ │ │ ├── 1f4e9.svg │ │ │ │ │ ├── 1f4ea.svg │ │ │ │ │ ├── 1f4eb.svg │ │ │ │ │ ├── 1f4ec.svg │ │ │ │ │ ├── 1f4ed.svg │ │ │ │ │ ├── 1f4ee.svg │ │ │ │ │ ├── 1f4ef.svg │ │ │ │ │ ├── 1f4f0.svg │ │ │ │ │ ├── 1f4f1.svg │ │ │ │ │ ├── 1f4f2.svg │ │ │ │ │ ├── 1f4f3.svg │ │ │ │ │ ├── 1f4f4.svg │ │ │ │ │ ├── 1f4f5.svg │ │ │ │ │ ├── 1f4f6.svg │ │ │ │ │ ├── 1f4f7.svg │ │ │ │ │ ├── 1f4f8.svg │ │ │ │ │ ├── 1f4f9.svg │ │ │ │ │ ├── 1f4fa.svg │ │ │ │ │ ├── 1f4fb.svg │ │ │ │ │ ├── 1f4fc.svg │ │ │ │ │ ├── 1f4fd.svg │ │ │ │ │ ├── 1f4ff.svg │ │ │ │ │ ├── 1f500.svg │ │ │ │ │ ├── 1f501.svg │ │ │ │ │ ├── 1f502.svg │ │ │ │ │ ├── 1f503.svg │ │ │ │ │ ├── 1f504.svg │ │ │ │ │ ├── 1f505.svg │ │ │ │ │ ├── 1f506.svg │ │ │ │ │ ├── 1f507.svg │ │ │ │ │ ├── 1f508.svg │ │ │ │ │ ├── 1f509.svg │ │ │ │ │ ├── 1f50a.svg │ │ │ │ │ ├── 1f50b.svg │ │ │ │ │ ├── 1f50c.svg │ │ │ │ │ ├── 1f50d.svg │ │ │ │ │ ├── 1f50e.svg │ │ │ │ │ ├── 1f50f.svg │ │ │ │ │ ├── 1f510.svg │ │ │ │ │ ├── 1f511.svg │ │ │ │ │ ├── 1f512.svg │ │ │ │ │ ├── 1f513.svg │ │ │ │ │ ├── 1f514.svg │ │ │ │ │ ├── 1f515.svg │ │ │ │ │ ├── 1f516.svg │ │ │ │ │ ├── 1f517.svg │ │ │ │ │ ├── 1f518.svg │ │ │ │ │ ├── 1f519.svg │ │ │ │ │ ├── 1f51a.svg │ │ │ │ │ ├── 1f51b.svg │ │ │ │ │ ├── 1f51c.svg │ │ │ │ │ ├── 1f51d.svg │ │ │ │ │ ├── 1f51e.svg │ │ │ │ │ ├── 1f51f.svg │ │ │ │ │ ├── 1f520.svg │ │ │ │ │ ├── 1f521.svg │ │ │ │ │ ├── 1f522.svg │ │ │ │ │ ├── 1f523.svg │ │ │ │ │ ├── 1f524.svg │ │ │ │ │ ├── 1f525.svg │ │ │ │ │ ├── 1f526.svg │ │ │ │ │ ├── 1f527.svg │ │ │ │ │ ├── 1f528.svg │ │ │ │ │ ├── 1f529.svg │ │ │ │ │ ├── 1f52a.svg │ │ │ │ │ ├── 1f52b.svg │ │ │ │ │ ├── 1f52c.svg │ │ │ │ │ ├── 1f52d.svg │ │ │ │ │ ├── 1f52e.svg │ │ │ │ │ ├── 1f52f.svg │ │ │ │ │ ├── 1f530.svg │ │ │ │ │ ├── 1f531.svg │ │ │ │ │ ├── 1f532.svg │ │ │ │ │ ├── 1f533.svg │ │ │ │ │ ├── 1f534.svg │ │ │ │ │ ├── 1f535.svg │ │ │ │ │ ├── 1f536.svg │ │ │ │ │ ├── 1f537.svg │ │ │ │ │ ├── 1f538.svg │ │ │ │ │ ├── 1f539.svg │ │ │ │ │ ├── 1f53a.svg │ │ │ │ │ ├── 1f53b.svg │ │ │ │ │ ├── 1f53c.svg │ │ │ │ │ ├── 1f53d.svg │ │ │ │ │ ├── 1f549.svg │ │ │ │ │ ├── 1f54a.svg │ │ │ │ │ ├── 1f54b.svg │ │ │ │ │ ├── 1f54c.svg │ │ │ │ │ ├── 1f54d.svg │ │ │ │ │ ├── 1f54e.svg │ │ │ │ │ ├── 1f550.svg │ │ │ │ │ ├── 1f551.svg │ │ │ │ │ ├── 1f552.svg │ │ │ │ │ ├── 1f553.svg │ │ │ │ │ ├── 1f554.svg │ │ │ │ │ ├── 1f555.svg │ │ │ │ │ ├── 1f556.svg │ │ │ │ │ ├── 1f557.svg │ │ │ │ │ ├── 1f558.svg │ │ │ │ │ ├── 1f559.svg │ │ │ │ │ ├── 1f55a.svg │ │ │ │ │ ├── 1f55b.svg │ │ │ │ │ ├── 1f55c.svg │ │ │ │ │ ├── 1f55d.svg │ │ │ │ │ ├── 1f55e.svg │ │ │ │ │ ├── 1f55f.svg │ │ │ │ │ ├── 1f560.svg │ │ │ │ │ ├── 1f561.svg │ │ │ │ │ ├── 1f562.svg │ │ │ │ │ ├── 1f563.svg │ │ │ │ │ ├── 1f564.svg │ │ │ │ │ ├── 1f565.svg │ │ │ │ │ ├── 1f566.svg │ │ │ │ │ ├── 1f567.svg │ │ │ │ │ ├── 1f56f.svg │ │ │ │ │ ├── 1f570.svg │ │ │ │ │ ├── 1f573.svg │ │ │ │ │ ├── 1f574-1f3fb.svg │ │ │ │ │ ├── 1f574-1f3fc.svg │ │ │ │ │ ├── 1f574-1f3fd.svg │ │ │ │ │ ├── 1f574-1f3fe.svg │ │ │ │ │ ├── 1f574-1f3ff.svg │ │ │ │ │ ├── 1f574.svg │ │ │ │ │ ├── 1f575-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fb.svg │ │ │ │ │ ├── 1f575-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fc.svg │ │ │ │ │ ├── 1f575-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fd.svg │ │ │ │ │ ├── 1f575-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f575-1f3fe.svg │ │ │ │ │ ├── 1f575-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f575-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f575-1f3ff.svg │ │ │ │ │ ├── 1f575-fe0f-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f575-fe0f-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f575.svg │ │ │ │ │ ├── 1f576.svg │ │ │ │ │ ├── 1f577.svg │ │ │ │ │ ├── 1f578.svg │ │ │ │ │ ├── 1f579.svg │ │ │ │ │ ├── 1f57a-1f3fb.svg │ │ │ │ │ ├── 1f57a-1f3fc.svg │ │ │ │ │ ├── 1f57a-1f3fd.svg │ │ │ │ │ ├── 1f57a-1f3fe.svg │ │ │ │ │ ├── 1f57a-1f3ff.svg │ │ │ │ │ ├── 1f57a.svg │ │ │ │ │ ├── 1f587.svg │ │ │ │ │ ├── 1f58a.svg │ │ │ │ │ ├── 1f58b.svg │ │ │ │ │ ├── 1f58c.svg │ │ │ │ │ ├── 1f58d.svg │ │ │ │ │ ├── 1f590-1f3fb.svg │ │ │ │ │ ├── 1f590-1f3fc.svg │ │ │ │ │ ├── 1f590-1f3fd.svg │ │ │ │ │ ├── 1f590-1f3fe.svg │ │ │ │ │ ├── 1f590-1f3ff.svg │ │ │ │ │ ├── 1f590.svg │ │ │ │ │ ├── 1f595-1f3fb.svg │ │ │ │ │ ├── 1f595-1f3fc.svg │ │ │ │ │ ├── 1f595-1f3fd.svg │ │ │ │ │ ├── 1f595-1f3fe.svg │ │ │ │ │ ├── 1f595-1f3ff.svg │ │ │ │ │ ├── 1f595.svg │ │ │ │ │ ├── 1f596-1f3fb.svg │ │ │ │ │ ├── 1f596-1f3fc.svg │ │ │ │ │ ├── 1f596-1f3fd.svg │ │ │ │ │ ├── 1f596-1f3fe.svg │ │ │ │ │ ├── 1f596-1f3ff.svg │ │ │ │ │ ├── 1f596.svg │ │ │ │ │ ├── 1f5a4.svg │ │ │ │ │ ├── 1f5a5.svg │ │ │ │ │ ├── 1f5a8.svg │ │ │ │ │ ├── 1f5b1.svg │ │ │ │ │ ├── 1f5b2.svg │ │ │ │ │ ├── 1f5bc.svg │ │ │ │ │ ├── 1f5c2.svg │ │ │ │ │ ├── 1f5c3.svg │ │ │ │ │ ├── 1f5c4.svg │ │ │ │ │ ├── 1f5d1.svg │ │ │ │ │ ├── 1f5d2.svg │ │ │ │ │ ├── 1f5d3.svg │ │ │ │ │ ├── 1f5dc.svg │ │ │ │ │ ├── 1f5dd.svg │ │ │ │ │ ├── 1f5de.svg │ │ │ │ │ ├── 1f5e1.svg │ │ │ │ │ ├── 1f5e3.svg │ │ │ │ │ ├── 1f5e8.svg │ │ │ │ │ ├── 1f5ef.svg │ │ │ │ │ ├── 1f5f3.svg │ │ │ │ │ ├── 1f5fa.svg │ │ │ │ │ ├── 1f5fb.svg │ │ │ │ │ ├── 1f5fc.svg │ │ │ │ │ ├── 1f5fd.svg │ │ │ │ │ ├── 1f5fe.svg │ │ │ │ │ ├── 1f5ff.svg │ │ │ │ │ ├── 1f600.svg │ │ │ │ │ ├── 1f601.svg │ │ │ │ │ ├── 1f602.svg │ │ │ │ │ ├── 1f603.svg │ │ │ │ │ ├── 1f604.svg │ │ │ │ │ ├── 1f605.svg │ │ │ │ │ ├── 1f606.svg │ │ │ │ │ ├── 1f607.svg │ │ │ │ │ ├── 1f608.svg │ │ │ │ │ ├── 1f609.svg │ │ │ │ │ ├── 1f60a.svg │ │ │ │ │ ├── 1f60b.svg │ │ │ │ │ ├── 1f60c.svg │ │ │ │ │ ├── 1f60d.svg │ │ │ │ │ ├── 1f60e.svg │ │ │ │ │ ├── 1f60f.svg │ │ │ │ │ ├── 1f610.svg │ │ │ │ │ ├── 1f611.svg │ │ │ │ │ ├── 1f612.svg │ │ │ │ │ ├── 1f613.svg │ │ │ │ │ ├── 1f614.svg │ │ │ │ │ ├── 1f615.svg │ │ │ │ │ ├── 1f616.svg │ │ │ │ │ ├── 1f617.svg │ │ │ │ │ ├── 1f618.svg │ │ │ │ │ ├── 1f619.svg │ │ │ │ │ ├── 1f61a.svg │ │ │ │ │ ├── 1f61b.svg │ │ │ │ │ ├── 1f61c.svg │ │ │ │ │ ├── 1f61d.svg │ │ │ │ │ ├── 1f61e.svg │ │ │ │ │ ├── 1f61f.svg │ │ │ │ │ ├── 1f620.svg │ │ │ │ │ ├── 1f621.svg │ │ │ │ │ ├── 1f622.svg │ │ │ │ │ ├── 1f623.svg │ │ │ │ │ ├── 1f624.svg │ │ │ │ │ ├── 1f625.svg │ │ │ │ │ ├── 1f626.svg │ │ │ │ │ ├── 1f627.svg │ │ │ │ │ ├── 1f628.svg │ │ │ │ │ ├── 1f629.svg │ │ │ │ │ ├── 1f62a.svg │ │ │ │ │ ├── 1f62b.svg │ │ │ │ │ ├── 1f62c.svg │ │ │ │ │ ├── 1f62d.svg │ │ │ │ │ ├── 1f62e.svg │ │ │ │ │ ├── 1f62f.svg │ │ │ │ │ ├── 1f630.svg │ │ │ │ │ ├── 1f631.svg │ │ │ │ │ ├── 1f632.svg │ │ │ │ │ ├── 1f633.svg │ │ │ │ │ ├── 1f634.svg │ │ │ │ │ ├── 1f635.svg │ │ │ │ │ ├── 1f636.svg │ │ │ │ │ ├── 1f637.svg │ │ │ │ │ ├── 1f638.svg │ │ │ │ │ ├── 1f639.svg │ │ │ │ │ ├── 1f63a.svg │ │ │ │ │ ├── 1f63b.svg │ │ │ │ │ ├── 1f63c.svg │ │ │ │ │ ├── 1f63d.svg │ │ │ │ │ ├── 1f63e.svg │ │ │ │ │ ├── 1f63f.svg │ │ │ │ │ ├── 1f640.svg │ │ │ │ │ ├── 1f641.svg │ │ │ │ │ ├── 1f642.svg │ │ │ │ │ ├── 1f643.svg │ │ │ │ │ ├── 1f644.svg │ │ │ │ │ ├── 1f645-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fb.svg │ │ │ │ │ ├── 1f645-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fc.svg │ │ │ │ │ ├── 1f645-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fd.svg │ │ │ │ │ ├── 1f645-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f645-1f3fe.svg │ │ │ │ │ ├── 1f645-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f645-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f645-1f3ff.svg │ │ │ │ │ ├── 1f645-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f645-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f645.svg │ │ │ │ │ ├── 1f646-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fb.svg │ │ │ │ │ ├── 1f646-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fc.svg │ │ │ │ │ ├── 1f646-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fd.svg │ │ │ │ │ ├── 1f646-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f646-1f3fe.svg │ │ │ │ │ ├── 1f646-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f646-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f646-1f3ff.svg │ │ │ │ │ ├── 1f646-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f646-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f646.svg │ │ │ │ │ ├── 1f647-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fb.svg │ │ │ │ │ ├── 1f647-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fc.svg │ │ │ │ │ ├── 1f647-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fd.svg │ │ │ │ │ ├── 1f647-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f647-1f3fe.svg │ │ │ │ │ ├── 1f647-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f647-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f647-1f3ff.svg │ │ │ │ │ ├── 1f647-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f647-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f647.svg │ │ │ │ │ ├── 1f648.svg │ │ │ │ │ ├── 1f649.svg │ │ │ │ │ ├── 1f64a.svg │ │ │ │ │ ├── 1f64b-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fb.svg │ │ │ │ │ ├── 1f64b-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fc.svg │ │ │ │ │ ├── 1f64b-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fd.svg │ │ │ │ │ ├── 1f64b-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3fe.svg │ │ │ │ │ ├── 1f64b-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64b-1f3ff.svg │ │ │ │ │ ├── 1f64b-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64b-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64b.svg │ │ │ │ │ ├── 1f64c-1f3fb.svg │ │ │ │ │ ├── 1f64c-1f3fc.svg │ │ │ │ │ ├── 1f64c-1f3fd.svg │ │ │ │ │ ├── 1f64c-1f3fe.svg │ │ │ │ │ ├── 1f64c-1f3ff.svg │ │ │ │ │ ├── 1f64c.svg │ │ │ │ │ ├── 1f64d-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fb.svg │ │ │ │ │ ├── 1f64d-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fc.svg │ │ │ │ │ ├── 1f64d-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fd.svg │ │ │ │ │ ├── 1f64d-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3fe.svg │ │ │ │ │ ├── 1f64d-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64d-1f3ff.svg │ │ │ │ │ ├── 1f64d-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64d-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64d.svg │ │ │ │ │ ├── 1f64e-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fb.svg │ │ │ │ │ ├── 1f64e-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fc.svg │ │ │ │ │ ├── 1f64e-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fd.svg │ │ │ │ │ ├── 1f64e-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3fe.svg │ │ │ │ │ ├── 1f64e-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64e-1f3ff.svg │ │ │ │ │ ├── 1f64e-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f64e-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f64e.svg │ │ │ │ │ ├── 1f64f-1f3fb.svg │ │ │ │ │ ├── 1f64f-1f3fc.svg │ │ │ │ │ ├── 1f64f-1f3fd.svg │ │ │ │ │ ├── 1f64f-1f3fe.svg │ │ │ │ │ ├── 1f64f-1f3ff.svg │ │ │ │ │ ├── 1f64f.svg │ │ │ │ │ ├── 1f680.svg │ │ │ │ │ ├── 1f681.svg │ │ │ │ │ ├── 1f682.svg │ │ │ │ │ ├── 1f683.svg │ │ │ │ │ ├── 1f684.svg │ │ │ │ │ ├── 1f685.svg │ │ │ │ │ ├── 1f686.svg │ │ │ │ │ ├── 1f687.svg │ │ │ │ │ ├── 1f688.svg │ │ │ │ │ ├── 1f689.svg │ │ │ │ │ ├── 1f68a.svg │ │ │ │ │ ├── 1f68b.svg │ │ │ │ │ ├── 1f68c.svg │ │ │ │ │ ├── 1f68d.svg │ │ │ │ │ ├── 1f68e.svg │ │ │ │ │ ├── 1f68f.svg │ │ │ │ │ ├── 1f690.svg │ │ │ │ │ ├── 1f691.svg │ │ │ │ │ ├── 1f692.svg │ │ │ │ │ ├── 1f693.svg │ │ │ │ │ ├── 1f694.svg │ │ │ │ │ ├── 1f695.svg │ │ │ │ │ ├── 1f696.svg │ │ │ │ │ ├── 1f697.svg │ │ │ │ │ ├── 1f698.svg │ │ │ │ │ ├── 1f699.svg │ │ │ │ │ ├── 1f69a.svg │ │ │ │ │ ├── 1f69b.svg │ │ │ │ │ ├── 1f69c.svg │ │ │ │ │ ├── 1f69d.svg │ │ │ │ │ ├── 1f69e.svg │ │ │ │ │ ├── 1f69f.svg │ │ │ │ │ ├── 1f6a0.svg │ │ │ │ │ ├── 1f6a1.svg │ │ │ │ │ ├── 1f6a2.svg │ │ │ │ │ ├── 1f6a3-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fb.svg │ │ │ │ │ ├── 1f6a3-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fc.svg │ │ │ │ │ ├── 1f6a3-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fd.svg │ │ │ │ │ ├── 1f6a3-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3fe.svg │ │ │ │ │ ├── 1f6a3-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6a3-1f3ff.svg │ │ │ │ │ ├── 1f6a3-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6a3-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6a3.svg │ │ │ │ │ ├── 1f6a4.svg │ │ │ │ │ ├── 1f6a5.svg │ │ │ │ │ ├── 1f6a6.svg │ │ │ │ │ ├── 1f6a7.svg │ │ │ │ │ ├── 1f6a8.svg │ │ │ │ │ ├── 1f6a9.svg │ │ │ │ │ ├── 1f6aa.svg │ │ │ │ │ ├── 1f6ab.svg │ │ │ │ │ ├── 1f6ac.svg │ │ │ │ │ ├── 1f6ad.svg │ │ │ │ │ ├── 1f6ae.svg │ │ │ │ │ ├── 1f6af.svg │ │ │ │ │ ├── 1f6b0.svg │ │ │ │ │ ├── 1f6b1.svg │ │ │ │ │ ├── 1f6b2.svg │ │ │ │ │ ├── 1f6b3.svg │ │ │ │ │ ├── 1f6b4-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fb.svg │ │ │ │ │ ├── 1f6b4-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fc.svg │ │ │ │ │ ├── 1f6b4-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fd.svg │ │ │ │ │ ├── 1f6b4-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3fe.svg │ │ │ │ │ ├── 1f6b4-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b4-1f3ff.svg │ │ │ │ │ ├── 1f6b4-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b4-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b4.svg │ │ │ │ │ ├── 1f6b5-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fb.svg │ │ │ │ │ ├── 1f6b5-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fc.svg │ │ │ │ │ ├── 1f6b5-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fd.svg │ │ │ │ │ ├── 1f6b5-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3fe.svg │ │ │ │ │ ├── 1f6b5-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b5-1f3ff.svg │ │ │ │ │ ├── 1f6b5-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b5-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b5.svg │ │ │ │ │ ├── 1f6b6-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fb.svg │ │ │ │ │ ├── 1f6b6-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fc.svg │ │ │ │ │ ├── 1f6b6-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fd.svg │ │ │ │ │ ├── 1f6b6-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3fe.svg │ │ │ │ │ ├── 1f6b6-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b6-1f3ff.svg │ │ │ │ │ ├── 1f6b6-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f6b6-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f6b6.svg │ │ │ │ │ ├── 1f6b7.svg │ │ │ │ │ ├── 1f6b8.svg │ │ │ │ │ ├── 1f6b9.svg │ │ │ │ │ ├── 1f6ba.svg │ │ │ │ │ ├── 1f6bb.svg │ │ │ │ │ ├── 1f6bc.svg │ │ │ │ │ ├── 1f6bd.svg │ │ │ │ │ ├── 1f6be.svg │ │ │ │ │ ├── 1f6bf.svg │ │ │ │ │ ├── 1f6c0-1f3fb.svg │ │ │ │ │ ├── 1f6c0-1f3fc.svg │ │ │ │ │ ├── 1f6c0-1f3fd.svg │ │ │ │ │ ├── 1f6c0-1f3fe.svg │ │ │ │ │ ├── 1f6c0-1f3ff.svg │ │ │ │ │ ├── 1f6c0.svg │ │ │ │ │ ├── 1f6c1.svg │ │ │ │ │ ├── 1f6c2.svg │ │ │ │ │ ├── 1f6c3.svg │ │ │ │ │ ├── 1f6c4.svg │ │ │ │ │ ├── 1f6c5.svg │ │ │ │ │ ├── 1f6cb.svg │ │ │ │ │ ├── 1f6cc-1f3fb.svg │ │ │ │ │ ├── 1f6cc-1f3fc.svg │ │ │ │ │ ├── 1f6cc-1f3fd.svg │ │ │ │ │ ├── 1f6cc-1f3fe.svg │ │ │ │ │ ├── 1f6cc-1f3ff.svg │ │ │ │ │ ├── 1f6cc.svg │ │ │ │ │ ├── 1f6cd.svg │ │ │ │ │ ├── 1f6ce.svg │ │ │ │ │ ├── 1f6cf.svg │ │ │ │ │ ├── 1f6d0.svg │ │ │ │ │ ├── 1f6d1.svg │ │ │ │ │ ├── 1f6d2.svg │ │ │ │ │ ├── 1f6e0.svg │ │ │ │ │ ├── 1f6e1.svg │ │ │ │ │ ├── 1f6e2.svg │ │ │ │ │ ├── 1f6e3.svg │ │ │ │ │ ├── 1f6e4.svg │ │ │ │ │ ├── 1f6e5.svg │ │ │ │ │ ├── 1f6e9.svg │ │ │ │ │ ├── 1f6eb.svg │ │ │ │ │ ├── 1f6ec.svg │ │ │ │ │ ├── 1f6f0.svg │ │ │ │ │ ├── 1f6f3.svg │ │ │ │ │ ├── 1f6f4.svg │ │ │ │ │ ├── 1f6f5.svg │ │ │ │ │ ├── 1f6f6.svg │ │ │ │ │ ├── 1f910.svg │ │ │ │ │ ├── 1f911.svg │ │ │ │ │ ├── 1f912.svg │ │ │ │ │ ├── 1f913.svg │ │ │ │ │ ├── 1f914.svg │ │ │ │ │ ├── 1f915.svg │ │ │ │ │ ├── 1f916.svg │ │ │ │ │ ├── 1f917.svg │ │ │ │ │ ├── 1f918-1f3fb.svg │ │ │ │ │ ├── 1f918-1f3fc.svg │ │ │ │ │ ├── 1f918-1f3fd.svg │ │ │ │ │ ├── 1f918-1f3fe.svg │ │ │ │ │ ├── 1f918-1f3ff.svg │ │ │ │ │ ├── 1f918.svg │ │ │ │ │ ├── 1f919-1f3fb.svg │ │ │ │ │ ├── 1f919-1f3fc.svg │ │ │ │ │ ├── 1f919-1f3fd.svg │ │ │ │ │ ├── 1f919-1f3fe.svg │ │ │ │ │ ├── 1f919-1f3ff.svg │ │ │ │ │ ├── 1f919.svg │ │ │ │ │ ├── 1f91a-1f3fb.svg │ │ │ │ │ ├── 1f91a-1f3fc.svg │ │ │ │ │ ├── 1f91a-1f3fd.svg │ │ │ │ │ ├── 1f91a-1f3fe.svg │ │ │ │ │ ├── 1f91a-1f3ff.svg │ │ │ │ │ ├── 1f91a.svg │ │ │ │ │ ├── 1f91b-1f3fb.svg │ │ │ │ │ ├── 1f91b-1f3fc.svg │ │ │ │ │ ├── 1f91b-1f3fd.svg │ │ │ │ │ ├── 1f91b-1f3fe.svg │ │ │ │ │ ├── 1f91b-1f3ff.svg │ │ │ │ │ ├── 1f91b.svg │ │ │ │ │ ├── 1f91c-1f3fb.svg │ │ │ │ │ ├── 1f91c-1f3fc.svg │ │ │ │ │ ├── 1f91c-1f3fd.svg │ │ │ │ │ ├── 1f91c-1f3fe.svg │ │ │ │ │ ├── 1f91c-1f3ff.svg │ │ │ │ │ ├── 1f91c.svg │ │ │ │ │ ├── 1f91d.svg │ │ │ │ │ ├── 1f91e-1f3fb.svg │ │ │ │ │ ├── 1f91e-1f3fc.svg │ │ │ │ │ ├── 1f91e-1f3fd.svg │ │ │ │ │ ├── 1f91e-1f3fe.svg │ │ │ │ │ ├── 1f91e-1f3ff.svg │ │ │ │ │ ├── 1f91e.svg │ │ │ │ │ ├── 1f920.svg │ │ │ │ │ ├── 1f921.svg │ │ │ │ │ ├── 1f922.svg │ │ │ │ │ ├── 1f923.svg │ │ │ │ │ ├── 1f924.svg │ │ │ │ │ ├── 1f925.svg │ │ │ │ │ ├── 1f926-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fb.svg │ │ │ │ │ ├── 1f926-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fc.svg │ │ │ │ │ ├── 1f926-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fd.svg │ │ │ │ │ ├── 1f926-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f926-1f3fe.svg │ │ │ │ │ ├── 1f926-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f926-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f926-1f3ff.svg │ │ │ │ │ ├── 1f926-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f926-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f926.svg │ │ │ │ │ ├── 1f927.svg │ │ │ │ │ ├── 1f930-1f3fb.svg │ │ │ │ │ ├── 1f930-1f3fc.svg │ │ │ │ │ ├── 1f930-1f3fd.svg │ │ │ │ │ ├── 1f930-1f3fe.svg │ │ │ │ │ ├── 1f930-1f3ff.svg │ │ │ │ │ ├── 1f930.svg │ │ │ │ │ ├── 1f933-1f3fb.svg │ │ │ │ │ ├── 1f933-1f3fc.svg │ │ │ │ │ ├── 1f933-1f3fd.svg │ │ │ │ │ ├── 1f933-1f3fe.svg │ │ │ │ │ ├── 1f933-1f3ff.svg │ │ │ │ │ ├── 1f933.svg │ │ │ │ │ ├── 1f934-1f3fb.svg │ │ │ │ │ ├── 1f934-1f3fc.svg │ │ │ │ │ ├── 1f934-1f3fd.svg │ │ │ │ │ ├── 1f934-1f3fe.svg │ │ │ │ │ ├── 1f934-1f3ff.svg │ │ │ │ │ ├── 1f934.svg │ │ │ │ │ ├── 1f935-1f3fb.svg │ │ │ │ │ ├── 1f935-1f3fc.svg │ │ │ │ │ ├── 1f935-1f3fd.svg │ │ │ │ │ ├── 1f935-1f3fe.svg │ │ │ │ │ ├── 1f935-1f3ff.svg │ │ │ │ │ ├── 1f935.svg │ │ │ │ │ ├── 1f936-1f3fb.svg │ │ │ │ │ ├── 1f936-1f3fc.svg │ │ │ │ │ ├── 1f936-1f3fd.svg │ │ │ │ │ ├── 1f936-1f3fe.svg │ │ │ │ │ ├── 1f936-1f3ff.svg │ │ │ │ │ ├── 1f936.svg │ │ │ │ │ ├── 1f937-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fb.svg │ │ │ │ │ ├── 1f937-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fc.svg │ │ │ │ │ ├── 1f937-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fd.svg │ │ │ │ │ ├── 1f937-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f937-1f3fe.svg │ │ │ │ │ ├── 1f937-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f937-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f937-1f3ff.svg │ │ │ │ │ ├── 1f937-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f937-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f937.svg │ │ │ │ │ ├── 1f938-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fb.svg │ │ │ │ │ ├── 1f938-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fc.svg │ │ │ │ │ ├── 1f938-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fd.svg │ │ │ │ │ ├── 1f938-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f938-1f3fe.svg │ │ │ │ │ ├── 1f938-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f938-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f938-1f3ff.svg │ │ │ │ │ ├── 1f938-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f938-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f938.svg │ │ │ │ │ ├── 1f939-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fb.svg │ │ │ │ │ ├── 1f939-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fc.svg │ │ │ │ │ ├── 1f939-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fd.svg │ │ │ │ │ ├── 1f939-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f939-1f3fe.svg │ │ │ │ │ ├── 1f939-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f939-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f939-1f3ff.svg │ │ │ │ │ ├── 1f939-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f939-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f939.svg │ │ │ │ │ ├── 1f93a.svg │ │ │ │ │ ├── 1f93c-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93c-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93c.svg │ │ │ │ │ ├── 1f93d-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fb.svg │ │ │ │ │ ├── 1f93d-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fc.svg │ │ │ │ │ ├── 1f93d-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fd.svg │ │ │ │ │ ├── 1f93d-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3fe.svg │ │ │ │ │ ├── 1f93d-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93d-1f3ff.svg │ │ │ │ │ ├── 1f93d-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93d-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93d.svg │ │ │ │ │ ├── 1f93e-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fb.svg │ │ │ │ │ ├── 1f93e-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fc.svg │ │ │ │ │ ├── 1f93e-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fd.svg │ │ │ │ │ ├── 1f93e-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3fe.svg │ │ │ │ │ ├── 1f93e-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93e-1f3ff.svg │ │ │ │ │ ├── 1f93e-200d-2640-fe0f.svg │ │ │ │ │ ├── 1f93e-200d-2642-fe0f.svg │ │ │ │ │ ├── 1f93e.svg │ │ │ │ │ ├── 1f940.svg │ │ │ │ │ ├── 1f941.svg │ │ │ │ │ ├── 1f942.svg │ │ │ │ │ ├── 1f943.svg │ │ │ │ │ ├── 1f944.svg │ │ │ │ │ ├── 1f945.svg │ │ │ │ │ ├── 1f947.svg │ │ │ │ │ ├── 1f948.svg │ │ │ │ │ ├── 1f949.svg │ │ │ │ │ ├── 1f94a.svg │ │ │ │ │ ├── 1f94b.svg │ │ │ │ │ ├── 1f950.svg │ │ │ │ │ ├── 1f951.svg │ │ │ │ │ ├── 1f952.svg │ │ │ │ │ ├── 1f953.svg │ │ │ │ │ ├── 1f954.svg │ │ │ │ │ ├── 1f955.svg │ │ │ │ │ ├── 1f956.svg │ │ │ │ │ ├── 1f957.svg │ │ │ │ │ ├── 1f958.svg │ │ │ │ │ ├── 1f959.svg │ │ │ │ │ ├── 1f95a.svg │ │ │ │ │ ├── 1f95b.svg │ │ │ │ │ ├── 1f95c.svg │ │ │ │ │ ├── 1f95d.svg │ │ │ │ │ ├── 1f95e.svg │ │ │ │ │ ├── 1f980.svg │ │ │ │ │ ├── 1f981.svg │ │ │ │ │ ├── 1f982.svg │ │ │ │ │ ├── 1f983.svg │ │ │ │ │ ├── 1f984.svg │ │ │ │ │ ├── 1f985.svg │ │ │ │ │ ├── 1f986.svg │ │ │ │ │ ├── 1f987.svg │ │ │ │ │ ├── 1f988.svg │ │ │ │ │ ├── 1f989.svg │ │ │ │ │ ├── 1f98a.svg │ │ │ │ │ ├── 1f98b.svg │ │ │ │ │ ├── 1f98c.svg │ │ │ │ │ ├── 1f98d.svg │ │ │ │ │ ├── 1f98e.svg │ │ │ │ │ ├── 1f98f.svg │ │ │ │ │ ├── 1f990.svg │ │ │ │ │ ├── 1f991.svg │ │ │ │ │ ├── 1f9c0.svg │ │ │ │ │ ├── 203c.svg │ │ │ │ │ ├── 2049.svg │ │ │ │ │ ├── 2122.svg │ │ │ │ │ ├── 2139.svg │ │ │ │ │ ├── 2194.svg │ │ │ │ │ ├── 2195.svg │ │ │ │ │ ├── 2196.svg │ │ │ │ │ ├── 2197.svg │ │ │ │ │ ├── 2198.svg │ │ │ │ │ ├── 2199.svg │ │ │ │ │ ├── 21a9.svg │ │ │ │ │ ├── 21aa.svg │ │ │ │ │ ├── 23-20e3.svg │ │ │ │ │ ├── 231a.svg │ │ │ │ │ ├── 231b.svg │ │ │ │ │ ├── 2328.svg │ │ │ │ │ ├── 23cf.svg │ │ │ │ │ ├── 23e9.svg │ │ │ │ │ ├── 23ea.svg │ │ │ │ │ ├── 23eb.svg │ │ │ │ │ ├── 23ec.svg │ │ │ │ │ ├── 23ed.svg │ │ │ │ │ ├── 23ee.svg │ │ │ │ │ ├── 23ef.svg │ │ │ │ │ ├── 23f0.svg │ │ │ │ │ ├── 23f1.svg │ │ │ │ │ ├── 23f2.svg │ │ │ │ │ ├── 23f3.svg │ │ │ │ │ ├── 23f8.svg │ │ │ │ │ ├── 23f9.svg │ │ │ │ │ ├── 23fa.svg │ │ │ │ │ ├── 24c2.svg │ │ │ │ │ ├── 25aa.svg │ │ │ │ │ ├── 25ab.svg │ │ │ │ │ ├── 25b6.svg │ │ │ │ │ ├── 25c0.svg │ │ │ │ │ ├── 25fb.svg │ │ │ │ │ ├── 25fc.svg │ │ │ │ │ ├── 25fd.svg │ │ │ │ │ ├── 25fe.svg │ │ │ │ │ ├── 2600.svg │ │ │ │ │ ├── 2601.svg │ │ │ │ │ ├── 2602.svg │ │ │ │ │ ├── 2603.svg │ │ │ │ │ ├── 2604.svg │ │ │ │ │ ├── 260e.svg │ │ │ │ │ ├── 2611.svg │ │ │ │ │ ├── 2614.svg │ │ │ │ │ ├── 2615.svg │ │ │ │ │ ├── 2618.svg │ │ │ │ │ ├── 261d-1f3fb.svg │ │ │ │ │ ├── 261d-1f3fc.svg │ │ │ │ │ ├── 261d-1f3fd.svg │ │ │ │ │ ├── 261d-1f3fe.svg │ │ │ │ │ ├── 261d-1f3ff.svg │ │ │ │ │ ├── 261d.svg │ │ │ │ │ ├── 2620.svg │ │ │ │ │ ├── 2622.svg │ │ │ │ │ ├── 2623.svg │ │ │ │ │ ├── 2626.svg │ │ │ │ │ ├── 262a.svg │ │ │ │ │ ├── 262e.svg │ │ │ │ │ ├── 262f.svg │ │ │ │ │ ├── 2638.svg │ │ │ │ │ ├── 2639.svg │ │ │ │ │ ├── 263a.svg │ │ │ │ │ ├── 2640.svg │ │ │ │ │ ├── 2642.svg │ │ │ │ │ ├── 2648.svg │ │ │ │ │ ├── 2649.svg │ │ │ │ │ ├── 264a.svg │ │ │ │ │ ├── 264b.svg │ │ │ │ │ ├── 264c.svg │ │ │ │ │ ├── 264d.svg │ │ │ │ │ ├── 264e.svg │ │ │ │ │ ├── 264f.svg │ │ │ │ │ ├── 2650.svg │ │ │ │ │ ├── 2651.svg │ │ │ │ │ ├── 2652.svg │ │ │ │ │ ├── 2653.svg │ │ │ │ │ ├── 2660.svg │ │ │ │ │ ├── 2663.svg │ │ │ │ │ ├── 2665.svg │ │ │ │ │ ├── 2666.svg │ │ │ │ │ ├── 2668.svg │ │ │ │ │ ├── 267b.svg │ │ │ │ │ ├── 267f.svg │ │ │ │ │ ├── 2692.svg │ │ │ │ │ ├── 2693.svg │ │ │ │ │ ├── 2694.svg │ │ │ │ │ ├── 2695.svg │ │ │ │ │ ├── 2696.svg │ │ │ │ │ ├── 2697.svg │ │ │ │ │ ├── 2699.svg │ │ │ │ │ ├── 269b.svg │ │ │ │ │ ├── 269c.svg │ │ │ │ │ ├── 26a0.svg │ │ │ │ │ ├── 26a1.svg │ │ │ │ │ ├── 26aa.svg │ │ │ │ │ ├── 26ab.svg │ │ │ │ │ ├── 26b0.svg │ │ │ │ │ ├── 26b1.svg │ │ │ │ │ ├── 26bd.svg │ │ │ │ │ ├── 26be.svg │ │ │ │ │ ├── 26c4.svg │ │ │ │ │ ├── 26c5.svg │ │ │ │ │ ├── 26c8.svg │ │ │ │ │ ├── 26ce.svg │ │ │ │ │ ├── 26cf.svg │ │ │ │ │ ├── 26d1.svg │ │ │ │ │ ├── 26d3.svg │ │ │ │ │ ├── 26d4.svg │ │ │ │ │ ├── 26e9.svg │ │ │ │ │ ├── 26ea.svg │ │ │ │ │ ├── 26f0.svg │ │ │ │ │ ├── 26f1.svg │ │ │ │ │ ├── 26f2.svg │ │ │ │ │ ├── 26f3.svg │ │ │ │ │ ├── 26f4.svg │ │ │ │ │ ├── 26f5.svg │ │ │ │ │ ├── 26f7-1f3fb.svg │ │ │ │ │ ├── 26f7-1f3fc.svg │ │ │ │ │ ├── 26f7-1f3fd.svg │ │ │ │ │ ├── 26f7-1f3fe.svg │ │ │ │ │ ├── 26f7-1f3ff.svg │ │ │ │ │ ├── 26f7.svg │ │ │ │ │ ├── 26f8.svg │ │ │ │ │ ├── 26f9-1f3fb-200d-2640-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fb-200d-2642-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fb.svg │ │ │ │ │ ├── 26f9-1f3fc-200d-2640-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fc-200d-2642-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fc.svg │ │ │ │ │ ├── 26f9-1f3fd-200d-2640-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fd-200d-2642-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fd.svg │ │ │ │ │ ├── 26f9-1f3fe-200d-2640-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fe-200d-2642-fe0f.svg │ │ │ │ │ ├── 26f9-1f3fe.svg │ │ │ │ │ ├── 26f9-1f3ff-200d-2640-fe0f.svg │ │ │ │ │ ├── 26f9-1f3ff-200d-2642-fe0f.svg │ │ │ │ │ ├── 26f9-1f3ff.svg │ │ │ │ │ ├── 26f9-fe0f-200d-2640-fe0f.svg │ │ │ │ │ ├── 26f9-fe0f-200d-2642-fe0f.svg │ │ │ │ │ ├── 26f9.svg │ │ │ │ │ ├── 26fa.svg │ │ │ │ │ ├── 26fd.svg │ │ │ │ │ ├── 2702.svg │ │ │ │ │ ├── 2705.svg │ │ │ │ │ ├── 2708.svg │ │ │ │ │ ├── 2709.svg │ │ │ │ │ ├── 270a-1f3fb.svg │ │ │ │ │ ├── 270a-1f3fc.svg │ │ │ │ │ ├── 270a-1f3fd.svg │ │ │ │ │ ├── 270a-1f3fe.svg │ │ │ │ │ ├── 270a-1f3ff.svg │ │ │ │ │ ├── 270a.svg │ │ │ │ │ ├── 270b-1f3fb.svg │ │ │ │ │ ├── 270b-1f3fc.svg │ │ │ │ │ ├── 270b-1f3fd.svg │ │ │ │ │ ├── 270b-1f3fe.svg │ │ │ │ │ ├── 270b-1f3ff.svg │ │ │ │ │ ├── 270b.svg │ │ │ │ │ ├── 270c-1f3fb.svg │ │ │ │ │ ├── 270c-1f3fc.svg │ │ │ │ │ ├── 270c-1f3fd.svg │ │ │ │ │ ├── 270c-1f3fe.svg │ │ │ │ │ ├── 270c-1f3ff.svg │ │ │ │ │ ├── 270c.svg │ │ │ │ │ ├── 270d-1f3fb.svg │ │ │ │ │ ├── 270d-1f3fc.svg │ │ │ │ │ ├── 270d-1f3fd.svg │ │ │ │ │ ├── 270d-1f3fe.svg │ │ │ │ │ ├── 270d-1f3ff.svg │ │ │ │ │ ├── 270d.svg │ │ │ │ │ ├── 270f.svg │ │ │ │ │ ├── 2712.svg │ │ │ │ │ ├── 2714.svg │ │ │ │ │ ├── 2716.svg │ │ │ │ │ ├── 271d.svg │ │ │ │ │ ├── 2721.svg │ │ │ │ │ ├── 2728.svg │ │ │ │ │ ├── 2733.svg │ │ │ │ │ ├── 2734.svg │ │ │ │ │ ├── 2744.svg │ │ │ │ │ ├── 2747.svg │ │ │ │ │ ├── 274c.svg │ │ │ │ │ ├── 274e.svg │ │ │ │ │ ├── 2753.svg │ │ │ │ │ ├── 2754.svg │ │ │ │ │ ├── 2755.svg │ │ │ │ │ ├── 2757.svg │ │ │ │ │ ├── 2763.svg │ │ │ │ │ ├── 2764.svg │ │ │ │ │ ├── 2795.svg │ │ │ │ │ ├── 2796.svg │ │ │ │ │ ├── 2797.svg │ │ │ │ │ ├── 27a1.svg │ │ │ │ │ ├── 27b0.svg │ │ │ │ │ ├── 27bf.svg │ │ │ │ │ ├── 2934.svg │ │ │ │ │ ├── 2935.svg │ │ │ │ │ ├── 2a-20e3.svg │ │ │ │ │ ├── 2b05.svg │ │ │ │ │ ├── 2b06.svg │ │ │ │ │ ├── 2b07.svg │ │ │ │ │ ├── 2b1b.svg │ │ │ │ │ ├── 2b1c.svg │ │ │ │ │ ├── 2b50.svg │ │ │ │ │ ├── 2b55.svg │ │ │ │ │ ├── 30-20e3.svg │ │ │ │ │ ├── 3030.svg │ │ │ │ │ ├── 303d.svg │ │ │ │ │ ├── 31-20e3.svg │ │ │ │ │ ├── 32-20e3.svg │ │ │ │ │ ├── 3297.svg │ │ │ │ │ ├── 3299.svg │ │ │ │ │ ├── 33-20e3.svg │ │ │ │ │ ├── 34-20e3.svg │ │ │ │ │ ├── 35-20e3.svg │ │ │ │ │ ├── 36-20e3.svg │ │ │ │ │ ├── 37-20e3.svg │ │ │ │ │ ├── 38-20e3.svg │ │ │ │ │ ├── 39-20e3.svg │ │ │ │ │ ├── a9.svg │ │ │ │ │ ├── ae.svg │ │ │ │ │ └── e50a.svg │ │ │ └── styles │ │ │ │ ├── .gitkeep │ │ │ │ ├── cssVars.ts │ │ │ │ ├── font-awesome.min.css │ │ │ │ ├── mixins.sass │ │ │ │ ├── reset.css │ │ │ │ ├── style.sass │ │ │ │ ├── twemoji.scss │ │ │ │ └── variables.sass │ │ ├── browser.ts │ │ ├── components │ │ │ ├── Button │ │ │ │ ├── Button.stories.tsx │ │ │ │ ├── Button.tsx │ │ │ │ └── package.json │ │ │ ├── Checkbox │ │ │ │ └── Checkbox.tsx │ │ │ ├── ContextMenu │ │ │ │ ├── ContextMenu.tsx │ │ │ │ ├── ContextMenuManager.tsx │ │ │ │ └── package.json │ │ │ ├── DragNumberInput │ │ │ │ ├── DragNumberInput.sass │ │ │ │ ├── DragNumberInput.stories.tsx │ │ │ │ ├── DragNumberInput.tsx │ │ │ │ └── package.json │ │ │ ├── Dropdown │ │ │ │ ├── Dropdown.sass │ │ │ │ ├── Dropdown.stories.tsx │ │ │ │ ├── Dropdown.tsx │ │ │ │ └── package.json │ │ │ ├── Droppable │ │ │ │ └── Droppable.tsx │ │ │ ├── ExternalLink │ │ │ │ ├── ExternalLink.tsx │ │ │ │ └── package.json │ │ │ ├── Form │ │ │ │ ├── Form.sass │ │ │ │ └── index.tsx │ │ │ ├── FormSection │ │ │ │ ├── FormSection.stories.tsx │ │ │ │ └── FormSection.tsx │ │ │ ├── Icon │ │ │ │ └── Icon.tsx │ │ │ ├── Input │ │ │ │ ├── Input.stories.tsx │ │ │ │ └── Input.tsx │ │ │ ├── LabelInput │ │ │ │ ├── LabelInput.stories.tsx │ │ │ │ ├── LabelInput.tsx │ │ │ │ └── package.json │ │ │ ├── ModalContent │ │ │ │ ├── ModalContent.stories.tsx │ │ │ │ └── ModalContent.tsx │ │ │ ├── ModalOwner │ │ │ │ ├── ModalOwner.sass │ │ │ │ └── ModalOwner.tsx │ │ │ ├── MountTransition │ │ │ │ ├── MountTransition.tsx │ │ │ │ └── package.json │ │ │ ├── Pane │ │ │ │ ├── Pane.tsx │ │ │ │ └── package.json │ │ │ ├── Portal │ │ │ │ └── Portal.tsx │ │ │ ├── PropertyInput │ │ │ │ ├── Inputs │ │ │ │ │ ├── AssetTypeInput.tsx │ │ │ │ │ ├── BoolTypeInput.tsx │ │ │ │ │ ├── ColorTypeInput.tsx │ │ │ │ │ ├── EnumTypeInput.tsx │ │ │ │ │ ├── Inputs.i18n.ts │ │ │ │ │ ├── NumberTypeInput.tsx │ │ │ │ │ └── StringTypeInput.tsx │ │ │ │ ├── PropertyInput.stories.tsx │ │ │ │ └── PropertyInput.tsx │ │ │ ├── SelectBox │ │ │ │ ├── SelectBox.stories.tsx │ │ │ │ └── SelectBox.tsx │ │ │ └── Workspace │ │ │ │ ├── Workspace.tsx │ │ │ │ └── package.json │ │ ├── declarations.d.ts │ │ ├── domain │ │ │ ├── Editor │ │ │ │ ├── EditorStore.ts │ │ │ │ ├── actions.ts │ │ │ │ ├── models.ts │ │ │ │ ├── operations.i18n.ts │ │ │ │ ├── operations.ts │ │ │ │ ├── selectors.ts │ │ │ │ └── types.ts │ │ │ ├── History │ │ │ │ ├── HistoryGroup.ts │ │ │ │ ├── HistoryStore.ts │ │ │ │ ├── actions.ts │ │ │ │ └── operations.ts │ │ │ ├── Preference │ │ │ │ ├── PreferenceStore.ts │ │ │ │ ├── actions.ts │ │ │ │ ├── models.spec.ts │ │ │ │ ├── models.ts │ │ │ │ ├── operations.ts │ │ │ │ ├── selectors.ts │ │ │ │ ├── validation.spec.ts │ │ │ │ └── validation.ts │ │ │ ├── Project │ │ │ │ ├── Commands │ │ │ │ │ ├── AddAssetCommand.ts │ │ │ │ │ ├── AddClipCommand.ts │ │ │ │ │ ├── AddEffectIntoClipCommand.ts │ │ │ │ │ ├── AddEffectKeyframeCommand.ts │ │ │ │ │ ├── AddKeyframeCommand.ts │ │ │ │ │ ├── AddLayerCommand.ts │ │ │ │ │ ├── CreateCompositionCommand.ts │ │ │ │ │ ├── ModifyAssetCommand.ts │ │ │ │ │ ├── ModifyClipCommand.ts │ │ │ │ │ ├── ModifyClipExpressionCommand.ts │ │ │ │ │ ├── ModifyClipKeyframeCommand.ts │ │ │ │ │ ├── ModifyClipsCommand.ts │ │ │ │ │ ├── ModifyCompositionCommand.ts │ │ │ │ │ ├── ModifyEffectCommand.ts │ │ │ │ │ ├── ModifyEffectExpressionCommand.ts │ │ │ │ │ ├── ModifyEffectKeyframeCommand.ts │ │ │ │ │ ├── ModifyLayerCommand.ts │ │ │ │ │ ├── MoveClipToLayerCommand.ts │ │ │ │ │ ├── MoveLayerOrderCommand.ts │ │ │ │ │ ├── RemoveAssetCommand.ts │ │ │ │ │ ├── RemoveClipCommand.ts │ │ │ │ │ ├── RemoveCompositionCommand.ts │ │ │ │ │ ├── RemoveEffectCommand.ts │ │ │ │ │ ├── RemoveEffectKeyframeCommand.ts │ │ │ │ │ ├── RemoveKeyframeCommand.ts │ │ │ │ │ └── RemoveLayerCommand.ts │ │ │ │ ├── ProjectStore.ts │ │ │ │ ├── __snapshots__ │ │ │ │ │ └── models.spec.ts.snap │ │ │ │ ├── actions.ts │ │ │ │ ├── models.spec.ts │ │ │ │ ├── models.ts │ │ │ │ ├── operations.ts │ │ │ │ └── selectors.ts │ │ │ └── Renderer │ │ │ │ ├── FSPluginLoader.ts │ │ │ │ ├── PluginScriptLoader.spec.ts │ │ │ │ ├── PluginScriptLoader.ts │ │ │ │ ├── RendererStore.ts │ │ │ │ ├── actions.ts │ │ │ │ ├── models.ts │ │ │ │ ├── operations.i18n.ts │ │ │ │ ├── operations.ts │ │ │ │ ├── selectors.ts │ │ │ │ └── specFixtures │ │ │ │ ├── PostEffectPlugin.js │ │ │ │ └── globals.js │ │ ├── index.html │ │ ├── main.tsx │ │ ├── modals │ │ │ ├── AboutModal │ │ │ │ ├── AboutModal.i18n.ts │ │ │ │ ├── AboutModal.sass │ │ │ │ ├── AboutModal.tsx │ │ │ │ ├── Licenses.ts │ │ │ │ └── package.json │ │ │ ├── CompositionSettingModal │ │ │ │ ├── CompositionSettingModal.i18n.ts │ │ │ │ ├── CompositionSettingModal.tsx │ │ │ │ └── package.json │ │ │ ├── ImportPackModal │ │ │ │ ├── ImportPackModal.i18n.ts │ │ │ │ ├── ImportPackModal.sass │ │ │ │ ├── ImportPackModal.stories.tsx │ │ │ │ └── ImportPackModal.tsx │ │ │ ├── Modal │ │ │ │ ├── Modal.sass │ │ │ │ ├── Modal.tsx │ │ │ │ ├── ModalController.tsx │ │ │ │ └── package.json │ │ │ └── RenderingSettingModal │ │ │ │ ├── RenderingSettingModal.i18n.tsx │ │ │ │ ├── RenderingSettingModal.stories.tsx │ │ │ │ └── RenderingSettingModal.tsx │ │ ├── utils │ │ │ ├── Dev │ │ │ │ └── ExampleProject1 │ │ │ │ │ ├── Dawn.mp3 │ │ │ │ │ ├── LICENSE.md │ │ │ │ │ ├── big_buck_bunny.mp4 │ │ │ │ │ ├── image.png │ │ │ │ │ └── index.ts │ │ │ ├── EventEmitter.ts │ │ │ ├── I18n.ts │ │ │ ├── Monaco │ │ │ │ ├── Monaco.ts │ │ │ │ ├── console.d.ts.txt │ │ │ │ └── package.json │ │ │ ├── React.tsx │ │ │ ├── Spread.ts │ │ │ ├── TimePixelConversion.spec.ts │ │ │ ├── TimePixelConversion.ts │ │ │ ├── Timecode.spec.ts │ │ │ ├── Timecode.ts │ │ │ ├── UIActions.ts │ │ │ ├── decorate.ts │ │ │ ├── hooks.ts │ │ │ ├── keepAliveOperation.ts │ │ │ ├── makeMousetrapHandler.ts │ │ │ ├── platform.ts │ │ │ ├── propsToDataset.ts │ │ │ ├── safeAssign.ts │ │ │ └── selectFile.ts │ │ └── views │ │ │ ├── AppMenu │ │ │ ├── AppMenu.i18n.ts │ │ │ ├── AppMenu.tsx │ │ │ └── package.json │ │ │ ├── AppView │ │ │ ├── AppView.sass │ │ │ ├── AppView.tsx │ │ │ ├── GlobalEvents.ts │ │ │ ├── ShortcutHandler.ts │ │ │ └── package.json │ │ │ ├── AssetsView │ │ │ ├── AssetsView.i18n.ts │ │ │ ├── AssetsView.sass │ │ │ ├── AssetsView.tsx │ │ │ └── package.json │ │ │ ├── KeyframeEditor │ │ │ ├── EffectList.tsx │ │ │ ├── ExpressionEditor.sass │ │ │ ├── ExpressionEditor.tsx │ │ │ ├── KeyframeEditor.i18n.ts │ │ │ ├── KeyframeEditor.sass │ │ │ ├── KeyframeEditor.tsx │ │ │ ├── KeyframeGraph.sass │ │ │ ├── KeyframeGraph.tsx │ │ │ ├── KeyframeMediator.tsx │ │ │ ├── ScriptParamEditor.sass │ │ │ ├── ScriptParamEditor.tsx │ │ │ └── package.json │ │ │ ├── NavigationView │ │ │ ├── NavigationView.i18n.ts │ │ │ ├── NavigationView.sass │ │ │ ├── NavigationView.tsx │ │ │ └── package.json │ │ │ ├── Notifications │ │ │ ├── Notifications.i18n.ts │ │ │ ├── Notifications.sass │ │ │ └── Notifications.tsx │ │ │ ├── Preference │ │ │ ├── Panes │ │ │ │ └── Development │ │ │ │ │ ├── Plugin.i18n.ts │ │ │ │ │ └── Plugin.tsx │ │ │ ├── Preference.i18n.ts │ │ │ ├── Preference.sass │ │ │ └── index.tsx │ │ │ ├── PreviewView │ │ │ ├── PreviewView.i18n.ts │ │ │ ├── PreviewView.sass │ │ │ ├── PreviewView.tsx │ │ │ └── package.json │ │ │ ├── RenderingWaiter │ │ │ ├── RenderingWaiter.i18n.ts │ │ │ ├── RenderingWaiter.sass │ │ │ ├── index.tsx │ │ │ └── parrot.gif │ │ │ └── Timeline │ │ │ ├── Clip.i18n.ts │ │ │ ├── Clip.sass │ │ │ ├── Clip.tsx │ │ │ ├── ClipDragContext.tsx │ │ │ ├── ClipDragMediator.tsx │ │ │ ├── ClipsMediator.sass │ │ │ ├── Gradations.i18n.tsx │ │ │ ├── Gradations.sass │ │ │ ├── Gradations.tsx │ │ │ ├── Layer.i18n.ts │ │ │ ├── Layer.sass │ │ │ ├── Layer.tsx │ │ │ ├── LayerLabel.i18n.ts │ │ │ ├── LayerLabel.sass │ │ │ ├── LayerLabel.tsx │ │ │ ├── LayerLabelList.tsx │ │ │ ├── Timeline.i18n.ts │ │ │ ├── Timeline.sass │ │ │ ├── Timeline.tsx │ │ │ └── package.json │ ├── tsconfig.json │ └── tsconfig.test.json ├── deream │ ├── .gitignore │ ├── .npmignore │ ├── LICENSE.md │ ├── README.md │ ├── declarations.d.ts │ ├── example.js │ ├── exporter.ts │ ├── index.ts │ └── package.json ├── experimental-plugins │ ├── color-collection │ │ ├── index.ts │ │ └── package.json │ └── package.json ├── post-effect-plugins │ ├── chromakey │ │ ├── fragment.frag │ │ ├── index.ts │ │ ├── package.json │ │ └── vertex.vert │ ├── color-slider │ │ ├── index.ts │ │ └── package.json │ ├── index.spec.ts │ ├── jest.config.js │ ├── numeric-slider │ │ ├── index.ts │ │ └── package.json │ ├── package.json │ ├── repeat-tile │ │ ├── index.ts │ │ └── package.json │ ├── the-world │ │ ├── index.ts │ │ └── package.json │ ├── time-posterization │ │ ├── index.ts │ │ └── package.json │ ├── tsconfig.json │ ├── tsconfig.test.json │ └── webgl │ │ ├── index.ts │ │ ├── package.json │ │ └── vertex.vert ├── unworked-plugins │ ├── .gitkeep │ ├── color-keying │ │ ├── index.ts │ │ └── package.json │ ├── composition-layer │ │ ├── composition-layer.ts │ │ └── package.json │ ├── declarations.d.ts │ ├── filler │ │ ├── index.ts │ │ └── package.json │ ├── gaussian-blur │ │ ├── index.ts │ │ └── package.json │ ├── mmd │ │ ├── .gitignore │ │ ├── index.ts │ │ ├── package.json │ │ └── yarn.lock │ ├── noise │ │ ├── index.ts │ │ └── package.json │ └── package.json └── web-example │ ├── .gitignore │ ├── package.json │ ├── src │ ├── ExamplePlugin.ts │ └── index.ts │ ├── tsconfig.json │ └── webpack.config.ts ├── setup.sh ├── tsconfig.base.json ├── tslint.json └── yarn.lock /.dependabot/config.yml: -------------------------------------------------------------------------------- 1 | version: 1 2 | 3 | update_configs: 4 | - package_manager: "javascript" 5 | directory: "/" 6 | update_schedule: "weekly" 7 | allowed_updates: 8 | - match: 9 | dependency_type: "direct" 10 | - match: 11 | update_type: "security" 12 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | charset = utf-8 11 | 12 | [*.{styl,sass}] 13 | indent_style = space 14 | indent_size = 2 15 | trim_trailing_whitespace = true 16 | 17 | [*.{js,ts,tsx}] 18 | indent_style = space 19 | indent_size = 2 20 | 21 | [{*.json,.travis.yml}] 22 | indent_style = space 23 | indent_size = 4 24 | 25 | [{package.json,tsconfig.json,.prettierrc,.vscode/settings.json}] 26 | indent_style = space 27 | indent_size = 2 28 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | patreon: ra_gg 2 | open_collective: delirvfx 3 | custom: ['https://www.pixiv.net/fanbox/creator/37608853'] 4 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Ticket: 2 | 3 | Has breaking changes to public API?: 4 | 5 | #### Description 6 | 7 | #### Annotation to release 8 | 9 | #### Breaking changes (In delir-core Public API or Expression/p5.js intergration API) 10 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push] 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | 9 | strategy: 10 | matrix: 11 | os: [macOS-10.14, windows-2016, ubuntu-18.04] 12 | 13 | steps: 14 | - uses: actions/checkout@v1 15 | - name: Setup Node.js for use with actions 16 | uses: actions/setup-node@v1.1.0 17 | with: 18 | node-version: '11.x' 19 | - name: Cache 20 | uses: actions/cache@v1.0.0 21 | with: 22 | path: ~/.cache/yarn 23 | key: ${{ matrix.os }}-${{ hashFiles(format('{0}{1}', github.workspace, '/yarn.lock')) }} 24 | restore-keys: | 25 | ${{ matrix.os }}- 26 | - name: Install deps 27 | run: | 28 | npm i -g yarn 29 | yarn install 30 | - name: Build 31 | run: yarn build 32 | - uses: actions/upload-artifact@master 33 | with: 34 | name: build-${{ matrix.os }} 35 | path: release 36 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | npm-debug.log 4 | yarn-error.log 5 | node_modules/ 6 | 7 | /prepublish 8 | /release 9 | /tmp 10 | /.vscode/extensions.json 11 | /build-assets/icons 12 | -------------------------------------------------------------------------------- /.node-version: -------------------------------------------------------------------------------- 1 | 11.13.0 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "all", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "printWidth": 120, 6 | "singleQuote": true 7 | } 8 | -------------------------------------------------------------------------------- /.sasslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "class-name-format": [2, { 4 | "convention": "camelcase" 5 | }], 6 | "mixins-before-declarations": [0], 7 | "mixin-name-format": [2, { 8 | "allow-leading-underscore": false, 9 | "convention": "camelcase" 10 | }], 11 | "no-ids": [0], 12 | "no-duplicate-properties": [2], 13 | "property-sort-order": [2, { 14 | "order": ["smacss"], 15 | }], 16 | "quotes": [2, { 17 | "style": "single" 18 | }] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | sudo: false 2 | language: node_js 3 | 4 | cache: 5 | yarn: true 6 | directories: 7 | - node_modules 8 | 9 | node_js: 10 | - '11' 11 | 12 | env: 13 | - CXX=g++-4.8 14 | 15 | install: 16 | - npm i -g yarn 17 | - yarn install -s --no-optional 18 | # Remove problem optional module 19 | - rm -rf ./node_modules/speaker 20 | 21 | script: 22 | - cd packages/core 23 | - yarn prepublishOnly 24 | - cd - 25 | - cd packages/delir 26 | - yarn build-storybook 27 | - cd - 28 | - yarn test-core 29 | - yarn test-front 30 | - yarn test-plugins 31 | - yarn test-contrib-pep 32 | 33 | addons: 34 | apt: 35 | sources: 36 | - ubuntu-toolchain-r-test 37 | packages: 38 | - g++-4.8 39 | - libfontconfig1-dev 40 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "typescript.tsdk": "./node_modules/typescript/lib", 3 | "tslint.autoFixOnSave": true, 4 | "prettier.disableLanguages": ["vue", "json", "markdown"] 5 | } 6 | -------------------------------------------------------------------------------- /.yarnclean: -------------------------------------------------------------------------------- 1 | # test directories 2 | __tests__ 3 | test 4 | tests 5 | powered-test 6 | 7 | # asset directories 8 | docs 9 | doc 10 | website 11 | images 12 | assets 13 | 14 | # examples 15 | example 16 | examples 17 | 18 | # code coverage directories 19 | coverage 20 | .nyc_output 21 | 22 | # build scripts 23 | Makefile 24 | Gulpfile.js 25 | Gruntfile.js 26 | 27 | # configs 28 | appveyor.yml 29 | circle.yml 30 | codeship-services.yml 31 | codeship-steps.yml 32 | wercker.yml 33 | .tern-project 34 | .gitattributes 35 | .editorconfig 36 | .*ignore 37 | .eslintrc 38 | .jshintrc 39 | .flowconfig 40 | .documentup.json 41 | .yarn-metadata.json 42 | .travis.yml 43 | 44 | # misc 45 | *.md 46 | 47 | # Fuck 48 | @types/react-native 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2019 Ragg 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 | 23 | -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/assets/screenshot.png -------------------------------------------------------------------------------- /build-assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/build-assets/icon.png -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | rootDir: '.', 3 | preset: 'ts-jest', 4 | testRegex: 'src/.*\\.spec\\.tsx?$', 5 | moduleFileExtensions: ['ts', 'js'], 6 | globals: { 7 | 'ts-jest': { 8 | tsConfig: 'tsconfig.test.json', 9 | }, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /packages/contrib-posteffect/index.spec.ts: -------------------------------------------------------------------------------- 1 | import glob from 'glob-promise' 2 | import semver from 'semver' 3 | import delirPackageJson from '../core/package.json' 4 | 5 | describe('Plugins', () => { 6 | const coreVersion = delirPackageJson.version 7 | 8 | it('Check compliancy to engines version', async () => { 9 | const packages = await glob('./*/package.json', { cwd: __dirname }) 10 | 11 | let hasError = false 12 | for (const path of packages) { 13 | const { name, engines } = require(path) 14 | const supportedVersion = engines['@delirvfx/core'] 15 | const satis = semver.satisfies(coreVersion, supportedVersion) 16 | 17 | if (!satis) { 18 | // tslint:disable-next-line 19 | console.error( 20 | `Plugin \`${name}\` not satisfy version to @delirvfx/core@${coreVersion} (set to ${supportedVersion})`, 21 | ) 22 | } 23 | 24 | hasError = satis != true || hasError 25 | } 26 | 27 | expect(hasError).toBe(false) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /packages/contrib-posteffect/jest.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path') 2 | 3 | module.exports = { 4 | ...require('../../jest.config'), 5 | testRegex: '.*\\.spec\\.ts$', 6 | globals: { 7 | 'ts-jest': { 8 | tsConfig: join(__dirname, 'tsconfig.test.json'), 9 | isolatedModules: true, 10 | }, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /packages/contrib-posteffect/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/contrib-posteffect/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/core-test-helper/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/core-test-helper", 3 | "version": "0.0.0", 4 | "main": "index.ts", 5 | "author": "ragg ", 6 | "license": "MIT", 7 | "description": "Test helpers for @delivfx/core(@delirvfx/core)", 8 | "dependencies": { 9 | "@delirvfx/core": "*" 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | npm-debug.log 3 | 4 | node_modules/ 5 | src/**/*.js 6 | lib/ 7 | typings/ 8 | -------------------------------------------------------------------------------- /packages/core/.npmignore: -------------------------------------------------------------------------------- 1 | /plugin-example 2 | /spec 3 | /src 4 | /CHANGELOG.md 5 | /jest.config.js 6 | /plugin-example.zip 7 | /SCHEMA_CHANGELOG.md 8 | /tsconfig.json 9 | /tsconfig.test.json 10 | -------------------------------------------------------------------------------- /packages/core/README.md: -------------------------------------------------------------------------------- 1 | # @delirvfx/core 2 | 3 | An Web technology based VFX engine for best VFX app you make! 4 | 5 | The engine / modules of [Delir](https://github.com/ra-gg/Delir). 6 | 7 | ## Standalone usage 8 | 9 | See [this example](https://github.com/ra-gg/Delir/tree/master/packages/web-example/src/index.ts) 10 | -------------------------------------------------------------------------------- /packages/core/SCHEMA_CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Project schema Changelog 2 | 3 | #### version: 2017091401 4 | Initial version (delir-core: 0.4.0) 5 | -------------------------------------------------------------------------------- /packages/core/jest.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path') 2 | 3 | module.exports = { 4 | ...require('../../jest.config'), 5 | globals: { 6 | 'ts-jest': { 7 | tsConfig: join(__dirname, 'tsconfig.test.json'), 8 | isolatedModules: true, 9 | }, 10 | }, 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/core", 3 | "version": "0.12.0", 4 | "description": "JavaScript VFX Engine", 5 | "main": "lib/index.js", 6 | "types": "lib/index.d.ts", 7 | "author": "Ragg ", 8 | "license": "MIT", 9 | "homepage": "https://github.com/Ragg-/Delir/tree/master/src/delir-core", 10 | "scripts": { 11 | "prepublishOnly": "rm -rf ./{typings,lib} && tsc --emitDeclarationOnly --declaration --outDir ./lib && tsc --outDir lib" 12 | }, 13 | "devDependencies": { 14 | "@delirvfx/core-test-helper": "*", 15 | "@types/audiobuffer-to-wav": "1.0.0", 16 | "@types/jest": "24.0.25", 17 | "@types/joi": "14.3.4", 18 | "@types/lodash": "4.14.123", 19 | "@types/semver": "6.0.2", 20 | "@types/uuid": "3.4.5", 21 | "jest": "24.9.0", 22 | "ts-jest": "24.2.0" 23 | }, 24 | "dependencies": { 25 | "bezier-easing": "2.1.0", 26 | "fontmanager-redux": "0.4.0", 27 | "joi-browser": "^13.4.0", 28 | "lodash": "4.17.15", 29 | "p5": "1.0.0", 30 | "semver": "6.3.0", 31 | "typescript": "3.7.4", 32 | "uuid": "3.3.3" 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/core/plugin-example.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/core/plugin-example.zip -------------------------------------------------------------------------------- /packages/core/plugin-example/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | Thumbs.db 3 | 4 | /dist/ -------------------------------------------------------------------------------- /packages/core/plugin-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "delir-plugin-example", 3 | "version": "0.0.0", 4 | "description": "Example plugin for Delir", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "dev": "./node_modules/.bin/webpack --watch", 8 | "build": "./node_modules/.bin/webpack" 9 | }, 10 | "engines": { 11 | "@delirvfx/core": "0.11.x" 12 | }, 13 | "delir": { 14 | "name": "サンプルプラグイン", 15 | "type": "post-effect" 16 | }, 17 | "devDependencies": { 18 | "@delirvfx/core": "0.11.x", 19 | "ts-loader": "6.2.0", 20 | "typescript": "3.4.5", 21 | "webpack": "4.41.2", 22 | "webpack-cli": "3.3.9" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/plugin-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": ".", 4 | "target": "es2016", 5 | "lib": ["dom", "es2015", "es2016"], 6 | "moduleResolution": "node" 7 | }, 8 | "files": ["src/index.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/core/plugin-example/webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack') 2 | const path = require('path') 3 | 4 | const sourceDir = path.join(__dirname, 'src') 5 | const distDir = path.join(__dirname, 'dist') 6 | 7 | module.exports = { 8 | target: 'web', 9 | context: sourceDir, 10 | entry: { 11 | index: './index.ts', 12 | }, 13 | output: { 14 | filename: '[name].js', 15 | path: distDir, 16 | libraryTarget: 'commonjs-module', 17 | }, 18 | resolve: { 19 | extensions: ['.js', '.ts'], 20 | modules: ['node_modules'], 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.ts$/, 26 | loader: 'ts-loader', 27 | options: { 28 | // If you want to type checking, please set 'false' to this option. 29 | transpileOnly: true, 30 | }, 31 | }, 32 | ], 33 | }, 34 | plugins: [new webpack.ExternalsPlugin('commonjs', ['@delirvfx/core'])], 35 | } 36 | -------------------------------------------------------------------------------- /packages/core/src/Editor/Editor.tsx: -------------------------------------------------------------------------------- 1 | import { Engine } from '../Engine' 2 | 3 | export class Editor { 4 | public player: Engine 5 | public project: Project 6 | 7 | constructor() { 8 | this.player = new Engine() 9 | } 10 | 11 | public openProject(project: any) { 12 | this.player.project 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/Engine/AssetProxy.ts: -------------------------------------------------------------------------------- 1 | import { Asset } from '../Entity' 2 | 3 | export class AssetProxy { 4 | get id(): string { 5 | return this._asset.id 6 | } 7 | 8 | /** 9 | * Asset file extension (without `.` prefix) 10 | */ 11 | get fileType(): string { 12 | return this._asset.fileType 13 | } 14 | 15 | get name(): string { 16 | return this._asset.name 17 | } 18 | 19 | get path(): string { 20 | return this._asset.path 21 | } 22 | 23 | constructor(private _asset: Asset) { 24 | Object.seal(this) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /packages/core/src/Engine/ExpressionSupport/EffectProxy.ts: -------------------------------------------------------------------------------- 1 | export interface EffectProxy { 2 | params: Record 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/Engine/ExpressionSupport/ExpressionCompiler.ts: -------------------------------------------------------------------------------- 1 | import TypeScript from 'typescript' 2 | 3 | export const compileTypeScript = (code: string, compilerOption: TypeScript.CompilerOptions = {}) => { 4 | const option: TypeScript.CompilerOptions = { 5 | target: TypeScript.ScriptTarget.ES2015, 6 | lib: ['es2015', 'es2016'], 7 | ...compilerOption, 8 | } 9 | 10 | return TypeScript.transpile(code, option) 11 | } 12 | -------------------------------------------------------------------------------- /packages/core/src/Engine/IRenderingStreamObserver.ts: -------------------------------------------------------------------------------- 1 | export interface RenderingStatus { 2 | readonly time: number 3 | readonly frame: number 4 | readonly durationFrame: number 5 | readonly samplingRate: number 6 | } 7 | 8 | export interface IRenderingStreamObserver { 9 | onStateChanged?: (status: RenderingStatus) => void 10 | onFrame?: (canvas: Readonly, status: RenderingStatus) => void 11 | onAudioBuffered?: (buffers: Float32Array[], status: RenderingStatus) => void 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/src/Engine/ParamType.ts: -------------------------------------------------------------------------------- 1 | import { AssetProxy } from '../Engine/AssetProxy' 2 | import { ColorRGB as _ColorRGB, ColorRGBA as _ColorRGBA, Expression } from '../Values' 3 | 4 | /** The type of value given to the parameter */ 5 | export namespace ParamType { 6 | export type ColorRGB = _ColorRGB 7 | export type ColorRGBA = _ColorRGBA 8 | export type Bool = boolean 9 | export type String = string 10 | export type Number = number 11 | export type Float = number 12 | export type Enum = string 13 | export type Asset = AssetProxy 14 | export type Code = Expression 15 | } 16 | -------------------------------------------------------------------------------- /packages/core/src/Engine/RenderContext/ClipPreRenderContext.ts: -------------------------------------------------------------------------------- 1 | import { Clip } from '../../Entity' 2 | import { RealParameterValues } from '../ParametersTable' 3 | import { IRenderContextBase } from './IRenderContextBase' 4 | 5 | export interface ClipPreRenderContext 6 | extends IRenderContextBase, 7 | ClipPreRenderContextAttributes {} 8 | 9 | export interface ClipPreRenderContextAttributes { 10 | clip: Clip 11 | parameters: T 12 | } 13 | -------------------------------------------------------------------------------- /packages/core/src/Engine/RenderContext/ClipRenderContext.ts: -------------------------------------------------------------------------------- 1 | import { Clip } from '../../Entity' 2 | import { ReferenceableEffectsParams } from '../ExpressionSupport/ExpressionContext' 3 | import { RealParameterValues } from '../ParametersTable' 4 | import { IRenderContextBase } from './IRenderContextBase' 5 | 6 | export interface ClipRenderContext 7 | extends IRenderContextBase, 8 | ClipRenderContextAttributes {} 9 | 10 | export interface ClipRenderContextAttributes { 11 | clip: Readonly 12 | parameters: T 13 | beforeExpressionParameters: T 14 | clipEffectParams: ReferenceableEffectsParams 15 | 16 | timeOnClip: number 17 | frameOnClip: number 18 | 19 | // Destinations 20 | srcCanvas: HTMLCanvasElement | null 21 | destCanvas: HTMLCanvasElement 22 | srcAudioBuffer: Float32Array[] | null 23 | destAudioBuffer: Float32Array[] 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/src/Engine/RenderContext/EffectPreRenderContext.ts: -------------------------------------------------------------------------------- 1 | import { Effect } from '../../Entity' 2 | import { ReferenceableEffectsParams } from '../ExpressionSupport/ExpressionContext' 3 | import { RealParameterValues } from '../ParametersTable' 4 | import { IRenderContextBase } from './IRenderContextBase' 5 | 6 | export interface EffectPreRenderContext 7 | extends IRenderContextBase, 8 | EffectPreRenderContextAttributes {} 9 | 10 | export interface EffectPreRenderContextAttributes { 11 | effect: Effect 12 | parameters: T 13 | clipEffectParams: ReferenceableEffectsParams 14 | } 15 | -------------------------------------------------------------------------------- /packages/core/src/Engine/RenderContext/EffectRenderContext.ts: -------------------------------------------------------------------------------- 1 | import { Effect } from '../../Entity' 2 | import { ReferenceableEffectsParams } from '../ExpressionSupport/ExpressionContext' 3 | import { RealParameterValues } from '../ParametersTable' 4 | import { IRenderContextBase } from './IRenderContextBase' 5 | 6 | export interface EffectRenderContext 7 | extends IRenderContextBase, 8 | EffectRenderContextAttributes {} 9 | 10 | export interface EffectRenderContextAttributes { 11 | effect: Effect 12 | parameters: T 13 | clipEffectParams: ReferenceableEffectsParams 14 | 15 | timeOnClip: number 16 | frameOnClip: number 17 | 18 | srcCanvas: HTMLCanvasElement 19 | destCanvas: HTMLCanvasElement 20 | } 21 | -------------------------------------------------------------------------------- /packages/core/src/Engine/RenderContext/IRenderContextBase.ts: -------------------------------------------------------------------------------- 1 | import { Composition } from '../../Entity' 2 | import DependencyResolver from '../DependencyResolver' 3 | import WebGLContext from '../WebGL/WebGLContext' 4 | 5 | export interface IRenderContextBase { 6 | time: number 7 | timeOnComposition: number 8 | 9 | frame: number 10 | frameOnComposition: number 11 | 12 | // Composition properties 13 | width: number 14 | height: number 15 | framerate: number 16 | durationFrames: number 17 | samplingRate: number 18 | audioChannels: number 19 | neededSamples: number 20 | isAudioBufferingNeeded: boolean 21 | transparentBackground: boolean 22 | 23 | rootComposition: Readonly 24 | 25 | resolver: DependencyResolver 26 | 27 | // Destinations 28 | destCanvas: HTMLCanvasElement 29 | destAudioBuffer: Float32Array[] 30 | audioContext: OfflineAudioContext 31 | gl: WebGLContext 32 | } 33 | -------------------------------------------------------------------------------- /packages/core/src/Engine/Renderer/Adjustment/Adjustment.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | import Type from '../../../PluginSupport/TypeDescriptor' 4 | import { TypeDescriptor } from '../../../PluginSupport/TypeDescriptor' 5 | import { ParamType } from '../../ParamType' 6 | import { ClipPreRenderContext } from '../../RenderContext/ClipPreRenderContext' 7 | import { ClipRenderContext } from '../../RenderContext/ClipRenderContext' 8 | import { IRenderer } from '../RendererBase' 9 | 10 | interface Param { 11 | opacity: ParamType.Number 12 | } 13 | 14 | export class AdjustmentRenderer implements IRenderer { 15 | public static get rendererId(): string { 16 | return 'adjustment' 17 | } 18 | 19 | public static provideAssetAssignMap() { 20 | return {} 21 | } 22 | 23 | public static provideParameters(): TypeDescriptor { 24 | return Type.number('opacity', { 25 | label: 'Opacity', 26 | defaultValue: () => 100, 27 | animatable: true, 28 | }) 29 | } 30 | 31 | public async beforeRender(context: ClipPreRenderContext) { 32 | return 33 | } 34 | 35 | public async render(context: ClipRenderContext) { 36 | const ctx = context.destCanvas.getContext('2d')! 37 | ctx.drawImage(context.srcCanvas!, 0, 0) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/core/src/Engine/Renderer/P5js/P5Hooks.ts: -------------------------------------------------------------------------------- 1 | import P5 from 'p5' 2 | import DependencyResolver from '../../DependencyResolver' 3 | 4 | export class P5Hooks { 5 | public p5: any 6 | private node: HTMLDivElement 7 | 8 | constructor(private resolver: DependencyResolver) { 9 | // nodeを渡さないとdocument.body.appendChildされてしまう! 10 | // https://github.com/processing/p5.js/blob/a64959e2722c4cad9327246be494f0b472ccd54c/src/core/rendering.js#L98 11 | this.node = document.createElement('div') 12 | 13 | this.p5 = new P5((p5: any) => { 14 | p5._loop = false // disable auto rendering 15 | p5.setup = () => {} // noop 16 | p5.draw = () => {} // noop 17 | p5.loadImage = this.loadImage 18 | }, this.node) 19 | } 20 | 21 | get preloadCount() { 22 | return this.p5._preloadCount 23 | } 24 | 25 | private loadImage = (path: string, successCallback: (pImg: any) => void, failureCallback: (e: any) => void) => { 26 | const match = /^delir:(.+)/.exec(path) 27 | 28 | if (match) { 29 | path = this.resolver.resolveAsset(match[1])!.path 30 | } 31 | 32 | return P5.prototype.loadImage.call(this.p5, path, successCallback, failureCallback) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/core/src/Engine/Renderer/P5js/P5js.spec.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs-extra' 2 | import { join } from 'path' 3 | import { Expression } from '../../../Values' 4 | import { RenderContextBase } from '../../RenderContext/RenderContextBase' 5 | import { P5jsRenderer } from './P5js' 6 | 7 | jest.mock('./P5Hooks', () => ({ 8 | __esModule: true, 9 | P5Hooks: class { 10 | public p5 = { 11 | canvas: {}, 12 | createCanvas: () => {}, 13 | } 14 | }, 15 | })) 16 | 17 | describe('P5js', () => { 18 | const renderer = new P5jsRenderer() 19 | it('Should accessible specified global objects', async () => { 20 | const sketch = (await fs.readFile(join(__dirname, 'specFixtures/globals.js'))).toString() 21 | const request = new RenderContextBase({ 22 | width: 100, 23 | height: 100, 24 | } as any).toClipPreRenderContext({ 25 | parameters: { 26 | sketch: new Expression('javascript', sketch), 27 | opacity: 1, 28 | }, 29 | }) 30 | 31 | await renderer.beforeRender(request) 32 | }) 33 | }) 34 | -------------------------------------------------------------------------------- /packages/core/src/Engine/Renderer/P5js/P5jsContextTypeDefinition.ts: -------------------------------------------------------------------------------- 1 | export const P5jsContextTypeDefinition = ` 2 | interface ClipAttributes { 3 | params: Readonly<{[propertyName: string]: any}> 4 | effect(effectName: string): EffectAttributes 5 | } 6 | 7 | interface EffectAttributes { 8 | params: { [paramName: string]: any } 9 | } 10 | 11 | declare const delir: { 12 | ctx: { 13 | time: number 14 | frame: number 15 | timeOnComposition: number 16 | frameOnComposition: number 17 | width: number 18 | height: number 19 | audioBuffer: Float32Array[] 20 | duration: number 21 | durationFrames: number 22 | currentValue: any 23 | clip: ClipAttributes 24 | } 25 | } 26 | ` 27 | -------------------------------------------------------------------------------- /packages/core/src/Engine/Renderer/P5js/specFixtures/globals.js: -------------------------------------------------------------------------------- 1 | const assert = b => { 2 | if (b === false) throw 'Assertion failed' 3 | } 4 | assert(typeof console.log === 'function') 5 | assert(typeof Math.abs === 'function') 6 | assert(typeof Array === 'function') 7 | assert(typeof Date === 'function') 8 | -------------------------------------------------------------------------------- /packages/core/src/Engine/Renderer/RendererBase.ts: -------------------------------------------------------------------------------- 1 | import { TypeDescriptor } from '../../PluginSupport/TypeDescriptor' 2 | import { ClipPreRenderContext } from '../RenderContext/ClipPreRenderContext' 3 | import { ClipRenderContext } from '../RenderContext/ClipRenderContext' 4 | 5 | export interface IRendererStatic { 6 | rendererId: string 7 | 8 | new (): IRenderer 9 | provideAssetAssignMap(): { [extName: string]: string } 10 | provideParameters(): TypeDescriptor 11 | } 12 | 13 | export interface IRenderer { 14 | beforeRender(request: ClipPreRenderContext): Promise 15 | render(request: ClipRenderContext): Promise 16 | } 17 | -------------------------------------------------------------------------------- /packages/core/src/Engine/index.ts: -------------------------------------------------------------------------------- 1 | import * as Renderer from './Renderer/index' 2 | 3 | import { createExpressionContext } from './ExpressionSupport/createExpressionContext' 4 | import { compileTypeScript } from './ExpressionSupport/ExpressionCompiler' 5 | export { expressionContextTypeDefinition } from './ExpressionSupport/ExpressionContext' 6 | export { default as Engine } from './Engine' 7 | export { Renderer as Renderers } 8 | export { ParamType } from './ParamType' 9 | export const ExpressionSupport = { createExpressionContext, compileTypeScript } 10 | -------------------------------------------------------------------------------- /packages/core/src/Entity/Asset.ts: -------------------------------------------------------------------------------- 1 | import uuid from 'uuid' 2 | import { Branded } from '../helper/Branded' 3 | import { safeAssign } from '../helper/safeAssign' 4 | 5 | interface AssetProps { 6 | id?: string 7 | fileType: string 8 | name: string 9 | path: string 10 | } 11 | 12 | type AssetId = Branded 13 | 14 | class Asset implements AssetProps { 15 | public id: Asset.Id 16 | 17 | /** Asset file extension (without `.` prefix) */ 18 | public fileType: string 19 | public name: string 20 | /** Full file path with schema (likes 'file:///path/to/asset.mp4) */ 21 | public path: string 22 | 23 | constructor(props: AssetProps) { 24 | this.id = uuid.v4() as Asset.Id 25 | safeAssign(this, props as AssetProps & { id: Asset.Id }) 26 | } 27 | 28 | public patch(props: Partial) { 29 | if (props.path && !/^.+:\/\//.test(props.path)) { 30 | throw new Error('Invalid asset path, path must be start with schema') 31 | } 32 | 33 | safeAssign(this, props) 34 | } 35 | } 36 | 37 | namespace Asset { 38 | export type Id = AssetId 39 | } 40 | 41 | export { Asset } 42 | -------------------------------------------------------------------------------- /packages/core/src/Entity/Effect.ts: -------------------------------------------------------------------------------- 1 | import uuid from 'uuid' 2 | 3 | import { Branded } from '../helper/Branded' 4 | import { safeAssign } from '../helper/safeAssign' 5 | import { Animatable } from './Animatable' 6 | 7 | export interface EffectProps { 8 | id?: string 9 | processor: string 10 | referenceName?: string | null 11 | } 12 | 13 | type EffectId = Branded 14 | 15 | class Effect extends Animatable implements EffectProps { 16 | public id: Effect.Id 17 | public processor: string 18 | public referenceName: string | null = null 19 | 20 | constructor(props: EffectProps) { 21 | super() 22 | 23 | this.id = uuid.v4() as Effect.Id 24 | safeAssign(this, props as EffectProps & { id: Effect.Id }) 25 | } 26 | 27 | public patch(props: Partial) { 28 | safeAssign(this, props) 29 | } 30 | 31 | /** Clone effect with different Id */ 32 | public clone(): Effect { 33 | const { expressions, keyframes } = super.cloneKeyframes() 34 | const effect = new Effect({ ...this, id: uuid.v4() }) 35 | effect.expressions = expressions 36 | effect.keyframes = keyframes 37 | return effect 38 | } 39 | } 40 | 41 | namespace Effect { 42 | export type Id = EffectId 43 | } 44 | 45 | export { Effect } 46 | -------------------------------------------------------------------------------- /packages/core/src/Entity/index.ts: -------------------------------------------------------------------------------- 1 | export { Asset } from './Asset' 2 | export { Clip } from './Clip' 3 | export { Composition } from './Composition' 4 | export { Effect } from './Effect' 5 | export { Keyframe, KeyframeValueTypes } from './Keyframe' 6 | export { Layer } from './Layer' 7 | export { Project } from './Project' 8 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/DelirException.ts: -------------------------------------------------------------------------------- 1 | export interface ErrorDetail { 2 | before?: Error 3 | } 4 | 5 | export class DelirException extends Error { 6 | public before?: Error 7 | public message: string 8 | public detail?: ErrorDetail 9 | 10 | constructor(message: string, detail: T = {} as T) { 11 | super(message) 12 | 13 | this.message = message 14 | this.before = detail.before 15 | this.detail = detail 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/EffectPluginMissingException.ts: -------------------------------------------------------------------------------- 1 | import { DelirException, ErrorDetail } from './DelirException' 2 | 3 | interface MissingDetail extends ErrorDetail { 4 | effectId: string 5 | } 6 | 7 | export class EffectPluginMissingException extends DelirException {} 8 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/PlugiinAssertionFailedException.ts: -------------------------------------------------------------------------------- 1 | import { DelirException } from './DelirException' 2 | 3 | export class PluginAssertionFailedException extends DelirException {} 4 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/PluginLoadFailException.ts: -------------------------------------------------------------------------------- 1 | import { DelirException, ErrorDetail } from './DelirException' 2 | 3 | interface Reason extends ErrorDetail { 4 | reason: string[] 5 | } 6 | 7 | export class PluginLoadFailException extends DelirException {} 8 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/RenderingAbortedException.ts: -------------------------------------------------------------------------------- 1 | import { DelirException } from './DelirException' 2 | 3 | export class RenderingAbortedException extends DelirException {} 4 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/RenderingFailedException.ts: -------------------------------------------------------------------------------- 1 | import { DelirException } from './DelirException' 2 | 3 | export class RenderingFailedException extends DelirException {} 4 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/UnknownPluginReferenceException.ts: -------------------------------------------------------------------------------- 1 | import { DelirException } from './DelirException' 2 | 3 | export class UnknownPluginReferenceException extends DelirException {} 4 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/UserCodeException.ts: -------------------------------------------------------------------------------- 1 | interface ExceptionLocation { 2 | type: 'clip' | 'effect' 3 | entityId: string 4 | paramName: string 5 | } 6 | 7 | export class UserCodeException extends Error { 8 | public sourceError: Error 9 | public location: ExceptionLocation 10 | 11 | constructor( 12 | message: string, 13 | context: { 14 | sourceError: Error 15 | location: ExceptionLocation 16 | }, 17 | ) { 18 | super(message) 19 | this.sourceError = context.sourceError 20 | this.location = context.location 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/core/src/Exceptions/index.ts: -------------------------------------------------------------------------------- 1 | export { DelirException } from './DelirException' 2 | export { PluginLoadFailException } from './PluginLoadFailException' 3 | export { UnknownPluginReferenceException } from './UnknownPluginReferenceException' 4 | export { PluginAssertionFailedException } from './PlugiinAssertionFailedException' 5 | export { RenderingFailedException } from './RenderingFailedException' 6 | export { RenderingAbortedException } from './RenderingAbortedException' 7 | export { EffectPluginMissingException } from './EffectPluginMissingException' 8 | export { UserCodeException } from './UserCodeException' 9 | -------------------------------------------------------------------------------- /packages/core/src/Migration/ProjectMigrator.spec.ts: -------------------------------------------------------------------------------- 1 | import * as p2017091401 from '../../spec/fixture/project/2017091401.delir.json' 2 | import { deserializeProject } from '../Exporter' 3 | import ProjectMigrator from './ProjectMigrator' 4 | 5 | describe('ProjectMigrator', () => { 6 | it('Migrate to 2019052601 from 2017091401', () => { 7 | const beforeMigration = deserializeProject(p2017091401) 8 | const afterMigration = ProjectMigrator.migrate(beforeMigration) 9 | expect(afterMigration.assets).toMatchSnapshot() 10 | }) 11 | }) 12 | -------------------------------------------------------------------------------- /packages/core/src/Migration/ProjectMigrator.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | import { Project } from '../Entity/Project' 3 | import { walkAssets } from './MigrationHelper' 4 | 5 | export default { 6 | isMigratable: (project: Project) => { 7 | if (project.formatVersion === '2017091401') { 8 | return true 9 | } 10 | 11 | return false 12 | }, 13 | 14 | /** Migrate project to latest schema at migratable version */ 15 | migrate: (project: Project) => { 16 | if (project.formatVersion === '2017091401') { 17 | walkAssets(project, asset => { 18 | asset.path = `file://${asset.path}` 19 | }) 20 | } 21 | 22 | return project 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/src/Migration/__snapshots__/ProjectMigrator.spec.ts.snap: -------------------------------------------------------------------------------- 1 | // Jest Snapshot v1, https://goo.gl/fbAQLP 2 | 3 | exports[`ProjectMigrator Migrate to 2019052601 from 2017091401 1`] = ` 4 | Array [ 5 | Asset { 6 | "fileType": "mp4", 7 | "id": "78262d20-af63-4520-abfd-34e85e855618", 8 | "name": "BigBuckBunny", 9 | "path": "file:///Users/ragg/workspace/delir/packages/delir/utils/Dev/ExampleProject1/big_buck_bunny.mp4", 10 | }, 11 | Asset { 12 | "fileType": "mp3", 13 | "id": "3748e817-9c43-43d4-be63-b8ddcd25a2fc", 14 | "name": "Audio", 15 | "path": "file:///Users/ragg/workspace/delir/packages/delir/utils/Dev/ExampleProject1/audio.mp3", 16 | }, 17 | Asset { 18 | "fileType": "png", 19 | "id": "0bbb7142-e2c2-4a8a-9a98-4adc833bcff1", 20 | "name": "Image", 21 | "path": "file:///Users/ragg/workspace/delir/packages/delir/utils/Dev/ExampleProject1/image.png", 22 | }, 23 | ] 24 | `; 25 | -------------------------------------------------------------------------------- /packages/core/src/PluginSupport/PluginBase.ts: -------------------------------------------------------------------------------- 1 | export default class PluginBase {} 2 | -------------------------------------------------------------------------------- /packages/core/src/PluginSupport/PostEffectBase.ts: -------------------------------------------------------------------------------- 1 | import { EffectPreRenderContext, EffectRenderContext } from '..' 2 | import PluginBase from './PluginBase' 3 | import { TypeDescriptor } from './TypeDescriptor' 4 | 5 | export interface EffectPluginClass { 6 | new (): EffectPluginBase 7 | provideParameters(): TypeDescriptor 8 | } 9 | 10 | export default abstract class EffectPluginBase extends PluginBase { 11 | public static provideParameters(): TypeDescriptor { 12 | // None 13 | return new TypeDescriptor() 14 | } 15 | 16 | public abstract async initialize(context: EffectPreRenderContext): Promise 17 | 18 | public abstract async render(context: EffectRenderContext): Promise 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/PluginSupport/index.ts: -------------------------------------------------------------------------------- 1 | export { default as PluginBase } from './PluginBase' 2 | export { default as PostEffectBase } from './PostEffectBase' 3 | export { default as PluginRegistry } from './PluginRegistry' 4 | export { default as TypeDescriptor } from './TypeDescriptor' 5 | 6 | import * as Types from './types' 7 | export { Types } 8 | -------------------------------------------------------------------------------- /packages/core/src/PluginSupport/types.ts: -------------------------------------------------------------------------------- 1 | import { DeepReadonly } from '../helper/proxyFreeze' 2 | import PluginBase from './PluginBase' 3 | 4 | export type PluginTypes = 'post-effect' 5 | 6 | export interface PackageJSONDelirSection { 7 | name: string 8 | type: PluginTypes 9 | // acceptFileTypes?: {[extension: string]: string} 10 | } 11 | 12 | export interface DelirPluginPackageJson { 13 | name: string 14 | version: string 15 | author: string | string[] 16 | main?: string 17 | engines: { 18 | 'delir-core'?: string 19 | '@delirvfx/core': string 20 | } 21 | delir: PackageJSONDelirSection 22 | } 23 | 24 | export interface PluginEntry { 25 | id: string 26 | type: PluginTypes 27 | packageJson: DelirPluginPackageJson 28 | class: typeof PluginBase 29 | // parameters: TypeDescriptor 30 | } 31 | 32 | export interface PluginSummary { 33 | id: string 34 | name: string 35 | type: PluginTypes 36 | package: DeepReadonly 37 | } 38 | -------------------------------------------------------------------------------- /packages/core/src/Values/AssetPointer.ts: -------------------------------------------------------------------------------- 1 | export default class AssetPointer { 2 | constructor(public assetId: string | null = null) {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/Values/Expression.ts: -------------------------------------------------------------------------------- 1 | export interface ExpressionJSON { 2 | language: string 3 | code: string 4 | } 5 | 6 | export default class Expression { 7 | public static fromJSON(json: ExpressionJSON) { 8 | return new Expression(json.language, json.code) 9 | } 10 | 11 | constructor(public language: string, public code: string) {} 12 | 13 | public toJSON() { 14 | return { 15 | language: this.language, 16 | code: this.code, 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/Values/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Point2D } from './point-2d' 2 | export { default as Point3D } from './point-3d' 3 | export { default as Size2D } from './size-2d' 4 | export { default as Size3D } from './size-3d' 5 | export { default as AssetPointer } from './AssetPointer' 6 | export { default as ColorRGB } from './ColorRGB' 7 | export { default as ColorRGBA } from './ColorRGBA' 8 | export { default as Expression } from './Expression' 9 | -------------------------------------------------------------------------------- /packages/core/src/Values/point-2d.ts: -------------------------------------------------------------------------------- 1 | export default class Point2D { 2 | constructor(public x: number, public y: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/Values/point-3d.ts: -------------------------------------------------------------------------------- 1 | export default class Point3D { 2 | constructor(public x: number, public y: number, public z: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/Values/size-2d.ts: -------------------------------------------------------------------------------- 1 | export default class Size2D { 2 | constructor(public width: number, public height: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/Values/size-3d.ts: -------------------------------------------------------------------------------- 1 | export default class Size3D { 2 | constructor(public width: number, public height: number, public depth: number) {} 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/helper/Branded.ts: -------------------------------------------------------------------------------- 1 | export type Branded = T & { [k in Ident]: never } 2 | -------------------------------------------------------------------------------- /packages/core/src/helper/FPSCounter.ts: -------------------------------------------------------------------------------- 1 | export default class FPSCounter { 2 | private lastCommitTime: number = 0 3 | private _latestFPS: number = 0 4 | 5 | public increase = () => { 6 | const now = Date.now() 7 | this._latestFPS = 1000 / (now - this.lastCommitTime) 8 | this.lastCommitTime = now 9 | } 10 | 11 | public latestFPS = () => { 12 | return this._latestFPS 13 | } 14 | 15 | public reset = () => { 16 | this.lastCommitTime = Date.now() 17 | this._latestFPS = 0 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /packages/core/src/helper/defaults.ts: -------------------------------------------------------------------------------- 1 | const hasOwnProperty = (obj: Object, key: string) => Object.prototype.hasOwnProperty.call(obj, key) 2 | 3 | export default function defaults(obj: T, defaults: D, nullable = false): T & D { 4 | const merged: any = { ...(obj as object) } as T & D 5 | 6 | for (const key in defaults) { 7 | const _key = key as string 8 | 9 | if (hasOwnProperty(obj, key)) { 10 | merged[_key] = nullable 11 | ? (obj as any)[_key] 12 | : (obj as any)[_key] == null 13 | ? (defaults as any)[_key] 14 | : (obj as any)[_key] 15 | } else { 16 | merged[_key] = (defaults as any)[_key] 17 | } 18 | } 19 | 20 | return merged 21 | } 22 | -------------------------------------------------------------------------------- /packages/core/src/helper/neverCheck.ts: -------------------------------------------------------------------------------- 1 | export const neverCheck = (value: never) => { 2 | throw new Error(`Unexpected value given ${value}`) 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/src/helper/proxyFreeze.ts: -------------------------------------------------------------------------------- 1 | // prettier-ignore 2 | export type DeepReadonly = 3 | T extends object ? { readonly [K in keyof T]: DeepReadonly } 4 | : T extends Array ? ReadonlyArray 5 | : T 6 | 7 | export const proxyDeepFreeze = (obj: T): DeepReadonly => { 8 | if (obj === null) { 9 | return obj as DeepReadonly 10 | } 11 | 12 | if (typeof obj === 'object') { 13 | return new Proxy(obj as any, { 14 | get(target: T, property: string) { 15 | return proxyDeepFreeze((target as any)[property]) 16 | }, 17 | set() { 18 | throw new Error('Can not set value Object is readonly') 19 | }, 20 | }) 21 | } 22 | 23 | return obj as DeepReadonly 24 | } 25 | -------------------------------------------------------------------------------- /packages/core/src/helper/safeAssign.ts: -------------------------------------------------------------------------------- 1 | export const safeAssign = (dest: T, ...source: Partial[]): T => { 2 | return Object.assign(dest, ...source) 3 | } 4 | -------------------------------------------------------------------------------- /packages/core/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": "./src/", 5 | "allowJs": false, 6 | "resolveJsonModule": false 7 | }, 8 | "files": ["./src/index", "./src/declarations.d.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /packages/core/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "resolveJsonModule": true, 5 | "module": "commonjs" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/delir/.storybook/addons.ts: -------------------------------------------------------------------------------- 1 | import '@storybook/addon-knobs/register' 2 | -------------------------------------------------------------------------------- /packages/delir/.storybook/config.tsx: -------------------------------------------------------------------------------- 1 | import { configure } from '@storybook/react' 2 | import { addDecorator } from '@storybook/react' 3 | import React from 'react' 4 | import { createGlobalStyle } from 'styled-components' 5 | import { cssVars } from '../src/assets/styles/cssVars' 6 | import '../src/assets/styles/font-awesome.min.css' 7 | import '../src/assets/styles/style.sass' 8 | import './patch.sass' 9 | 10 | const GlobalStyles = createGlobalStyle` 11 | body { 12 | --color-theming: ${cssVars.colors.theming}; 13 | } 14 | ` 15 | 16 | addDecorator(storyFn => ( 17 | <> 18 | 19 | {storyFn()} 20 | 21 | )) 22 | configure(require.context('../src', true, /\.stories\.tsx$/), module) 23 | -------------------------------------------------------------------------------- /packages/delir/.storybook/patch.sass: -------------------------------------------------------------------------------- 1 | :global(#root) 2 | display: block 3 | width: auto 4 | height: auto 5 | min-width: 100% 6 | min-height: 100% 7 | overflow: visible 8 | padding: 16px 9 | background: #353535 10 | color: #fff 11 | -------------------------------------------------------------------------------- /packages/delir/__spec__/__bootstrap__.js: -------------------------------------------------------------------------------- 1 | global.expect = require('expect.js') 2 | global.__DEV__ = false 3 | 4 | const stylus = require('stylus') 5 | 6 | require('ts-node').register({ 7 | fast: true, 8 | compilerOptions: { 9 | target: 'es2015', 10 | module: 'commonjs', 11 | }, 12 | }) 13 | 14 | require('css-modules-require-hook')({ 15 | extensions: ['.styl', '.sass'], 16 | preprocessCss: (css, filename) => 17 | stylus(css) 18 | .set('filename', filename) 19 | .render(), 20 | }) 21 | -------------------------------------------------------------------------------- /packages/delir/jest.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path') 2 | 3 | module.exports = { 4 | ...require('../../jest.config'), 5 | testRegex: '.*\\.spec\\.tsx?$', 6 | globals: { 7 | 'ts-jest': { 8 | tsConfig: join(__dirname, 'tsconfig.test.json'), 9 | isolatedModules: true, 10 | }, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /packages/delir/src/assets/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /packages/delir/src/assets/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /packages/delir/src/assets/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /packages/delir/src/assets/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /packages/delir/src/assets/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /packages/delir/src/assets/images/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/images/.gitkeep -------------------------------------------------------------------------------- /packages/delir/src/assets/images/delir.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/empty.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/images/empty.png -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f1f2-1f1e8.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f3fb.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f3fc.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f3fd.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f3fe.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f3ff.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f4a7.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f4d0.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f4f1.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f534.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f535.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f536.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f537.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f538.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f539.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f53a.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f53b.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f5e8.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f6d1.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/1f944.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/23f9.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/25aa.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/25ab.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/25fb.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/25fc.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/25fd.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/25fe.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2665.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2666.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/26aa.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/26ab.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2714.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2795.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2796.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2b1b.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2b1c.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/images/twemoji-svg/2b55.svg: -------------------------------------------------------------------------------- 1 | image/svg+xml 2 | -------------------------------------------------------------------------------- /packages/delir/src/assets/styles/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/assets/styles/.gitkeep -------------------------------------------------------------------------------- /packages/delir/src/assets/styles/cssVars.ts: -------------------------------------------------------------------------------- 1 | import { lighten, rgba } from 'polished' 2 | 3 | export const cssVars = { 4 | animate: { 5 | bgColorDuration: '200ms', 6 | clipAppearDuration: 300, 7 | function: 'cubic-bezier(.3, 1, .72, 1.06)', 8 | }, 9 | textColors: { 10 | muted: '#888', 11 | }, 12 | colors: { 13 | error: '#f83737', 14 | theming: '#7b14ea', 15 | appBg: '#353535', 16 | popupBg: lighten(0.08, '#353535'), 17 | listArea: rgba('#000', 0.2), 18 | listItemHovered: rgba('#fff', 0.08), 19 | dragover: rgba('#fff', 0.08), 20 | }, 21 | style: { 22 | activeBoxShadow: `0 0 0 3px ${rgba('#aa5bff', 0.4)}`, 23 | popupDropshadow: `0 0 4px ${rgba('#112', 0.5)}`, 24 | }, 25 | size: { 26 | radius: '4px', 27 | }, 28 | zIndex: { 29 | popup: 1000, 30 | }, 31 | } 32 | -------------------------------------------------------------------------------- /packages/delir/src/assets/styles/mixins.sass: -------------------------------------------------------------------------------- 1 | = disable-scrollbar 2 | &::-webkit-scrollbar 3 | display: none 4 | 5 | = thin-scrollbar 6 | &::-webkit-scrollbar 7 | width: 3px 8 | height: 3px 9 | background-color: rgba(#fff, .2) 10 | 11 | &::-webkit-scrollbar-thumb 12 | width: 3px 13 | height: 3px 14 | border-radius: 500px 15 | background-color: rgba(#fff, .2) 16 | 17 | &:hover, &:active 18 | background-color: rgba(#fff, .8) 19 | 20 | 21 | // &::-webkit-scrollbar-track-piece 22 | // background rgba(#fff, 0) 23 | // transition background .1s 24 | // 25 | // &:hover, &:active 26 | // background rgba(#fff, .5) 27 | -------------------------------------------------------------------------------- /packages/delir/src/assets/styles/reset.css: -------------------------------------------------------------------------------- 1 | html, 2 | body, 3 | div, 4 | span, 5 | applet, 6 | object, 7 | iframe, 8 | h1, 9 | h2, 10 | h3, 11 | h4, 12 | h5, 13 | h6, 14 | p, 15 | blockquote, 16 | pre, 17 | a, 18 | abbr, 19 | acronym, 20 | address, 21 | big, 22 | cite, 23 | code, 24 | del, 25 | dfn, 26 | em, 27 | img, 28 | ins, 29 | kbd, 30 | q, 31 | s, 32 | samp, 33 | small, 34 | strike, 35 | strong, 36 | sub, 37 | sup, 38 | tt, 39 | var, 40 | dl, 41 | dt, 42 | dd, 43 | ol, 44 | ul, 45 | li, 46 | fieldset, 47 | form, 48 | label, 49 | legend, 50 | table, 51 | caption, 52 | tbody, 53 | tfoot, 54 | thead, 55 | tr, 56 | th, 57 | td { 58 | margin: 0; 59 | padding: 0; 60 | border: 0; 61 | outline: 0; 62 | font-weight: inherit; 63 | font-style: inherit; 64 | font-family: inherit; 65 | font-size: 100%; 66 | vertical-align: baseline; 67 | } 68 | body { 69 | line-height: 1; 70 | color: #000; 71 | background: #fff; 72 | } 73 | ol, 74 | ul { 75 | list-style: none; 76 | } 77 | table { 78 | border-collapse: separate; 79 | border-spacing: 0; 80 | vertical-align: middle; 81 | } 82 | caption, 83 | th, 84 | td { 85 | text-align: left; 86 | font-weight: normal; 87 | vertical-align: middle; 88 | } 89 | a img { 90 | border: none; 91 | } 92 | -------------------------------------------------------------------------------- /packages/delir/src/assets/styles/variables.sass: -------------------------------------------------------------------------------- 1 | $pane-border-width: 1px 2 | // $pane-background: linear-gradient(to bottom, hsl(0, 0%, 10%), hsl(0, 0%, 9%)) 3 | $pane-background: transparent 4 | 5 | $color-theming: #7b14ea 6 | 7 | $color-text: #fff 8 | $color-info: #00acee 9 | $color-error: #f83737 10 | $color-error-lighten: rgba(#f83737, .5) 11 | $color-disabled: #9a9a9a 12 | 13 | $color-app-bg: #353535 14 | $color-app-bg-dark: #2c2c2c 15 | $color-app-bg-border-dark: #222 16 | $color-dropdown-bg: var(--background) 17 | $color-dropdown-border: var(--pane-border-color) 18 | $color-text: #fff 19 | $color-text-subbed: #aaa 20 | 21 | $animate-bgcolor-duration: 100ms 22 | $animate-modal-fade-duration: 400ms 23 | $animate-function: cubic-bezier(.3, 1, .72, 1.06) 24 | 25 | // z-index 26 | $z-index-frame-cursor: 100 27 | $z-index-expression-editor: 200 28 | $z-index-range-selection: 4000 29 | $z-index-dropdown: 5000 30 | $z-index-notifications: 10000 31 | $z-index-modal-window: 15000 32 | -------------------------------------------------------------------------------- /packages/delir/src/components/Button/Button.stories.tsx: -------------------------------------------------------------------------------- 1 | import { select, text, withKnobs } from '@storybook/addon-knobs' 2 | import { storiesOf } from '@storybook/react' 3 | import React from 'react' 4 | import { Button } from './Button' 5 | 6 | storiesOf('Components|Button', module) 7 | .addDecorator(withKnobs) 8 | .add('Button', () => { 9 | const label = text('label', 'Hello!') 10 | return ( 11 | 14 | ) 15 | }) 16 | -------------------------------------------------------------------------------- /packages/delir/src/components/Button/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./Button.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/Checkbox/Checkbox.tsx: -------------------------------------------------------------------------------- 1 | import { cssVars } from 'assets/styles/cssVars' 2 | import styled from 'styled-components' 3 | 4 | export const Checkbox = styled.input.attrs(() => ({ type: 'checkbox' }))` 5 | display: inline-flex; 6 | align-items: center; 7 | justify-content: center; 8 | width: 16px; 9 | height: 16px; 10 | margin: 0; 11 | overflow: hidden; 12 | 13 | text-align: center; 14 | vertical-align: middle; 15 | line-height: 14px; 16 | 17 | border: none; 18 | border-radius: ${cssVars.size.radius}; 19 | background-color: #bbb; 20 | outline: none; 21 | transition: background-color ${cssVars.animate.function} ${cssVars.animate.bgColorDuration}; 22 | 23 | -webkit-appearance: none; 24 | 25 | &::before { 26 | content: '✔'; 27 | color: #bbb; 28 | line-height: 1; 29 | } 30 | 31 | &:checked { 32 | background-color: #007dff; 33 | 34 | &::before { 35 | color: #fff; 36 | } 37 | } 38 | ` 39 | -------------------------------------------------------------------------------- /packages/delir/src/components/ContextMenu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./ContextMenu.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/DragNumberInput/DragNumberInput.sass: -------------------------------------------------------------------------------- 1 | .DragNumberInput 2 | display: inline-block 3 | 4 | width: 100% 5 | min-width: 1em 6 | min-height: 1em 7 | padding: 0 4px 8 | transition: border-bottom-color .1s 9 | 10 | border: 0 11 | border-bottom: 1px dotted #ff7a00 12 | 13 | outline: none 14 | background-color: transparent 15 | color: #ff7a00 16 | font-family: inherit 17 | 18 | text-align: right 19 | cursor: ew-resize 20 | box-sizing: border-box 21 | 22 | &[readonly] 23 | border-bottom: 1px solid transparent 24 | color: var(--text-subbed) 25 | 26 | cursor: default 27 | cursor: default 28 | user-select: none 29 | 30 | :global(.platform-win) 31 | .DragNumberInput 32 | cursor: text 33 | -------------------------------------------------------------------------------- /packages/delir/src/components/DragNumberInput/DragNumberInput.stories.tsx: -------------------------------------------------------------------------------- 1 | import { boolean, number, withKnobs } from '@storybook/addon-knobs' 2 | import { storiesOf } from '@storybook/react' 3 | import React from 'react' 4 | import DragNumberInput from './DragNumberInput' 5 | 6 | storiesOf('Components|DragNumberInput', module) 7 | .addDecorator(withKnobs) 8 | .add('DragNumberInput', () => { 9 | return ( 10 |
11 | 12 |
13 | ) 14 | }) 15 | -------------------------------------------------------------------------------- /packages/delir/src/components/DragNumberInput/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./DragNumberInput.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/Dropdown/Dropdown.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .dropdownInspector 4 | width: 0 5 | height: 0 6 | 7 | .dropdown 8 | position: fixed 9 | z-index: $z-index-dropdown 10 | opacity: 0 11 | pointer-events: none 12 | box-shadow: 0 0 4px rgba(#112, .5) 13 | 14 | transition-property: opacity 15 | transition-duration: 50ms 16 | transition-timing-function: ease-in-out 17 | 18 | &.--shown 19 | opacity: 1 20 | pointer-events: all 21 | -------------------------------------------------------------------------------- /packages/delir/src/components/Dropdown/Dropdown.stories.tsx: -------------------------------------------------------------------------------- 1 | import { withKnobs } from '@storybook/addon-knobs' 2 | import { storiesOf } from '@storybook/react' 3 | import React, { useRef } from 'react' 4 | import { Dropdown } from './Dropdown' 5 | 6 | storiesOf('Components|Dropdown', module) 7 | .addDecorator(withKnobs) 8 | .add('Dropdown', () => { 9 | const dropdownRef = useRef(null) 10 | 11 | return ( 12 |
dropdownRef.current!.toggle()}> 13 | Show / Hide 14 | 15 |
    16 |
  • Menu 1
  • 17 |
  • Menu 2
  • 18 |
19 |
20 |
21 | ) 22 | }) 23 | -------------------------------------------------------------------------------- /packages/delir/src/components/Dropdown/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./Dropdown.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/ExternalLink/ExternalLink.tsx: -------------------------------------------------------------------------------- 1 | import { remote } from 'electron' 2 | import React, { useCallback } from 'react' 3 | 4 | interface Props { 5 | href: string 6 | className?: string 7 | children: React.ReactChild 8 | } 9 | 10 | export const ExternalLink = (props: Props) => { 11 | const { href, className, children } = props 12 | 13 | const openLink = useCallback( 14 | (e: React.MouseEvent) => { 15 | remote.shell.openExternal(href) 16 | e.preventDefault() 17 | }, 18 | [href], 19 | ) 20 | 21 | return ( 22 | 23 | {children} 24 | 25 | ) 26 | } 27 | -------------------------------------------------------------------------------- /packages/delir/src/components/ExternalLink/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./ExternalLink.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/Form/index.tsx: -------------------------------------------------------------------------------- 1 | import s from './Form.sass' 2 | export default s 3 | -------------------------------------------------------------------------------- /packages/delir/src/components/FormSection/FormSection.stories.tsx: -------------------------------------------------------------------------------- 1 | import { text, withKnobs } from '@storybook/addon-knobs' 2 | import React from 'react' 3 | import { Input } from '../Input/Input' 4 | import { FormSection } from './FormSection' 5 | 6 | export default { 7 | title: 'Components|FormSection', 8 | decorators: [withKnobs], 9 | } 10 | 11 | export const normal = () => ( 12 | <> 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | ) 21 | -------------------------------------------------------------------------------- /packages/delir/src/components/FormSection/FormSection.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode } from 'react' 2 | import styled from 'styled-components' 3 | import { cssVars } from '../../assets/styles/cssVars' 4 | 5 | interface Props { 6 | label: ReactNode 7 | labelType?: keyof JSX.IntrinsicElements 8 | error?: string | null 9 | children?: ReactNode 10 | } 11 | 12 | const Container = styled.label` 13 | display: block; 14 | 15 | & + & { 16 | margin-top: 16px; 17 | } 18 | ` 19 | 20 | const Label = styled.span` 21 | display: block; 22 | margin-bottom: 4px; 23 | ` 24 | 25 | const Content = styled.div` 26 | display: block; 27 | ` 28 | 29 | const Error = styled.div` 30 | display: block; 31 | margin-top: 4px; 32 | line-height: 1.5; 33 | color: ${cssVars.colors.error}; 34 | ` 35 | 36 | export const FormSection = ({ label, labelType, error, children }: Props) => ( 37 | 38 | 39 | {children} 40 | {error && {error}} 41 | 42 | ) 43 | -------------------------------------------------------------------------------- /packages/delir/src/components/Icon/Icon.tsx: -------------------------------------------------------------------------------- 1 | import classNames from 'classnames' 2 | import React from 'react' 3 | 4 | export const Icon = ({ kind, className }: { kind: string; className?: string }) => ( 5 | 6 | ) 7 | -------------------------------------------------------------------------------- /packages/delir/src/components/Input/Input.stories.tsx: -------------------------------------------------------------------------------- 1 | import { boolean, text, withKnobs } from '@storybook/addon-knobs' 2 | import React from 'react' 3 | import { Input } from './Input' 4 | 5 | export default { 6 | title: 'Components|Input', 7 | decorators: [withKnobs], 8 | } 9 | 10 | export const normal = () => ( 11 | 17 | ) 18 | export const multiline = () => ( 19 | 25 | ) 26 | -------------------------------------------------------------------------------- /packages/delir/src/components/LabelInput/LabelInput.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { LabelInput } from './LabelInput' 3 | 4 | export default { 5 | title: 'Components|LabelInput', 6 | } 7 | 8 | export const normal = () => 9 | -------------------------------------------------------------------------------- /packages/delir/src/components/LabelInput/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./LabelInput.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/ModalContent/ModalContent.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | import { Button } from '../Button/Button' 4 | import { ModalContent } from './ModalContent' 5 | 6 | export default { 7 | title: 'ModalContent', 8 | } 9 | 10 | const Wrapper = styled.div` 11 | position: fixed; 12 | top: 0; 13 | left: 0; 14 | display: flex; 15 | width: 100%; 16 | height: 100%; 17 | align-items: flex-start; 18 | justify-content: center; 19 | background-color: #222; 20 | --background: #353535; 21 | ` 22 | 23 | export const normal = () => ( 24 | 25 | 28 | 29 | 30 | 31 | } 32 | > 33 |

Example modal

34 | Hi 35 |
36 |
37 | ) 38 | -------------------------------------------------------------------------------- /packages/delir/src/components/ModalContent/ModalContent.tsx: -------------------------------------------------------------------------------- 1 | import { cssVars } from 'assets/styles/cssVars' 2 | import React, { ReactNode } from 'react' 3 | import styled from 'styled-components' 4 | 5 | const Container = styled.div` 6 | min-width: 500px; 7 | max-width: 800px; 8 | width: 70vw; 9 | padding: 24px 16px 16px; 10 | background: ${cssVars.colors.popupBg}; 11 | border-radius: 0 0 4px 4px; 12 | box-shadow: ${cssVars.style.popupDropshadow}; 13 | 14 | h1 { 15 | font-size: 24px; 16 | line-height: 32px; 17 | margin-bottom: 16px; 18 | } 19 | 20 | h2 { 21 | font-size: 20px; 22 | margin: 24px 0 12px; 23 | } 24 | ` 25 | 26 | const Footer = styled.div` 27 | display: flex 28 | align-items: center 29 | justify-content: flex-end 30 | margin-top: 24px 31 | ` 32 | 33 | interface Props { 34 | children: ReactNode 35 | className?: string 36 | footer: ReactNode 37 | } 38 | 39 | export const ModalContent = ({ children, className, footer }: Props) => ( 40 | 41 | {children} 42 |
{footer}
43 |
44 | ) 45 | -------------------------------------------------------------------------------- /packages/delir/src/components/ModalOwner/ModalOwner.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .root 4 | display: flex 5 | position: fixed 6 | top: 0 7 | left: 0 8 | align-items: flex-start 9 | justify-content: center 10 | width: 100vw 11 | height: 100vh 12 | background-color: rgba(#000, .5) 13 | z-index: $z-index-modal-window 14 | -------------------------------------------------------------------------------- /packages/delir/src/components/MountTransition/MountTransition.tsx: -------------------------------------------------------------------------------- 1 | import React, { useEffect } from 'react' 2 | import { AnimatedValue, useTransition } from 'react-spring' 3 | 4 | type TransionOption = Parameters[2] 5 | 6 | interface Props extends TransionOption { 7 | children: (style: AnimatedValue<{}>) => JSX.Element 8 | } 9 | 10 | export const MountTransition = (props: Props): JSX.Element | null => { 11 | const [mounted, setState] = React.useState(false) 12 | const transitions = useTransition(mounted, null, props) 13 | 14 | useEffect(() => { 15 | setState(true) 16 | return () => setState(false) 17 | }) 18 | 19 | const { props: style } = transitions[0]! 20 | return mounted ? props.children(style) : null 21 | } 22 | -------------------------------------------------------------------------------- /packages/delir/src/components/MountTransition/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./MountTransition.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/Pane/Pane.tsx: -------------------------------------------------------------------------------- 1 | import classnames from 'classnames' 2 | import React, { FunctionComponent } from 'react' 3 | 4 | interface Props extends React.HTMLAttributes { 5 | resizable?: boolean 6 | allowFocus?: boolean 7 | className?: string 8 | } 9 | 10 | export const Pane: FunctionComponent = props => { 11 | const { className, allowFocus, resizable, children, ...rest } = props 12 | 13 | return ( 14 |
21 | {resizable ?
: null} 22 | {children} 23 |
24 | ) 25 | } 26 | 27 | Pane.defaultProps = { 28 | allowFocus: false, 29 | resizable: true, 30 | draggable: false, 31 | } 32 | -------------------------------------------------------------------------------- /packages/delir/src/components/Pane/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./Pane.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/components/Portal/Portal.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNode, useEffect, useMemo } from 'react' 2 | import { createPortal } from 'react-dom' 3 | 4 | export const Portal = ({ children }: { children: ReactNode }) => { 5 | const root = useMemo(() => document.createElement('div'), []) 6 | 7 | useEffect(() => { 8 | document.body.appendChild(root) 9 | return () => { 10 | document.body.removeChild(root) 11 | } 12 | }, []) 13 | 14 | return <>{createPortal(children, root)} 15 | } 16 | -------------------------------------------------------------------------------- /packages/delir/src/components/PropertyInput/Inputs/BoolTypeInput.tsx: -------------------------------------------------------------------------------- 1 | import { Checkbox } from 'components/Checkbox/Checkbox' 2 | import React, { ChangeEvent, useCallback, useState } from 'react' 3 | 4 | interface Props { 5 | value: boolean 6 | onChange: (value: boolean) => void 7 | } 8 | 9 | export const BoolTypeInput = ({ value, onChange }: Props) => { 10 | const [currentValue, setValue] = useState(value) 11 | const handleChange = useCallback((e: ChangeEvent) => { 12 | const { checked } = e.currentTarget 13 | setValue(checked) 14 | onChange(checked) 15 | }, []) 16 | 17 | return 18 | } 19 | -------------------------------------------------------------------------------- /packages/delir/src/components/PropertyInput/Inputs/EnumTypeInput.tsx: -------------------------------------------------------------------------------- 1 | import { SelectBox } from 'components/SelectBox/SelectBox' 2 | import React, { useCallback } from 'react' 3 | import { useMemo, useState } from 'react' 4 | 5 | interface Props { 6 | value: string 7 | items: string[] 8 | onChange: (value: string) => void 9 | } 10 | 11 | export const EnumTypeInput = ({ value, items, onChange }: Props) => { 12 | const [currentValue, setValue] = useState(value) 13 | 14 | const handleChange = useCallback( 15 | (value: string) => { 16 | onChange(value) 17 | setValue(value) 18 | }, 19 | [value, onChange], 20 | ) 21 | 22 | return ( 23 | 24 | {items.map(item => ( 25 | 26 | ))} 27 | 28 | ) 29 | } 30 | -------------------------------------------------------------------------------- /packages/delir/src/components/PropertyInput/Inputs/Inputs.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from 'utils/I18n' 2 | import { Platform } from 'utils/platform' 3 | 4 | export default I18n({ 5 | ja: { 6 | ok: `更新`, 7 | okWithShortcutKey: `更新 (${Platform.cmdOrCtrl}+Enter)`, 8 | discard: 'キャンセル', 9 | noAssets: '利用可能なアセットはありません', 10 | }, 11 | en: { 12 | ok: `Change`, 13 | okWithShortcutKey: `Change (${Platform.cmdOrCtrl}+Enter)`, 14 | discard: 'Cancel', 15 | noAssets: 'No usable assets', 16 | }, 17 | }) 18 | -------------------------------------------------------------------------------- /packages/delir/src/components/PropertyInput/Inputs/NumberTypeInput.tsx: -------------------------------------------------------------------------------- 1 | import DragNumberInput from 'components/DragNumberInput/DragNumberInput' 2 | import React, { useCallback, useState } from 'react' 3 | 4 | interface Props { 5 | value: number 6 | float: boolean 7 | onChange: (value: number) => void 8 | } 9 | 10 | export const NumberTypeInput = ({ value, float, onChange }: Props) => { 11 | const [currentValue, setValue] = useState(value) 12 | 13 | const handleChange = useCallback((value: number) => { 14 | setValue(value) 15 | onChange(value) 16 | }, []) 17 | 18 | return 19 | } 20 | -------------------------------------------------------------------------------- /packages/delir/src/components/PropertyInput/PropertyInput.stories.tsx: -------------------------------------------------------------------------------- 1 | import { Values } from '@delirvfx/core' 2 | import { boolean } from '@storybook/addon-knobs' 3 | import React from 'react' 4 | import { ColorTypeInput } from './Inputs/ColorTypeInput' 5 | import { StringTypeInput } from './Inputs/StringTypeInput' 6 | 7 | export default { 8 | title: 'Components|PropertyInput', 9 | } 10 | 11 | export const color = () => { 12 | const alpha = boolean('alpha', false) 13 | const value = alpha ? new Values.ColorRGBA(0, 0, 0, 1) : new Values.ColorRGB(0, 0, 0) 14 | return {}} /> 15 | } 16 | 17 | export const string = () => { 18 | return {}} /> 19 | } 20 | -------------------------------------------------------------------------------- /packages/delir/src/components/SelectBox/SelectBox.stories.tsx: -------------------------------------------------------------------------------- 1 | import { boolean } from '@storybook/addon-knobs' 2 | import React from 'react' 3 | import { SelectBox } from './SelectBox' 4 | 5 | export default { 6 | title: 'Components|Selectbox', 7 | } 8 | 9 | export const normal = () => ( 10 | 11 | 12 | 13 | 14 | ) 15 | -------------------------------------------------------------------------------- /packages/delir/src/components/Workspace/Workspace.tsx: -------------------------------------------------------------------------------- 1 | import classnames from 'classnames' 2 | import _ from 'lodash' 3 | import React, { FunctionComponent } from 'react' 4 | 5 | export interface Props extends React.DOMAttributes { 6 | className?: string 7 | acceptPaneDragIn?: boolean 8 | direction: 'vertical' | 'horizontal' 9 | } 10 | 11 | export const Workspace: FunctionComponent = ({ 12 | children, 13 | className, 14 | acceptPaneDragIn, 15 | direction, 16 | ...misc 17 | }: Props) => { 18 | return ( 19 |
20 | {children} 21 |
22 | ) 23 | } 24 | 25 | Workspace.defaultProps = { 26 | acceptPaneDragIn: false, 27 | } 28 | -------------------------------------------------------------------------------- /packages/delir/src/components/Workspace/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./Workspace.tsx" 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Editor/actions.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { action, actions } from '@fleur/fleur' 3 | 4 | import { NotificationEntry } from './EditorStore' 5 | import { DragEntity } from './operations' 6 | import { ClipboardEntry, ParameterTarget } from './types' 7 | 8 | export const EditorActions = actions('Editor', { 9 | setActiveProject: action<{ 10 | project: Delir.Entity.Project 11 | path?: string | null 12 | }>(), 13 | clearActiveProject: action<{}>(), 14 | setDragEntity: action(), 15 | clearDragEntity: action<{}>(), 16 | changeActiveComposition: action<{ compositionId: string }>(), 17 | changeActiveLayer: action<{ layerId: string }>(), 18 | changeSelectClip: action<{ clipIds: string[] }>(), 19 | addOrRemoveSelectClip: action<{ clipIds: string[] }>(), 20 | changeActiveParam: action<{ target: ParameterTarget | null }>(), 21 | addMessage: action(), 22 | removeMessage: action<{ id: string }>(), 23 | seekPreviewFrame: action<{ frame: number }>(), 24 | setClipboardEntry: action<{ entry: ClipboardEntry }>(), 25 | changePreferenceOpenState: action<{ open: boolean }>(), 26 | }) 27 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Editor/models.ts: -------------------------------------------------------------------------------- 1 | export const NotificationTimeouts = { 2 | verbose: 2000, 3 | error: 6000, 4 | userConfirmationNecessary: undefined, 5 | } 6 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Editor/operations.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | import { Platform } from '../../utils/platform' 3 | 4 | export default I18n({ 5 | ja: { 6 | saved: '保存しました!', 7 | letsSave: `そろそろプロジェクトを保存しましょう (${Platform.cmdOrCtrl}+S)`, 8 | autoSaved: 'プロジェクトを自動保存しました (:fileName)', 9 | packageExporting: 'プロジェクトパッケージを作成中です', 10 | packageExportCompleted: 'プロジェクトパッケージを保存しました', 11 | }, 12 | en: { 13 | saved: 'Project saved.', 14 | letsSave: `Let\'s save the project soon. (${Platform.cmdOrCtrl}+S)`, 15 | autoSaved: 'Project auto saved. (:fileName)', 16 | packageExporting: 'Project package saving now in progressing', 17 | packageExportCompleted: 'Project package saving completed', 18 | }, 19 | }) 20 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Editor/selectors.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { selector, selectorWithStore } from '@fleur/fleur' 3 | import { getClipsByIds, getCompositionById } from '../Project/selectors' 4 | import EditorStore from './EditorStore' 5 | import { ClipboardEntry } from './types' 6 | 7 | export const getSelectedClipIds = selector(getState => { 8 | return getState(EditorStore).selectClipIds 9 | }) 10 | 11 | export const getSelectedClips = selectorWithStore(getStore => { 12 | const clipIds = getSelectedClipIds(getStore) 13 | return getClipsByIds(getStore, clipIds).filter(clip => clip != null) as Delir.Entity.Clip[] 14 | }) 15 | 16 | export const getActiveLayerId = selector(getState => getState(EditorStore).activeLayerId) 17 | 18 | export const getActiveComp = selectorWithStore(getStore => { 19 | const id = getStore(EditorStore).state.activeComp?.id 20 | if (!id) return null 21 | return getCompositionById(getStore, id) 22 | }) 23 | 24 | export const getCurrentPreviewFrame = selector(getState => getState(EditorStore).currentPreviewFrame) 25 | 26 | export const getClipboardEntry = selector(getState => getState(EditorStore).clipboard as ClipboardEntry | null) 27 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Editor/types.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | 3 | export interface ParameterTarget { 4 | type: 'clip' | 'effect' 5 | entityId: string 6 | paramName: string 7 | } 8 | 9 | export interface ClipboardEntryClip { 10 | type: 'clip' 11 | entities: { 12 | offset: number 13 | clips: Delir.Entity.Clip[] 14 | }[] 15 | } 16 | 17 | export type ClipboardEntry = ClipboardEntryClip 18 | -------------------------------------------------------------------------------- /packages/delir/src/domain/History/HistoryGroup.ts: -------------------------------------------------------------------------------- 1 | import { OperationContext } from '@fleur/fleur' 2 | import { Command } from './HistoryStore' 3 | 4 | export class HistoryGroup implements Command { 5 | constructor(private commands: Command[]) {} 6 | 7 | public undo(context: OperationContext) { 8 | for (const command of this.commands) { 9 | command.undo(context) 10 | } 11 | } 12 | 13 | public redo(context: OperationContext) { 14 | for (const command of this.commands) { 15 | command.redo(context) 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/delir/src/domain/History/actions.ts: -------------------------------------------------------------------------------- 1 | import { action, actions } from '@fleur/fleur' 2 | 3 | import { Command } from './HistoryStore' 4 | 5 | export const HistoryActions = actions('History', { 6 | pushHistory: action<{ command: Command }>(), 7 | clearHistory: action<{}>(), 8 | undoing: action<{}>(), 9 | redoing: action<{}>(), 10 | }) 11 | -------------------------------------------------------------------------------- /packages/delir/src/domain/History/operations.ts: -------------------------------------------------------------------------------- 1 | import { operation } from '@fleur/fleur' 2 | import { HistoryActions } from './actions' 3 | import HistoryStore, { Command } from './HistoryStore' 4 | 5 | export const pushHistory = operation((context, { command }: { command: Command }) => { 6 | context.dispatch(HistoryActions.pushHistory, { command }) 7 | }) 8 | 9 | export const clearHistory = operation(({ dispatch }) => { 10 | dispatch(HistoryActions.clearHistory, {}) 11 | }) 12 | 13 | export const doUndo = operation(context => { 14 | const command = context.getStore(HistoryStore).getUndoCommand() 15 | 16 | if (command) { 17 | command.undo(context) 18 | context.dispatch(HistoryActions.undoing, {}) 19 | } 20 | }) 21 | 22 | export const doRedo = operation(context => { 23 | const command = context.getStore(HistoryStore).getRedoCommand() 24 | 25 | if (command) { 26 | command.redo(context) 27 | context.dispatch(HistoryActions.redoing, {}) 28 | } 29 | }) 30 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Preference/PreferenceStore.ts: -------------------------------------------------------------------------------- 1 | import { listen, reducerStore, Store } from '@fleur/fleur' 2 | import _ from 'lodash' 3 | 4 | import { PreferenceActions } from './actions' 5 | 6 | export interface Preference { 7 | editor: { 8 | /** Audio volume of 0 to 100 */ 9 | audioVolume: number 10 | } 11 | develop: { 12 | pluginDirs: string[] 13 | } 14 | renderer: { 15 | ignoreMissingEffect: boolean 16 | } 17 | } 18 | 19 | export const defaultPreferance = { 20 | editor: { 21 | audioVolume: 100, 22 | }, 23 | develop: { 24 | pluginDirs: [], 25 | }, 26 | renderer: { 27 | ignoreMissingEffect: false, 28 | }, 29 | } 30 | 31 | export default reducerStore('PreferenceStore', () => ({ ...defaultPreferance })) 32 | .listen(PreferenceActions.restorePreference, (draft, { preference }) => { 33 | _.merge(draft, preference) 34 | }) 35 | .listen(PreferenceActions.changePreference, (draft, { patch }) => { 36 | _.merge(draft, patch) 37 | }) 38 | .listen(PreferenceActions.changeDevelopPluginDirs, (draft, { dirs }) => { 39 | draft.develop.pluginDirs = dirs 40 | }) 41 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Preference/actions.ts: -------------------------------------------------------------------------------- 1 | import { action, actions } from '@fleur/fleur' 2 | 3 | import { Preference } from './PreferenceStore' 4 | 5 | type DeepPartial = { [P in keyof T]?: T[P] extends object ? DeepPartial : T[P] } 6 | 7 | export const PreferenceActions = actions('Preference', { 8 | restorePreference: action<{ preference: Preference }>(), 9 | changePreference: action<{ patch: DeepPartial }>(), 10 | changeDevelopPluginDirs: action<{ dirs: string[] }>(), 11 | }) 12 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Preference/models.spec.ts: -------------------------------------------------------------------------------- 1 | import { validateSchema } from './models' 2 | 3 | describe('PreferenceStore', () => { 4 | describe('Schema validation', () => { 5 | it('Should passing validation with correct schema', () => { 6 | const actual = validateSchema({ 7 | renderer: { 8 | ignoreMissingEffect: true, 9 | }, 10 | }) 11 | 12 | expect(actual).toBe(null) 13 | }) 14 | 15 | it('Should failed validation with correct schema', () => { 16 | const actual = validateSchema({ 17 | renderer: { 18 | ignoreMissingEffect: '💩', 19 | }, 20 | }) 21 | 22 | expect(actual).toBeInstanceOf(Error) 23 | }) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Preference/models.ts: -------------------------------------------------------------------------------- 1 | import Joi from 'joi' 2 | 3 | const preferenceSchema = Joi.object() 4 | .keys({ 5 | editor: Joi.object() 6 | .keys({ 7 | audioVolume: Joi.number() 8 | .min(0) 9 | .max(100) 10 | .required(), 11 | }) 12 | .strict(), 13 | develop: Joi.object() 14 | .keys({ 15 | pluginDirs: Joi.array().items(Joi.string()), 16 | }) 17 | .strict(), 18 | renderer: Joi.object() 19 | .keys({ 20 | ignoreMissingEffect: Joi.boolean().required(), 21 | }) 22 | .strict(), 23 | }) 24 | .strict() 25 | 26 | export const validateSchema = (obj: any): Joi.ValidationError | null => { 27 | const result = Joi.validate(obj, preferenceSchema) 28 | return result.error 29 | } 30 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Preference/selectors.ts: -------------------------------------------------------------------------------- 1 | import { selector } from '@fleur/fleur' 2 | import PreferenceStore from './PreferenceStore' 3 | 4 | export const getDevPluginDirs = selector(getState => getState(PreferenceStore).develop.pluginDirs) 5 | 6 | export const getAudioVolume = selector(getState => getState(PreferenceStore).editor.audioVolume) 7 | 8 | export const getAllPreferences = selector(getState => getState(PreferenceStore)) 9 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Preference/validation.spec.ts: -------------------------------------------------------------------------------- 1 | import { validateSchema } from './validation' 2 | 3 | describe('PreferenceStore', () => { 4 | describe('Schema validation', () => { 5 | it('Should passing validation with correct schema', () => { 6 | const actual = validateSchema({ 7 | renderer: { 8 | ignoreMissingEffect: true, 9 | }, 10 | }) 11 | 12 | expect(actual).toBe(null) 13 | }) 14 | 15 | it('Should failed validation with correct schema', () => { 16 | const actual = validateSchema({ 17 | renderer: { 18 | ignoreMissingEffect: '💩', 19 | }, 20 | }) 21 | 22 | expect(actual).toBeInstanceOf(Error) 23 | }) 24 | }) 25 | }) 26 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Preference/validation.ts: -------------------------------------------------------------------------------- 1 | import Joi from 'joi' 2 | 3 | const preferenceSchema = Joi.object() 4 | .keys({ 5 | editor: Joi.object() 6 | .keys({ 7 | audioVolume: Joi.number() 8 | .min(0) 9 | .max(100) 10 | .required(), 11 | }) 12 | .strict(), 13 | renderer: Joi.object() 14 | .keys({ 15 | ignoreMissingEffect: Joi.boolean().required(), 16 | }) 17 | .strict(true), 18 | }) 19 | .strict(true) 20 | 21 | export const validateSchema = (obj: any): Joi.ValidationError | null => { 22 | const result = Joi.validate(obj, preferenceSchema) 23 | return result.error 24 | } 25 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/AddAssetCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { Command } from '../../History/HistoryStore' 5 | import { ProjectActions } from '../actions' 6 | 7 | export class AddAssetCommand implements Command { 8 | constructor(private addedAsset: Delir.Entity.Asset) {} 9 | 10 | public undo(context: OperationContext) { 11 | context.dispatch(ProjectActions.removeAsset, { 12 | targetAssetId: this.addedAsset.id, 13 | }) 14 | } 15 | 16 | public redo(context: OperationContext) { 17 | context.dispatch(ProjectActions.addAsset, { 18 | asset: this.addedAsset, 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/AddClipCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { EditorActions } from '../../Editor/actions' 5 | import { Command } from '../../History/HistoryStore' 6 | import { ProjectActions } from '../actions' 7 | 8 | export class AddClipCommand implements Command { 9 | constructor( 10 | private parentCompositionId: string, 11 | private targetLayerId: string, 12 | private addedClip: Delir.Entity.Clip, 13 | ) {} 14 | 15 | public undo(context: OperationContext) { 16 | this.focusToParentComposition(context) 17 | 18 | context.dispatch(ProjectActions.removeClip, { 19 | targetClipId: this.addedClip.id, 20 | }) 21 | } 22 | 23 | public redo(context: OperationContext) { 24 | this.focusToParentComposition(context) 25 | 26 | context.dispatch(ProjectActions.addClip, { 27 | targetLayerId: this.targetLayerId, 28 | newClip: this.addedClip, 29 | }) 30 | } 31 | 32 | private focusToParentComposition(context: OperationContext) { 33 | context.dispatch(EditorActions.changeActiveComposition, { 34 | compositionId: this.parentCompositionId, 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/AddEffectIntoClipCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { EditorActions } from '../../Editor/actions' 5 | import { Command } from '../../History/HistoryStore' 6 | import { ProjectActions } from '../actions' 7 | 8 | export class AddEffectIntoClipCommand implements Command { 9 | constructor(private clipId: string, private addedEffect: Delir.Entity.Effect) {} 10 | 11 | public undo(context: OperationContext) { 12 | this.focusToParentClip(context) 13 | 14 | context.dispatch(ProjectActions.removeEffectFromClip, { 15 | holderClipId: this.clipId, 16 | targetEffectId: this.addedEffect.id, 17 | }) 18 | } 19 | 20 | public redo(context: OperationContext) { 21 | this.focusToParentClip(context) 22 | 23 | context.dispatch(ProjectActions.addEffectIntoClip, { 24 | clipId: this.clipId, 25 | effect: this.addedEffect, 26 | }) 27 | } 28 | 29 | private focusToParentClip(context: OperationContext) { 30 | context.dispatch(EditorActions.changeSelectClip, { 31 | clipIds: [this.clipId], 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/AddLayerCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { EditorActions } from '../../Editor/actions' 5 | import { Command } from '../../History/HistoryStore' 6 | import { ProjectActions } from '../actions' 7 | 8 | export class AddLayerCommand implements Command { 9 | constructor(private targetCompositionId: string, private addedLayer: Delir.Entity.Layer, private index: number) {} 10 | 11 | public undo(context: OperationContext) { 12 | this.focusToParentComposition(context) 13 | 14 | context.dispatch(ProjectActions.removeLayer, { 15 | targetLayerId: this.addedLayer.id, 16 | }) 17 | } 18 | 19 | public redo(context: OperationContext) { 20 | this.focusToParentComposition(context) 21 | 22 | context.dispatch(ProjectActions.addLayer, { 23 | targetCompositionId: this.targetCompositionId, 24 | layer: this.addedLayer, 25 | index: this.index, 26 | }) 27 | } 28 | 29 | private focusToParentComposition(context: OperationContext) { 30 | context.dispatch(EditorActions.changeActiveComposition, { 31 | compositionId: this.targetCompositionId, 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/CreateCompositionCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { Command } from '../../History/HistoryStore' 5 | import { ProjectActions } from '../actions' 6 | 7 | export class CreateCompositionCommand implements Command { 8 | constructor(private createdComposition: Delir.Entity.Composition) {} 9 | 10 | public undo(context: OperationContext) { 11 | context.dispatch(ProjectActions.removeComposition, { 12 | targetCompositionId: this.createdComposition.id, 13 | }) 14 | } 15 | 16 | public redo(context: OperationContext) { 17 | context.dispatch(ProjectActions.createComposition, { 18 | composition: this.createdComposition, 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/ModifyAssetCommand.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | import * as Delir from '@delirvfx/core' 4 | import { OperationContext } from '@fleur/fleur' 5 | import { Command } from '../../History/HistoryStore' 6 | import { ProjectActions } from '../actions' 7 | 8 | export class ModifyAssetCommand implements Command { 9 | private toPreviousPatch: Partial 10 | 11 | constructor( 12 | private subjectAssetId: string, 13 | unpatched: Partial, 14 | private patch: Partial, 15 | ) { 16 | this.toPreviousPatch = _.pick(unpatched, Object.keys(patch)) as Partial 17 | } 18 | 19 | public undo(context: OperationContext) { 20 | context.dispatch(ProjectActions.modifyAsset, { 21 | assetId: this.subjectAssetId, 22 | patch: this.toPreviousPatch, 23 | }) 24 | } 25 | 26 | public redo(context: OperationContext) { 27 | context.dispatch(ProjectActions.modifyAsset, { 28 | assetId: this.subjectAssetId, 29 | patch: this.patch, 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/ModifyCompositionCommand.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | import * as Delir from '@delirvfx/core' 4 | import { OperationContext } from '@fleur/fleur' 5 | import { Command } from '../../History/HistoryStore' 6 | import { ProjectActions } from '../actions' 7 | 8 | export class ModifyCompositionCommand implements Command { 9 | private toPreviousPatch: Partial 10 | 11 | constructor( 12 | private subjectCompositionId: string, 13 | unpatched: Partial, 14 | private patch: Partial, 15 | ) { 16 | this.toPreviousPatch = _.pick(unpatched, Object.keys(patch)) as Partial 17 | } 18 | 19 | public undo(context: OperationContext) { 20 | context.dispatch(ProjectActions.modifyComposition, { 21 | targetCompositionId: this.subjectCompositionId, 22 | patch: this.toPreviousPatch, 23 | }) 24 | } 25 | 26 | public redo(context: OperationContext) { 27 | context.dispatch(ProjectActions.modifyComposition, { 28 | targetCompositionId: this.subjectCompositionId, 29 | patch: this.patch, 30 | }) 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/ModifyEffectExpressionCommand.ts: -------------------------------------------------------------------------------- 1 | import _ from 'lodash' 2 | 3 | import * as Delir from '@delirvfx/core' 4 | import { OperationContext } from '@fleur/fleur' 5 | import { Command } from '../../History/HistoryStore' 6 | import { ProjectActions } from '../actions' 7 | 8 | export class ModifyEffectExpressionCommand implements Command { 9 | constructor( 10 | private targetClipId: string, 11 | private effectId: string, 12 | private paramName: string, 13 | private previousValue: Delir.Values.Expression | null, 14 | private nextValue: Delir.Values.Expression, 15 | ) {} 16 | 17 | public undo(context: OperationContext) { 18 | context.dispatch(ProjectActions.modifyEffectExpression, { 19 | targetClipId: this.targetClipId, 20 | targetEffectId: this.effectId, 21 | paramName: this.paramName, 22 | expression: this.previousValue, 23 | }) 24 | } 25 | 26 | public redo(context: OperationContext) { 27 | context.dispatch(ProjectActions.modifyEffectExpression, { 28 | targetClipId: this.targetClipId, 29 | targetEffectId: this.effectId, 30 | paramName: this.paramName, 31 | expression: this.nextValue, 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/RemoveAssetCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { Command } from '../../History/HistoryStore' 5 | import { ProjectActions } from '../actions' 6 | 7 | export class RemoveAssetCommand implements Command { 8 | constructor(private removedAsset: Delir.Entity.Asset) {} 9 | 10 | public undo(context: OperationContext) { 11 | context.dispatch(ProjectActions.addAsset, { 12 | asset: this.removedAsset, 13 | }) 14 | } 15 | 16 | public redo(context: OperationContext) { 17 | context.dispatch(ProjectActions.removeAsset, { 18 | targetAssetId: this.removedAsset.id, 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/RemoveClipCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { EditorActions } from '../../Editor/actions' 5 | import { Command } from '../../History/HistoryStore' 6 | import { ProjectActions } from '../actions' 7 | 8 | export class RemoveClipCommand implements Command { 9 | constructor( 10 | private parentLayerId: string, 11 | private removedClip: Delir.Entity.Clip, 12 | private parentCompositionId: string, 13 | ) {} 14 | 15 | public undo(context: OperationContext) { 16 | this.focusToParentComposition(context) 17 | 18 | context.dispatch(ProjectActions.addClip, { 19 | targetLayerId: this.parentLayerId, 20 | newClip: this.removedClip, 21 | }) 22 | } 23 | 24 | public redo(context: OperationContext) { 25 | this.focusToParentComposition(context) 26 | 27 | context.dispatch(ProjectActions.removeClip, { 28 | targetClipId: this.removedClip.id, 29 | }) 30 | } 31 | 32 | private focusToParentComposition(context: OperationContext) { 33 | context.dispatch(EditorActions.changeActiveComposition, { 34 | compositionId: this.parentCompositionId, 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/Commands/RemoveCompositionCommand.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { OperationContext } from '@fleur/fleur' 3 | 4 | import { Command } from '../../History/HistoryStore' 5 | import { ProjectActions } from '../actions' 6 | 7 | export class RemoveCompositionCommand implements Command { 8 | constructor(private removedComposition: Delir.Entity.Composition) {} 9 | 10 | public undo(context: OperationContext) { 11 | context.dispatch(ProjectActions.createComposition, { 12 | composition: this.removedComposition, 13 | }) 14 | } 15 | 16 | public redo(context: OperationContext) { 17 | context.dispatch(ProjectActions.removeComposition, { 18 | targetCompositionId: this.removedComposition.id, 19 | }) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/models.spec.ts: -------------------------------------------------------------------------------- 1 | import { mockClip, mockComposition, mockEffect, mockLayer, mockProject } from '@delirvfx/core-test-helper' 2 | import { times } from 'lodash' 3 | import { migrateProject } from './models' 4 | 5 | describe('Project/models', () => { 6 | it('Should migrate from old effect id to next id', () => { 7 | const project = mockProject() 8 | const comp = mockComposition({ id: 'comp1', layers: [mockLayer({ id: ' layerId' })] }) 9 | project.addComposition(comp) 10 | 11 | times(2).forEach(idx => { 12 | const clip = mockClip({ id: 'clip-${idx}' }) 13 | ;[ 14 | '@ragg/delir-posteffect-color-slider', 15 | '@ragg/delir-posteffect-numeric-slider', 16 | '@ragg/delir-posteffect-the-world', 17 | ].forEach((processor, idx) => { 18 | clip.addEffect(mockEffect({ id: `layer${idx}`, processor })) 19 | }) 20 | 21 | comp.layers[0].addClip(clip) 22 | }) 23 | 24 | const newProject = migrateProject(project) 25 | expect(newProject).toMatchSnapshot() 26 | }) 27 | }) 28 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/models.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import immer from 'immer' 3 | 4 | const effectReplaceMap: { [oldName: string]: string } = { 5 | '@ragg/delir-posteffect-color-slider': '@delirvfx/posteffect-color-slider', 6 | '@ragg/delir-posteffect-numeric-slider': '@delirvfx/posteffect-numeric-slider', 7 | '@ragg/delir-posteffect-the-world': '@delirvfx/posteffect-the-world', 8 | } 9 | 10 | export const migrateProject = (project: Delir.Entity.Project): Delir.Entity.Project => { 11 | return immer(project, project => { 12 | Delir.MigrationHelper.walkEffects((project as any) as Delir.Entity.Project, effect => { 13 | const { processor } = effect 14 | const newId = effectReplaceMap[processor] 15 | 16 | if (newId) { 17 | effect.processor = newId 18 | } 19 | }) 20 | }) 21 | } 22 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Project/selectors.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import { selector } from '@fleur/fleur' 3 | import ProjectStore from './ProjectStore' 4 | 5 | export const getProject = selector(getState => getState(ProjectStore).project as Delir.Entity.Project | null) 6 | 7 | export const getAssetById = selector([getProject], ([project], assetId: string) => { 8 | return project ? project.findAsset(assetId) : null 9 | }) 10 | 11 | export const getCompositionById = selector([getProject], ([project], compositionId: string) => { 12 | return project?.findComposition(compositionId) ?? null 13 | }) 14 | 15 | export const getClipById = selector((getState, clipId: string) => { 16 | const { project } = getState(ProjectStore) 17 | if (!project) return [] 18 | return project.findClip(clipId) 19 | }) 20 | 21 | export const getClipsByIds = selector((getState, clipIds: string[]) => { 22 | const { project } = getState(ProjectStore) 23 | if (!project) return [] 24 | return clipIds.map(id => project.findClip(id)) 25 | }) 26 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Renderer/actions.ts: -------------------------------------------------------------------------------- 1 | import { action, actions } from '@fleur/fleur' 2 | import { EncodingOption, RenderingProgress } from '@ragg/deream' 3 | 4 | export const RendererActions = actions('Renderer', { 5 | registerPlugins: action<{ plugins: any[] }>(), 6 | unregisterPlugins: action<{ ids: string[] }>(), 7 | clearCache: action<{}>(), 8 | setPreviewCanvas: action<{ canvas: HTMLCanvasElement }>(), 9 | setAudioVolume: action<{ volume: number }>(), 10 | startPreview: action<{ compositionId: string; beginFrame: number; ignoreMissingEffect: boolean }>(), 11 | stopPreview: action<{}>(), 12 | setInRenderingStatus: action<{ isInRendering: boolean }>(), 13 | setRenderingProgress: action<{ progress: RenderingProgress | null }>(), 14 | }) 15 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Renderer/models.ts: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | 3 | export const hasErrorInClip = (clip: Delir.Entity.Clip, error: Delir.Exceptions.UserCodeException | null) => { 4 | if (!error) return false 5 | if (error.location.type === 'clip' && error.location.entityId === clip.id) return true 6 | return error.location.type === 'effect' && !!clip.effects.find(effect => error.location.entityId === effect.id) 7 | } 8 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Renderer/operations.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from 'utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | renderingFailed: { 6 | title: 'レンダリングに失敗しました', 7 | }, 8 | }, 9 | en: { 10 | renderingFailed: { 11 | title: 'Failed to rendering', 12 | }, 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Renderer/selectors.ts: -------------------------------------------------------------------------------- 1 | import { selectorWithStore } from '@fleur/fleur' 2 | import RendererStore from './RendererStore' 3 | 4 | export const getLoadedPlugins = selectorWithStore(getStore => getStore(RendererStore).getPostEffectPlugins()) 5 | -------------------------------------------------------------------------------- /packages/delir/src/domain/Renderer/specFixtures/globals.js: -------------------------------------------------------------------------------- 1 | document 2 | console 3 | -------------------------------------------------------------------------------- /packages/delir/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Delir 9 | 33 | 34 | 35 | 36 |
37 | Loading 38 |
39 |
40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /packages/delir/src/modals/AboutModal/AboutModal.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | licenses: { 6 | title: 'Delirの開発に利用されているオープンソースライブラリです 🙏', 7 | }, 8 | close: '閉じる', 9 | }, 10 | en: { 11 | licenses: { 12 | title: 'Threse are the open source libraries use to make Delir 🙏', 13 | }, 14 | close: 'Close', 15 | }, 16 | }) 17 | -------------------------------------------------------------------------------- /packages/delir/src/modals/AboutModal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./AboutModal.tsx", 3 | "types": "./AboutModal.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/modals/CompositionSettingModal/CompositionSettingModal.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | fields: { 6 | compositionName: 'コンポジション名', 7 | dimensions: '解像度(px)', 8 | backgroundColor: '背景色', 9 | framerate: 'フレームレート', 10 | durationSec: '時間 (秒)', 11 | samplingRate: 'サンプリングレート', 12 | audioChannels: 'チャンネル数', 13 | }, 14 | values: { 15 | audioChannels: { 16 | stereo: 'ステレオ(2ch)', 17 | mono: 'モノラル(1ch)', 18 | }, 19 | }, 20 | cancel: 'キャンセル', 21 | apply: '適用', 22 | create: '作成', 23 | }, 24 | en: { 25 | fields: { 26 | compositionName: 'Composition Name', 27 | dimensions: 'Resolution(px)', 28 | backgroundColor: 'Background Color', 29 | framerate: 'Framerate', 30 | durationSec: 'Duration (sec)', 31 | samplingRate: 'Sampling rate', 32 | audioChannels: 'Audio Channels', 33 | }, 34 | values: { 35 | audioChannels: { 36 | stereo: 'Stereo (2ch)', 37 | mono: 'Mono (1ch)', 38 | }, 39 | }, 40 | cancel: 'Cancel', 41 | apply: 'Apply', 42 | create: 'Create', 43 | }, 44 | }) 45 | -------------------------------------------------------------------------------- /packages/delir/src/modals/CompositionSettingModal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./CompositionSettingModal.tsx", 3 | "typings": "./CompositionSettingModal.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/modals/ImportPackModal/ImportPackModal.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | title: 'プロジェクトパッケージを開く', 6 | importing: '開くパッケージファイルを選択 (.delirpp)', 7 | extracting: '展開先フォルダを選択', 8 | buttons: { 9 | continue: '開く', 10 | cancel: 'キャンセル', 11 | }, 12 | errors: { 13 | requireImportFile: 'パッケージファイルを選択してください', 14 | requireExportDir: '展開先フォルダを選択', 15 | }, 16 | }, 17 | en: { 18 | title: 'Import project package', 19 | importing: 'Select importing project package (.delirpp)', 20 | extracting: 'Select where to extract the project', 21 | buttons: { 22 | continue: 'Open', 23 | cancel: 'Cancel', 24 | }, 25 | errors: { 26 | requireImportFile: 'Require to select importing package file', 27 | requireExportDir: 'Require to select extract directory', 28 | }, 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /packages/delir/src/modals/ImportPackModal/ImportPackModal.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .root 4 | background-color: var(--background) 5 | -------------------------------------------------------------------------------- /packages/delir/src/modals/ImportPackModal/ImportPackModal.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { ImportPackModal } from './ImportPackModal' 3 | 4 | export default { 5 | title: 'Modals|ImportPackModal', 6 | } 7 | 8 | export const normal = () => {}} /> 9 | -------------------------------------------------------------------------------- /packages/delir/src/modals/Modal/Modal.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .root 4 | position: fixed 5 | top: 0 6 | left: 0 7 | z-index: $z-index-modal-window 8 | 9 | display: flex 10 | width: 100vw 11 | height: 100vh 12 | align-items: flex-start 13 | justify-content: center 14 | 15 | backdrop-filter: blur(0px) 16 | background-color: rgba(#000, .5) 17 | opacity: 0 18 | 19 | pointer-events: none 20 | 21 | transition: $animate-modal-fade-duration $animate-function 22 | transition-property: opacity, backdrop-filter 23 | 24 | &.--show 25 | backdrop-filter: blur(2px) 26 | opacity: 1 27 | pointer-events: all 28 | -------------------------------------------------------------------------------- /packages/delir/src/modals/Modal/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./ModalWindow.tsx", 3 | "typings": "./ModalWindow.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/modals/RenderingSettingModal/RenderingSettingModal.i18n.tsx: -------------------------------------------------------------------------------- 1 | import I18n from 'utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | title: 'レンダリング', 6 | cancel: 'キャンセル', 7 | startRendering: 'レンダリングを開始', 8 | encodingPreset: 'プリセット', 9 | saveTo: '保存先', 10 | saveToPlaceholder: 'クリックしてファイル選択', 11 | advancedOptions: '詳細設定', 12 | bitrate: 'ビットレート', 13 | videoCodec: 'ビデオコーデック', 14 | useAlpha: 'アルファチャンネル(透過)を有効にする(コーデックが対応している場合のみ)', 15 | audioCodec: 'オーディオコーデック', 16 | errors: { 17 | destRequired: '保存先を選択してください', 18 | }, 19 | }, 20 | en: { 21 | title: 'Start rendering', 22 | cancel: 'Cancel', 23 | startRendering: 'Start rendering', 24 | encodingPreset: 'Encoding preset', 25 | saveTo: 'Save to', 26 | saveToPlaceholder: 'Click to select a file', 27 | advancedOptions: 'Advanced options', 28 | bitrate: 'Bitrate', 29 | videoCodec: 'Video codec', 30 | useAlpha: 'Enable alpha channel (if codec supported)', 31 | audioCodec: 'Audio codec', 32 | errors: { 33 | destRequired: 'Require to select destination file', 34 | }, 35 | }, 36 | }) 37 | -------------------------------------------------------------------------------- /packages/delir/src/modals/RenderingSettingModal/RenderingSettingModal.stories.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { RenderingSettingModal } from './RenderingSettingModal' 3 | 4 | export default { 5 | title: 'Modals|RenderingSetting', 6 | } 7 | 8 | export const normal = () => {}} /> 9 | -------------------------------------------------------------------------------- /packages/delir/src/utils/Dev/ExampleProject1/Dawn.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/utils/Dev/ExampleProject1/Dawn.mp3 -------------------------------------------------------------------------------- /packages/delir/src/utils/Dev/ExampleProject1/LICENSE.md: -------------------------------------------------------------------------------- 1 | Big Buck Bunny (big_buck_bunny.mp4) 2 | (c) copyright 2008, Blender Foundation / www.bigbuckbunny.org 3 | 4 | Dawn (Dawn.mp3) by ragg 5 | -------------------------------------------------------------------------------- /packages/delir/src/utils/Dev/ExampleProject1/big_buck_bunny.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/utils/Dev/ExampleProject1/big_buck_bunny.mp4 -------------------------------------------------------------------------------- /packages/delir/src/utils/Dev/ExampleProject1/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/utils/Dev/ExampleProject1/image.png -------------------------------------------------------------------------------- /packages/delir/src/utils/EventEmitter.ts: -------------------------------------------------------------------------------- 1 | export class EventEmitter { 2 | protected exclusiveEvents: string[] = [] 3 | private listeners: { [K in keyof T]: ((arg: T[K]) => void)[] } = Object.create({}) 4 | 5 | public on(event: K, listener: (arg: T[K]) => void) { 6 | const listeners = (this.listeners[event] = this.listeners[event] || []) 7 | 8 | if (this.exclusiveEvents.includes(event as string)) { 9 | this.listeners[event] = [listener] 10 | } else { 11 | listeners.push(listener) 12 | } 13 | } 14 | 15 | public off(event: K, listener: (arg: T[K]) => void) { 16 | if (!this.listeners[event]) return 17 | 18 | const index = this.listeners[event].findIndex(l => l === listener) 19 | if (index === -1) return 20 | this.listeners[event].splice(index, 1) 21 | } 22 | 23 | public emit(event: K, arg: T[K]) { 24 | if (!this.listeners[event]) return 25 | this.listeners[event].forEach(listener => listener(arg)) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/delir/src/utils/Monaco/console.d.ts.txt: -------------------------------------------------------------------------------- 1 | interface Console { 2 | assert(test?: boolean, message?: string, ...optionalParams: any[]): void; 3 | clear(): void; 4 | count(countTitle?: string): void; 5 | debug(message?: any, ...optionalParams: any[]): void; 6 | dir(value?: any, ...optionalParams: any[]): void; 7 | dirxml(value: any): void; 8 | error(message?: any, ...optionalParams: any[]): void; 9 | exception(message?: string, ...optionalParams: any[]): void; 10 | group(groupTitle?: string, ...optionalParams: any[]): void; 11 | groupCollapsed(groupTitle?: string, ...optionalParams: any[]): void; 12 | groupEnd(): void; 13 | info(message?: any, ...optionalParams: any[]): void; 14 | log(message?: any, ...optionalParams: any[]): void; 15 | msIsIndependentlyComposed(element: Element): boolean; 16 | profile(reportName?: string): void; 17 | profileEnd(): void; 18 | select(element: Element): void; 19 | table(...data: any[]): void; 20 | time(timerName?: string): void; 21 | timeEnd(timerName?: string): void; 22 | trace(message?: any, ...optionalParams: any[]): void; 23 | warn(message?: any, ...optionalParams: any[]): void; 24 | } 25 | 26 | declare const console: Console; 27 | -------------------------------------------------------------------------------- /packages/delir/src/utils/Monaco/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./Monaco.ts", 3 | "typings": "./Monaco.ts" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/utils/React.tsx: -------------------------------------------------------------------------------- 1 | import React, { ReactNodeArray } from 'react' 2 | 3 | export const preserveLineBreak = (str: string): ReactNodeArray => { 4 | const lines = str.split('\n') 5 | return lines.map((line, idx) => [idx > 0 ?
: '', line]).flat(Infinity) 6 | } 7 | -------------------------------------------------------------------------------- /packages/delir/src/utils/Spread.ts: -------------------------------------------------------------------------------- 1 | class A { 2 | public a: number 3 | public c: string 4 | public b() {} 5 | } 6 | 7 | type RemoveMethodKeys = { [K in keyof T]: T[K] extends (...args: any[]) => any ? never : K }[keyof T] 8 | export type SpreadType = Pick> 9 | -------------------------------------------------------------------------------- /packages/delir/src/utils/Timecode.ts: -------------------------------------------------------------------------------- 1 | export const frameToTimeCode = (frame: number, frameRate: number) => { 2 | const seconds = frame / frameRate 3 | const timeFrame = (frame % frameRate).toString().padStart(2, '0') 4 | const timeSeconds = (seconds % 60 | 0).toString().padStart(2, '0') 5 | const timeMinutes = ((seconds / 60) % 60 | 0).toString().padStart(2, '0') 6 | const timeHour = ((seconds / 60 / 60) | 0).toString().padStart(2, '0') 7 | 8 | return `${timeHour}:${timeMinutes}:${timeSeconds}:${timeFrame}` 9 | } 10 | -------------------------------------------------------------------------------- /packages/delir/src/utils/decorate.ts: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | interface Decorator { 4 | (component: React.ComponentType): React.ComponentType 5 | } 6 | 7 | export const decorate = (decorators: Decorator[], decoratee: React.ComponentType): React.ComponentType => { 8 | return decorators.reduce((decorated, decorator) => { 9 | return decorator(decorated) 10 | }, decoratee) as React.ComponentType 11 | } 12 | -------------------------------------------------------------------------------- /packages/delir/src/utils/keepAliveOperation.ts: -------------------------------------------------------------------------------- 1 | import { OperationContext } from '@fleur/fleur' 2 | import { Operation, OperationArgs } from '@fleur/fleur/typings/Operations' 3 | 4 | type Disposer = (() => void) | void 5 | 6 | interface KeepAliveOperation { 7 | (context: OperationContext, ...args: T): Promise 8 | dispose: Operation 9 | } 10 | 11 | interface Operator { 12 | (context: OperationContext, ...args: any[]): Promise | Disposer 13 | } 14 | 15 | export const keepAliveOperation = (operator: O) => { 16 | let disposer: (() => void) | void 17 | let alived = false 18 | 19 | const operation: KeepAliveOperation> = async ( 20 | context: OperationContext, 21 | ...args: OperationArgs 22 | ) => { 23 | if (alived) return 24 | disposer = await operator(context, ...args) 25 | alived = true 26 | } 27 | 28 | operation.dispose = async () => { 29 | await (disposer && disposer()) 30 | alived = false 31 | } 32 | 33 | return operation 34 | } 35 | -------------------------------------------------------------------------------- /packages/delir/src/utils/makeMousetrapHandler.ts: -------------------------------------------------------------------------------- 1 | // Mousetrap is fired event on Input element when _belongsTo is satisfied 2 | export const makeMousetrapIgnoreInputHandler = (fn: (e: KeyboardEvent, combo: string) => void) => { 3 | return (e: KeyboardEvent, combo: string) => { 4 | const target: HTMLElement = (e.target || e.srcElement) as HTMLElement 5 | 6 | // See: https://github.com/ccampbell/mousetrap/blob/master/mousetrap.js#L986 7 | if ( 8 | target.tagName === 'INPUT' || 9 | target.tagName === 'SELECT' || 10 | target.tagName === 'TEXTAREA' || 11 | target.isContentEditable 12 | ) { 13 | return 14 | } 15 | 16 | fn(e, combo) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/delir/src/utils/platform.ts: -------------------------------------------------------------------------------- 1 | import os from 'os' 2 | 3 | export const Platform = { 4 | get cmdOrCtrl() { 5 | return this.isMacOS ? 'Cmd' : 'Ctrl' 6 | }, 7 | 8 | isWindows: os.type() === 'Windows_NT', 9 | isMacOS: os.type() === 'Darwin', 10 | isLinux: os.type() === 'Linux', 11 | } 12 | -------------------------------------------------------------------------------- /packages/delir/src/utils/propsToDataset.ts: -------------------------------------------------------------------------------- 1 | /** Extract `data-` attributes in props */ 2 | export const propsToDataset = (props: { [prop: string]: any }): { [K in keyof T]: string } => { 3 | const MATCHER = /^data-(.+?)$/ 4 | const REPLACER = /(-[a-z])/g 5 | 6 | const keys = Object.keys(props).filter(prop => MATCHER.exec(prop)) 7 | 8 | const dataset: any = Object.create(null) 9 | keys.forEach(key => { 10 | const propName = key.match(MATCHER)![1].replace(REPLACER, (_, repValue: string) => repValue.toUpperCase().slice(-1)) 11 | dataset[propName] = props[key] 12 | }) 13 | 14 | return Object.freeze(dataset) 15 | } 16 | 17 | /** Extract `data-` attributes in props to array for hooks dependency list */ 18 | export const propsToDatasetArray = (props: Record): any[] => { 19 | const dataset = propsToDataset(props) 20 | const result: any[] = [] 21 | Object.entries(dataset).forEach(([key, value]) => result.push(key, value)) 22 | return result 23 | } 24 | 25 | export default propsToDataset 26 | -------------------------------------------------------------------------------- /packages/delir/src/utils/safeAssign.ts: -------------------------------------------------------------------------------- 1 | export const safeAssign = (dest: T, ...source: Partial[]): T => { 2 | return Object.assign(dest, ...source) 3 | } 4 | -------------------------------------------------------------------------------- /packages/delir/src/utils/selectFile.ts: -------------------------------------------------------------------------------- 1 | export const selectFile = async ({ 2 | extensions, 3 | directory, 4 | multiple, 5 | }: { 6 | extensions?: string[] 7 | directory?: boolean 8 | multiple?: boolean 9 | } = {}): Promise => { 10 | const input = document.createElement('input') 11 | input.type = 'file' 12 | input.accept = (extensions || []).map(ext => `.${ext}`).join(',') 13 | input.multiple = !!multiple 14 | if (directory) input.setAttribute('webkitDirectory', '') 15 | 16 | return new Promise(resolve => { 17 | const resolveCallback = () => { 18 | resolve([...input.files!]) 19 | } 20 | 21 | input.addEventListener('change', resolveCallback, { once: true }) 22 | 23 | input.focus() 24 | input.click() 25 | }) 26 | } 27 | -------------------------------------------------------------------------------- /packages/delir/src/views/AppMenu/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./AppMenu.tsx", 3 | "typings": "./AppMenu.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/views/AppView/AppView.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .preference 4 | position: fixed 5 | top: 0 6 | left: 0 7 | z-index: $z-index-modal-window 8 | 9 | width: 100vw 10 | height: 100vh 11 | -------------------------------------------------------------------------------- /packages/delir/src/views/AppView/GlobalEvents.ts: -------------------------------------------------------------------------------- 1 | import { EventEmitter } from '../../utils/EventEmitter' 2 | 3 | export enum GlobalEvent { 4 | copyViaApplicationMenu = 'copy', 5 | cutViaApplicationMenu = 'cut', 6 | pasteViaApplicationMenu = 'paste', 7 | } 8 | 9 | interface Events { 10 | [GlobalEvent.copyViaApplicationMenu]: {} 11 | [GlobalEvent.cutViaApplicationMenu]: {} 12 | [GlobalEvent.pasteViaApplicationMenu]: {} 13 | } 14 | 15 | export const GlobalEvents = new (class extends EventEmitter { 16 | protected exclusiveEvents = [ 17 | GlobalEvent.copyViaApplicationMenu, 18 | GlobalEvent.cutViaApplicationMenu, 19 | GlobalEvent.pasteViaApplicationMenu, 20 | ] 21 | })() 22 | -------------------------------------------------------------------------------- /packages/delir/src/views/AppView/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./AppView.tsx", 3 | "typings": "./AppView.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/views/AssetsView/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./AssetsView.tsx", 3 | "typings": "./AssetsView.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/views/KeyframeEditor/EffectList.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import { SortableContainer, SortableElement } from 'react-sortable-hoc' 3 | import { SortableHandle } from 'react-sortable-hoc' 4 | 5 | export const EffectSortHandle = SortableHandle(() => ) 6 | 7 | export const EffectListItem = SortableElement( 8 | ({ className, children }: { className?: string; children: React.ReactNode }) => ( 9 |
{children}
10 | ), 11 | ) 12 | 13 | export const EffectList = SortableContainer((props: { children: React.ReactNode }) =>
{props.children}
) 14 | -------------------------------------------------------------------------------- /packages/delir/src/views/KeyframeEditor/ExpressionEditor.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .ExpressionEditor 4 | position: absolute 5 | top: 0 6 | z-index: $z-index-expression-editor 7 | 8 | display: flex 9 | flex-flow: column 10 | width: 100% 11 | height: 100% 12 | 13 | .ExpressionEditor__Title 14 | display: inline-block 15 | margin-right: 8px 16 | width: 14em 17 | text-overflow: ellipsis 18 | white-space: nowrap 19 | 20 | .ExpressionEditor__Toolbar 21 | padding: 4px 8px 22 | background-color: var(--background) 23 | 24 | .ExpressionEditor__Editor 25 | flex: 1 26 | -------------------------------------------------------------------------------- /packages/delir/src/views/KeyframeEditor/KeyframeEditor.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | contextMenu: { 6 | expression: 'エクスプレッションを編集', 7 | copyParamName: 'パラメータ名をコピー', 8 | copyReferenceName: 'エフェクト名をコピー', 9 | effect: '✨ エフェクト', 10 | pluginUnavailable: '利用可能なポストエフェクトがありません', 11 | removeEffect: 'エフェクトを削除', 12 | }, 13 | pluginMissing: '不明なプラグイン: :processorId', 14 | editScriptParam: '編集', 15 | save: '保存', 16 | }, 17 | en: { 18 | contextMenu: { 19 | expression: 'Edit Expression', 20 | copyParamName: 'Copy parameter name', 21 | copyReferenceName: 'Copy effect name', 22 | effect: '✨ Add Effects', 23 | pluginUnavailable: 'No available post-effect', 24 | removeEffect: 'Remove effect', 25 | }, 26 | pluginMissing: 'Missing plugin: :processorId', 27 | editScriptParam: 'Edit', 28 | save: 'Save', 29 | }, 30 | }) 31 | -------------------------------------------------------------------------------- /packages/delir/src/views/KeyframeEditor/KeyframeGraph.sass: -------------------------------------------------------------------------------- 1 | .keyframeGraph 2 | outline: none 3 | 4 | .keyframeInner 5 | transform-origin: 4px 4px 6 | transform: rotateZ(45deg) 7 | fill: #fff 8 | transition-property: fill 9 | transition-duration: .2s 10 | 11 | &.keyframeInner--selected 12 | fill: #1ac5ff 13 | 14 | .keyframeLineToHandle 15 | stroke: rgba(#fff, .2) 16 | -------------------------------------------------------------------------------- /packages/delir/src/views/KeyframeEditor/ScriptParamEditor.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .ScriptParamEditor 4 | position: absolute 5 | top: 0 6 | z-index: $z-index-expression-editor 7 | 8 | display: flex 9 | flex-flow: column 10 | width: 100% 11 | height: 100% 12 | 13 | .title 14 | display: inline-block 15 | margin-right: 8px 16 | width: 14em 17 | text-overflow: ellipsis 18 | white-space: nowrap 19 | 20 | .toolbar 21 | padding: 4px 8px 22 | background-color: var(--background) 23 | 24 | .editor 25 | flex: 1 26 | -------------------------------------------------------------------------------- /packages/delir/src/views/KeyframeEditor/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./KeyframeEditor.tsx", 3 | "typings": "./KeyframeEditor.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/views/NavigationView/NavigationView.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from 'utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | preview: 'プレビュー (スペースキー)', 6 | rendering: 'レンダリング', 7 | }, 8 | en: { 9 | preview: 'Preview (Space key)', 10 | rendering: 'Rendering', 11 | }, 12 | }) 13 | -------------------------------------------------------------------------------- /packages/delir/src/views/NavigationView/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./NavigationView.tsx", 3 | "typings": "./NavigationView.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/views/Notifications/Notifications.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | userCodeError: 'スクリプト内でエラーが発生しました', 6 | }, 7 | en: { 8 | userCodeError: 'Cause error in your script', 9 | }, 10 | }) 11 | -------------------------------------------------------------------------------- /packages/delir/src/views/Preference/Panes/Development/Plugin.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | title: 'プラグイン', 6 | watchesTitle: '更新監視中のプラグイン', 7 | remove: '削除', 8 | add: '追加', 9 | noEntry: '変更監視中のプラグインはありません', 10 | }, 11 | en: { 12 | title: 'Development / Plugins', 13 | watchesTitle: 'Update watching plugin directories', 14 | remove: 'Unwatch', 15 | add: 'Add', 16 | noEntry: 'No any plugin watches', 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /packages/delir/src/views/Preference/Preference.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | sidebar: { 6 | renderer: 'レンダラー', 7 | rendererGeneral: '一般', 8 | devel: '開発', 9 | develPlugin: 'プラグイン', 10 | }, 11 | rendererGeneral: { 12 | title: 'レンダリング / 一般', 13 | ignoreMissingEffect: '行方不明のエフェクトを無視する', 14 | ignoreMissingEffectDesc: 'エフェクトのインストール漏れを警告されたい場合はチェックを外してください', 15 | }, 16 | close: '閉じる (Esc)', 17 | }, 18 | en: { 19 | sidebar: { 20 | renderer: 'Renderer', 21 | rendererGeneral: 'General', 22 | devel: 'Development', 23 | develPlugin: 'Plugin', 24 | }, 25 | rendererGeneral: { 26 | title: 'Rendering / General', 27 | ignoreMissingEffect: 'Ignore missing effect', 28 | ignoreMissingEffectDesc: 'Please remove the check if you want to be warned about omission of effect installation', 29 | }, 30 | close: 'Close (Esc)', 31 | }, 32 | }) 33 | -------------------------------------------------------------------------------- /packages/delir/src/views/PreviewView/PreviewView.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: {}, 5 | en: {}, 6 | }) 7 | -------------------------------------------------------------------------------- /packages/delir/src/views/PreviewView/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./PreviewView.tsx", 3 | "typings": "./PreviewView.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/src/views/RenderingWaiter/RenderingWaiter.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | step: { 6 | started: 'レンダリングを開始しました', 7 | rendering: 'レンダリング中… :progression%', 8 | encoding: 'エンコード中…', 9 | concat: '結合中…', 10 | completed: '完了しました', 11 | }, 12 | close: '閉じる', 13 | }, 14 | en: { 15 | step: { 16 | started: 'Rendering started', 17 | rendering: 'Rendering... :progression%', 18 | encoding: 'Encoding...', 19 | concat: 'Concating...', 20 | completed: 'Rendering completed', 21 | }, 22 | close: 'Close', 23 | }, 24 | }) 25 | -------------------------------------------------------------------------------- /packages/delir/src/views/RenderingWaiter/RenderingWaiter.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .RenderingWaiter 4 | position: fixed 5 | top: 0 6 | left: 0 7 | z-index: $z-index-modal-window 8 | 9 | display: flex 10 | flex-flow: column 11 | align-items: center 12 | justify-content: center 13 | flex-wrap: wrap 14 | width: 100vw 15 | height: 100vh 16 | background: rgba($color-app-bg-dark, .8) 17 | 18 | :global(.platform-mac) 19 | .RenderingWaiter 20 | top: 21px 21 | 22 | .spinner 23 | animation: spin .5s infinite linear 24 | 25 | .completedParrot 26 | height: 3em 27 | 28 | .status 29 | display: flex 30 | justify-content: center 31 | 32 | .statusText 33 | display: flex 34 | align-items: center 35 | margin-left: 16px 36 | font-size: 24px 37 | 38 | .doneButton 39 | margin-top: 8px 40 | 41 | @keyframes spin 42 | 0% 43 | transform: rotate(0deg) 44 | 45 | 100% 46 | transform: rotate(359deg) 47 | -------------------------------------------------------------------------------- /packages/delir/src/views/RenderingWaiter/parrot.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/delir/src/views/RenderingWaiter/parrot.gif -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/Clip.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | contextMenu: { 6 | seekToHeadOfClip: '⏪クリップの先頭にシーク', 7 | seekToTailOfClip: '⏩クリップの後ろにシーク', 8 | effect: '✨エフェクト', 9 | remove: '🚯 削除', 10 | pluginUnavailable: '利用可能なポストエフェクトがありません', 11 | }, 12 | renderers: { 13 | audio: 'audio', 14 | video: 'video', 15 | image: 'image', 16 | text: 'text', 17 | adjustment: 'adjust', 18 | p5js: 'p5.js', 19 | solid: 'solid', 20 | }, 21 | }, 22 | en: { 23 | contextMenu: { 24 | seekToHeadOfClip: '⏪Seek to clip head', 25 | seekToTailOfClip: '⏩Seek to clip tail', 26 | effect: '✨Effect', 27 | remove: '🚯 Remove', 28 | pluginUnavailable: 'No available post-effect', 29 | }, 30 | renderers: { 31 | audio: 'audio', 32 | video: 'video', 33 | image: 'image', 34 | text: 'text', 35 | adjustment: 'adjust', 36 | p5js: 'p5.js', 37 | solid: 'solid', 38 | }, 39 | }, 40 | }) 41 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/ClipDragContext.tsx: -------------------------------------------------------------------------------- 1 | import React, { useContext } from 'react' 2 | 3 | export type EmitClipDragHandler = (arg: { nextX: number; nextY: number; originalPlacedFrame: number }) => void 4 | 5 | export type EmitClipResizeHandler = (arg: { nextX: number; originalPlacedFrame: number; deltaWidth: number }) => void 6 | 7 | interface ClipDragContext { 8 | emitClipDrag: EmitClipDragHandler 9 | emitClipDragEnd: EmitClipDragHandler 10 | emitClipResize: EmitClipResizeHandler 11 | emitClipResizeEnd: EmitClipResizeHandler 12 | } 13 | 14 | export type ClipDragProps = ClipDragContext 15 | export const ClipDragContext = React.createContext(null!) 16 | 17 | export const useClipDragContext = () => { 18 | return useContext(ClipDragContext) 19 | } 20 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/ClipsMediator.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .root 4 | flex: 1 5 | padding-bottom: 16px 6 | 7 | .selectionArea 8 | background-color: rgba(#fff, .3) 9 | border: 1px solid rgba(#fff, .6) 10 | z-index: $z-index-range-selection 11 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/Gradations.i18n.tsx: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | contextMenu: { 6 | seekToHead: '先頭へシーク', 7 | }, 8 | }, 9 | en: { 10 | contextMenu: { 11 | seekToHead: 'Seek to start', 12 | }, 13 | }, 14 | }) 15 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/Layer.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | contextMenu: { 6 | createClip: 'クリップを作成', 7 | addLayerHere: '➕ ここにレイヤーを追加', 8 | }, 9 | renderers: { 10 | audio: '🔊 オーディオ', 11 | video: '🎥 ムービー', 12 | image: '🖼️ 画像', 13 | text: '📝 テキスト', 14 | adjustment: '✨ 調整クリップ', 15 | p5js: '🔡 p5.js スクリプト', 16 | solid: '◻️ 平面', 17 | }, 18 | }, 19 | en: { 20 | contextMenu: { 21 | createClip: 'Create clip', 22 | addLayerHere: '➕ Add layer here', 23 | }, 24 | renderers: { 25 | audio: '🔊 Audio', 26 | video: '🎥 Video', 27 | image: '🖼️ Image', 28 | text: '📝 Text', 29 | adjustment: '✨ Adjustment clip', 30 | p5js: '🔡 p5.js script', 31 | solid: '◻️ Solid', 32 | }, 33 | }, 34 | }) 35 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/Layer.sass: -------------------------------------------------------------------------------- 1 | @import '../../assets/styles/variables' 2 | 3 | .Layer 4 | min-width: 100% 5 | border-bottom: 1px solid rgba(#fff, .1) 6 | 7 | &.active 8 | background-color: rgba(#fff, .1) 9 | 10 | &.dragover 11 | background-color: rgba(#fff, .08) 12 | 13 | &.active.dragover 14 | background-color: rgba(#fff, .16) 15 | 16 | .clipsContainer 17 | position: relative 18 | box-sizing: border-box 19 | display: block 20 | height: 24px 21 | padding: 2px 0 22 | padding-left: 4px 23 | overflow: visible 24 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/LayerLabel.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | contextMenu: { 6 | addLayerHere: '➕ ここにレイヤーを追加', 7 | removeLayer: '🚯 レイヤーを削除', 8 | renameLayer: '✏️ レイヤー名を変更 (Enter)', 9 | }, 10 | }, 11 | en: { 12 | contextMenu: { 13 | addLayerHere: '➕ Add layer here', 14 | removeLayer: '🚯 Remove layer', 15 | renameLayer: '✏️ Rename layer (Enter)', 16 | }, 17 | }, 18 | }) 19 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/LayerLabelList.tsx: -------------------------------------------------------------------------------- 1 | import * as Delir from '@delirvfx/core' 2 | import React from 'react' 3 | import { SortableContainer } from 'react-sortable-hoc' 4 | 5 | import { LayerLabel } from './LayerLabel' 6 | 7 | interface Props { 8 | layers: Delir.Entity.Layer[] 9 | onLayerSelect: (layerId: string) => void 10 | onLayerRemove: (layerId: string) => void 11 | } 12 | 13 | export const LayerLabelList = SortableContainer((props: Props) => ( 14 |
    15 | {props.layers.map((layer, idx) => ( 16 | 24 | ))} 25 |
26 | )) 27 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/Timeline.i18n.ts: -------------------------------------------------------------------------------- 1 | import I18n from '../../utils/I18n' 2 | 3 | export default I18n({ 4 | ja: { 5 | placeHolder: { 6 | layerName: 'レイヤー', 7 | }, 8 | layers: 'レイヤー', 9 | errors: { 10 | compositionNotSelected: '落ち着いて。まだどのコンポジションを編集するか決めてない。', 11 | }, 12 | }, 13 | en: { 14 | placeHolder: { 15 | layerName: 'Unnamed Layer', 16 | }, 17 | layers: 'Layers', 18 | errors: { 19 | compositionNotSelected: 'Must be select any composition before add assets to timeline', 20 | }, 21 | }, 22 | }) 23 | -------------------------------------------------------------------------------- /packages/delir/src/views/Timeline/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "./Timeline.tsx", 3 | "typings": "./Timeline.tsx" 4 | } 5 | -------------------------------------------------------------------------------- /packages/delir/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "compilerOptions": { 4 | "baseUrl": "./src", 5 | "jsx": "react", 6 | "outDir": "dist" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/delir/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/deream/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | *.mp4 4 | -------------------------------------------------------------------------------- /packages/deream/.npmignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | example.js 3 | *.mp4 4 | -------------------------------------------------------------------------------- /packages/deream/LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016 ragg 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 | -------------------------------------------------------------------------------- /packages/deream/README.md: -------------------------------------------------------------------------------- 1 | # Deream 2 | `Delir`'s Rendering stream observer implement for destinate video to file 3 | -------------------------------------------------------------------------------- /packages/deream/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'audiobuffer-to-wav' { 2 | interface AudioBufferLike { 3 | sampleRate: number 4 | numberOfChannels: number 5 | getChannelData: (channel: number) => Float32Array 6 | } 7 | 8 | const _: (buffer: AudioBufferLike, opts: { float32: boolean }) => ArrayBuffer 9 | export = _ 10 | } 11 | 12 | declare module 'arraybuffer-to-buffer' { 13 | const _: (ab: ArrayBuffer) => Buffer 14 | export = _ 15 | } 16 | -------------------------------------------------------------------------------- /packages/deream/example.js: -------------------------------------------------------------------------------- 1 | const deream = require('./index') 2 | const Canvas = require('canvas') 3 | 4 | const streamIn = deream({ 5 | args: { 6 | // ffmpeg options 7 | // 'y' : '', 8 | 'c:v': 'libx264', 9 | 'b:v': '1024k', 10 | // 'r:v': '30' 11 | }, 12 | // path to destination file 13 | inputFrames: 30, 14 | dest: 'dest.mp4', 15 | }) 16 | 17 | const canvas = new Canvas(640, 360) 18 | const context = canvas.getContext('2d') 19 | 20 | // make 2seconds/30fps movie 21 | for (let i = 0; i < 30 * 10; i++) { 22 | const frameHex = `00${i.toString(16)}`.slice(-2) 23 | context.fillStyle = ['#', frameHex, frameHex, frameHex].join('') 24 | context.fillRect(0, 0, 640, 360) 25 | 26 | // write PNG Buffer 27 | streamIn.write(canvas.toBuffer()) 28 | i % 20 == 0 && console.log('write %d of %d frames', i, 30 * 10) 29 | } 30 | 31 | streamIn.end() 32 | console.log('done') 33 | -------------------------------------------------------------------------------- /packages/deream/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ragg/deream", 3 | "version": "0.0.3", 4 | "description": "Encode Motion JPEG stream to movie with ffmpeg / Node.js", 5 | "main": "index.ts", 6 | "typings": "index.ts", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git+https://github.com/Ragg-/deream-stream.git" 13 | }, 14 | "keywords": [ 15 | "ffmpeg", 16 | "movie", 17 | "stream" 18 | ], 19 | "author": "ragg ", 20 | "license": "MIT", 21 | "bugs": { 22 | "url": "https://github.com/Ragg-/deream-stream/issues" 23 | }, 24 | "homepage": "https://github.com/Ragg-/deream-stream#readme", 25 | "devDependencies": { 26 | "@types/duplexer3": "0.1.0", 27 | "@types/mz": "2.7.0" 28 | }, 29 | "dependencies": { 30 | "arraybuffer-to-buffer": "0.0.7", 31 | "audiobuffer-to-wav": "1.0.0", 32 | "duplexer3": "0.1.4", 33 | "mz": "2.7.0" 34 | }, 35 | "sideEffect": false 36 | } 37 | -------------------------------------------------------------------------------- /packages/experimental-plugins/color-collection/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/posteffect-color-collection", 3 | "version": "0.1.0", 4 | "author": "Hanakla (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.11.x" 9 | }, 10 | "delir": { 11 | "name": "Color collection", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/experimental-plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ragg/delir-experimental-plugins", 3 | "version": "0.0.0", 4 | "license": "MIT" 5 | } 6 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/chromakey/fragment.frag: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | 3 | uniform sampler2D source; 4 | varying vec2 vTexCoord; 5 | 6 | uniform vec3 keyColor; 7 | uniform float threshold; 8 | 9 | void main(void) { 10 | vec4 color = texture2D(source, vTexCoord); 11 | float diff = length(keyColor - color.rgb); 12 | 13 | if (diff < threshold) { 14 | discard; 15 | } else { 16 | gl_FragColor = color; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/chromakey/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/posteffect-chromakey", 3 | "version": "0.0.0", 4 | "author": "ragg (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.12.x" 9 | }, 10 | "delir": { 11 | "name": "Chroma key", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/chromakey/vertex.vert: -------------------------------------------------------------------------------- 1 | // #ifdef GL_ES 2 | // precision highp float; 3 | // #endif 4 | 5 | // attribute vec3 position; 6 | // attribute vec2 texCoord; 7 | 8 | // varying vec2 vTexCoord; 9 | // varying vec4 vPosition; 10 | // varying vec2 vSourceCoord; 11 | // varying vec2 vAlphaCoord; 12 | 13 | // uniform vec4 sourceArea; 14 | // uniform vec4 alphaArea; 15 | 16 | // void main(void) { 17 | // gl_Position = vec4(position, 1.0); 18 | // vTexCoord = vec2(texCoord.s, texCoord.t); 19 | // vSourceCoord = vec2(sourceArea.x + texCoord.s * sourceArea.z, sourceArea.y + texCoord.t * sourceArea.w); 20 | // vAlphaCoord = vec2(alphaArea.x + texCoord.s * alphaArea.z, alphaArea.y + texCoord.t * alphaArea.w); 21 | // } 22 | 23 | 24 | 25 | // attribute vec3 position; 26 | // attribute vec2 coord; 27 | 28 | // varying vec2 texCoord; 29 | 30 | // void main(){ 31 | // texCoord = coord; 32 | // gl_Position = vec4(position, 1.0); 33 | // } 34 | 35 | 36 | 37 | attribute vec2 position; 38 | attribute vec2 coord; 39 | varying vec2 texCoord; 40 | 41 | void main(void) { 42 | gl_Position = vec4(position, 0.0, 1.0); 43 | texCoord = coord; 44 | } 45 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/color-slider/index.ts: -------------------------------------------------------------------------------- 1 | import { EffectPreRenderContext, EffectRenderContext, ParamType, PostEffectBase, Type, Values } from '@delirvfx/core' 2 | 3 | interface Params { 4 | value: ParamType.ColorRGBA 5 | } 6 | 7 | export default class TheWorldPostEffect extends PostEffectBase { 8 | /** 9 | * Provide usable parameters 10 | */ 11 | public static provideParameters() { 12 | return Type.colorRgba('value', { 13 | label: 'Value', 14 | defaultValue: () => new Values.ColorRGBA(0, 0, 0, 255), 15 | animatable: true, 16 | }) 17 | } 18 | 19 | /** 20 | * Called when before rendering start. 21 | * 22 | * If you want initializing before rendering (likes load audio, image, etc...) 23 | * Do it in this method. 24 | */ 25 | public async initialize(context: EffectPreRenderContext) {} 26 | 27 | /** 28 | * Render frame into destination canvas. 29 | * @param context 30 | */ 31 | public async render(context: EffectRenderContext) {} 32 | } 33 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/color-slider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/posteffect-color-slider", 3 | "version": "0.1.0", 4 | "author": "ragg (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.12.x" 9 | }, 10 | "delir": { 11 | "name": "Color slider", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/index.spec.ts: -------------------------------------------------------------------------------- 1 | import glob from 'glob-promise' 2 | import semver from 'semver' 3 | import delirPackageJson from '../core/package.json' 4 | 5 | describe('Plugins', () => { 6 | const coreVersion = delirPackageJson.version 7 | 8 | it('Check compliancy to engines version', async () => { 9 | const packages = await glob('./*/package.json', { cwd: __dirname }) 10 | 11 | let hasError = false 12 | for (const path of packages) { 13 | const { name, engines } = require(path) 14 | const supportedVersion = engines['@delirvfx/core'] 15 | const satis = semver.satisfies(coreVersion, supportedVersion) 16 | 17 | if (!satis) { 18 | // tslint:disable-next-line 19 | console.error( 20 | `Plugin \`${name}\` not satisfy version to @delirvfx/core@${coreVersion} (set to ${supportedVersion})`, 21 | ) 22 | } 23 | 24 | hasError = satis != true || hasError 25 | } 26 | 27 | expect(hasError).toBe(false) 28 | }) 29 | }) 30 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/jest.config.js: -------------------------------------------------------------------------------- 1 | const { join } = require('path') 2 | 3 | module.exports = { 4 | ...require('../../jest.config'), 5 | testRegex: '.*\\.spec\\.ts$', 6 | globals: { 7 | 'ts-jest': { 8 | tsConfig: join(__dirname, 'tsconfig.test.json'), 9 | isolatedModules: true, 10 | }, 11 | }, 12 | } 13 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/numeric-slider/index.ts: -------------------------------------------------------------------------------- 1 | import { EffectPreRenderContext, EffectRenderContext, ParamType, PostEffectBase, Type } from '@delirvfx/core' 2 | 3 | interface Params { 4 | value: ParamType.Float 5 | } 6 | 7 | export default class TheWorldPostEffect extends PostEffectBase { 8 | /** 9 | * Provide usable parameters 10 | */ 11 | public static provideParameters() { 12 | return Type.float('value', { label: 'Value', defaultValue: () => 0, animatable: true }) 13 | } 14 | 15 | /** 16 | * Called when before rendering start. 17 | * 18 | * If you want initializing before rendering (likes load audio, image, etc...) 19 | * Do it in this method. 20 | */ 21 | public async initialize(context: EffectPreRenderContext) {} 22 | 23 | /** 24 | * Render frame into destination canvas. 25 | * @param context 26 | */ 27 | public async render(context: EffectRenderContext) {} 28 | } 29 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/numeric-slider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/posteffect-numeric-slider", 3 | "version": "0.1.0", 4 | "author": "ragg (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.12.x" 9 | }, 10 | "delir": { 11 | "name": "Numeric slider", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ragg/delir-post-effect-plugins", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "scripts": { 6 | "test": "jest" 7 | }, 8 | "devDependencies": { 9 | "glob-promise": "^3.4.0", 10 | "jest": "24.9.0", 11 | "semver": "6.3.0" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/repeat-tile/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/posteffect-repeat-tile", 3 | "version": "0.1.0", 4 | "author": "Hanakla (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.12.x" 9 | }, 10 | "delir": { 11 | "name": "Repeat Tile", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/the-world/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/posteffect-the-world", 3 | "version": "0.1.0", 4 | "author": "ragg (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.12.x" 9 | }, 10 | "delir": { 11 | "name": "The world", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/time-posterization/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/time-posterization", 3 | "version": "0.1.0", 4 | "author": "Hanakla (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.12.x" 9 | }, 10 | "delir": { 11 | "name": "Time posterization", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json" 3 | } 4 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/tsconfig.test.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "module": "commonjs" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/webgl/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@delirvfx/posteffect-webgl", 3 | "version": "0.1.0", 4 | "author": "ragg (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.12.x" 9 | }, 10 | "delir": { 11 | "name": "WebGL Shader", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/post-effect-plugins/webgl/vertex.vert: -------------------------------------------------------------------------------- 1 | attribute vec2 position; 2 | attribute vec2 coord; 3 | varying vec2 texCoord; 4 | 5 | void main(void) { 6 | gl_Position = vec4(position, 0.0, 1.0); 7 | texCoord = coord; 8 | } 9 | -------------------------------------------------------------------------------- /packages/unworked-plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/delirvfx/Delir/e0182548eb43de90c1750dc2f456fc7f11d59e87/packages/unworked-plugins/.gitkeep -------------------------------------------------------------------------------- /packages/unworked-plugins/color-keying/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | // Type, 3 | // TypeDescriptor, 4 | LayerPluginBase, 5 | // PluginPreRenderRequest, 6 | RenderRequest, 7 | // Exceptions 8 | } from '@delirvfx/core' 9 | 10 | export default class CompositionLayer extends LayerPluginBase { 11 | public static pluginDidLoad() {} 12 | 13 | public async render(req: RenderRequest) {} 14 | } 15 | -------------------------------------------------------------------------------- /packages/unworked-plugins/color-keying/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "delir-plugin-color-keying", 3 | "version": "0.0.0-alpha.1", 4 | "author": "Ragg ", 5 | "main": "index.js", 6 | "engines": { 7 | "delir": "0.0.x" 8 | }, 9 | "delir": { 10 | "feature": "CustomLayer", 11 | "targetApi": { 12 | "renderer": "0.0.x" 13 | }, 14 | "acceptFileTypes": {} 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/unworked-plugins/composition-layer/composition-layer.ts: -------------------------------------------------------------------------------- 1 | import { 2 | // Type, 3 | // TypeDescriptor, 4 | LayerPluginBase, 5 | // PluginPreRenderRequest, 6 | RenderRequest, 7 | // Exceptions 8 | } from '@delirvfx/core' 9 | 10 | export default class CompositionLayer extends LayerPluginBase { 11 | public static pluginDidLoad() {} 12 | 13 | public async render(req: RenderRequest) {} 14 | } 15 | -------------------------------------------------------------------------------- /packages/unworked-plugins/composition-layer/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "composition-layer", 3 | "version": "0.0.0", 4 | "author": "Ragg ", 5 | "main": "composition-layer.js", 6 | "engines": { 7 | "delir": "0.0.x" 8 | }, 9 | "delir": { 10 | "feature": "CustomLayer", 11 | "targetApi": { 12 | "renderer": "0.0.x" 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /packages/unworked-plugins/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'tooloud' { 2 | const _: any 3 | export default _ 4 | } 5 | -------------------------------------------------------------------------------- /packages/unworked-plugins/filler/index.ts: -------------------------------------------------------------------------------- 1 | import { PostEffectBase, PreRenderRequest, RenderRequest, Type, TypeDescriptor } from '@delirvfx/core' 2 | 3 | export default class Filler extends PostEffectBase { 4 | public static provideParameters(): TypeDescriptor { 5 | return Type.colorRgba('color', { 6 | label: 'Color', 7 | }) 8 | } 9 | 10 | public async initialize(req: PreRenderRequest) { 11 | // const canvas = document.createElement('canvas') 12 | // canvas.width = req.width 13 | // canvas.height = req.height 14 | } 15 | 16 | public async render(req: RenderRequest) { 17 | const param = req.parameters as any 18 | const canvas = req.destCanvas 19 | const ctx = canvas.getContext('2d')! 20 | ctx.fillStyle = param.color.toString() 21 | ctx.fillRect(0, 0, canvas.width, canvas.height) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/unworked-plugins/filler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "delir-plugin-filler", 3 | "version": "0.0.1", 4 | "author": "Ragg ", 5 | "main": "index.js", 6 | "engines": { 7 | "@delirvfx/core": "0.7.x" 8 | }, 9 | "delir": { 10 | "name": "フィラー", 11 | "type": "post-effect" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /packages/unworked-plugins/gaussian-blur/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ragg/delir-posteffect-gaussian-blur", 3 | "version": "0.1.0", 4 | "author": "Ragg (https://twitter.com/@_ragg_)", 5 | "license": "MIT", 6 | "main": "index.js", 7 | "engines": { 8 | "@delirvfx/core": "0.8.x" 9 | }, 10 | "delir": { 11 | "name": "Gaussian blur", 12 | "type": "post-effect" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /packages/unworked-plugins/mmd/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /packages/unworked-plugins/mmd/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ragg/delir-plugin-mmd", 3 | "version": "0.0.1", 4 | "author": "Ragg ", 5 | "main": "index.js", 6 | "engines": { 7 | "@delirvfx/core": "0.7.x" 8 | }, 9 | "delir": { 10 | "name": "MMD Renderer", 11 | "type": "post-effect" 12 | }, 13 | "dependencies": { 14 | "three": "0.87.1", 15 | "three-mmd-loader": "0.0.11" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/unworked-plugins/noise/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "noise", 3 | "version": "0.0.0", 4 | "author": "Ragg ", 5 | "main": "index.js", 6 | "engines": { 7 | "delir": "0.0.x" 8 | }, 9 | "delir": { 10 | "package-name": "Tooloud Noise", 11 | "feature": "Effect", 12 | "targetApi": { 13 | "renderer": "0.0.x" 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/unworked-plugins/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ragg/delir-unworked-plugins", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "dependencies": { 6 | "tooloud": "2.0.4" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /packages/web-example/.gitignore: -------------------------------------------------------------------------------- 1 | public/ 2 | -------------------------------------------------------------------------------- /packages/web-example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "web-example", 3 | "version": "0.0.0", 4 | "main": "index.js", 5 | "author": "Mitsuka Hanakura", 6 | "license": "MIT", 7 | "scripts": { 8 | "start": "webpack --mode development --watch" 9 | }, 10 | "dependencies": { 11 | "@delirvfx/core": "*", 12 | "lodash-es": "4.17.15", 13 | "random-emoji": "1.0.2" 14 | }, 15 | "devDependencies": { 16 | "@types/lodash-es": "4.17.3", 17 | "@types/webpack": "4.41.0", 18 | "html-webpack-plugin": "3.2.0", 19 | "ts-node": "^8.5.4", 20 | "webpack": "^4.41.5", 21 | "webpack-cli": "^3.3.9" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /packages/web-example/src/ExamplePlugin.ts: -------------------------------------------------------------------------------- 1 | import { EffectRenderContext, PostEffectBase } from '@delirvfx/core' 2 | import randomEmoji from 'random-emoji' 3 | 4 | export class ExamplePlugin extends PostEffectBase { 5 | private emojis: string[] 6 | 7 | public async initialize() { 8 | this.emojis = this.generateEmoji(10) 9 | } 10 | 11 | public async render(context: EffectRenderContext<{}>) { 12 | if (context.frame % 3 === 0) { 13 | this.emojis.push(this.generateEmoji(1)) 14 | this.emojis.shift() 15 | } 16 | 17 | const ctx = context.destCanvas.getContext('2d') 18 | ctx.fillStyle = '#000' 19 | ctx.font = '32px "sans-serif"' 20 | ctx.textBaseline = 'top' 21 | ctx.fillText(`This is post effect ${this.emojis.join('')}`, 10, 10) 22 | } 23 | 24 | private generateEmoji(count: number) { 25 | return randomEmoji.random({ count }).map((e: any) => e.character) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /packages/web-example/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "moduleResolution": "node", 4 | "allowSyntheticDefaultImports": true, 5 | "esModuleInterop": true, 6 | "target": "es2016", 7 | "lib": ["dom", "es2015", "es2016"] 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/web-example/webpack.config.ts: -------------------------------------------------------------------------------- 1 | import HtmlWebpackPlugin from 'html-webpack-plugin' 2 | import { join } from 'path' 3 | import webpack from 'webpack' 4 | 5 | export default (): webpack.Configuration => ({ 6 | entry: './src/index', 7 | output: { 8 | path: join(__dirname, 'public'), 9 | filename: '[name].js', 10 | }, 11 | resolve: { 12 | extensions: ['.js', '.ts'], 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.ts?/, 18 | loader: 'ts-loader', 19 | options: { 20 | transpileOnly: true, 21 | }, 22 | }, 23 | ], 24 | }, 25 | plugins: [ 26 | new HtmlWebpackPlugin({ 27 | filename: 'index.html', 28 | title: 'Delir web example', 29 | // template: 'src/index.html', 30 | }), 31 | ], 32 | }) 33 | -------------------------------------------------------------------------------- /setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | yarn 3 | yarn rebuild 4 | -------------------------------------------------------------------------------- /tsconfig.base.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "strictNullChecks": true, 5 | "noImplicitAny": true, 6 | "noImplicitThis": true, 7 | "noUnusedLocals": false, 8 | "noUnusedParameters": false, 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "downlevelIteration": true, 12 | "forceConsistentCasingInFileNames": true, 13 | "allowJs": true, 14 | "target": "es2016", 15 | "module": "commonjs", 16 | "moduleResolution": "node", 17 | "resolveJsonModule": true, 18 | "esModuleInterop": true, 19 | "allowSyntheticDefaultImports": true, 20 | "jsx": "react", 21 | "lib": ["dom", "dom.iterable", "es2015", "es2016", "es2017", "es2018", "es2019"] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "tslint-config-prettier" 4 | ], 5 | "rules": { 6 | "class-name": [ true ], 7 | "curly": [ true, "ignore-same-line" ], 8 | "interface-over-type-literal": [ true ], 9 | "member-access": [ true ], 10 | "member-ordering": [ true, { "order": [ 11 | "public-static-field", 12 | "public-static-method", 13 | "protected-static-field", 14 | "protected-static-method", 15 | "private-static-field", 16 | "private-static-method", 17 | "public-instance-field", 18 | "protected-instance-field", 19 | "private-instance-field", 20 | "public-constructor", 21 | "protected-constructor", 22 | "private-constructor", 23 | "public-instance-method", 24 | "protected-instance-method", 25 | "private-instance-method" 26 | ] } ], 27 | "no-string-literal": [ true ], 28 | "no-console": [ true ], 29 | "ordered-imports": [ true ] 30 | } 31 | } 32 | --------------------------------------------------------------------------------