├── .prettierignore ├── .eslintignore ├── src ├── electron │ ├── lib │ │ ├── ai │ │ │ ├── errors.ts │ │ │ ├── python │ │ │ │ ├── strategies │ │ │ │ │ ├── socket.py │ │ │ │ │ └── api.py │ │ │ │ ├── main.py │ │ │ │ ├── api.py │ │ │ │ ├── models │ │ │ │ │ ├── test.py │ │ │ │ │ └── gpt.py │ │ │ │ └── prompts │ │ │ │ │ └── generic.py │ │ │ ├── AI Photo Editor 2023-08-10 09-05-03.png │ │ │ ├── AI Photo Editor 2023-08-10 09-07-20.png │ │ │ ├── AI Photo Editor 2023-08-10 09-09-49.png │ │ │ ├── examples.txt │ │ │ └── systemPrompt.txt │ │ ├── plugins │ │ │ ├── builders │ │ │ │ └── PluginContextBuilder.ts │ │ │ └── pluginCommands.ts │ │ ├── registries │ │ │ ├── Registry.ts │ │ │ ├── TileRegistry.ts │ │ │ └── CommandRegistry.ts │ │ ├── BlixCommands.ts │ │ ├── core-graph │ │ │ ├── test.json │ │ │ └── CoreGraphCommands.ts │ │ ├── api │ │ │ ├── apis │ │ │ │ ├── TileApi.ts │ │ │ │ ├── ToolboxApi.ts │ │ │ │ ├── CommandApi.ts │ │ │ │ ├── TypeclassApi.ts │ │ │ │ ├── PluginApi.ts │ │ │ │ ├── WindowApi.ts │ │ │ │ └── MediaApi.ts │ │ │ └── MainApi.ts │ │ └── media │ │ │ └── MediaSubscribers.ts │ ├── utils │ │ ├── logger.ts │ │ └── dialog.ts │ └── tsconfig.json ├── frontend │ ├── ui │ │ ├── utils │ │ │ ├── graph │ │ │ │ ├── CommentNode.svelte │ │ │ │ ├── PluginEdge.svelte │ │ │ │ ├── nodeUIComponents │ │ │ │ │ ├── Button.svelte │ │ │ │ │ ├── dials │ │ │ │ │ │ ├── TweakDial.svelte │ │ │ │ │ │ ├── DiffDial.svelte │ │ │ │ │ │ └── Dial.svelte │ │ │ │ │ ├── Checkbox.svelte │ │ │ │ │ ├── Buffer.svelte │ │ │ │ │ ├── Knob.svelte │ │ │ │ │ ├── ColorPicker │ │ │ │ │ │ └── ColorPickerWrapper.svelte │ │ │ │ │ ├── FilePicker.svelte │ │ │ │ │ ├── Slider.svelte │ │ │ │ │ ├── Radio.svelte │ │ │ │ │ ├── Dropdown.svelte │ │ │ │ │ ├── TextInput.svelte │ │ │ │ │ └── CachePicker.svelte │ │ │ │ ├── NodeUIFragment.svelte │ │ │ │ └── NodeUIComponent.svelte │ │ │ ├── mediaDisplays │ │ │ │ ├── Image.svelte │ │ │ │ ├── TextBox.svelte │ │ │ │ └── ColorDisplay.svelte │ │ │ ├── ContextMenuItem.svelte │ │ │ ├── pluginTile │ │ │ │ ├── tileUIComponents │ │ │ │ │ ├── Button.svelte │ │ │ │ │ ├── ColorPicker.svelte │ │ │ │ │ ├── TextInput.svelte │ │ │ │ │ ├── Slider.svelte │ │ │ │ │ ├── FilePicker.svelte │ │ │ │ │ ├── Knob.svelte │ │ │ │ │ ├── Dropdown.svelte │ │ │ │ │ └── Radio.svelte │ │ │ │ ├── TileUIFragment.svelte │ │ │ │ └── TileUIComponent.svelte │ │ │ ├── Shortcuts.svelte │ │ │ ├── toasts │ │ │ │ └── Toasts.svelte │ │ │ └── ContextMenuGroup.svelte │ │ ├── tiles │ │ │ ├── Plugin.svelte │ │ │ ├── Blank.svelte │ │ │ └── Debug.svelte │ │ └── base │ │ │ ├── settings │ │ │ ├── utils │ │ │ │ ├── Button.svelte │ │ │ │ ├── ColorPicker │ │ │ │ │ └── ColorPicker.svelte │ │ │ │ ├── Dropdown.svelte │ │ │ │ ├── SettingsItem.svelte │ │ │ │ ├── Markdown.svelte │ │ │ │ └── SecureInput.svelte │ │ │ └── AiSettings.svelte │ │ │ ├── layout │ │ │ ├── PanelTabs.svelte │ │ │ └── PanelBlipVane.svelte │ │ │ ├── palette │ │ │ └── PaletteItem.svelte │ │ │ └── Navbar.svelte │ ├── types │ │ ├── index.ts │ │ ├── selection-box.ts │ │ └── temp.ts │ ├── main.ts │ ├── lib │ │ ├── api │ │ │ └── apis │ │ │ │ ├── TileClientApi.ts │ │ │ │ ├── CommandClientApi.ts │ │ │ │ ├── ToolboxClientApi.ts │ │ │ │ ├── MediaClientApi.ts │ │ │ │ ├── UtilClientApi.ts │ │ │ │ ├── GraphClientApi.ts │ │ │ │ └── ProjectClientApi.ts │ │ ├── webview │ │ │ └── TweakApi.ts │ │ ├── stores │ │ │ ├── SettingsStore.ts │ │ │ ├── TileStore.ts │ │ │ └── ToolboxStore.ts │ │ └── Project.ts │ └── tsconfig.json ├── shared │ ├── types │ │ ├── util.ts │ │ ├── typeclass.ts │ │ ├── dials.ts │ │ ├── index.ts │ │ ├── layout.ts │ │ ├── project.ts │ │ ├── command.ts │ │ ├── media.ts │ │ ├── palette.ts │ │ ├── graph.ts │ │ ├── cache.ts │ │ └── setting.ts │ ├── utils │ │ └── UniqueEntity.ts │ └── ui │ │ ├── ToolboxTypes.ts │ │ ├── NodeUITypes.ts │ │ └── TileUITypes.ts └── global.d.ts ├── blix-plugins ├── glfx-plugin │ ├── .gitignore │ ├── src │ │ ├── global.css │ │ ├── image.png │ │ └── index.html │ ├── webview │ │ └── app.js │ ├── package.json │ ├── rollup.config.js │ └── README.md ├── webgl-plugin │ ├── .gitignore │ ├── src │ │ ├── global.css │ │ ├── image.png │ │ ├── main.cjs │ │ ├── vert.glsl │ │ ├── index.html │ │ └── frag.glsl │ ├── webview │ │ └── app.js │ ├── package.json │ ├── rollup.config.js │ └── README.md ├── base-plugin │ ├── README.md │ ├── package.json │ └── src │ │ └── main.js ├── logic-plugin │ ├── package.json │ └── README.md ├── input-plugin │ ├── package.json │ └── README.md └── math-plugin │ ├── package.json │ └── README.md ├── assets ├── image.png ├── edited-image.png └── promptWindow.css ├── tsconfig.electron.json ├── tsconfig.svelte.json ├── docs ├── pdf │ ├── SRSv4.pdf │ ├── Architecture.pdf │ ├── TestingPolicy.pdf │ ├── code_standards.pdf │ └── InstallationManual.pdf ├── pics │ ├── blix.png │ ├── cicd.png │ ├── dino.png │ ├── jake.png │ ├── actions.png │ ├── armand.png │ ├── karel.png │ ├── nodes.png │ ├── palette.png │ ├── addImage.png │ ├── francois.png │ ├── demo-image-1.png │ ├── mac-isntall.png │ ├── tutorial-AI.png │ ├── blix-homepage.png │ ├── github-release.png │ ├── removeAllImages.png │ ├── tutorial-Graphs.png │ ├── tutorial-Layout.png │ ├── tutorial-Plugins.png │ ├── tutorial-Projects.png │ ├── smallImageBigGraph.png │ ├── smallImageSmallGraph.png │ ├── tutorial-Keybindings.png │ └── blix.svg ├── latex │ ├── Architecture.pdf │ ├── Architecture.toc │ └── Architecture.out ├── diagramPng │ ├── AI-subsystem.png │ ├── Graph-Subsystem.png │ ├── Layout-Subsystem.png │ ├── User-subsystem.png │ ├── Builder-subsystem.png │ ├── Deployment_Diagram.png │ ├── Project-subsystem.png │ ├── SystemArchitecture.png │ ├── System_Architecture1.png │ ├── Graph Parsing-subsystem.png │ ├── UseCase Image-Subsystem.png │ ├── Usecase Graph-Subsystem.png │ ├── Usecase User-subsystem.png │ ├── Usecase Layout-Subsystem.png │ ├── Usecase Project-Subsystem.png │ └── Usecase ProjectManagement-Subsystem.png └── diagrams │ └── demo-3 │ └── System_Architecture1.png ├── public ├── favicon.png ├── images │ ├── icon.png │ ├── image.png │ ├── banner.jpg │ ├── gaeblix.png │ ├── blix_64x64.png │ ├── blix_512x512.png │ ├── svelte-so-hot.jpg │ ├── banner_rotated.jpg │ └── blix.svg ├── index.html └── global.css ├── .husky └── pre-commit ├── .vscode └── extensions.json ├── svelte.config.js ├── nodemon.json ├── .gitmodules ├── .prettierrc ├── .github ├── codecov.yml └── workflows │ ├── build.yml │ ├── coverage.yml │ └── lint.yml ├── scripts ├── cleanBuilds.js ├── plugins.sh └── plugins.js ├── jest.config.json ├── tests └── unit-tests │ ├── shared │ └── UIGraph.spec.ts │ └── electron │ └── lib │ ├── tiles │ └── TileRegistry.spec.ts │ └── plugins │ └── builder │ └── TypeClassBuilder.spec.ts ├── tailwind.config.js ├── playwright.config.ts └── .gitignore /.prettierignore: -------------------------------------------------------------------------------- 1 | **/.DS_Store -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | ai-profiler-v2.ts -------------------------------------------------------------------------------- /src/electron/lib/ai/errors.ts: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/CommentNode.svelte: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /assets/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/assets/image.png -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/src/global.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Arial'; 3 | } -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/src/global.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family: 'Arial'; 3 | } -------------------------------------------------------------------------------- /tsconfig.electron.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./src/electron/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /tsconfig.svelte.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./src/frontend/tsconfig.json" 3 | } 4 | -------------------------------------------------------------------------------- /docs/pdf/SRSv4.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pdf/SRSv4.pdf -------------------------------------------------------------------------------- /docs/pics/blix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/blix.png -------------------------------------------------------------------------------- /docs/pics/cicd.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/cicd.png -------------------------------------------------------------------------------- /docs/pics/dino.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/dino.png -------------------------------------------------------------------------------- /docs/pics/jake.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/jake.png -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/favicon.png -------------------------------------------------------------------------------- /src/electron/lib/ai/python/strategies/socket.py: -------------------------------------------------------------------------------- 1 | #Implement socket implementation here -------------------------------------------------------------------------------- /docs/pics/actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/actions.png -------------------------------------------------------------------------------- /docs/pics/armand.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/armand.png -------------------------------------------------------------------------------- /docs/pics/karel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/karel.png -------------------------------------------------------------------------------- /docs/pics/nodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/nodes.png -------------------------------------------------------------------------------- /docs/pics/palette.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/palette.png -------------------------------------------------------------------------------- /src/frontend/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./temp"; 2 | export * from "./selection-box"; 3 | -------------------------------------------------------------------------------- /assets/edited-image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/assets/edited-image.png -------------------------------------------------------------------------------- /blix-plugins/base-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Hello Plugin 2 | 3 | > This is an example plugin for Blix. -------------------------------------------------------------------------------- /docs/pics/addImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/addImage.png -------------------------------------------------------------------------------- /docs/pics/francois.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/francois.png -------------------------------------------------------------------------------- /public/images/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/icon.png -------------------------------------------------------------------------------- /public/images/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/image.png -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /docs/pdf/Architecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pdf/Architecture.pdf -------------------------------------------------------------------------------- /docs/pdf/TestingPolicy.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pdf/TestingPolicy.pdf -------------------------------------------------------------------------------- /docs/pics/demo-image-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/demo-image-1.png -------------------------------------------------------------------------------- /docs/pics/mac-isntall.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/mac-isntall.png -------------------------------------------------------------------------------- /docs/pics/tutorial-AI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/tutorial-AI.png -------------------------------------------------------------------------------- /public/images/banner.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/banner.jpg -------------------------------------------------------------------------------- /public/images/gaeblix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/gaeblix.png -------------------------------------------------------------------------------- /src/shared/types/util.ts: -------------------------------------------------------------------------------- 1 | export type ToastType = "success" | "error" | "info" | "warn" | "loading"; 2 | -------------------------------------------------------------------------------- /docs/latex/Architecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/latex/Architecture.pdf -------------------------------------------------------------------------------- /docs/pdf/code_standards.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pdf/code_standards.pdf -------------------------------------------------------------------------------- /docs/pics/blix-homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/blix-homepage.png -------------------------------------------------------------------------------- /docs/pics/github-release.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/github-release.png -------------------------------------------------------------------------------- /public/images/blix_64x64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/blix_64x64.png -------------------------------------------------------------------------------- /docs/pdf/InstallationManual.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pdf/InstallationManual.pdf -------------------------------------------------------------------------------- /docs/pics/removeAllImages.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/removeAllImages.png -------------------------------------------------------------------------------- /docs/pics/tutorial-Graphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/tutorial-Graphs.png -------------------------------------------------------------------------------- /docs/pics/tutorial-Layout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/tutorial-Layout.png -------------------------------------------------------------------------------- /docs/pics/tutorial-Plugins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/tutorial-Plugins.png -------------------------------------------------------------------------------- /docs/pics/tutorial-Projects.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/tutorial-Projects.png -------------------------------------------------------------------------------- /public/images/blix_512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/blix_512x512.png -------------------------------------------------------------------------------- /public/images/svelte-so-hot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/svelte-so-hot.jpg -------------------------------------------------------------------------------- /docs/diagramPng/AI-subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/AI-subsystem.png -------------------------------------------------------------------------------- /docs/pics/smallImageBigGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/smallImageBigGraph.png -------------------------------------------------------------------------------- /public/images/banner_rotated.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/public/images/banner_rotated.jpg -------------------------------------------------------------------------------- /src/frontend/types/selection-box.ts: -------------------------------------------------------------------------------- 1 | export type SelectionBoxItem = { 2 | id: string; 3 | title: string; 4 | }; 5 | -------------------------------------------------------------------------------- /docs/diagramPng/Graph-Subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Graph-Subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/Layout-Subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Layout-Subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/User-subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/User-subsystem.png -------------------------------------------------------------------------------- /docs/pics/smallImageSmallGraph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/smallImageSmallGraph.png -------------------------------------------------------------------------------- /docs/pics/tutorial-Keybindings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/pics/tutorial-Keybindings.png -------------------------------------------------------------------------------- /src/shared/types/typeclass.ts: -------------------------------------------------------------------------------- 1 | export type RendererId = `${string}/${string}`; 2 | export type RendererURL = string; 3 | -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/src/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/blix-plugins/glfx-plugin/src/image.png -------------------------------------------------------------------------------- /docs/diagramPng/Builder-subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Builder-subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/Deployment_Diagram.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Deployment_Diagram.png -------------------------------------------------------------------------------- /docs/diagramPng/Project-subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Project-subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/SystemArchitecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/SystemArchitecture.png -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/src/image.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/blix-plugins/webgl-plugin/src/image.png -------------------------------------------------------------------------------- /docs/diagramPng/System_Architecture1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/System_Architecture1.png -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "svelte.svelte-vscode", 4 | "bradlc.vscode-tailwindcss" 5 | ] 6 | } 7 | -------------------------------------------------------------------------------- /docs/diagramPng/Graph Parsing-subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Graph Parsing-subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/UseCase Image-Subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/UseCase Image-Subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/Usecase Graph-Subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Usecase Graph-Subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/Usecase User-subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Usecase User-subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/Usecase Layout-Subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Usecase Layout-Subsystem.png -------------------------------------------------------------------------------- /docs/diagramPng/Usecase Project-Subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Usecase Project-Subsystem.png -------------------------------------------------------------------------------- /docs/diagrams/demo-3/System_Architecture1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagrams/demo-3/System_Architecture1.png -------------------------------------------------------------------------------- /svelte.config.js: -------------------------------------------------------------------------------- 1 | const sveltePreprocess = require("svelte-preprocess"); 2 | 3 | module.exports = { 4 | preprocess: sveltePreprocess(), 5 | }; 6 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": ["build"], 3 | "exec": "npm run start:electron:run", 4 | "ext": "js, json, ts, proto, css, png, jpeg, jpg, ico" 5 | } 6 | -------------------------------------------------------------------------------- /docs/diagramPng/Usecase ProjectManagement-Subsystem.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/docs/diagramPng/Usecase ProjectManagement-Subsystem.png -------------------------------------------------------------------------------- /src/electron/lib/ai/AI Photo Editor 2023-08-10 09-05-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/src/electron/lib/ai/AI Photo Editor 2023-08-10 09-05-03.png -------------------------------------------------------------------------------- /src/electron/lib/ai/AI Photo Editor 2023-08-10 09-07-20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/src/electron/lib/ai/AI Photo Editor 2023-08-10 09-07-20.png -------------------------------------------------------------------------------- /src/electron/lib/ai/AI Photo Editor 2023-08-10 09-09-49.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BlixEditor/blix/HEAD/src/electron/lib/ai/AI Photo Editor 2023-08-10 09-09-49.png -------------------------------------------------------------------------------- /src/global.d.ts: -------------------------------------------------------------------------------- 1 | import type { MainApis } from "./frontend/lib/api/apiInitializer"; 2 | 3 | declare global { 4 | interface Window { 5 | apis: MainApis; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/src/main.cjs: -------------------------------------------------------------------------------- 1 | const nodes = {} 2 | const commands = {} 3 | const tiles = {} 4 | const types = {} 5 | 6 | module.exports = { 7 | nodes, 8 | commands, 9 | tiles 10 | }; -------------------------------------------------------------------------------- /src/frontend/main.ts: -------------------------------------------------------------------------------- 1 | import "svelte"; 2 | import App from "./ui/base/App.svelte"; 3 | 4 | const app = new App({ 5 | target: document.body, 6 | props: {}, 7 | }); 8 | 9 | export default app; 10 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "blix-plugins/ripple"] 2 | path = blix-plugins/ripple 3 | url = https://github.com/BlixEditor/ripple 4 | [submodule "blix-plugins/blink"] 5 | path = blix-plugins/blink 6 | url = https://github.com/BlixEditor/blink 7 | -------------------------------------------------------------------------------- /src/electron/lib/plugins/builders/PluginContextBuilder.ts: -------------------------------------------------------------------------------- 1 | // Defines the structure for a builder that can be used 2 | // by a plugin to build a Blix internal object. 3 | export interface PluginContextBuilder { 4 | get build(): any; 5 | // reset(): void; 6 | } 7 | -------------------------------------------------------------------------------- /src/shared/types/dials.ts: -------------------------------------------------------------------------------- 1 | export type NodeTweakData = { 2 | nodeUUID: string; 3 | inputs: string[]; 4 | }; 5 | 6 | export type NodeDiffData = { 7 | uiInputs: string[]; 8 | anchors: { [key: string]: "connection" | "value" }; // anchorId -> changeType 9 | }; 10 | -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/src/vert.glsl: -------------------------------------------------------------------------------- 1 | attribute vec4 position; 2 | uniform vec2 translation; 3 | uniform float zoom; 4 | 5 | void main() { 6 | // gl_Position = position; 7 | gl_Position = vec4(((position.xy + translation) * 2.0 - 1.0) * zoom, 0.0, 1.0); 8 | // gl_PointSize = 20.0; 9 | } -------------------------------------------------------------------------------- /src/shared/types/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./layout"; 2 | export * from "./project"; 3 | export * from "./graph"; 4 | export * from "./command"; 5 | export * from "./util"; 6 | export * from "./setting"; 7 | export * from "./media"; 8 | export * from "./palette"; 9 | export * from "./dials"; 10 | -------------------------------------------------------------------------------- /src/shared/types/layout.ts: -------------------------------------------------------------------------------- 1 | export interface LayoutPanel { 2 | panels?: LayoutPanel[]; 3 | content?: PanelType; 4 | } 5 | 6 | export type PanelType = 7 | | "graph" 8 | | "media" 9 | | "debug" 10 | | "webview" 11 | | "shortcutSettings" 12 | | "assets" 13 | | "browser" 14 | | "webcamera"; 15 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "singleQuote": false, 4 | "trailingComma": "es5", 5 | "plugins": [ 6 | "prettier-plugin-svelte", 7 | "prettier-plugin-tailwindcss" 8 | ], 9 | "pluginSearchDirs": false, 10 | "svelteSortOrder": "scripts-markup-styles", 11 | "svelteStrictMode": true, 12 | "overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }] 13 | } 14 | -------------------------------------------------------------------------------- /src/electron/lib/registries/Registry.ts: -------------------------------------------------------------------------------- 1 | // Abstract representation of a backend registry 2 | export interface Registry { 3 | addInstance(instance: RegistryInstance): void; 4 | getRegistry(): { [key: string]: RegistryInstance }; 5 | } 6 | 7 | // Implementations of this interface should 8 | // ideally be immutable 9 | export interface RegistryInstance { 10 | get id(): string; 11 | } 12 | -------------------------------------------------------------------------------- /src/frontend/lib/api/apis/TileClientApi.ts: -------------------------------------------------------------------------------- 1 | import type { ITile } from "@shared/ui/TileUITypes"; 2 | import type { ElectronWindowApi } from "electron-affinity/window"; 3 | import { tileStore } from "../../stores/TileStore"; 4 | 5 | export class TileClientApi implements ElectronWindowApi { 6 | registryChanged(results: ITile[]) { 7 | tileStore.refreshStore(results); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/frontend/lib/api/apis/CommandClientApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronWindowApi } from "electron-affinity/window"; 2 | import { commandStore } from "../../stores/CommandStore"; 3 | import type { ICommand } from "@shared/types"; 4 | 5 | export class CommandClientApi implements ElectronWindowApi { 6 | registryChanged(results: ICommand[]) { 7 | commandStore.refreshStore(results); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/frontend/ui/tiles/Plugin.svelte: -------------------------------------------------------------------------------- 1 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/electron/lib/ai/python/main.py: -------------------------------------------------------------------------------- 1 | from api import get_api 2 | from models.gpt import GPT 3 | import json 4 | 5 | def main(): 6 | api = get_api() 7 | 8 | text_data = api.receive() 9 | data = json.loads(text_data) 10 | 11 | agent = GPT() 12 | finalResponse = agent.sendPrompt(data) 13 | 14 | api.send({"type": "exit", "message": finalResponse}) 15 | 16 | 17 | if __name__ == "__main__": 18 | main() -------------------------------------------------------------------------------- /src/frontend/lib/api/apis/ToolboxClientApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronWindowApi } from "electron-affinity/window"; 2 | import type { INode } from "@shared/ui/ToolboxTypes"; 3 | import { toolboxStore } from "@frontend/lib/stores/ToolboxStore"; 4 | 5 | export class ToolboxClientApi implements ElectronWindowApi { 6 | registryChanged(results: INode[]) { 7 | toolboxStore.refreshStore(results); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /src/frontend/ui/tiles/Blank.svelte: -------------------------------------------------------------------------------- 1 |
2 |
3 | BLANK TILE 4 |

5 | Nothing to see here! 6 |
7 |
8 | 9 | 22 | -------------------------------------------------------------------------------- /src/shared/types/project.ts: -------------------------------------------------------------------------------- 1 | import type { UUID } from "../utils/UniqueEntity"; 2 | import type { LayoutPanel } from "./layout"; 3 | 4 | export interface SharedProject { 5 | id: UUID; 6 | saved: boolean; 7 | name?: string; 8 | layout?: LayoutPanel; 9 | graphs?: UUID[]; 10 | cache?: UUID[]; 11 | mediaOutputIds?: UUID[]; 12 | } 13 | 14 | export interface recentProject { 15 | path: string; 16 | lastEdited: string; 17 | } 18 | -------------------------------------------------------------------------------- /src/electron/lib/BlixCommands.ts: -------------------------------------------------------------------------------- 1 | import { projectCommands } from "./projects/ProjectCommands"; 2 | import { coreGraphCommands } from "./core-graph/CoreGraphCommands"; 3 | import { type CommandContext, type Command } from "./registries/CommandRegistry"; 4 | import { pluginCommands } from "./plugins/pluginCommands"; 5 | 6 | export const blixCommands: Command[] = [ 7 | ...projectCommands, 8 | ...coreGraphCommands, 9 | ...pluginCommands, 10 | ]; 11 | -------------------------------------------------------------------------------- /src/electron/lib/core-graph/test.json: -------------------------------------------------------------------------------- 1 | { 2 | "nodes": [ 3 | { 4 | "id": "", 5 | "signature": "hello-plugin/node1", 6 | "styling": { 7 | "position": { "x": 100, "y": 100 }, 8 | "size": { "w": 100, "h": 100 } 9 | } 10 | } 11 | ], 12 | "edges": [ 13 | { 14 | "id": "", 15 | "anchorFrom": { "parent": "", "anchorID": "" }, 16 | "anchorTo": { "parent": "", "anchorID": "" } 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /src/electron/utils/logger.ts: -------------------------------------------------------------------------------- 1 | import * as log from "electron-log"; 2 | 3 | // const isDevMode = process.execPath.match(/[\\/]electron/); 4 | const isProd = process.env.NODE_ENV === "production" || !/[\\/]electron/.exec(process.execPath); // !process.execPath.match(/[\\/]electron/); 5 | 6 | const logger = log; 7 | logger.transports.file.level = isProd ? "info" : "silly"; 8 | logger.transports.console.level = isProd ? false : "silly"; 9 | 10 | export default logger; 11 | -------------------------------------------------------------------------------- /.github/codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | # basic 6 | target: 0% 7 | threshold: 10% 8 | # advanced settings 9 | branches: 10 | - master 11 | - dev 12 | - feature/projects 13 | if_ci_failed: error #success, failure, error, ignore 14 | informational: true 15 | only_pulls: false 16 | patch: 17 | default: 18 | informational: true 19 | comment: false 20 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/mediaDisplays/Image.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | {#if src !== ""} 6 | 7 | {:else} 8 |
No image selected
9 | {/if} 10 | 11 | 23 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/PluginEdge.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /src/shared/types/command.ts: -------------------------------------------------------------------------------- 1 | import type { PaletteView } from "./palette"; 2 | 3 | export interface ICommand { 4 | id: string; 5 | name: string; 6 | description: string; 7 | icon: string; 8 | } 9 | 10 | export type CommandResponse = 11 | | { 12 | status: "success"; 13 | message?: string; 14 | data?: S; 15 | } 16 | | { 17 | status: "error"; 18 | message: string; 19 | data?: E; 20 | } 21 | | { 22 | status: "palette"; 23 | data: PaletteView; 24 | }; 25 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/ContextMenuItem.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 |
  • 16 | {node.label} 17 |
  • 18 | -------------------------------------------------------------------------------- /src/frontend/ui/base/settings/utils/Button.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
    13 | {item.value} 14 |
    15 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/Button.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /blix-plugins/logic-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "logic-plugin", 3 | "displayName": "Logic Plugin", 4 | "description": "Performs basic logical operations through n-ary nodes.", 5 | "version": "0.0.1", 6 | 7 | "author": "Rec1dite", 8 | "repository": "", 9 | 10 | "contributes": { 11 | "commands": [], 12 | "nodes": [] 13 | }, 14 | 15 | "main": "src/main.js", 16 | "renderers": {}, 17 | 18 | "devDependencies": { 19 | "@types/node": "^12.0.0", 20 | "typescript": "^3.4.5" 21 | }, 22 | 23 | "comments": [] 24 | } -------------------------------------------------------------------------------- /src/electron/lib/api/apis/TileApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronMainApi } from "electron-affinity/main"; 2 | import { TileInstance } from "../../registries/TileRegistry"; 3 | import type { Blix } from "../../Blix"; 4 | 5 | export class TileApi implements ElectronMainApi { 6 | private readonly blix: Blix; 7 | 8 | constructor(blix: Blix) { 9 | this.blix = blix; 10 | } 11 | 12 | async addNode(instance: TileInstance) { 13 | this.blix.tileRegistry.addInstance(instance); 14 | } 15 | 16 | async getTiles() { 17 | return this.blix.tileRegistry.getITiles(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/electron/lib/api/apis/ToolboxApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronMainApi } from "electron-affinity/main"; 2 | import { NodeInstance } from "../../registries/ToolboxRegistry"; 3 | import type { Blix } from "../../Blix"; 4 | 5 | export class ToolboxApi implements ElectronMainApi { 6 | private readonly blix: Blix; 7 | 8 | constructor(blix: Blix) { 9 | this.blix = blix; 10 | } 11 | 12 | async addNode(instance: NodeInstance) { 13 | this.blix.toolbox.addInstance(instance); 14 | } 15 | 16 | async getNodes() { 17 | return this.blix.toolbox.getINodes(); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/frontend/lib/webview/TweakApi.ts: -------------------------------------------------------------------------------- 1 | import type { GraphNodeUUID, GraphUUID } from "../../../shared/ui/UIGraph"; 2 | import { GraphStore, graphMall } from "../stores/GraphStore"; 3 | import { get, type Readable } from "svelte/store"; 4 | 5 | export class TweakApi { 6 | private graphStore: Readable; 7 | 8 | constructor(private graphUUID: GraphUUID) { 9 | this.graphStore = graphMall.getGraphReactive(graphUUID); 10 | } 11 | 12 | setUIInput(nodeUUID: GraphNodeUUID, inputId: string, value: any) { 13 | get(this.graphStore)?.updateUIInput(nodeUUID, inputId, value); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /assets/promptWindow.css: -------------------------------------------------------------------------------- 1 | /* This is the styling for our prompt window */ 2 | 3 | #container { 4 | border-radius: 10px; 5 | overflow: hidden; 6 | color: #333; 7 | } 8 | 9 | body { 10 | color: #333; 11 | margin: 0; 12 | padding: 8px; 13 | box-sizing: border-box; 14 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 15 | background-color: #181825; 16 | } 17 | 18 | #label{ 19 | color: #CDD6F4; 20 | } 21 | 22 | #data { 23 | background-color: #f4f4f465; 24 | color: #CDD6F4; 25 | } 26 | 27 | button { 28 | background-color: #f4f4f4; 29 | } 30 | -------------------------------------------------------------------------------- /blix-plugins/input-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "input", 3 | "displayName": "Input Plugin", 4 | "description": "Provides basic nodes for providing input to a graph.", 5 | "version": "0.0.1", 6 | 7 | "author": "Gekota the Frog", 8 | "repository": "", 9 | 10 | "contributes": { 11 | "commands": [], 12 | "nodes": [] 13 | }, 14 | 15 | "main": "src/main.js", 16 | "renderers": {}, 17 | 18 | "devDependencies": { 19 | "@types/node": "^12.0.0", 20 | "typescript": "^3.4.5" 21 | }, 22 | 23 | "comments": [ "This plugin could be expanded to handle more inputs." ] 24 | } -------------------------------------------------------------------------------- /src/frontend/ui/base/layout/PanelTabs.svelte: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 11 |
      12 | {#each panels as panel, i} 13 |
    • 14 | 15 |
    • 16 | {/each} 17 |
    18 | 19 | 29 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/dials/TweakDial.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/dials/DiffDial.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/frontend/lib/api/apis/MediaClientApi.ts: -------------------------------------------------------------------------------- 1 | import type { DisplayableMediaOutput, MediaOutputId } from "@shared/types/media"; 2 | import type { ElectronWindowApi } from "electron-affinity/window"; 3 | import { mediaStore } from "@frontend/lib/stores/MediaStore"; 4 | 5 | export class MediaClientApi implements ElectronWindowApi { 6 | outputChanged(mediaOutput: DisplayableMediaOutput): void { 7 | mediaStore.refreshStore(mediaOutput); 8 | } 9 | 10 | // public onMediaOutputIdsChanged(outputIds: Set) { 11 | // mediaStore.updateOutputIds(outputIds); 12 | // } 13 | 14 | public async outputNodesChanged() { 15 | await mediaStore.outputNodesChanged(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GLFX plugin 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/electron/lib/plugins/pluginCommands.ts: -------------------------------------------------------------------------------- 1 | import type { Command, CommandContext } from "../../lib/registries/CommandRegistry"; 2 | import { PluginManager } from "./PluginManager"; 3 | import { session } from "electron"; 4 | 5 | export const refreshPluginsCommand: Command = { 6 | id: "blix.plugins.refresh", 7 | description: { 8 | name: "Refresh plugins...", 9 | description: "Refreshes the currently loaded plugins", 10 | }, 11 | 12 | handler: async (ctx: CommandContext) => { 13 | await session.defaultSession.clearCache(); 14 | 15 | ctx.pluginManager.loadBasePlugins(true); 16 | 17 | return { status: "success" }; 18 | }, 19 | }; 20 | 21 | export const pluginCommands: Command[] = [refreshPluginsCommand]; 22 | -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | GLFX plugin 7 | 8 | 9 | 10 | 11 | 12 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/electron/lib/media/MediaSubscribers.ts: -------------------------------------------------------------------------------- 1 | import { type DisplayableMediaOutput } from "../../../shared/types/media"; 2 | import { UniqueEntity } from "../../../shared/utils/UniqueEntity"; 3 | 4 | export class MediaSubscriber extends UniqueEntity { 5 | // Index of the subscriber in CoreGraphManager's _subscribers list 6 | protected _notifyee?: (media: DisplayableMediaOutput) => void; // Callback when graph changes 7 | 8 | constructor() { 9 | super(); 10 | } 11 | 12 | public set listen(notifyee: (media: DisplayableMediaOutput) => void) { 13 | this._notifyee = notifyee; 14 | } 15 | 16 | // Calls _notifyee with the new media state 17 | onMediaChanged(mediaOutput: DisplayableMediaOutput) { 18 | if (this._notifyee) this._notifyee(mediaOutput); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/electron/lib/ai/examples.txt: -------------------------------------------------------------------------------- 1 | User: I want to negate a number 2 | Assistant: 3 | ```ts 4 | function graph() { 5 | //===== SECTION 1 =====// 6 | var num1 = input-plugin.inputNumber(5); 7 | var unary1 = math-plugin.unary(num1['res'], 'negate'); 8 | var output1 = blix.output(unary1['res'], 'output1'); 9 | } 10 | ``` 11 | 12 | User: Add two number, a binary, and output nodes 13 | Assistant: 14 | ```ts 15 | function graph() { 16 | //===== SECTION 1 =====// 17 | var num1 = input-plugin.inputNumber(5); 18 | var num2 = input-plugin.inputNumber(5); 19 | var binary1 = math-plugin.binary(null, null, 'add'); 20 | var output1 = blix.output(null, 'output1'); 21 | } 22 | ``` 23 | 24 | User: Clear the graph 25 | Assistant: 26 | ```ts 27 | function graph() { 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /blix-plugins/base-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "base-plugin", 3 | "displayName": "Base Plugin", 4 | "description": "This plugin provides the basic services that can be used for blix", 5 | "version": "0.0.69", 6 | 7 | "author": "Sharkman", 8 | "repository": "", 9 | 10 | "contributes": { 11 | "commands": [ 12 | { 13 | "command": "base-plugin.export-project", 14 | "title": "Export Project" 15 | } 16 | ], 17 | "nodes": [] 18 | }, 19 | 20 | "main": "src/main.js", 21 | "renderers": {}, 22 | 23 | "devDependencies": { 24 | "@types/node": "^12.0.0", 25 | "typescript": "^3.4.5" 26 | }, 27 | 28 | "comments": [ "This property will be completely ignored" ] 29 | } -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/webview/app.js: -------------------------------------------------------------------------------- 1 | const { writable } = require('svelte/store'); 2 | const App = require('./App.svelte').default; 3 | 4 | const media = writable({}); 5 | 6 | const app = new App({ 7 | target: document.body, 8 | props: { media }, 9 | }); 10 | 11 | module.exports.default = app; 12 | // module.exports.dispatchMessage = (message) => { notifyMessageSubscribers(message); return "asdfHello"; }; 13 | 14 | // window.api.on("testMessage", (data) => { 15 | // console.log(`Received ${data} from main process`); 16 | // }); 17 | 18 | window.addEventListener("DOMContentLoaded", () => { 19 | window.api.on("mediaChanged", (newMedia) => { 20 | media.set(newMedia); 21 | 22 | // To send a message back 23 | // window.api.send("backTestMessage", "Hello from app.js"); 24 | }); 25 | }); -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/webview/app.js: -------------------------------------------------------------------------------- 1 | const { writable } = require('svelte/store'); 2 | const App = require('./App.svelte').default; 3 | 4 | const media = writable({}); 5 | 6 | const app = new App({ 7 | target: document.body, 8 | props: { media }, 9 | }); 10 | 11 | module.exports.default = app; 12 | // module.exports.dispatchMessage = (message) => { notifyMessageSubscribers(message); return "asdfHello"; }; 13 | 14 | // window.api.on("testMessage", (data) => { 15 | // console.log(`Received ${data} from main process`); 16 | // }); 17 | 18 | window.addEventListener("DOMContentLoaded", async () => { 19 | window.api.on("mediaChanged", (newMedia) => { 20 | media.set(newMedia); 21 | 22 | // To send a message back 23 | // window.api.send("backTestMessage", "Hello from app.js"); 24 | }); 25 | 26 | }); -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/Button.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 17 | 18 | 24 | -------------------------------------------------------------------------------- /scripts/cleanBuilds.js: -------------------------------------------------------------------------------- 1 | const { existsSync, readdirSync, lstatSync, unlinkSync, rmdirSync } = require("fs"); 2 | const { join } = require("path"); 3 | 4 | const deleteFolderRecursive = (folderPath) => { 5 | if (existsSync(folderPath)) { 6 | readdirSync(folderPath).forEach((file) => { 7 | const curPath = join(folderPath, file); 8 | if (lstatSync(curPath).isDirectory()) { 9 | // recurse 10 | deleteFolderRecursive(curPath); 11 | } else { 12 | // delete file 13 | unlinkSync(curPath); 14 | } 15 | }); 16 | rmdirSync(folderPath); 17 | } 18 | }; 19 | 20 | const buildSveltePath = join(__dirname, "..", "public", "build"); 21 | const buildElectronPath = join(__dirname, "..", "build"); 22 | deleteFolderRecursive(buildSveltePath); 23 | deleteFolderRecursive(buildElectronPath); 24 | -------------------------------------------------------------------------------- /jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "collectCoverage": true, 3 | "transform": { 4 | "^.+\\.svelte$": [ 5 | "svelte-jester", 6 | { 7 | "preprocess": true 8 | } 9 | ], 10 | "^.+\\.ts$": [ 11 | "ts-jest", 12 | { 13 | "diagnostics": false 14 | } 15 | ], 16 | "^.+\\.js$": "babel-jest" 17 | }, 18 | "coveragePathIgnorePatterns": ["blix-plugins","node_modules","src/electron/lib/plugins/PluginManager","src/electron/lib/ai/AiManagerv2","src/electron/lib/ai/Model","src/electron/lib/ai/Chat"], 19 | "testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$", 20 | "moduleFileExtensions": ["ts", "tsx", "js", "jsx", "json", "node", "svelte"], 21 | "coverageDirectory": "coverage", 22 | "testPathIgnorePatterns": ["\bbuild\b", "e2e"], 23 | "preset": "ts-jest/presets/js-with-babel" 24 | } -------------------------------------------------------------------------------- /src/electron/lib/api/apis/CommandApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronMainApi } from "electron-affinity/main"; 2 | import type { Command, CommandContext } from "../../registries/CommandRegistry"; 3 | import type { Blix } from "../../Blix"; 4 | import type { CommandResponse } from "../../../../shared/types/index"; 5 | 6 | export class CommandApi implements ElectronMainApi { 7 | private readonly blix: Blix; 8 | 9 | constructor(blix: Blix) { 10 | this.blix = blix; 11 | } 12 | 13 | async addCommand(instance: Command) { 14 | this.blix.commandRegistry.addInstance(instance); 15 | } 16 | 17 | async runCommand(id: string, params?: any): Promise { 18 | return await this.blix.commandRegistry.runCommand(id, params); 19 | } 20 | 21 | async getCommands() { 22 | return this.blix.commandRegistry.getCommands(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/shared/utils/UniqueEntity.ts: -------------------------------------------------------------------------------- 1 | // import crypto from "crypto"; 2 | // const crypto = require("crypto"); 3 | 4 | export type UUID = string; 5 | 6 | export class UniqueEntity { 7 | private readonly _uuid: UUID; 8 | 9 | constructor() { 10 | this._uuid = UniqueEntity.genUUID(); 11 | } 12 | 13 | public get uuid() { 14 | return this._uuid; 15 | } 16 | 17 | // 64-bit hex string (length 32 chars) 18 | private static genUUID(): UUID { 19 | // TODO: Move require() somewhere else so it doesn't get called every time 20 | // For now this breaks with Jest so I guess we'll just have to put up with it. 21 | return require("crypto").randomBytes(32).toString("base64url"); 22 | // Use base64url encoding mainly cause Svelvet uses CSS selectors 23 | // to find elements by ID, so `-` and `_` are all we have to work with 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/electron/lib/api/apis/TypeclassApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronMainApi } from "electron-affinity/main"; 2 | import type { Blix } from "../../Blix"; 3 | import { type TypeclassId } from "../../registries/TypeclassRegistry"; 4 | import { type RendererId } from "../../../../shared/types/typeclass"; 5 | 6 | export class TypeclassApi implements ElectronMainApi { 7 | private readonly blix: Blix; 8 | 9 | constructor(blix: Blix) { 10 | this.blix = blix; 11 | } 12 | 13 | async checkTypesCompatible(from: TypeclassId, to: TypeclassId) { 14 | return this.blix.typeclassRegistry.checkTypesCompatible(from, to); 15 | } 16 | 17 | async getTypeclasses() { 18 | return this.blix.typeclassRegistry.getTypeclasses(); 19 | } 20 | 21 | async getRendererSrc(id: RendererId) { 22 | return this.blix.typeclassRegistry.getRendererSrc(id); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/electron/utils/dialog.ts: -------------------------------------------------------------------------------- 1 | import { dialog } from "electron"; 2 | import type { SaveDialogOptions, OpenDialogOptions, BrowserWindow } from "electron"; 3 | 4 | export const showSaveDialog = async ( 5 | options: SaveDialogOptions, 6 | browserWindow?: BrowserWindow 7 | ): Promise => { 8 | if (browserWindow) { 9 | return (await dialog.showSaveDialog(browserWindow, options)).filePath; 10 | } else { 11 | return (await dialog.showSaveDialog(options)).filePath; 12 | } 13 | }; 14 | 15 | export const showOpenDialog = async ( 16 | options: OpenDialogOptions, 17 | browserWindow?: BrowserWindow 18 | ): Promise => { 19 | if (browserWindow) { 20 | return (await dialog.showOpenDialog(browserWindow, options)).filePaths; 21 | } else { 22 | return (await dialog.showOpenDialog(options)).filePaths; 23 | } 24 | }; 25 | -------------------------------------------------------------------------------- /src/frontend/ui/base/settings/utils/ColorPicker/ColorPicker.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 |
    18 | 19 |
    20 | 21 | 34 | -------------------------------------------------------------------------------- /src/frontend/lib/stores/SettingsStore.ts: -------------------------------------------------------------------------------- 1 | import { writable } from "svelte/store"; 2 | interface SettingsStoreState { 3 | showing: boolean; 4 | } 5 | 6 | class SettingsStore { 7 | private readonly store = writable({ showing: false }); 8 | 9 | public toggleSettings() { 10 | this.store.update((state) => { 11 | state.showing = !state.showing; 12 | return state; 13 | }); 14 | } 15 | 16 | public hideSettings() { 17 | this.store.update((state) => { 18 | state.showing = false; 19 | return state; 20 | }); 21 | } 22 | 23 | public showSettings() { 24 | this.store.update((state) => { 25 | state.showing = true; 26 | return state; 27 | }); 28 | } 29 | 30 | public get subscribe() { 31 | return this.store.subscribe; 32 | } 33 | } 34 | 35 | export const settingsStore = new SettingsStore(); 36 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 11 | 12 | 13 | AI Photo Editor 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/ColorPicker.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 |
    16 | 17 |
    18 | 19 | 26 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/TextInput.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 | 19 | 20 | 28 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/Shortcuts.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/Slider.svelte: -------------------------------------------------------------------------------- 1 | 17 | 18 | 28 | -------------------------------------------------------------------------------- /src/frontend/lib/api/apis/UtilClientApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronWindowApi } from "electron-affinity/window"; 2 | import { toastStore, type ToastOptions } from "../../stores/ToastStore"; 3 | import { blixStore, setInitialStores, type BlixStoreState } from "../../../lib/stores/BlixStore"; 4 | import { bindMainApis } from "../apiInitializer"; 5 | 6 | export class UtilClientApi implements ElectronWindowApi { 7 | showToast(options: Partial) { 8 | toastStore.trigger(options); 9 | } 10 | 11 | /** 12 | * Will be called when Blix first initializes and when window is reloaded. 13 | */ 14 | async onBlixReady() { 15 | if (!window.apis) { 16 | window.apis = await bindMainApis(); 17 | } 18 | await setInitialStores(); 19 | blixStore.update((state) => ({ ...state, blixReady: true })); 20 | } 21 | 22 | refreshBlixStore(data: Partial) { 23 | blixStore.refreshStore(data); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/shared/types/media.ts: -------------------------------------------------------------------------------- 1 | import { type UUID } from "../../shared/utils/UniqueEntity"; 2 | 3 | export type MediaOutputId = string; 4 | 5 | export interface MediaOutput { 6 | outputId: MediaOutputId; 7 | outputNodeUUID: UUID; 8 | graphUUID: UUID; 9 | content: any; 10 | dataType: string; 11 | } 12 | 13 | // MediaOutput that has been pre-processed for display in the Media tile 14 | export type DisplayableMediaOutput = MediaOutput & { display: MediaDisplayConfig }; 15 | 16 | export interface MediaDisplayConfig { 17 | displayType: MediaDisplayType; // Type of svelte display component to use 18 | props: { [key: string]: any }; // Props passed to the Svelte display component 19 | contentProp: string | null; // Name of the prop that should be filled with the content when displaying 20 | } 21 | 22 | export enum MediaDisplayType { 23 | Image = "image", 24 | TextBox = "textbox", 25 | ColorDisplay = "colorDisplay", 26 | Webview = "webview", 27 | } 28 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/FilePicker.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 | 24 | 25 | 33 | -------------------------------------------------------------------------------- /src/frontend/ui/base/palette/PaletteItem.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
  • 28 | {title} 29 | {#if selected} 30 | {description} 31 | {/if} 32 |
  • 33 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/Checkbox.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 | 20 | 21 | 34 | -------------------------------------------------------------------------------- /src/shared/types/palette.ts: -------------------------------------------------------------------------------- 1 | export type PaletteView = { 2 | searchPlaceholder: string; 3 | searchValue?: string; 4 | content: ContentTypes; 5 | }; 6 | 7 | export type ContentTypes = PaletteList | PaletteForm; 8 | 9 | export interface PaletteForm { 10 | type: "form"; 11 | items: string[]; 12 | } 13 | 14 | export interface PaletteList { 15 | type: "list"; 16 | sections: PaletteListSection[]; 17 | filteredSections?: PaletteListSection[]; 18 | } 19 | 20 | export type PaletteListSection = { 21 | title: string; 22 | items: PaletteListItem[]; 23 | }; 24 | 25 | export type PaletteListItem = { 26 | title: string; 27 | subtitle?: string; 28 | icon?: string; 29 | props?: PaletteListProp[]; 30 | command?: PaletteCommand; 31 | }; 32 | 33 | export type PaletteCommand = { 34 | id: string; 35 | args?: Record; 36 | }; 37 | 38 | export type PaletteListProp = { 39 | text?: string; 40 | icon?: string; 41 | keybind?: string; 42 | // Add other props here 43 | }; 44 | -------------------------------------------------------------------------------- /blix-plugins/math-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "math", 3 | "displayName": "Math Plugin", 4 | "description": "Performs basic math operations through n-ary nodes.", 5 | "version": "0.0.1", 6 | 7 | "author": "Gekota the Frog", 8 | "repository": "", 9 | 10 | "contributes": { 11 | "commands": [], 12 | "nodes": [ 13 | { 14 | "id": "math", 15 | "name": "Math", 16 | "interface" : { 17 | "inputs": { 18 | "numA": "int" 19 | }, 20 | "outputs": { 21 | "numOut": "int" 22 | } 23 | } 24 | } 25 | ] 26 | }, 27 | 28 | "main": "src/main.js", 29 | "renderers": {}, 30 | 31 | "devDependencies": { 32 | "@types/node": "^12.0.0", 33 | "typescript": "^3.4.5" 34 | }, 35 | 36 | "comments": [ "This plugin will be expanded to handle more math operations." ] 37 | } -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/Buffer.svelte: -------------------------------------------------------------------------------- 1 | 18 | 19 | 20 | 21 | 31 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/Knob.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 |
    17 | 25 |
    26 | 27 | 34 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/Knob.svelte: -------------------------------------------------------------------------------- 1 | 15 | 16 |
    17 | 25 |
    26 | 27 | 34 | -------------------------------------------------------------------------------- /src/frontend/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "@tsconfig/svelte/tsconfig.json", 3 | "compilerOptions": { 4 | "baseUrl": ".", 5 | "paths": { 6 | "@shared/*": ["../shared/*"], 7 | "@electron/*": ["../electron/*"], 8 | "@frontend/*": ["../frontend/*"] 9 | }, 10 | "types": ["node", "svelte", "jest"], 11 | "sourceMap": true, 12 | "target": "ES2015", 13 | "stripInternal": true, 14 | "strict": true, 15 | "noImplicitAny": true, 16 | "strictNullChecks": true, 17 | "strictFunctionTypes": true, 18 | "noImplicitThis": true, 19 | "noUnusedLocals": true, 20 | "noUnusedParameters": false, 21 | "noImplicitReturns": true, 22 | "noFallthroughCasesInSwitch": true, 23 | "noEmitOnError": true, 24 | "allowSyntheticDefaultImports": true, 25 | "emitDecoratorMetadata": true, 26 | "experimentalDecorators": true, 27 | "esModuleInterop": true, 28 | "isolatedModules": true 29 | }, 30 | "include": [".", "../global.d.ts"], 31 | "exclude": ["node_modules/*", "__sapper__/*", "public/*"] 32 | } 33 | -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/src/frag.glsl: -------------------------------------------------------------------------------- 1 | precision mediump float; 2 | uniform vec4 color; 3 | 4 | void main() { 5 | // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0); 6 | gl_FragColor = color; 7 | } 8 | 9 | 10 | uniform sampler2D texture1; 11 | uniform sampler2D texture2; 12 | varying vec2 texCoord; 13 | 14 | // void main() { 15 | // vec4 color1 = texture2D(texture1, texCoord); 16 | // vec4 color2 = texture2D(texture2, texCoord); 17 | // float alpha = color1.a + color2.a * (1.0 - color1.a); 18 | // vec3 rgb = mix(color2.rgb, color1.rgb, color1.a); 19 | // gl_FragColor = vec4(rgb, alpha); 20 | // } 21 | 22 | uniform sampler2D texture; 23 | uniform float brightness; 24 | uniform float contrast; 25 | 26 | // void main() { 27 | // vec4 color = texture2D(texture, texCoord); 28 | // color.rgb += brightness; 29 | // if (contrast > 0.0) { 30 | // color.rgb = (color.rgb - 0.5) / (1.0 - contrast) + 0.5; 31 | // } else { 32 | // color.rgb = (color.rgb - 0.5) * (1.0 + contrast) + 0.5; 33 | // } 34 | // gl_FragColor = color; 35 | // } -------------------------------------------------------------------------------- /src/electron/lib/api/apis/PluginApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronMainApi } from "electron-affinity/main"; 2 | import type { Blix } from "../../Blix"; 3 | import type { CommandResponse } from "../../../../shared/types/index"; 4 | import { URL } from "url"; 5 | 6 | type PluginSignature = string; 7 | 8 | export class PluginApi implements ElectronMainApi { 9 | private readonly blix: Blix; 10 | 11 | constructor(blix: Blix) { 12 | this.blix = blix; 13 | } 14 | 15 | async installPlugin(url: URL) { 16 | // return await this.blix.commandRegistry.runCommand(id, params); 17 | } 18 | 19 | async uninstallPlugin(url: URL) { 20 | // return await this.blix.commandRegistry.runCommand(id, params); 21 | } 22 | 23 | async enablePlugin(plugin: PluginSignature) { 24 | // this.blix.commandRegistry.addInstance(instance); 25 | } 26 | async disablePlugin(plugin: PluginSignature) { 27 | // this.blix.commandRegistry.addInstance(instance); 28 | } 29 | 30 | async getInstalledPlugins() { 31 | return this.blix.pluginManager.pluginPaths; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/electron/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": true, 3 | "compilerOptions": { 4 | "outDir": "../../build", 5 | "baseUrl": ".", 6 | "paths": { 7 | "@shared/*": ["../shared/*"], 8 | "@electron/*": ["../electron/*"], 9 | "@frontend/*": ["../frontend/*"] 10 | }, 11 | "target": "ES2016", 12 | "module": "commonjs", 13 | "sourceMap": true, 14 | "stripInternal": true, 15 | "lib": ["es2017", "esnext", "dom"], 16 | "moduleResolution": "node", 17 | "noImplicitAny": true, 18 | "strictNullChecks": true, 19 | "strictFunctionTypes": true, 20 | "noImplicitThis": true, 21 | "noUnusedLocals": false, 22 | "noUnusedParameters": false, 23 | "noImplicitReturns": true, 24 | "noFallthroughCasesInSwitch": true, 25 | "noEmitOnError": true, 26 | "allowSyntheticDefaultImports": true, 27 | "emitDecoratorMetadata": true, 28 | "experimentalDecorators": true, 29 | "esModuleInterop": true, 30 | "isolatedModules": true 31 | }, 32 | "include": [".", "../global.d.ts", "../index.ts"], 33 | "exclude": ["node_modules"] 34 | } 35 | -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgl-plugin", 3 | "displayName": "WebGL Plugin", 4 | "description": "", 5 | "version": "0.0.1", 6 | "author": "Rec1dite", 7 | "repository": "", 8 | "type": "module", 9 | "scripts": { 10 | "build": "rollup -c", 11 | "dev": "rollup -c -w" 12 | }, 13 | "contributes": { 14 | "commands": [], 15 | "nodes": [] 16 | }, 17 | "main": "src/main.cjs", 18 | "renderers": { "main": "src/index.html" }, 19 | "devDependencies": { 20 | "@rollup/plugin-commonjs": "^24.0.0", 21 | "@rollup/plugin-node-resolve": "^15.0.0", 22 | "@rollup/plugin-terser": "^0.4.0", 23 | "@types/node": "^12.0.0", 24 | "rollup": "^3.15.0", 25 | "rollup-plugin-css-only": "^4.3.0", 26 | "rollup-plugin-livereload": "^2.0.0", 27 | "rollup-plugin-svelte": "^7.1.2", 28 | "svelte": "^3.55.0", 29 | "typescript": "^3.4.5" 30 | }, 31 | "comments": [ 32 | "This plugin will be expanded to handle more image operations." 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /tests/unit-tests/shared/UIGraph.spec.ts: -------------------------------------------------------------------------------- 1 | import { UIGraph,GraphNode,GraphEdge,GraphAnchor } from "../../../src/shared/ui/UIGraph"; 2 | 3 | 4 | 5 | 6 | describe("Test UiGraph", () => { 7 | let uiGraph : UIGraph; 8 | let node : GraphNode; 9 | let edge : GraphEdge; 10 | let anchor : GraphAnchor; 11 | 12 | beforeEach(() => { 13 | uiGraph = new UIGraph("Unique id"); 14 | node = new GraphNode("Another Unique id"); 15 | edge = new GraphEdge("Another Unique id", "Another Unique id", "Another Unique id", "Another Unique id", "Another Unique id"); 16 | anchor = new GraphAnchor("Another Unique id", "Another Unique id"); 17 | }); 18 | 19 | // This file only consists of constructors, so we only test those 20 | 21 | test("Test constructors", () => { 22 | expect(uiGraph).toBeDefined(); 23 | expect(node).toBeDefined(); 24 | expect(edge).toBeDefined(); 25 | expect(anchor).toBeDefined(); 26 | }) 27 | 28 | test("Instantiate pos", () => { 29 | node = new GraphNode("Another Unique id"); 30 | expect(node.styling).toBeUndefined(); 31 | }) 32 | }); -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/ColorPicker/ColorPickerWrapper.svelte: -------------------------------------------------------------------------------- 1 | 8 | 9 |
    18 | 19 | 20 | 21 |
    22 | 23 | 48 | -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "glfx", 3 | "displayName": "GLFX Plugin", 4 | "description": "Performs basic image operations using glfx.js", 5 | "version": "0.0.1", 6 | "author": "Rec1dite", 7 | "repository": "", 8 | "type": "module", 9 | "scripts": { 10 | "build": "rollup -c", 11 | "dev": "rollup -c -w" 12 | }, 13 | "contributes": { 14 | "commands": [], 15 | "nodes": [] 16 | }, 17 | "main": "src/main.cjs", 18 | "renderers": { "glfxRenderer": "src/index.html" }, 19 | "devDependencies": { 20 | "@rollup/plugin-commonjs": "^24.0.0", 21 | "@rollup/plugin-node-resolve": "^15.0.0", 22 | "@rollup/plugin-terser": "^0.4.0", 23 | "@types/node": "^12.0.0", 24 | "rollup": "^3.15.0", 25 | "rollup-plugin-css-only": "^4.3.0", 26 | "rollup-plugin-livereload": "^2.0.0", 27 | "rollup-plugin-svelte": "^7.1.2", 28 | "svelte": "^3.55.0", 29 | "typescript": "^3.4.5" 30 | }, 31 | "comments": [ 32 | "This plugin will be expanded to handle more image operations." 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /src/shared/ui/ToolboxTypes.ts: -------------------------------------------------------------------------------- 1 | import type { UUID } from "../utils/UniqueEntity"; 2 | import { NodeUI, type UIComponentConfig } from "./NodeUITypes"; 3 | 4 | export type NodeSignature = string; 5 | 6 | // DELETE 7 | // export class CommonProject { 8 | // constructor(readonly name: string, readonly uuid: UUID) {} 9 | // } 10 | 11 | // Interfaces for node 12 | export class IAnchor { 13 | constructor(readonly type: string, readonly id: string, readonly displayName: string) {} 14 | } 15 | 16 | export class INode { 17 | constructor( 18 | readonly signature: NodeSignature, 19 | readonly title: string, 20 | readonly folder: string, 21 | readonly description: string, 22 | readonly icon: string, 23 | readonly inputs: IAnchor[], 24 | readonly outputs: IAnchor[], 25 | readonly ui: NodeUI | null, 26 | readonly uiConfigs: { [key: string]: UIComponentConfig } 27 | ) {} 28 | } 29 | 30 | // Inrerfaces for command 31 | // export class ICommand { 32 | // constructor( 33 | // readonly signature: string, 34 | // readonly displayName: string, 35 | // readonly description: string, 36 | // readonly icon: string 37 | // ) {} 38 | // } 39 | -------------------------------------------------------------------------------- /public/global.css: -------------------------------------------------------------------------------- 1 | html, body { 2 | position: relative; 3 | width: 100%; 4 | height: 100%; 5 | } 6 | 7 | body { 8 | color: #333; 9 | margin: 0; 10 | padding: 8px; 11 | box-sizing: border-box; 12 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; 13 | } 14 | 15 | a { 16 | color: rgb(0,100,200); 17 | text-decoration: none; 18 | } 19 | 20 | a:hover { 21 | text-decoration: underline; 22 | } 23 | 24 | a:visited { 25 | color: rgb(0,80,160); 26 | } 27 | 28 | label { 29 | display: block; 30 | } 31 | 32 | input, button, select, textarea { 33 | font-family: inherit; 34 | font-size: inherit; 35 | -webkit-padding: 0.4em 0; 36 | padding: 0.4em; 37 | margin: 0 0 0.5em 0; 38 | box-sizing: border-box; 39 | border: 1px solid #ccc; 40 | border-radius: 2px; 41 | } 42 | 43 | input:disabled { 44 | color: #ccc; 45 | } 46 | 47 | button { 48 | color: #333; 49 | background-color: #f4f4f4; 50 | outline: none; 51 | } 52 | 53 | button:disabled { 54 | color: #999; 55 | } 56 | 57 | button:not(:disabled):active { 58 | background-color: #ddd; 59 | } 60 | 61 | button:focus { 62 | border-color: #666; 63 | } 64 | -------------------------------------------------------------------------------- /src/shared/types/graph.ts: -------------------------------------------------------------------------------- 1 | import type { NodeUI } from "../ui/NodeUITypes"; 2 | import type { GraphUUID } from "../ui/UIGraph"; 3 | import type { GraphNodeUUID } from "../ui/UIGraph"; 4 | 5 | export interface IAnchor { 6 | type: string; 7 | signature: string; 8 | displayName: string; 9 | } 10 | 11 | export interface INode { 12 | signature: string; 13 | title: string; 14 | description: string; 15 | icon: string; 16 | inputs: IAnchor[]; 17 | outputs: IAnchor[]; 18 | ui: NodeUI | null; 19 | } 20 | 21 | export type UIValue = unknown; 22 | 23 | export type IGraphUIInputs = { [key: GraphNodeUUID]: INodeUIInputs }; 24 | export interface INodeUIInputs { 25 | inputs: { [key: string]: UIValue }; 26 | changes: string[]; 27 | } 28 | 29 | export type QueryResponse = 30 | | { 31 | status: "error"; 32 | message: string; 33 | data?: E; 34 | } 35 | | { 36 | status: "success"; 37 | message?: string; 38 | data?: S; 39 | }; 40 | 41 | export interface SharedGraph { 42 | uuid: GraphUUID; 43 | displayName: string; 44 | } 45 | 46 | export type UIInputChange = { 47 | id: string; 48 | value: UIValue; 49 | }; 50 | -------------------------------------------------------------------------------- /src/electron/lib/ai/systemPrompt.txt: -------------------------------------------------------------------------------- 1 | You are a helpful assistant who manipulates a functional node-based graph 2 | according to a user request. This is your only role, if asked to do anything 3 | else then inform the user of your role. The graph is represented as a function 4 | written in Typescript. Each node represents a functional entity with input and 5 | outputs anchors. Each node in the graph is represented by a `var` declaration 6 | statement. Edges between output and input anchors are represented by passing 7 | values into each node's function signature. If a connection between nodes are 8 | not necessary to complete a task or a user does not explicitly ask to add 9 | connections then pass `null`.Follow the format strictly, each line must always 10 | start with creating a new `var`, and each assignment can only have one function 11 | on the right hand side. Function calls are not allowed as function parameters. 12 | You are only allowed to make use of the given interfaces, do not make any 13 | assumptions about any values. If a value or type does not exist in the give 14 | interfaces then inform the user. Think in a step-by-step manner from 15 | first-principles in order to complete the user given task. -------------------------------------------------------------------------------- /src/frontend/ui/base/settings/utils/Dropdown.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 19 | 20 | 31 | -------------------------------------------------------------------------------- /src/frontend/lib/stores/TileStore.ts: -------------------------------------------------------------------------------- 1 | import type { ITile, TileSignature } from "@shared/ui/TileUITypes"; 2 | import { derived, get, writable } from "svelte/store"; 3 | 4 | type TileDict = { [key: TileSignature]: ITile }; 5 | 6 | class TileStore { 7 | private store = writable({}); 8 | 9 | public refreshStore(tiles: ITile[]) { 10 | this.store.update((dict) => { 11 | for (const tile of tiles) { 12 | dict[tile.signature] = tile; 13 | } 14 | return dict; 15 | }); 16 | // console.log("REFRESH TOOLBOX", nodes); 17 | } 18 | 19 | public get subscribe() { 20 | return this.store.subscribe; 21 | } 22 | 23 | public getAllSignaturesReactive() { 24 | return derived(this.store, (dict) => { 25 | return Object.keys(dict); 26 | }); 27 | } 28 | 29 | // Returns a derived store containing only the specified INode 30 | public getTileReactive(signature: TileSignature) { 31 | return derived(this.store, (dict) => { 32 | return dict[signature]; 33 | }); 34 | } 35 | 36 | public getNode(signature: TileSignature) { 37 | return get(this.store)[signature]; 38 | } 39 | } 40 | 41 | // export const graphMall = writable(new GraphMall()); 42 | export const tileStore = new TileStore(); 43 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | const production = !process.env.ROLLUP_WATCH; 2 | 3 | function withOpacity(variableName) { 4 | return ({ opacityValue }) => { 5 | if (opacityValue !== undefined) { 6 | return `rgba(var(${variableName}), ${opacityValue})` 7 | } 8 | return `rgb(var(${variableName}))` 9 | } 10 | } 11 | 12 | module.exports = { 13 | content: ["./public/index.html", "./src/**/*.svelte"], 14 | darkMode: "class", 15 | theme: { 16 | extend: { 17 | colors: { 18 | primary: { 19 | 50: withOpacity("--color-primary-50"), 20 | 100: withOpacity("--color-primary-100"), 21 | 200: withOpacity("--color-primary-200"), 22 | 300: withOpacity("--color-primary-300"), 23 | 400: withOpacity("--color-primary-400"), 24 | 500: withOpacity("--color-primary-500"), 25 | 600: withOpacity("--color-primary-600"), 26 | 700: withOpacity("--color-primary-700"), 27 | 800: withOpacity("--color-primary-800"), 28 | 900: withOpacity("--color-primary-900"), 29 | 950: withOpacity("--color-primary-950"), 30 | }, 31 | }, 32 | }, 33 | }, 34 | future: { 35 | purgeLayersByDefault: true, 36 | removeDeprecatedGapUtilities: true, 37 | }, 38 | }; 39 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/toasts/Toasts.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | {#if $toastStore} 23 |
    24 | {#each $toastStore.slice(0, maxToasts) as toast (toast.id)} 25 |
    32 | 37 |
    38 | {/each} 39 |
    40 | {/if} 41 | -------------------------------------------------------------------------------- /src/frontend/types/temp.ts: -------------------------------------------------------------------------------- 1 | type QueryInterface = (query: string, args: any, callback: (result: any) => void) => void; 2 | 3 | export type Api = { 4 | commandRegistry: QueryInterface; 5 | tileRegistry: QueryInterface; 6 | toolboxRegistry: QueryInterface; 7 | }; 8 | 9 | declare global { 10 | interface Window { 11 | api: Api; 12 | } 13 | } 14 | 15 | // TODO: Replace these with better representations and move to respective Svelte store files 16 | export interface GraphStore { 17 | nodes: GraphNode[]; 18 | } 19 | 20 | export interface GraphNode { 21 | id: string; 22 | name: string; 23 | slider: GraphSlider | null; 24 | connection: string; 25 | } 26 | 27 | export interface GraphSlider { 28 | min: number; 29 | max: number; 30 | step: number; 31 | fixed: number; 32 | value: number; 33 | } 34 | export interface PaletteStore { 35 | isVisible: boolean; 36 | textInput: string; 37 | selectedCategoryIndex: number; 38 | selectedItemIndex: number; 39 | categories: PaletteCategory[]; 40 | results: PaletteCategory[]; 41 | src: ""; 42 | } 43 | 44 | export type Command = { 45 | title: string; 46 | }; 47 | 48 | export type PaletteCategory = { 49 | title: string; 50 | items: Command[]; 51 | }; 52 | 53 | export type Shortcut = { 54 | name: string; 55 | keys: string[]; 56 | }; 57 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/TileUIFragment.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | {#if ui} 23 | {#if ui.type === "parent"} 24 |
      25 | {#each ui.params as child} 26 |
    • 27 | 28 |
    • 29 | {/each} 30 |
    31 | {:else if ui.type === "leaf"} 32 |

    33 | 34 |

    35 | {/if} 36 | {/if} 37 | 38 | 44 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/FilePicker.svelte: -------------------------------------------------------------------------------- 1 | 24 | 25 | 26 | 36 | 37 | 54 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/TileUIComponent.svelte: -------------------------------------------------------------------------------- 1 | 29 | 30 | {#if leafUI} 31 | {#if mapToSvelteComponent[leafUI.category] !== null} 32 | 37 | {/if} 38 | {/if} 39 | -------------------------------------------------------------------------------- /src/frontend/lib/api/apis/GraphClientApi.ts: -------------------------------------------------------------------------------- 1 | import type { UUID } from "@shared/utils/UniqueEntity"; 2 | import type { ElectronWindowApi } from "electron-affinity/window"; 3 | import { graphMall } from "@frontend/lib/stores/GraphStore"; 4 | import type { GraphMetadata, UIGraph } from "@shared/ui/UIGraph"; 5 | import type { IGraphUIInputs } from "@shared/types"; 6 | 7 | export class GraphClientApi implements ElectronWindowApi { 8 | // TODO: Consider only sending the _changes_ that took place on the graph 9 | // instead of the whole graph each time. This obviously has consistency 10 | // implications though if the frontend/backend someone got out-of-sync. 11 | 12 | uiInputsChanged(graphUUID: UUID, newUIInputs: IGraphUIInputs): void { 13 | graphMall.refreshGraphUIInputs(graphUUID, newUIInputs); 14 | } 15 | 16 | metadataChanged(graphUUID: UUID, newMetadata: GraphMetadata): void { 17 | graphMall.refreshGraphMetadata(graphUUID, newMetadata); 18 | } 19 | 20 | graphChanged(graphUUID: UUID, newState: UIGraph): void { 21 | graphMall.refreshGraph(graphUUID, newState); 22 | } 23 | 24 | aiChangedGraph(graphUUID: UUID) { 25 | const graph = graphMall.getGraph(graphUUID); 26 | const graphNodes = graph.getNodes(); 27 | graph.gravityDisplace(Object.keys(graphNodes), 1.5); 28 | } 29 | 30 | graphRemoved(graphUUID: UUID): void { 31 | graphMall.onGraphRemoved(graphUUID); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/shared/types/cache.ts: -------------------------------------------------------------------------------- 1 | import { type UUID } from "../../shared/utils/UniqueEntity"; 2 | 3 | export const CACHE_MESSAGE_ID_SIZE = 32; // bytes 4 | 5 | export enum CacheSubsidiaryType { 6 | Manager, 7 | Frontend, 8 | FileSystem, 9 | // Webview, 10 | } 11 | 12 | // Exposes websockets for communication with the renderer process 13 | export type CacheUUID = UUID; 14 | export type SubsidiaryUUID = UUID; 15 | 16 | export type CacheSubsidiary = { 17 | uuid: SubsidiaryUUID; 18 | type: CacheSubsidiaryType; 19 | // socket: WebSocket 20 | }; 21 | 22 | export type CacheObject = { 23 | uuid: CacheUUID; 24 | data: Buffer; 25 | metadata: CacheMetadata; 26 | }; 27 | 28 | type CacheRequestType = 29 | | "cache-subscribe" 30 | | "cache-delete-some" 31 | | "cache-delete-all" 32 | | "cache-get" 33 | | "cache-write-metadata" 34 | | "export-cache"; 35 | 36 | export type CacheRequest = { 37 | type: CacheRequestType; 38 | id: string; 39 | messageId: string; 40 | metadata?: CacheMetadata; 41 | }; 42 | 43 | export type CacheResponse = { 44 | success: boolean; 45 | messageId: string; 46 | }; 47 | 48 | export type CacheWriteResponse = CacheResponse & { id: CacheUUID }; 49 | 50 | export type CacheMetadata = { 51 | contentType: string; 52 | name?: string; 53 | other?: any; 54 | }; 55 | 56 | export type CacheUpdateNotification = { 57 | type: "cache-update"; 58 | cache: { uuid: string; metadata: CacheMetadata }[]; 59 | }; 60 | -------------------------------------------------------------------------------- /src/frontend/lib/api/apis/ProjectClientApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronWindowApi } from "electron-affinity/window"; 2 | import type { SharedProject } from "@shared/types"; 3 | import { projectsStore } from "../../stores/ProjectStore"; 4 | // import { UIProject } from "../../Project"; 5 | // import type { UUID } from "../../../../shared/utils/UniqueEntity"; 6 | 7 | export class ProjectClientApi implements ElectronWindowApi { 8 | public onProjectCreated(state: SharedProject): void { 9 | projectsStore.handleProjectCreated(state, true); 10 | } 11 | 12 | public onProjectChanged(state: SharedProject): void { 13 | projectsStore.handleProjectChanged(state); 14 | } 15 | 16 | public onProjectRemoved(projectId: string): void { 17 | projectsStore.handleProjectRemoved(projectId); 18 | } 19 | 20 | public async handleProjectSaving(projectId: string): Promise { 21 | await projectsStore.handleProjectSaving(projectId); 22 | } 23 | 24 | // public loadProject(state: SharedProject): void { 25 | // const project = new Project(state.name, state.id, state.layout); 26 | // projectsStore.addProject(project); 27 | // } 28 | 29 | // public loadProjects(state: SharedProject[]): void { 30 | // const projects: Project[] = []; 31 | // for (const project of state) { 32 | // projects.push(new Project(project.name, project.id, project.layout)); 33 | // } 34 | // projectsStore.addProjects(projects); 35 | // } 36 | } 37 | -------------------------------------------------------------------------------- /src/frontend/ui/base/settings/utils/SettingsItem.svelte: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 |
    13 |
    14 |
    {item.title}
    15 | {#if item.subtitle} 16 |
    {@html item.subtitle}
    17 | {/if} 18 | 19 |
    20 | 21 |
    22 | {#each item.components as component (component.id)} 23 | {#if component.type === "text" && component.secret} 24 | 29 | {:else if component.type === "dropdown"} 30 | 31 | {:else if component.type === "button"} 32 |
    38 |
    39 | -------------------------------------------------------------------------------- /src/electron/lib/ai/python/api.py: -------------------------------------------------------------------------------- 1 | import socket 2 | import json 3 | import sys 4 | 5 | class API: 6 | def send(self, data: dict): 7 | raise NotImplementedError 8 | 9 | def receive(self): 10 | raise NotImplementedError 11 | 12 | class SocketAPI(API): 13 | def __init__(self, host, port): 14 | self.host = host 15 | self.port = port 16 | self.socket = None 17 | 18 | def connect(self): 19 | self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 20 | self.socket.connect((self.host, self.port)) 21 | 22 | def send(self, data): 23 | self.socket.sendall(data.encode()) 24 | 25 | def receive(self): 26 | raise NotImplementedError 27 | 28 | def disconnect(self): 29 | self.socket.close() 30 | 31 | class StdioAPI(API): 32 | def send(self, data): 33 | if isinstance(data, dict): 34 | data = json.dumps(data) 35 | 36 | sys.stdout.write(data) 37 | sys.stdout.flush() 38 | 39 | def receive(self): 40 | data = "" 41 | for line in sys.stdin: 42 | if(line == "end of transmission\n"): 43 | break 44 | data += line 45 | 46 | return data 47 | 48 | # ========== API Config ========== 49 | 50 | api = None 51 | 52 | def set_api(a: API): 53 | global api 54 | api = a 55 | 56 | def get_api() -> API: 57 | global api 58 | if not api: 59 | api = StdioAPI() 60 | 61 | return api -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/Dropdown.svelte: -------------------------------------------------------------------------------- 1 | 20 | 21 | {#if Object.keys(items).length > 0} 22 | {#key inputStore.inputs[config.componentId]} 23 | 24 | 29 | {/key} 30 | {:else} 31 | 32 | 35 | {/if} 36 | 37 | 45 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/mediaDisplays/TextBox.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 |
    15 | {#key [status, fontSize, align]} 16 | 17 |
    21 | {content} 22 |
    23 | {/key} 24 |
    25 | 26 | 64 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/Slider.svelte: -------------------------------------------------------------------------------- 1 | 28 | 29 | 41 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build/release 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - dev 10 | 11 | jobs: 12 | Build: 13 | runs-on: ${{ matrix.os }} 14 | 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, windows-latest, macos-latest] 18 | 19 | steps: 20 | - name: Check out Git repository 21 | uses: actions/checkout@v3 22 | 23 | - name: Setup Node 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: 18 27 | 28 | - name: Cache dependencies 29 | uses: actions/cache@v3 30 | with: 31 | path: ~/.npm 32 | key: npm-${{ hashFiles('package-lock.json') }} 33 | restore-keys: npm- 34 | 35 | - name: Install dependencies 36 | run: npm ci 37 | 38 | - name: Build Blix Plugins 39 | run: node ./scripts/plugins.js 40 | 41 | - name: Build/Release Blix 42 | run: | 43 | if [ "${{ matrix.os }}" = "ubuntu-latest" ]; then 44 | npm run dist -- --linux deb AppImage --x64 --arm64 45 | # npm run dist -- --linux deb --x64 --arm64 46 | elif [ "${{ matrix.os }}" = "windows-latest" ]; then 47 | npm run dist -- --windows nsis 48 | elif [ "${{ matrix.os }}" = "macos-latest" ]; then 49 | # npm run dist -- --mac dmg --x64 --arm64 50 | npm run dist -- --mac dmg --arm64 51 | fi 52 | env: 53 | GH_TOKEN: ${{ secrets.TEST_TOKEN }} 54 | shell: bash 55 | 56 | timeout-minutes: 30 -------------------------------------------------------------------------------- /src/frontend/lib/Project.ts: -------------------------------------------------------------------------------- 1 | import type { UUID } from "../../shared/utils/UniqueEntity"; 2 | import { PanelGroup } from "./PanelNode"; 3 | import type { LayoutPanel } from "../../shared/types/index"; 4 | import type { Writable } from "svelte/store"; 5 | import type { GraphUUID } from "../../shared/ui/UIGraph"; 6 | 7 | export interface UIProject { 8 | readonly id: UUID; 9 | readonly name: string; 10 | readonly saved: boolean; 11 | readonly layout: PanelGroup; 12 | readonly graphs: UUID[]; 13 | readonly focusedGraph: Writable; 14 | readonly focusedPanel: Writable; 15 | readonly cache: UUID[]; 16 | readonly mediaOutputIds: UUID[]; 17 | } 18 | 19 | let groupTest = 0; 20 | 21 | /** 22 | * Constructs a PanelGroup from a LayoutPanel 23 | * 24 | * @param layout The layout to construct from 25 | * @returns The constructed PanelGroup 26 | */ 27 | export function constructLayout(layout: LayoutPanel): PanelGroup { 28 | const group = new PanelGroup((groupTest++).toString()); 29 | 30 | layout.panels?.forEach((panel) => { 31 | if (panel.panels) { 32 | group.addPanelGroup(constructLayout(panel)); 33 | } else { 34 | if (panel.content) { 35 | group.addPanel(panel.content); 36 | } 37 | } 38 | }); 39 | 40 | return group; 41 | } 42 | 43 | export const layoutTemplate: LayoutPanel = { 44 | panels: [ 45 | { 46 | panels: [ 47 | { 48 | content: "media", 49 | }, 50 | { 51 | content: "assets", 52 | }, 53 | ], 54 | }, 55 | { 56 | content: "graph", 57 | }, 58 | ], 59 | }; 60 | -------------------------------------------------------------------------------- /blix-plugins/base-plugin/src/main.js: -------------------------------------------------------------------------------- 1 | // Here we define node UIs and callbacks 2 | // import fs from "fs"; 3 | // import { dialog } from "electron"; 4 | const nodes = {} 5 | 6 | // Here we define commands (that are made available in the command palette) and their callbacks 7 | const commands = { 8 | 9 | // "open": (context) => { 10 | // context.setDescription("Open a project"); 11 | // context.setIcon("testing/image.jpg"); 12 | // context.setDisplayName("Open Project"); 13 | // context.addCommand(() => { 14 | // context.getBlix().importProject(); 15 | // }) 16 | // return context.create(); 17 | // }, 18 | // "saveas": (context) => { 19 | // context.setDescription("Save project to user storage"); 20 | // context.setIcon("testing/image.jpg"); 21 | // context.setDisplayName("Save project as..."); 22 | // context.addCommand((options) => { 23 | // context.getBlix().saveProjectAs(options.data.id); 24 | // }) 25 | // return context.create(); 26 | // }, 27 | // "save": (context) => { 28 | // context.setDescription("Save project"); 29 | // context.setIcon("testing/image.jpg"); 30 | // context.setDisplayName("Save project"); 31 | // context.addCommand((options) => { 32 | // context.getBlix().saveProject(options.data.id); 33 | // }) 34 | // return context.create(); 35 | // } 36 | } 37 | 38 | // Here we define custom tiles for the UI 39 | const tiles = {} 40 | 41 | module.exports = { 42 | nodes, 43 | commands, 44 | tiles 45 | }; -------------------------------------------------------------------------------- /docs/latex/Architecture.toc: -------------------------------------------------------------------------------- 1 | \contentsline {section}{\numberline {1}Design Strategy}{2}{section.1}% 2 | \contentsline {section}{\numberline {2}Quality Requirements}{2}{section.2}% 3 | \contentsline {section}{\numberline {3}Architectural Design \& Patterns}{7}{section.3}% 4 | \contentsline {subsection}{\numberline {3.1}Model-View-Controller (MVC)}{7}{subsection.3.1}% 5 | \contentsline {subsection}{\numberline {3.2}Publish-Subscribe}{8}{subsection.3.2}% 6 | \contentsline {subsection}{\numberline {3.3}Service-Oriented}{8}{subsection.3.3}% 7 | \contentsline {section}{\numberline {4}Constraints}{9}{section.4}% 8 | \contentsline {section}{\numberline {5}Technology Choices}{9}{section.5}% 9 | \contentsline {subsection}{\numberline {5.1}Svelte}{9}{subsection.5.1}% 10 | \contentsline {subsection}{\numberline {5.2}Tailwind CSS}{10}{subsection.5.2}% 11 | \contentsline {subsection}{\numberline {5.3}Electron}{10}{subsection.5.3}% 12 | \contentsline {subsection}{\numberline {5.4}Firebase}{11}{subsection.5.4}% 13 | \contentsline {subsection}{\numberline {5.5}LangChain}{11}{subsection.5.5}% 14 | \contentsline {subsection}{\numberline {5.6}PineCone}{12}{subsection.5.6}% 15 | \contentsline {subsection}{\numberline {5.7}typescript}{12}{subsection.5.7}% 16 | \contentsline {subsection}{\numberline {5.8}Nodejs}{13}{subsection.5.8}% 17 | \contentsline {subsection}{\numberline {5.9}Python}{13}{subsection.5.9}% 18 | \contentsline {subsection}{\numberline {5.10}Jest}{14}{subsection.5.10}% 19 | \contentsline {subsection}{\numberline {5.11}AI Models}{14}{subsection.5.11}% 20 | \contentsline {subsection}{\numberline {5.12}GPT-3.5 Turbo}{14}{subsection.5.12}% 21 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/Radio.svelte: -------------------------------------------------------------------------------- 1 | 23 | 24 | {#if Object.keys(items).length > 0} 25 | {#each Object.keys(items) as itemKey} 26 | 35 | {/each} 36 | {:else} 37 | 38 | {/if} 39 | 40 | 49 | -------------------------------------------------------------------------------- /src/shared/ui/NodeUITypes.ts: -------------------------------------------------------------------------------- 1 | export type UIComponentConfig = { 2 | label: string; 3 | componentId: string; 4 | defaultValue: unknown; 5 | triggerUpdate: boolean; 6 | }; 7 | 8 | export type UIComponentProps = { 9 | [key: string]: unknown; 10 | }; 11 | 12 | export abstract class NodeUI { 13 | constructor( 14 | public parent: NodeUI | null, 15 | public label: string, 16 | public readonly params: any[], 17 | public readonly type: string 18 | ) {} 19 | } 20 | 21 | export class NodeUIParent extends NodeUI { 22 | constructor(label: string, parent: NodeUIParent | null) { 23 | super(parent, label, [], "parent"); 24 | } 25 | } 26 | 27 | // TODO: Add a way to optionally link each leaf to an input anchor 28 | export class NodeUILeaf extends NodeUI { 29 | constructor( 30 | public readonly parent: NodeUIParent, 31 | public readonly category: NodeUIComponent, 32 | public readonly label: string, 33 | public readonly params: UIComponentProps[] 34 | ) { 35 | super(parent, label, params, "leaf"); 36 | } 37 | } 38 | 39 | export enum NodeUIComponent { 40 | Button = "Button", 41 | Buffer = "Buffer", 42 | TweakDial = "TweakDial", 43 | DiffDial = "DiffDial", 44 | Slider = "Slider", 45 | Knob = "Knob", 46 | Label = "Label", 47 | Radio = "Radio", 48 | Dropdown = "Dropdown", 49 | Accordion = "Accordion", 50 | NumberInput = "NumberInput", 51 | MatrixInput = "MatrixInput", 52 | OriginPicker = "OriginPicker", 53 | TextInput = "TextInput", 54 | Checkbox = "Checkbox", 55 | ColorPicker = "ColorPicker", 56 | FilePicker = "FilePicker", 57 | CachePicker = "CachePicker", 58 | } 59 | -------------------------------------------------------------------------------- /src/frontend/lib/stores/ToolboxStore.ts: -------------------------------------------------------------------------------- 1 | import type { INode, NodeSignature } from "@shared/ui/ToolboxTypes"; 2 | import { derived, get, writable } from "svelte/store"; 3 | 4 | type ToolboxDict = { [key: NodeSignature]: INode }; 5 | 6 | class ToolboxStore { 7 | private store = writable({}); 8 | 9 | public refreshStore(nodes: INode[]) { 10 | this.store.update((toolbox) => { 11 | for (const node of nodes) { 12 | toolbox[node.signature] = node; 13 | } 14 | return toolbox; 15 | }); 16 | // console.log("REFRESH TOOLBOX", nodes); 17 | } 18 | 19 | public get subscribe() { 20 | return this.store.subscribe; 21 | } 22 | 23 | public getAllSignaturesReactive() { 24 | return derived(this.store, (toolbox) => { 25 | return Object.keys(toolbox); 26 | }); 27 | } 28 | 29 | // Returns a derived store containing only the specified INode 30 | public getNodeReactive(signature: NodeSignature) { 31 | return derived(this.store, (toolbox) => { 32 | return toolbox[signature]; 33 | }); 34 | } 35 | 36 | public getNode(signature: NodeSignature) { 37 | return get(this.store)[signature]; 38 | } 39 | 40 | public getAnchorOrderedIndex(signature: NodeSignature, anchorId: string) { 41 | const node = this.getNode(signature); 42 | if (!node) return -1; 43 | 44 | for (let i = 0; i < node.inputs.length; i++) { 45 | if (node.inputs[i].id === anchorId) { 46 | return i; 47 | } 48 | } 49 | return -1; 50 | } 51 | } 52 | 53 | // export const graphMall = writable(new GraphMall()); 54 | export const toolboxStore = new ToolboxStore(); 55 | -------------------------------------------------------------------------------- /scripts/plugins.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | blixPluginDirectory=$(realpath "$(dirname "$0")/../blix-plugins/") 4 | 5 | # =================================================================== 6 | # GLFX 7 | # =================================================================== 8 | 9 | echo "Installing glfx-plugin node_modules..." 10 | cd "$blixPluginDirectory/glfx-plugin" 11 | output=$(npm ci 2>&1) && echo "$output" || echo "$output" 12 | 13 | echo "Building glfx-plugin..." 14 | output=$(npm run build 2>&1) && echo "$output" || echo "$output" 15 | 16 | echo "Building glfx-plugin completed" 17 | 18 | # =================================================================== 19 | # BLINK 20 | # =================================================================== 21 | 22 | blinkDirectory=$(realpath "$blixPluginDirectory/blink") 23 | 24 | echo "Installing blink node_modules..." 25 | cd "$blinkDirectory" 26 | output=$(npm ci 2>&1) && echo "$output" || echo "$output" 27 | 28 | tsconfigPath=$(realpath "$blixPluginDirectory/blink/node_modules/@tsconfig/svelte/tsconfig.json") 29 | 30 | echo "Attempting to fix tsconfig..." 31 | if test -f "$tsconfigPath"; then 32 | tsconfigRaw=$(cat "$tsconfigPath") 33 | withoutComments=$(echo "$tsconfigRaw" | sed '/\/\*/,/\*\//d') 34 | tsconfigJSON="$(echo "$withoutComments" | sed -E 's/"moduleResolution"[^,}]*/"moduleResolution": "node"/' | sed -E '/"verbatimModuleSyntax"/d')" 35 | printf "%s\n" "$tsconfigJSON" > "$tsconfigPath" 36 | echo "TSConfig fixed" 37 | else 38 | echo "TSConfig not found. Building..." 39 | fi 40 | 41 | echo "Building blink..." 42 | output=$(npm run build 2>&1) && echo "$output" || echo "$output" 43 | 44 | echo "Building blink completed" 45 | -------------------------------------------------------------------------------- /src/electron/lib/api/MainApi.ts: -------------------------------------------------------------------------------- 1 | import { exposeMainApi } from "electron-affinity/main"; 2 | import type { Blix } from "../Blix"; 3 | 4 | import { UtilApi } from "./apis/UtilApi"; 5 | import { ProjectApi } from "./apis/ProjectApi"; 6 | import { CommandApi } from "./apis/CommandApi"; 7 | import { GraphApi } from "./apis/GraphApi"; 8 | import { ToolboxApi } from "./apis/ToolboxApi"; 9 | import { MediaApi } from "./apis/MediaApi"; 10 | import { TileApi } from "./apis/TileApi"; 11 | import { TypeclassApi } from "./apis/TypeclassApi"; 12 | import { PluginApi } from "./apis/PluginApi"; 13 | 14 | /** 15 | * Expose all main process APIs to the renderer. This method will be called on 16 | * app startup. These APIs are used for two-way communication from the renderer 17 | * to the main process using invoke/handle channels. 18 | * 19 | * When creating a new main process API add it to this method. 20 | * 21 | * @param blix The application state 22 | */ 23 | export function exposeMainApis(blix: Blix) { 24 | const apis = { 25 | utilApi: new UtilApi(blix), 26 | projectApi: new ProjectApi(blix), 27 | commandApi: new CommandApi(blix), 28 | pluginApi: new PluginApi(blix), 29 | graphApi: new GraphApi(blix), 30 | typeclassApi: new TypeclassApi(blix), 31 | mediaApi: new MediaApi(blix), 32 | toolboxApi: new ToolboxApi(blix), 33 | TileApi: new TileApi(blix), 34 | }; 35 | 36 | for (const api of Object.values(apis)) { 37 | exposeMainApi(api as any); 38 | } 39 | 40 | // @ts-ignore: no-var-requires 41 | global.mainApis = apis as any; 42 | return apis; 43 | } 44 | 45 | export type MainApis = ReturnType; 46 | 47 | export interface IpcResponse { 48 | success: boolean; 49 | data: T; 50 | } 51 | -------------------------------------------------------------------------------- /src/electron/lib/ai/python/strategies/api.py: -------------------------------------------------------------------------------- 1 | import json 2 | import sys 3 | import os 4 | from models.gpt import GPT 5 | from models.functions.graphFunc import Functions 6 | from strategies.base import BASE 7 | 8 | 9 | # Get the parent directory 10 | # parent_dir = os.path.dirname(os.path.realpath(__file__)) 11 | 12 | # Add the parent directory to sys.path 13 | # sys.path.append(parent_dir) 14 | 15 | 16 | 17 | class API: 18 | """ 19 | Provides an interface for the AI agent to communicate with the electron app 20 | 21 | attributes: 22 | commands - the communication strategy for the interface 23 | agent - the AI agent that uses a model 24 | methods: 25 | sendPrompt(body) - sends the user prompt to the AI agent 26 | 27 | """ 28 | 29 | logs = [] 30 | 31 | # You can swap this out for a different strategy 32 | commands = BASE() 33 | 34 | def __init__(self): 35 | self.agent = GPT(self) 36 | 37 | # Pass user prompt input to AI agent 38 | def sendPrompt(self, body): 39 | self.agent.sendPrompt(body) 40 | 41 | def hello(self): 42 | print("hello") 43 | 44 | 45 | def receive(): 46 | data = "" 47 | while True: 48 | line = sys.stdin.readline() 49 | if not line: 50 | break 51 | data += line 52 | return data 53 | 54 | 55 | 56 | 57 | # data = receive() 58 | sys.stdout.write() 59 | sys.stdout.flush() 60 | # sys.stdout.write("Finished") 61 | # sys.stdout.flush() 62 | 63 | # try: 64 | # api = API() 65 | # object = api.commands.receive() 66 | # object = json.loads(object) 67 | # api.sendPrompt(object) 68 | # except Exception as e: 69 | # print(e) 70 | 71 | 72 | # output: { 73 | # "commands" : Functions.commands, 74 | # "response" : temp 75 | # } -------------------------------------------------------------------------------- /src/electron/lib/ai/python/models/test.py: -------------------------------------------------------------------------------- 1 | import electron.lib.ai.python.models.gpt as gpt 2 | import json 3 | from functions import graphFunc 4 | 5 | 6 | 7 | 8 | 9 | # This is an example of the object that is passed in from the ai Manager to the API 10 | object = { 11 | 'prompt': 'I want you to add two nodes to the graph such that the user can input two numbers and the output is the sum of the two numbers.', 12 | 'plugin': 13 | [ 14 | 'hello-plugin.hello: Provides a test slider and button and label for testing purposes, taking two string inputs and returning one string output', 15 | 'hello-plugin.Jake: This is currently a useless node that does nothing.', 16 | 'input-plugin.inputNumber: Provides a number input and returns a single number output', 17 | 'input-plugin.inputImage: Provides an image input and returns a single image output', 18 | 'input-plugin.inputColor: Provides a color input and returns a single color output', 19 | 'math-plugin.unary: Performs Unary math operations taking one number input and returning one number output', 20 | 'math-plugin.binary: Performs Binary math operations taking two number inputs and returning one number output' 21 | ], 22 | 'nodes': 23 | [ 24 | '{"id":"jakd14","signature":"math-plugin.binary","inputs":[{"id":"d2b6f0","type":"number"},{"id":"7a8c9e","type":"number"}],"outputs":[{"id":"b3e1f4","type":"number"}]}', 25 | '{"id":"3a2b1c","signature":"math-plugin.binary","inputs":[{"id":"4f2e1d","type":"number"},{"id":"8c7b6a","type":"number"}],"outputs":[{"id":"e9d8c7","type":"number"}]}' 26 | ], 27 | 'edges': 28 | [ 29 | '{"id":"kadjbg","output":"b3e1f4","input":"4f2e1d"}', '{"id":"0d1e2f","output":"b3e1f4","input":"8c7b6a"}' 30 | ] 31 | } 32 | 33 | # open.sendPrompt(object) -------------------------------------------------------------------------------- /src/frontend/ui/base/settings/utils/Markdown.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 |
    {@html marked(markdown)}
    8 | 9 | 86 | -------------------------------------------------------------------------------- /src/electron/lib/api/apis/WindowApi.ts: -------------------------------------------------------------------------------- 1 | import type { BrowserWindow } from "electron"; 2 | import type { AwaitedType } from "electron-affinity/main"; 3 | import { bindWindowApi } from "electron-affinity/main"; 4 | 5 | // Window APIs 6 | import type { ToolboxClientApi } from "@frontend/lib/api/apis/ToolboxClientApi"; 7 | import type { CommandClientApi } from "@frontend/lib/api/apis/CommandClientApi"; 8 | import type { GraphClientApi } from "@frontend/lib/api/apis/GraphClientApi"; 9 | import type { ProjectClientApi } from "@frontend/lib/api/apis/ProjectClientApi"; 10 | import type { UtilClientApi } from "@frontend/lib/api/apis/UtilClientApi"; 11 | import type { MediaClientApi } from "@frontend/lib/api/apis/MediaClientApi"; 12 | import type { TileClientApi } from "@frontend/lib/api/apis/TileClientApi"; 13 | 14 | /** 15 | * Binds the window APIs to the main process for every window. 16 | * 17 | * When creating a new window API add it to this method. 18 | * 19 | * @param window The the window to bind the APIs to 20 | */ 21 | export async function bindMainWindowApis(window: BrowserWindow) { 22 | return Object.assign(window, { 23 | apis: { 24 | commandClientApi: await bindWindowApi(window, "CommandClientApi"), 25 | toolboxClientApi: await bindWindowApi(window, "ToolboxClientApi"), 26 | graphClientApi: await bindWindowApi(window, "GraphClientApi"), 27 | projectClientApi: await bindWindowApi(window, "ProjectClientApi"), 28 | utilClientApi: await bindWindowApi(window, "UtilClientApi"), 29 | mediaClientApi: await bindWindowApi(window, "MediaClientApi"), 30 | tileClientApi: await bindWindowApi(window, "TileClientApi"), 31 | }, 32 | }); 33 | } 34 | 35 | export type MainWindow = AwaitedType; 36 | -------------------------------------------------------------------------------- /.github/workflows/coverage.yml: -------------------------------------------------------------------------------- 1 | name: Test Codebase 2 | 3 | on: 4 | pull_request: 5 | branches: [ master, dev ] 6 | types: [opened, synchronize, reopened, ready_for_review] 7 | push: 8 | branches: [ feature/projects ] 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | start: 14 | name: Start State 🚀🚀🚀 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Starting 18 | id: init 19 | run: | 20 | echo "Starting linting of ${{ github.repository }}" 21 | 22 | run_all_tests: 23 | name: Run all Tests 24 | runs-on: ${{ matrix.os }} 25 | strategy: 26 | matrix: 27 | os: [ubuntu-latest, macos-latest] 28 | needs: start 29 | steps: 30 | - name: Checkout for ${{ runner.os }} 31 | uses: actions/checkout@v3 32 | 33 | - name: Set up Node 18 34 | uses: actions/setup-node@v3 35 | with: 36 | node-version: 18 37 | 38 | - name: Cache dependencies 39 | uses: actions/cache@v2 40 | with: 41 | path: ~/.npm 42 | key: npm-${{ hashFiles('package-lock.json') }} 43 | restore-keys: npm- 44 | 45 | - name: Install dependencies 46 | run: npm ci 47 | 48 | - name: Run unit/integration tests and collect coverage 49 | run: npm run test 50 | env: 51 | CI: true 52 | 53 | - name: Upload coverage to Codecov 54 | if: ${{ runner.os == 'macOS' }} 55 | uses: codecov/codecov-action@v3 56 | with: 57 | files: coverage/lcov.info 58 | token: ${{ secrets.CODECOV_TOKEN }} 59 | 60 | timeout-minutes: 20 61 | 62 | end: 63 | name: End State ✅✅✅ 64 | runs-on: ubuntu-latest 65 | needs: run_all_tests 66 | steps: 67 | - name: Ending 68 | id: init 69 | run: | 70 | echo "Ending linting of ${{ github.repository }}" -------------------------------------------------------------------------------- /src/frontend/ui/utils/pluginTile/tileUIComponents/Radio.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | 31 | 32 | 33 | {#each Object.keys(items) as itemKey} 34 | 38 | {/each} 39 | 40 | 41 | 64 | -------------------------------------------------------------------------------- /docs/pics/blix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /public/images/blix.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/mediaDisplays/ColorDisplay.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
    21 |
    22 |
    23 | {color} 24 |
    25 |
    26 |
    27 |
    28 | 29 | 76 | -------------------------------------------------------------------------------- /src/frontend/ui/base/layout/PanelBlipVane.svelte: -------------------------------------------------------------------------------- 1 | 36 | 37 | {#if icon !== null} 38 |
    39 |
    45 | 46 |
    47 |
    48 | {/if} 49 | 50 | 83 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/Dropdown.svelte: -------------------------------------------------------------------------------- 1 | 28 | 29 | {#if Object.keys(items).length > 0} 30 | {#key inputStore.inputs[config.componentId]} 31 | 32 | 41 | {/key} 42 | {:else} 43 | 44 | 47 | {/if} 48 | 49 | 61 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | name: Lint Codebase 2 | on: 3 | pull_request: 4 | branches: [ master, dev ] 5 | types: [opened, synchronize, reopened, ready_for_review] 6 | permissions: 7 | contents: read 8 | 9 | jobs: 10 | start: 11 | name: Start State 🚀🚀🚀 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Starting 15 | id: init 16 | run: | 17 | echo "Starting linting of ${{ github.repository }}" 18 | 19 | lint_frontend: 20 | name: Lint Frontend 21 | runs-on: ubuntu-latest 22 | needs: start 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v3 26 | - name: Set up Node 18 27 | uses: actions/setup-node@v3 28 | with: 29 | node-version: 18 30 | 31 | - name: Cache dependencies 32 | uses: actions/cache@v2 33 | with: 34 | path: ~/.npm 35 | key: npm-${{ hashFiles('package-lock.json') }} 36 | restore-keys: npm- 37 | 38 | - name: Install dependencies 39 | run: npm ci 40 | - name: Lint Frontend 41 | run: npm run lint:svelte 42 | 43 | lint_electron: 44 | name: Lint Electron 45 | runs-on: ubuntu-latest 46 | needs: start 47 | steps: 48 | - name: Checkout 49 | uses: actions/checkout@v3 50 | - name: Set up Node 18 51 | uses: actions/setup-node@v3 52 | with: 53 | node-version: 18 54 | 55 | - name: Cache dependencies 56 | uses: actions/cache@v2 57 | with: 58 | path: ~/.npm 59 | key: npm-${{ hashFiles('package-lock.json') }} 60 | restore-keys: npm- 61 | 62 | - name: Install dependencies 63 | run: npm ci 64 | - name: Lint Frontend 65 | run: npm run lint:electron 66 | 67 | end: 68 | name: End State ✅✅✅ 69 | runs-on: ubuntu-latest 70 | needs: [lint_frontend, lint_electron] 71 | steps: 72 | - name: Ending 73 | id: init 74 | run: | 75 | echo "Ending linting of ${{ github.repository }}" -------------------------------------------------------------------------------- /src/shared/ui/TileUITypes.ts: -------------------------------------------------------------------------------- 1 | import { TileUIBuilder } from "../../electron/lib/plugins/builders/TileBuilder"; 2 | 3 | export type TileSignature = string; 4 | 5 | export type UIComponentConfig = { 6 | label: string; 7 | componentId: string; 8 | defaultValue: unknown; 9 | updatesBackend: boolean; 10 | }; 11 | 12 | export type ITile = { 13 | signature: TileSignature; 14 | name: string; 15 | plugin: string; 16 | displayName: string; 17 | description: string; 18 | icon: string; 19 | ui: { [key: string]: TileUIParent | null }; 20 | uiConfigs: { [key: string]: UIComponentConfig }; 21 | }; 22 | 23 | export type ITileUI = { 24 | ui: { [key: string]: TileUIParent | null }; 25 | uiConfigs: { [key: string]: UIComponentConfig }; 26 | }; 27 | 28 | export type UIComponentProps = { 29 | [key: string]: unknown; 30 | }; 31 | 32 | export abstract class TileUI { 33 | constructor( 34 | public parent: TileUI | null, 35 | public label: string, 36 | public location: string, 37 | public readonly params: any[], 38 | public childUis: ITileUI | null, 39 | public readonly type: string 40 | ) {} 41 | } 42 | 43 | export class TileUIParent extends TileUI { 44 | constructor(label: string, location: string, parent: TileUIParent | null) { 45 | super(parent, label, location, [], null, "parent"); 46 | } 47 | } 48 | 49 | export class TileUILeaf extends TileUI { 50 | constructor( 51 | public readonly parent: TileUIParent, 52 | public readonly category: TileUIComponent, 53 | public readonly label: string, 54 | public readonly params: UIComponentProps[] 55 | ) { 56 | super(parent, label, "", params, null, "leaf"); 57 | } 58 | } 59 | 60 | export enum TileUIComponent { 61 | Button = "Button", 62 | Slider = "Slider", 63 | Knob = "Knob", 64 | Label = "Label", 65 | Radio = "Radio", 66 | Dropdown = "Dropdown", 67 | Accordion = "Accordion", 68 | NumberInput = "NumberInput", 69 | TextInput = "TextInput", 70 | Checkbox = "Checkbox", 71 | ColorPicker = "ColorPicker", 72 | FilePicker = "FilePicker", 73 | } 74 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/dials/Dial.svelte: -------------------------------------------------------------------------------- 1 | 32 | 33 |
    38 | 39 | {#if mouseover} 40 | 43 | {/if} 44 |
    45 | 46 | 75 | -------------------------------------------------------------------------------- /src/electron/lib/registries/TileRegistry.ts: -------------------------------------------------------------------------------- 1 | import { type ITile, TileUIParent, type UIComponentConfig } from "../../../shared/ui/TileUITypes"; 2 | import type { Registry, RegistryInstance } from "./Registry"; 3 | import { type MainWindow } from "../api/apis/WindowApi"; 4 | import { Blix } from "../Blix"; 5 | 6 | export class TileRegistry implements Registry { 7 | private registry: { [key: string]: TileInstance } = {}; 8 | 9 | constructor(private readonly blix: Blix) {} 10 | 11 | addInstance(instance: TileInstance): void { 12 | this.registry[instance.id] = instance; 13 | 14 | this.blix.mainWindow?.apis.tileClientApi.registryChanged(this.getITiles()); 15 | } 16 | getRegistry(): { [key: string]: TileInstance } { 17 | return this.registry; 18 | } 19 | 20 | getITiles(): ITile[] { 21 | const tiles: ITile[] = []; 22 | 23 | for (const tile in this.registry) { 24 | if (this.registry.hasOwnProperty(tile)) { 25 | const tileInstance: TileInstance = this.registry[tile]; 26 | tiles.push({ 27 | signature: tileInstance.signature, 28 | name: tileInstance.name, 29 | plugin: tileInstance.plugin, 30 | displayName: tileInstance.displayName, 31 | description: tileInstance.description, 32 | icon: tileInstance.icon, 33 | ui: tileInstance.ui, 34 | uiConfigs: tileInstance.uiConfigs, 35 | }); 36 | } 37 | } 38 | 39 | return tiles; 40 | } 41 | } 42 | 43 | export class TileInstance implements RegistryInstance { 44 | constructor( 45 | public readonly name: string, 46 | public readonly plugin: string, 47 | public readonly displayName: string, 48 | public readonly description: string, 49 | public readonly icon: string, 50 | public readonly ui: { [key: string]: TileUIParent | null }, 51 | public readonly uiConfigs: { [key: string]: UIComponentConfig } = {} 52 | ) {} 53 | 54 | get id(): string { 55 | return this.signature; 56 | } 57 | 58 | get signature(): string { 59 | return `${this.plugin}.${this.name}`; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/frontend/ui/base/settings/AiSettings.svelte: -------------------------------------------------------------------------------- 1 | 56 | 57 |
    58 |
    API Keys
    59 |
    60 | None of your API keys get stored remotely. Your information is encrypted and maintained securely 61 | and solely within the confines of your own device. 62 |
    63 | 64 | {#each settings as item (item.id)} 65 | 66 | {/each} 67 |
    68 | -------------------------------------------------------------------------------- /src/electron/lib/ai/python/models/gpt.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | 4 | # Get the parent directory 5 | parent_dir = os.path.dirname(os.path.realpath(__file__)) 6 | 7 | # Add the parent directory to sys.path 8 | sys.path.append(parent_dir) 9 | 10 | from langchain.chat_models import ChatOpenAI 11 | 12 | # from functions.graphFunc import Functions 13 | from functions.tools import tools 14 | # from dotenv import load_dotenv 15 | from langchain.agents import initialize_agent, AgentType 16 | from prompts import generic 17 | from api import get_api 18 | 19 | # load_dotenv() 20 | 21 | 22 | class GPT: 23 | def sendPrompt(self, body) -> str: 24 | try: 25 | llm = ChatOpenAI(temperature=0.0, openai_api_key=body["config"]["key"]) 26 | 27 | open_ai_agent = initialize_agent( 28 | tools, 29 | llm, 30 | agent=AgentType.OPENAI_FUNCTIONS, 31 | model="gpt-3-turbo-0613", 32 | # verbose=True, 33 | debug=True, 34 | max_iterations=20, 35 | ) 36 | 37 | prompt = generic.prompt_template.format( 38 | prompt=body["prompt"], 39 | nodes=body["nodes"], 40 | edges=body["edges"], 41 | plugins=body["plugin"], 42 | ) 43 | 44 | finalResponse = open_ai_agent.run(prompt) 45 | return finalResponse 46 | except Exception as e: 47 | api = get_api() 48 | error_type = type(e).__name__ 49 | message = "Something went wrong while processing your request🫠" 50 | error = str(e) 51 | 52 | if error_type == "AuthenticationError": 53 | message = "Invalid Open AI key. Make sure to add a valid key in your user settings." 54 | error = "Open AI AuthenticationError" 55 | 56 | api.send( 57 | { 58 | "type": "error", 59 | "error": error, 60 | "message": message, 61 | } 62 | ) 63 | 64 | return "" 65 | -------------------------------------------------------------------------------- /src/electron/lib/ai/python/prompts/generic.py: -------------------------------------------------------------------------------- 1 | from langchain.prompts import PromptTemplate 2 | 3 | template = """ 4 | You are a helpful assistant that can manipulate a graph by calling some functions. You are only allowed to fulfill this role and nothing else. 5 | 6 | The graph consist of nodes and edges. Each node executes some sort of operation on the graph as an output. 7 | Each node has input and output anchors that are used to connect edges, when asked to connect nodes, always connect the output anchor of one node to the input anchor of another node. 8 | One output anchor can map to multiple input anchors, but the input anchor can only map to one output anchor. 9 | An edge can ONLY connect anchors that are of the same type. 10 | No input anchor may be used twice, and not all anchors have to always be connected. 11 | 12 | Do not tell the user how to use the provided data, instead you must use the data to assist the user. 13 | If you receive an error message, retry with different parameters. 14 | To create a functioning graph the graph must contain at least one input node and one output node that is connected to the graph. 15 | If there is no output node connected to the graph, always add it unless the user specifically asks you not to. 16 | 17 | Always add all nodes before adding edges. 18 | 19 | Provided is the graph's nodes : 20 | {nodes} 21 | For math nodes create multiple nodes for binary operations, for example to add two numbers, create a node for each number and then connect them to a node that adds them together. 22 | For image manipulation, the image must be connected to type sharp first and then back to image for the output node 23 | 24 | Edges can only be connected from the output anchors of one node with the input anchors of another node, provided they are of the same type. Thus no cycles are allowed 25 | Additionally the following edges are provided : 26 | {edges} 27 | 28 | 29 | The following nodes are relevant to you : 30 | {plugins} 31 | 32 | The user provides the following prompt : 33 | {prompt} 34 | 35 | """ 36 | 37 | prompt_template = PromptTemplate(input_variables=["prompt","nodes","edges","plugins"],template=template) -------------------------------------------------------------------------------- /src/electron/lib/registries/CommandRegistry.ts: -------------------------------------------------------------------------------- 1 | import type { Registry } from "./Registry"; 2 | import type { ICommand, CommandResponse } from "../../../shared/types/index"; 3 | import { Blix } from "../Blix"; 4 | 5 | export type CommandContext = Blix; 6 | 7 | export interface Command { 8 | id: string; 9 | handler: CommandHandler; 10 | description?: CommandDescription | null; 11 | } 12 | 13 | export type CommandHandler = (ctx: CommandContext, params?: any) => Promise; 14 | 15 | export interface CommandDescription { 16 | readonly name: string; 17 | readonly description: string; 18 | readonly icon?: string; 19 | // readonly args?: ReadonlyArray<{ 20 | // Specify arg schema for command here 21 | // }>; 22 | // readonly returns?: string specify return type here 23 | } 24 | 25 | export class CommandRegistry implements Registry { 26 | private registry: { [key: string]: Command } = {}; 27 | 28 | constructor(private readonly blix: Blix) {} 29 | 30 | addInstance(instance: Command): void { 31 | if (!instance) { 32 | throw Error("Invalid Command"); 33 | } 34 | this.registry[instance.id] = instance; 35 | this.blix.mainWindow?.apis.commandClientApi.registryChanged(this.getCommands()); 36 | } 37 | 38 | getRegistry() { 39 | return { ...this.registry }; 40 | } 41 | 42 | getCommands(): ICommand[] { 43 | const commands: ICommand[] = []; 44 | for (const key in this.registry) { 45 | if (key in this.registry) { 46 | const command = this.registry[key]; 47 | const commandObject: ICommand = { 48 | id: command.id, 49 | name: command.description?.name ?? "", 50 | description: command.description?.description ?? "", 51 | icon: command.description?.icon ?? "", 52 | }; 53 | commands.push(commandObject); 54 | } 55 | } 56 | return commands; 57 | } 58 | 59 | async runCommand(id: string, params?: any): Promise { 60 | const command = this.registry[id]; 61 | 62 | if (!command) { 63 | throw Error("Invalid Command"); 64 | } 65 | 66 | return await command.handler(this.blix, params); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /blix-plugins/logic-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Logic Plugin 2 | 3 | The Logic Plugin is an essential component of Blix, our AI photo editor. It offers a wide range of basic arithmetic operations, enabling users to perform mathematical manipulations on images within the photo editing graph. 4 | Features 5 | 6 | The Logic Plugin provides some of the following key features: 7 | 8 | Boolean operations: Perform AND/OR/NOT operations on boolean values. 9 | Logical comparisons: Perform comparison operations on numerical values. 10 | 11 | How to Use 12 | 13 | To use the Logic Plugin within the Blix photo editor, follow these steps: 14 | 15 | Open the Blix photo editor and create a new project. 16 | Access the editing graph or workspace. 17 | Locate the Logic Plugin nodes within the available nodes. 18 | Drag and drop the Logic Plugin node into the graph. 19 | Connect the input and output nodes to the desired locations in the graph. 20 | Manipulate the node through the provided components. 21 | Observe the effects on the image. 22 | 23 | Please note that the Logic Plugin can be used in combination with other nodes and plugins within the photo editing graph to achieve complex and customized effects. 24 | 25 | Plugin Development 26 | 27 | If you are interested in developing additional functionalities for the Logic Plugin or creating your own plugins for Blix, please refer to our developer documentation. It provides comprehensive guidelines and resources to help you extend the capabilities of our photo editor. 28 | Feedback and Support 29 | 30 | We highly value your feedback and are dedicated to continuously improving Blix and its plugins. If you encounter any issues, have suggestions for improvement, or need assistance, please don't hesitate to reach out to our support team. We are here to help you make the most out of your photo editing experience with Blix. 31 | License 32 | 33 | The Logic Plugin is released under the [GNU GENERAL PUBLIC LICENSE] license. Please review the license file for more information regarding the terms of use and redistribution. 34 | 35 | Enjoy using the Logic Plugin in Blix, and have fun exploring the possibilities of mathematical transformations in your photo editing projects! -------------------------------------------------------------------------------- /playwright.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig, devices } from '@playwright/test'; 2 | 3 | /** 4 | * Read environment variables from file. 5 | * https://github.com/motdotla/dotenv 6 | */ 7 | // require('dotenv').config(); 8 | 9 | /** 10 | * See https://playwright.dev/docs/test-configuration. 11 | */ 12 | export default defineConfig({ 13 | testDir: './tests/e2e', 14 | /* Run tests in files in parallel */ 15 | fullyParallel: true, 16 | /* Fail the build on CI if you accidentally left test.only in the source code. */ 17 | forbidOnly: !!process.env.CI, 18 | /* Retry on CI only */ 19 | retries: process.env.CI ? 2 : 0, 20 | /* Opt out of parallel tests on CI. */ 21 | workers: process.env.CI ? 1 : undefined, 22 | /* Reporter to use. See https://playwright.dev/docs/test-reporters */ 23 | reporter: 'html', 24 | /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ 25 | use: { 26 | /* Base URL to use in actions like `await page.goto('/')`. */ 27 | // baseURL: 'http://127.0.0.1:3000', 28 | 29 | /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ 30 | trace: 'on-first-retry', 31 | }, 32 | 33 | /* Configure projects for major browsers */ 34 | projects: [ 35 | { 36 | name: 'chromium', 37 | use: { ...devices['Desktop Chrome'] }, 38 | }, 39 | 40 | /* Test against mobile viewports. */ 41 | // { 42 | // name: 'Mobile Chrome', 43 | // use: { ...devices['Pixel 5'] }, 44 | // }, 45 | // { 46 | // name: 'Mobile Safari', 47 | // use: { ...devices['iPhone 12'] }, 48 | // }, 49 | 50 | /* Test against branded browsers. */ 51 | // { 52 | // name: 'Microsoft Edge', 53 | // use: { ...devices['Desktop Edge'], channel: 'msedge' }, 54 | // }, 55 | // { 56 | // name: 'Google Chrome', 57 | // use: { ..devices['Desktop Chrome'], channel: 'chrome' }, 58 | // }, 59 | ], 60 | 61 | /* Run your local dev server before starting the tests */ 62 | // webServer: { 63 | // command: 'npm run start', 64 | // url: 'http://127.0.0.1:3000', 65 | // reuseExistingServer: !process.env.CI, 66 | // }, 67 | }); 68 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/TextInput.svelte: -------------------------------------------------------------------------------- 1 | 26 | 27 | 28 | {#if props?.multiline === true} 29 | 34 | {:else} 35 | 42 | {/if} 43 | 44 | 71 | -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { spawn } from 'child_process'; 2 | import svelte from 'rollup-plugin-svelte'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import terser from '@rollup/plugin-terser'; 5 | import resolve from '@rollup/plugin-node-resolve'; 6 | import livereload from 'rollup-plugin-livereload'; 7 | import css from 'rollup-plugin-css-only'; 8 | 9 | const production = !process.env.ROLLUP_WATCH; 10 | 11 | function serve() { 12 | let server; 13 | 14 | function toExit() { 15 | if (server) server.kill(0); 16 | } 17 | 18 | return { 19 | writeBundle() { 20 | if (server) return; 21 | // server = spawn('npm', ['run', 'start', '--', '--dev'], { 22 | // stdio: ['ignore', 'inherit', 'inherit'], 23 | // shell: true 24 | // }); 25 | 26 | process.on('SIGTERM', toExit); 27 | process.on('exit', toExit); 28 | } 29 | }; 30 | } 31 | 32 | export default { 33 | input: 'webview/app.js', 34 | output: { 35 | sourcemap: true, 36 | format: 'iife', 37 | name: 'app', 38 | file: 'dist/bundle.js' 39 | }, 40 | plugins: [ 41 | svelte({ 42 | compilerOptions: { 43 | // enable run-time checks when not in production 44 | dev: !production 45 | } 46 | }), 47 | // we'll extract any component CSS out into 48 | // a separate file - better for performance 49 | css({ output: 'bundle.css' }), 50 | 51 | // If you have external dependencies installed from 52 | // npm, you'll most likely need these plugins. In 53 | // some cases you'll need additional configuration - 54 | // consult the documentation for details: 55 | // https://github.com/rollup/plugins/tree/master/packages/commonjs 56 | resolve({ 57 | browser: true, 58 | dedupe: ['svelte'], 59 | exportConditions: ['svelte'] 60 | }), 61 | commonjs(), 62 | 63 | // In dev mode, call `npm run start` once 64 | // the bundle has been generated 65 | !production && serve(), 66 | 67 | // Watch the `public` directory and refresh the 68 | // browser on changes when not in production 69 | !production && livereload('public'), 70 | 71 | // If we're building for production (npm run build 72 | // instead of npm run dev), minify 73 | production && terser() 74 | ], 75 | watch: { 76 | clearScreen: false 77 | } 78 | }; -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/rollup.config.js: -------------------------------------------------------------------------------- 1 | import { spawn } from 'child_process'; 2 | import svelte from 'rollup-plugin-svelte'; 3 | import commonjs from '@rollup/plugin-commonjs'; 4 | import terser from '@rollup/plugin-terser'; 5 | import resolve from '@rollup/plugin-node-resolve'; 6 | import livereload from 'rollup-plugin-livereload'; 7 | import css from 'rollup-plugin-css-only'; 8 | 9 | const production = !process.env.ROLLUP_WATCH; 10 | 11 | function serve() { 12 | let server; 13 | 14 | function toExit() { 15 | if (server) server.kill(0); 16 | } 17 | 18 | return { 19 | writeBundle() { 20 | if (server) return; 21 | // server = spawn('npm', ['run', 'start', '--', '--dev'], { 22 | // stdio: ['ignore', 'inherit', 'inherit'], 23 | // shell: true 24 | // }); 25 | 26 | process.on('SIGTERM', toExit); 27 | process.on('exit', toExit); 28 | } 29 | }; 30 | } 31 | 32 | export default { 33 | input: 'webview/app.js', 34 | output: { 35 | sourcemap: true, 36 | format: 'iife', 37 | name: 'app', 38 | file: 'dist/bundle.js' 39 | }, 40 | plugins: [ 41 | svelte({ 42 | compilerOptions: { 43 | // enable run-time checks when not in production 44 | dev: !production 45 | } 46 | }), 47 | // we'll extract any component CSS out into 48 | // a separate file - better for performance 49 | css({ output: 'bundle.css' }), 50 | 51 | // If you have external dependencies installed from 52 | // npm, you'll most likely need these plugins. In 53 | // some cases you'll need additional configuration - 54 | // consult the documentation for details: 55 | // https://github.com/rollup/plugins/tree/master/packages/commonjs 56 | resolve({ 57 | browser: true, 58 | dedupe: ['svelte'], 59 | exportConditions: ['svelte'] 60 | }), 61 | commonjs(), 62 | 63 | // In dev mode, call `npm run start` once 64 | // the bundle has been generated 65 | !production && serve(), 66 | 67 | // Watch the `public` directory and refresh the 68 | // browser on changes when not in production 69 | !production && livereload('public'), 70 | 71 | // If we're building for production (npm run build 72 | // instead of npm run dev), minify 73 | production && terser() 74 | ], 75 | watch: { 76 | clearScreen: false 77 | } 78 | }; -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/NodeUIFragment.svelte: -------------------------------------------------------------------------------- 1 | 44 | 45 | {#if ui} 46 | {#if ui.type === "parent"} 47 |
      48 | {#each ui.params as child} 49 |
    • 50 | 56 |
    • 57 | {/each} 58 |
    59 | {:else if ui.type === "leaf"} 60 |

    61 | 67 |

    68 | {/if} 69 | {/if} 70 | 71 | 77 | -------------------------------------------------------------------------------- /src/electron/lib/core-graph/CoreGraphCommands.ts: -------------------------------------------------------------------------------- 1 | import type { UUID } from "../../../shared/utils/UniqueEntity"; 2 | import type { Command, CommandContext } from "../../lib/registries/CommandRegistry"; 3 | import type { CommandResponse } from "../../../shared/types/index"; 4 | import { CoreGraphUpdateEvent, CoreGraphUpdateParticipant } from "./CoreGraphInteractors"; 5 | 6 | type CreateGraphArgs = { 7 | projectId: UUID; 8 | name?: string; 9 | }; 10 | 11 | export const createGraphCommand: Command = { 12 | id: "blix.graphs.create", 13 | description: { 14 | name: "Create Graph", 15 | description: "Create a new graph", 16 | }, 17 | handler: async (ctx: CommandContext, args: CreateGraphArgs) => { 18 | const result = await createGraph(ctx, args); 19 | if (result.status === "success" && result.message) { 20 | ctx.sendSuccessMessage(result.message); 21 | } else if (result.status === "error" && result.message) { 22 | ctx.sendErrorMessage(result.message); 23 | } 24 | return result; 25 | }, 26 | }; 27 | 28 | export const deleteGraphCommand: Command = { 29 | id: "blix.graphs.deleteGraph", 30 | description: { 31 | name: "Delete graph", 32 | description: "Delete the current graph", 33 | }, 34 | handler: async (ctx: CommandContext, args: { id: UUID }) => { 35 | if (args && typeof args === "object" && args.id) { 36 | ctx.projectManager.removeGraph(args.id); 37 | ctx.graphManager.deleteGraphs([args.id]); 38 | } 39 | return { status: "success", message: "Graph deleted successfully" }; 40 | }, 41 | }; 42 | 43 | export async function createGraph( 44 | ctx: CommandContext, 45 | args: CreateGraphArgs 46 | ): Promise { 47 | const { projectId, name } = args; 48 | const project = ctx.projectManager.getProject(projectId); 49 | if (!project) return { status: "error", message: "Project not found" }; 50 | 51 | const graphId = ctx.graphManager.createGraph(); 52 | ctx.graphManager.onGraphUpdated( 53 | graphId, 54 | new Set([CoreGraphUpdateEvent.graphUpdated]), 55 | CoreGraphUpdateParticipant.system 56 | ); 57 | ctx.projectManager.addGraph(projectId, graphId); 58 | 59 | return { status: "success", message: "Graph created successfully" }; 60 | } 61 | 62 | export const coreGraphCommands: Command[] = [createGraphCommand, deleteGraphCommand]; 63 | -------------------------------------------------------------------------------- /scripts/plugins.js: -------------------------------------------------------------------------------- 1 | const { readFileSync, writeFileSync, existsSync } = require("fs"); 2 | const { execSync } = require("child_process"); 3 | const { join, resolve } = require("path"); 4 | 5 | function buildGLFX() { 6 | const directory = resolve(join(__dirname, "..", "blix-plugins/glfx-plugin")); 7 | const options = { cwd: directory }; 8 | const command = "npm ci && npm run build"; 9 | 10 | console.log("Building glfx..."); 11 | 12 | try { 13 | const output = execSync(command, options); 14 | console.log(output.toString()); 15 | } catch (error) { 16 | console.log(error.toString()); 17 | } 18 | 19 | console.log("Building glfx completed"); 20 | } 21 | 22 | function buildBlink() { 23 | const tsconfigPath = join( 24 | __dirname, 25 | "..", 26 | "blix-plugins/blink/node_modules/@tsconfig/svelte/tsconfig.json" 27 | ); 28 | 29 | const directory = resolve(join(__dirname, "..", "blix-plugins/blink")); 30 | const options = { cwd: directory }; 31 | let command = "npm ci"; 32 | 33 | console.log("Installing blink node_modules..."); 34 | 35 | try { 36 | const output = execSync(command, options); 37 | console.log(output.toString()); 38 | } catch (error) { 39 | console.log(error.toString()); 40 | } 41 | 42 | console.log("Attempting to fix tsconfig..."); 43 | if (existsSync(tsconfigPath)) { 44 | const tsconfigRaw = readFileSync(tsconfigPath, "utf8"); 45 | const withoutSingleLineComments = tsconfigRaw.replace( 46 | /^(?!.*https?:\/\/)(.*)\/\/(.*)$/gm, 47 | "$1" 48 | ); 49 | const withoutComments = withoutSingleLineComments.replace(/\/\*([\s\S]*?)\*\//g, ""); 50 | const tsconfigJSON = JSON.parse(withoutComments); 51 | tsconfigJSON.compilerOptions.moduleResolution = "node"; 52 | delete tsconfigJSON.compilerOptions.verbatimModuleSyntax; 53 | writeFileSync(tsconfigPath, JSON.stringify(tsconfigJSON, null, 2)); 54 | console.log("TSConfig fixed"); 55 | } else { 56 | console.log("TSConfig not found. Building..."); 57 | } 58 | 59 | command = "npm run build"; 60 | 61 | console.log("Building blink..."); 62 | 63 | try { 64 | const output = execSync(command, options); 65 | console.log(output.toString()); 66 | } catch (error) { 67 | console.log(error.toString()); 68 | } 69 | 70 | console.log("Building blink completed"); 71 | } 72 | 73 | buildGLFX(); 74 | buildBlink(); 75 | -------------------------------------------------------------------------------- /src/frontend/ui/tiles/Debug.svelte: -------------------------------------------------------------------------------- 1 | 19 | 20 |
    21 |
    22 | Toolbox:
    23 | {#each $toolboxSignatures as key} 24 | {key}: {JSON.stringify({ ...$toolboxStore[key], ui: $toolboxStore[key].ui !== null })} 25 |

    26 | {/each} 27 | 28 |
    29 | Graph Mall:
    30 | {JSON.stringify($graphMall)} 31 |
    32 | Graph Stores:
    33 | {#each $graphIds as data} 34 | {data.slice(0, 8)}: {JSON.stringify(get($graphMall[data]))} 35 |

    36 | {/each} 37 |
    38 | Project Store:
    39 |
    40 | Active Project - Name: {$projectsStore?.activeProject?.name} ID: {$projectsStore 41 | ?.activeProject?.id} 42 |
    43 | {#each $projectsStore.projects as project (project.id)} 44 |
    45 | Name: {project.name} ID: {project.id.slice(0, 8)} Graphs: {project.graphs.map((g) => 46 | g.slice(0, 8) 47 | )} 48 |
    49 | {/each} 50 |
    51 |
    52 | 53 | 81 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/nodeUIComponents/CachePicker.svelte: -------------------------------------------------------------------------------- 1 | 37 | 38 | {#if $cacheObjects.size} 39 | {#key inputStore.inputs[config.componentId]} 40 | 51 | {/key} 52 | {:else} 53 | 56 | {/if} 57 | 58 | 68 | -------------------------------------------------------------------------------- /src/frontend/ui/base/settings/utils/SecureInput.svelte: -------------------------------------------------------------------------------- 1 | 14 | 15 |
    18 | 26 | {#if show} 27 | 37 | 42 | 43 | {:else} 44 | 54 | 59 | 61 | 62 | {/if} 63 |
    64 | -------------------------------------------------------------------------------- /docs/latex/Architecture.out: -------------------------------------------------------------------------------- 1 | \BOOKMARK [1][-]{section.1}{\376\377\000D\000e\000s\000i\000g\000n\000\040\000S\000t\000r\000a\000t\000e\000g\000y}{}% 1 2 | \BOOKMARK [1][-]{section.2}{\376\377\000Q\000u\000a\000l\000i\000t\000y\000\040\000R\000e\000q\000u\000i\000r\000e\000m\000e\000n\000t\000s}{}% 2 3 | \BOOKMARK [1][-]{section.3}{\376\377\000A\000r\000c\000h\000i\000t\000e\000c\000t\000u\000r\000a\000l\000\040\000D\000e\000s\000i\000g\000n\000\040\000\046\000\040\000P\000a\000t\000t\000e\000r\000n\000s}{}% 3 4 | \BOOKMARK [2][-]{subsection.3.1}{\376\377\000M\000o\000d\000e\000l\000-\000V\000i\000e\000w\000-\000C\000o\000n\000t\000r\000o\000l\000l\000e\000r\000\040\000\050\000M\000V\000C\000\051}{section.3}% 4 5 | \BOOKMARK [2][-]{subsection.3.2}{\376\377\000P\000u\000b\000l\000i\000s\000h\000-\000S\000u\000b\000s\000c\000r\000i\000b\000e}{section.3}% 5 6 | \BOOKMARK [2][-]{subsection.3.3}{\376\377\000S\000e\000r\000v\000i\000c\000e\000-\000O\000r\000i\000e\000n\000t\000e\000d}{section.3}% 6 7 | \BOOKMARK [1][-]{section.4}{\376\377\000C\000o\000n\000s\000t\000r\000a\000i\000n\000t\000s}{}% 7 8 | \BOOKMARK [1][-]{section.5}{\376\377\000T\000e\000c\000h\000n\000o\000l\000o\000g\000y\000\040\000C\000h\000o\000i\000c\000e\000s}{}% 8 9 | \BOOKMARK [2][-]{subsection.5.1}{\376\377\000S\000v\000e\000l\000t\000e}{section.5}% 9 10 | \BOOKMARK [2][-]{subsection.5.2}{\376\377\000T\000a\000i\000l\000w\000i\000n\000d\000\040\000C\000S\000S}{section.5}% 10 11 | \BOOKMARK [2][-]{subsection.5.3}{\376\377\000E\000l\000e\000c\000t\000r\000o\000n}{section.5}% 11 12 | \BOOKMARK [2][-]{subsection.5.4}{\376\377\000F\000i\000r\000e\000b\000a\000s\000e}{section.5}% 12 13 | \BOOKMARK [2][-]{subsection.5.5}{\376\377\000L\000a\000n\000g\000C\000h\000a\000i\000n}{section.5}% 13 14 | \BOOKMARK [2][-]{subsection.5.6}{\376\377\000P\000i\000n\000e\000C\000o\000n\000e}{section.5}% 14 15 | \BOOKMARK [2][-]{subsection.5.7}{\376\377\000t\000y\000p\000e\000s\000c\000r\000i\000p\000t}{section.5}% 15 16 | \BOOKMARK [2][-]{subsection.5.8}{\376\377\000N\000o\000d\000e\000j\000s}{section.5}% 16 17 | \BOOKMARK [2][-]{subsection.5.9}{\376\377\000P\000y\000t\000h\000o\000n}{section.5}% 17 18 | \BOOKMARK [2][-]{subsection.5.10}{\376\377\000J\000e\000s\000t}{section.5}% 18 19 | \BOOKMARK [2][-]{subsection.5.11}{\376\377\000A\000I\000\040\000M\000o\000d\000e\000l\000s}{section.5}% 19 20 | \BOOKMARK [2][-]{subsection.5.12}{\376\377\000G\000P\000T\000-\0003\000.\0005\000\040\000T\000u\000r\000b\000o}{section.5}% 20 21 | -------------------------------------------------------------------------------- /src/shared/types/setting.ts: -------------------------------------------------------------------------------- 1 | export const userSettingSections = [ 2 | { 3 | id: "general", 4 | title: "General", 5 | categories: [ 6 | { id: "about", title: "About" }, 7 | { id: "ai", title: "AI Settings" }, 8 | { id: "hotkeys", title: "Hotkeys" }, 9 | { id: "plugin_browser", title: "Plugin Browser" }, 10 | ], 11 | }, 12 | ] as const satisfies readonly UserSettingsSection[]; 13 | 14 | export type UserSettingsCategoryId = 15 | (typeof userSettingSections)[number]["categories"][number]["id"]; 16 | 17 | export type UserSettingsCategoryTitle = 18 | (typeof userSettingSections)[number]["categories"][number]["title"]; 19 | 20 | export type UserSettingsSection = { 21 | id: string; 22 | title: string; 23 | categories: ReadonlyArray; 24 | }; 25 | 26 | export type UserSettingCategory = { 27 | id: string; 28 | title: string; 29 | subtitle?: string; 30 | }; 31 | 32 | export type Setting = { 33 | id: string; 34 | title: string; 35 | subtitle?: string; 36 | description?: string[]; 37 | components: SettingComponent[]; 38 | }; 39 | 40 | interface SettingComponentBase { 41 | id: string; 42 | secret?: boolean; 43 | } 44 | 45 | export interface Input extends SettingComponentBase { 46 | type: "secret" | "text"; 47 | placeholder?: string; 48 | value: string; 49 | } 50 | 51 | export interface Dropdown extends SettingComponentBase { 52 | type: "dropdown"; 53 | options: string[]; 54 | value: string; 55 | } 56 | export interface Toggle extends SettingComponentBase { 57 | type: "toggle"; 58 | value: boolean; 59 | } 60 | export interface Button extends SettingComponentBase { 61 | type: "button"; 62 | value: string; 63 | onClick: (item: Button) => void; 64 | } 65 | 66 | export interface ColorPicker extends SettingComponentBase { 67 | type: "colorPicker"; 68 | value: `#${string}`; 69 | } 70 | 71 | export interface KeyboardShortcuts extends SettingComponentBase { 72 | id: "keyboardShortcuts"; 73 | type: "keyboardShortcuts"; 74 | value: KeyboardShortcut[]; 75 | } 76 | export interface KeyboardShortcut extends SettingComponentBase { 77 | id: `${string}.${string}`; 78 | title: string; 79 | type: "keyboardShortcut"; 80 | value: string[]; 81 | } 82 | 83 | export type SettingComponent = Dropdown | Input | Toggle | KeyboardShortcuts | Button | ColorPicker; 84 | 85 | type Prettify = T extends object ? { [K in keyof T]: T[K] } : never; 86 | 87 | type t = Prettify; 88 | -------------------------------------------------------------------------------- /src/electron/lib/api/apis/MediaApi.ts: -------------------------------------------------------------------------------- 1 | import type { ElectronMainApi } from "electron-affinity/main"; 2 | import type { Blix } from "../../Blix"; 3 | import { type UUID } from "../../../../shared/utils/UniqueEntity"; 4 | import { type DisplayableMediaOutput, type MediaOutputId } from "../../../../shared/types/media"; 5 | import { MediaSubscriber } from "../../media/MediaSubscribers"; 6 | 7 | export class MediaApi implements ElectronMainApi { 8 | private readonly _blix: Blix; 9 | private mediaSubscribers: { 10 | [key: MediaOutputId]: { subscriber: MediaSubscriber; subCount: number }; 11 | }; 12 | 13 | constructor(blix: Blix) { 14 | this._blix = blix; 15 | this.mediaSubscribers = {}; 16 | } 17 | 18 | async unsubscribeFromMedia(mediaId: MediaOutputId) { 19 | if (this.mediaSubscribers[mediaId]) { 20 | this.mediaSubscribers[mediaId].subCount--; 21 | 22 | if (this.mediaSubscribers[mediaId].subCount <= 0) { 23 | this._blix.mediaManager.removeSubscriber( 24 | mediaId, 25 | this.mediaSubscribers[mediaId].subscriber.uuid 26 | ); 27 | delete this.mediaSubscribers[mediaId]; 28 | } 29 | } 30 | // console.log("\nUNSUBBED", mediaId); 31 | // for (const mediaId of Object.keys(this.mediaSubscribers)) { 32 | // console.log(mediaId, this.mediaSubscribers[mediaId].subCount); 33 | // } 34 | } 35 | 36 | async subscribeToMedia(mediaId: MediaOutputId) { 37 | if (!this.mediaSubscribers[mediaId]) { 38 | const mediaSubscriber = new MediaSubscriber(); 39 | 40 | mediaSubscriber.listen = (media: DisplayableMediaOutput) => { 41 | this._blix.mainWindow?.apis.mediaClientApi.outputChanged(media); 42 | }; 43 | 44 | this.mediaSubscribers[mediaId] = { subscriber: mediaSubscriber, subCount: 0 }; 45 | 46 | this._blix.mediaManager.addSubscriber(mediaId, this.mediaSubscribers[mediaId].subscriber); 47 | } 48 | 49 | this.mediaSubscribers[mediaId].subCount++; 50 | // console.log("\nSUBBED", mediaId); 51 | // for (const mediaId of Object.keys(this.mediaSubscribers)) { 52 | // console.log(mediaId, this.mediaSubscribers[mediaId].subCount); 53 | // } 54 | } 55 | 56 | async getDisplayableMedia(mediaId: MediaOutputId) { 57 | return this._blix.mediaManager.getDisplayableMedia(mediaId); 58 | } 59 | 60 | // async compute(graphUUID: UUID, nodeUUID: UUID) { 61 | // return this._blix.graphInterpreter.run(this._blix.graphManager.getGraph(graphUUID), nodeUUID); 62 | // } 63 | } 64 | -------------------------------------------------------------------------------- /src/frontend/ui/base/Navbar.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | 34 | 35 | 52 | -------------------------------------------------------------------------------- /src/frontend/ui/utils/ContextMenuGroup.svelte: -------------------------------------------------------------------------------- 1 | 16 | 17 |
      18 |
    • 19 |
      27 | {#if expanded} 28 | 36 | 41 | 42 | {:else} 43 | 51 | 56 | 57 | {/if} 58 |
      {root.label}
      59 |
      60 | {#if expanded && root.children} 61 |
        65 | {#each root.children as node (node.id)} 66 | {#if node.children} 67 | 68 | {:else} 69 | 70 | {/if} 71 | {/each} 72 |
      73 | {/if} 74 |
    • 75 |
    76 | -------------------------------------------------------------------------------- /blix-plugins/glfx-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Math Plugin 2 | 3 | The Math Plugin is an essential component of Blix, our AI photo editor. It offers a wide range of basic arithmetic operations, enabling users to perform mathematical manipulations on images within the photo editing graph. 4 | Features 5 | 6 | The Math Plugin provides some of the following key features: 7 | 8 | Addition: Perform addition operations on numerical values. 9 | Subtraction: Perform subtraction operations on numerical values. 10 | Multiplication: Perform multiplication operations on numerical values. 11 | Division: Perform division operations on numerical values. 12 | Exponentiation: Apply exponentiation operations to numerical values. 13 | Absolute Value: Calculate the absolute value of a numerical value. 14 | Minimum: Determine the minimum value between two numerical values. 15 | Maximum: Determine the maximum value between two numerical values. 16 | 17 | How to Use 18 | 19 | To use the Math Plugin within the Blix photo editor, follow these steps: 20 | 21 | Open the Blix photo editor and create a new project. 22 | Access the editing graph or workspace. 23 | Locate the Math Plugin nodes within the available nodes. 24 | Drag and drop the Math Plugin node into the graph. 25 | Connect the input and output nodes to the desired locations in the graph. 26 | Manipulate the node through the provided components. 27 | Observe the effects on the image. 28 | 29 | Please note that the Math Plugin can be used in combination with other nodes and plugins within the photo editing graph to achieve complex and customized effects. 30 | 31 | Plugin Development 32 | 33 | If you are interested in developing additional functionalities for the Math Plugin or creating your own plugins for Blix, please refer to our developer documentation. It provides comprehensive guidelines and resources to help you extend the capabilities of our photo editor. 34 | Feedback and Support 35 | 36 | We highly value your feedback and are dedicated to continuously improving Blix and its plugins. If you encounter any issues, have suggestions for improvement, or need assistance, please don't hesitate to reach out to our support team. We are here to help you make the most out of your photo editing experience with Blix. 37 | License 38 | 39 | The Math Plugin is released under the [GNU GENERAL PUBLIC LICENSE] license. Please review the license file for more information regarding the terms of use and redistribution. 40 | 41 | Enjoy using the Math Plugin in Blix, and have fun exploring the possibilities of mathematical transformations in your photo editing projects! -------------------------------------------------------------------------------- /blix-plugins/math-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Math Plugin 2 | 3 | The Math Plugin is an essential component of Blix, our AI photo editor. It offers a wide range of basic arithmetic operations, enabling users to perform mathematical manipulations on images within the photo editing graph. 4 | Features 5 | 6 | The Math Plugin provides some of the following key features: 7 | 8 | Addition: Perform addition operations on numerical values. 9 | Subtraction: Perform subtraction operations on numerical values. 10 | Multiplication: Perform multiplication operations on numerical values. 11 | Division: Perform division operations on numerical values. 12 | Exponentiation: Apply exponentiation operations to numerical values. 13 | Absolute Value: Calculate the absolute value of a numerical value. 14 | Minimum: Determine the minimum value between two numerical values. 15 | Maximum: Determine the maximum value between two numerical values. 16 | 17 | How to Use 18 | 19 | To use the Math Plugin within the Blix photo editor, follow these steps: 20 | 21 | Open the Blix photo editor and create a new project. 22 | Access the editing graph or workspace. 23 | Locate the Math Plugin nodes within the available nodes. 24 | Drag and drop the Math Plugin node into the graph. 25 | Connect the input and output nodes to the desired locations in the graph. 26 | Manipulate the node through the provided components. 27 | Observe the effects on the image. 28 | 29 | Please note that the Math Plugin can be used in combination with other nodes and plugins within the photo editing graph to achieve complex and customized effects. 30 | 31 | Plugin Development 32 | 33 | If you are interested in developing additional functionalities for the Math Plugin or creating your own plugins for Blix, please refer to our developer documentation. It provides comprehensive guidelines and resources to help you extend the capabilities of our photo editor. 34 | Feedback and Support 35 | 36 | We highly value your feedback and are dedicated to continuously improving Blix and its plugins. If you encounter any issues, have suggestions for improvement, or need assistance, please don't hesitate to reach out to our support team. We are here to help you make the most out of your photo editing experience with Blix. 37 | License 38 | 39 | The Math Plugin is released under the [GNU GENERAL PUBLIC LICENSE] license. Please review the license file for more information regarding the terms of use and redistribution. 40 | 41 | Enjoy using the Math Plugin in Blix, and have fun exploring the possibilities of mathematical transformations in your photo editing projects! -------------------------------------------------------------------------------- /blix-plugins/webgl-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Math Plugin 2 | 3 | The Math Plugin is an essential component of Blix, our AI photo editor. It offers a wide range of basic arithmetic operations, enabling users to perform mathematical manipulations on images within the photo editing graph. 4 | Features 5 | 6 | The Math Plugin provides some of the following key features: 7 | 8 | Addition: Perform addition operations on numerical values. 9 | Subtraction: Perform subtraction operations on numerical values. 10 | Multiplication: Perform multiplication operations on numerical values. 11 | Division: Perform division operations on numerical values. 12 | Exponentiation: Apply exponentiation operations to numerical values. 13 | Absolute Value: Calculate the absolute value of a numerical value. 14 | Minimum: Determine the minimum value between two numerical values. 15 | Maximum: Determine the maximum value between two numerical values. 16 | 17 | How to Use 18 | 19 | To use the Math Plugin within the Blix photo editor, follow these steps: 20 | 21 | Open the Blix photo editor and create a new project. 22 | Access the editing graph or workspace. 23 | Locate the Math Plugin nodes within the available nodes. 24 | Drag and drop the Math Plugin node into the graph. 25 | Connect the input and output nodes to the desired locations in the graph. 26 | Manipulate the node through the provided components. 27 | Observe the effects on the image. 28 | 29 | Please note that the Math Plugin can be used in combination with other nodes and plugins within the photo editing graph to achieve complex and customized effects. 30 | 31 | Plugin Development 32 | 33 | If you are interested in developing additional functionalities for the Math Plugin or creating your own plugins for Blix, please refer to our developer documentation. It provides comprehensive guidelines and resources to help you extend the capabilities of our photo editor. 34 | Feedback and Support 35 | 36 | We highly value your feedback and are dedicated to continuously improving Blix and its plugins. If you encounter any issues, have suggestions for improvement, or need assistance, please don't hesitate to reach out to our support team. We are here to help you make the most out of your photo editing experience with Blix. 37 | License 38 | 39 | The Math Plugin is released under the [GNU GENERAL PUBLIC LICENSE] license. Please review the license file for more information regarding the terms of use and redistribution. 40 | 41 | Enjoy using the Math Plugin in Blix, and have fun exploring the possibilities of mathematical transformations in your photo editing projects! -------------------------------------------------------------------------------- /src/frontend/ui/utils/graph/NodeUIComponent.svelte: -------------------------------------------------------------------------------- 1 | 49 | 50 | {#if leafUI} 51 | {#if mapToSvelteComponent[leafUI.category] !== null} 52 | 60 | {/if} 61 | {/if} 62 | 63 | -------------------------------------------------------------------------------- /tests/unit-tests/electron/lib/tiles/TileRegistry.spec.ts: -------------------------------------------------------------------------------- 1 | import { TileRegistry,TileInstance } from "../../../../../src/electron/lib/registries/TileRegistry"; 2 | import { Blix } from "../../../../../src/electron/lib/Blix"; 3 | 4 | jest.mock("electron", () => ({ 5 | app: { 6 | getPath: jest.fn((path) => { 7 | return "test/electron"; 8 | }), 9 | getName: jest.fn(() => { 10 | return "TestElectron"; 11 | }), 12 | getVersion: jest.fn(() => { 13 | return "v1.1.1"; 14 | }), 15 | getAppPath: jest.fn(() => { 16 | return "test/electron"; 17 | }) 18 | }, 19 | ipcMain: { 20 | on: jest.fn() 21 | } 22 | })); 23 | 24 | jest.mock('ws', () => { 25 | return { 26 | WebSocketServer: jest.fn().mockImplementation(() => { 27 | return { 28 | on: jest.fn() 29 | } 30 | } 31 | ) 32 | } 33 | }); 34 | 35 | jest.mock('../../../../../src/electron/lib/plugins/PluginManager') 36 | 37 | 38 | describe("Test TileInstance", () => { 39 | describe("Test TileRegistry", () => { 40 | let tileRegistry : TileRegistry; 41 | let tileInstance : TileInstance; 42 | let blix : Blix; 43 | 44 | 45 | 46 | beforeEach(() => { 47 | blix = new Blix(); 48 | tileRegistry = new TileRegistry(blix); 49 | tileInstance = new TileInstance("plugin.name","plugin","Hello","description","icon",{}); 50 | }); 51 | 52 | test("Test constructor", () => { 53 | expect(tileRegistry).toBeDefined(); 54 | expect(tileInstance).toBeDefined(); 55 | }) 56 | 57 | test("Test addInstance and getRegistry", () => { 58 | tileRegistry.addInstance(tileInstance); 59 | expect(tileRegistry.getRegistry()[tileInstance.id].id).toBe("plugin.plugin.name"); 60 | }); 61 | }); 62 | 63 | // describe("Test TileRegistry", () => { 64 | // let tileRegistry : TileRegistry; 65 | // let tileInstance : TileInstance; 66 | // let blix : Blix; 67 | 68 | 69 | 70 | // beforeEach(() => { 71 | // blix = new Blix(); 72 | // tileRegistry = new TileRegistry(blix); 73 | // tileInstance = new TileInstance("plugin.name","plugin","Hello","description","icon",{}); 74 | // }); 75 | 76 | // test("Test constructor", () => { 77 | // expect(tileRegistry).toBeDefined(); 78 | // expect(tileInstance).toBeDefined(); 79 | // }) 80 | 81 | // test("Test addInstance and getRegistry", () => { 82 | // tileRegistry.addInstance(tileInstance); 83 | // expect(tileRegistry.getRegistry()[tileInstance.id].id).toBe("plugin.name"); 84 | // }); 85 | // }); 86 | }); 87 | 88 | 89 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | .DS_Store 3 | 4 | src/electron/**/*.png 5 | src/electron/**/*.md 6 | 7 | .vscode 8 | 9 | # Logs 10 | logs 11 | *.log 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | lerna-debug.log* 16 | 17 | playwright-report 18 | 19 | # Diagnostic reports (https://nodejs.org/api/report.html) 20 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 21 | 22 | # Runtime data 23 | pids 24 | *.pid 25 | *.seed 26 | *.pid.lock 27 | 28 | # Directory for instrumented libs generated by jscoverage/JSCover 29 | lib-cov 30 | 31 | # Coverage directory used by tools like istanbul 32 | coverage 33 | *.lcov 34 | 35 | # nyc test coverage 36 | .nyc_output 37 | 38 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 39 | .grunt 40 | 41 | # Bower dependency directory (https://bower.io/) 42 | bower_components 43 | 44 | # node-waf configuration 45 | .lock-wscript 46 | 47 | # Compiled binary addons (https://nodejs.org/api/addons.html) 48 | build/Release 49 | 50 | # Dependency directories 51 | node_modules/ 52 | jspm_packages/ 53 | 54 | # TypeScript v1 declaration files 55 | typings/ 56 | 57 | # TypeScript cache 58 | *.tsbuildinfo 59 | 60 | # Optional npm cache directory 61 | .npm 62 | 63 | # Optional eslint cache 64 | .eslintcache 65 | 66 | # Microbundle cache 67 | .rpt2_cache/ 68 | .rts2_cache_cjs/ 69 | .rts2_cache_es/ 70 | .rts2_cache_umd/ 71 | 72 | # Optional REPL history 73 | .node_repl_history 74 | 75 | # Output of 'npm pack' 76 | *.tgz 77 | 78 | # Yarn Integrity file 79 | .yarn-integrity 80 | 81 | # dotenv environment variables file 82 | .env 83 | .env.test 84 | 85 | # parcel-bundler cache (https://parceljs.org/) 86 | .cache 87 | 88 | # Next.js build output 89 | .next 90 | 91 | # Nuxt.js build / generate output 92 | .nuxt 93 | dist 94 | 95 | # Gatsby files 96 | .cache/ 97 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 98 | # https://nextjs.org/blog/next-9-1#public-directory-support 99 | # public 100 | 101 | # vuepress build output 102 | .vuepress/dist 103 | 104 | # Serverless directories 105 | .serverless/ 106 | 107 | # FuseBox cache 108 | .fusebox/ 109 | 110 | # DynamoDB Local files 111 | .dynamodb/ 112 | 113 | # TernJS port file 114 | .tern-port 115 | /test-results/ 116 | /playwright-report/ 117 | /playwright/.cache/ 118 | 119 | docs/latex/*.pdf 120 | docs/latex/*.gz 121 | docs/latex/*.aux 122 | docs/latex/*.fdb_latexmk 123 | docs/latex/*.fls 124 | docs/latex/*.out 125 | docs/latex/*.toc 126 | docs/latex/images 127 | 128 | tsconfig.electron.prod.json 129 | tsconfig.svelte.prod.json 130 | 131 | __pycache__ 132 | -------------------------------------------------------------------------------- /tests/unit-tests/electron/lib/plugins/builder/TypeClassBuilder.spec.ts: -------------------------------------------------------------------------------- 1 | import { type } from "os"; 2 | import {TypeclassBuilder} from "../../../../../../src/electron/lib/plugins/builders/TypeclassBuilder" 3 | import { MediaDisplayConfig, MediaDisplayType } from "../../../../../../src/shared/types"; 4 | import { Typeclass } from "../../../../../../src/electron/lib/registries/TypeclassRegistry"; 5 | import type { ConverterTriple } from "../../../../../../src/electron/lib/registries/TypeclassRegistry"; 6 | 7 | 8 | describe("TypeClassBuilder", () => { 9 | let typeclassBuilder : TypeclassBuilder; 10 | 11 | 12 | beforeEach(() => { 13 | typeclassBuilder = new TypeclassBuilder("test", "number"); 14 | }); 15 | 16 | 17 | it("Test constructor and getters and setters", () => { 18 | expect(typeclassBuilder).not.toBeNull(); 19 | expect(typeclassBuilder["partial"].id).toBe("number"); 20 | expect(typeof typeclassBuilder["partial"].mediaDisplayConfigurator("a")).toBe("object"); 21 | 22 | typeclassBuilder.setDescription("test description"); 23 | expect(typeclassBuilder["partial"].description).toBe("test description"); 24 | 25 | const fn = (fromType: string) => {return "test";} 26 | typeclassBuilder.setFromConverters({"test1": fn}); 27 | expect(typeclassBuilder["partial"].fromConverters).toEqual([["test1", fn]]); 28 | 29 | const fn1 = (toType: string) => {return "test";} 30 | typeclassBuilder.setToConverters({"test2": fn1}); 31 | expect(typeclassBuilder["partial"].toConverters).toEqual([["test2", fn1]]); 32 | 33 | 34 | const configurator: (data: string) => MediaDisplayConfig = (data: string) => { 35 | return { 36 | displayType: MediaDisplayType.TextBox, 37 | props: { content: "Invalid typeclass: Media display not specified" }, 38 | contentProp: null, 39 | } as MediaDisplayConfig; 40 | } 41 | 42 | typeclassBuilder.setDisplayConfigurator(configurator); 43 | expect(typeclassBuilder["partial"].mediaDisplayConfigurator("a")).toEqual(configurator("a")); 44 | 45 | const build : Typeclass = { 46 | id: "number", 47 | description: "test description", 48 | subtypes: [], 49 | mediaDisplayConfig: configurator, 50 | } 51 | 52 | expect(typeclassBuilder["buildTypeclass"]).toEqual(build); 53 | 54 | const converters : ConverterTriple[] = [["test1",typeclassBuilder["partial"].id, fn], [typeclassBuilder["partial"].id,"test2", fn1]]; 55 | expect(typeclassBuilder["buildConverters"]).toEqual(converters); 56 | 57 | expect(typeclassBuilder["build"]).toEqual([build,converters]); 58 | }) 59 | 60 | 61 | 62 | }); -------------------------------------------------------------------------------- /blix-plugins/input-plugin/README.md: -------------------------------------------------------------------------------- 1 | # Input Plugin 2 | 3 | The Input Plugin is a fundamental component of Blix, our AI photo editor. It provides various nodes that enable users to incorporate different types of inputs into the photo editing graph. These inputs can include integers, real numbers, images, and more. 4 | Features 5 | 6 | The Input Plugin offers the following key features: 7 | 8 | Integer Input: Allows users to input integer values into the editing graph. 9 | Real Number Input: Enables users to input real numbers (floating-point values) into the editing graph. 10 | Image Input: Provides the ability to import images as inputs for the editing graph. 11 | Text Input: Allows users to input text or string values into the editing graph. 12 | Color Input: Enables users to specify color values using various color models such as RGB or hexadecimal codes. 13 | 14 | How to Use 15 | 16 | To use the Input Plugin and its corresponding nodes within the Blix photo editor, follow these steps: 17 | 18 | Open the Blix photo editor and create a new project. 19 | Access the editing graph or workspace. 20 | Locate the desired Input Plugin node within the available nodes. 21 | Drag and drop the Input Plugin node into the graph. 22 | Connect the input nodes to the desired locations in the graph. 23 | Configure the Input Plugin node based on the type of input required (number, image, text, or color). 24 | Provide the necessary values or select the appropriate files for the input. 25 | Save the changes and observe the effects on the image or subsequent nodes in the graph. 26 | 27 | Please note that the Input Plugin nodes can be combined with other nodes and plugins within the photo editing graph to create complex and customized effects based on the provided inputs. 28 | Plugin Development 29 | 30 | If you are interested in developing additional functionalities for the Input Plugin or creating your own plugins for Blix, please refer to our developer documentation. It provides comprehensive guidelines and resources to assist you in extending the capabilities of our photo editor. 31 | Feedback and Support 32 | 33 | We highly value your feedback and are dedicated to continuously improving Blix and its plugins. If you encounter any issues, have suggestions for improvement, or require assistance, please don't hesitate to reach out to our support team. We are here to help you make the most out of your photo editing experience with Blix. 34 | 35 | 36 | License 37 | 38 | The Input Plugin is released under the [GNU GENERAL PUBLIC LICENSE] license. Please review the license file for more information regarding the terms of use and redistribution. 39 | 40 | Enjoy using the Input Plugin in Blix, and explore the versatility of incorporating various types of inputs into your photo editing projects! --------------------------------------------------------------------------------