{"id":15288691,"url":"https://github.com/yukiny0811/easy-node-editor","last_synced_at":"2025-04-13T02:13:22.735Z","repository":{"id":62052003,"uuid":"537568271","full_name":"yukiny0811/easy-node-editor","owner":"yukiny0811","description":"Developer-Friendly SwiftUI Node Editor","archived":false,"fork":false,"pushed_at":"2024-05-11T04:34:35.000Z","size":84,"stargazers_count":53,"open_issues_count":6,"forks_count":5,"subscribers_count":5,"default_branch":"main","last_synced_at":"2025-04-13T02:13:16.477Z","etag":null,"topics":["easy-to-use","node-editor","swift-library","swift-package","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/yukiny0811.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-09-16T18:03:00.000Z","updated_at":"2025-03-30T03:02:38.000Z","dependencies_parsed_at":"2024-10-23T13:57:58.865Z","dependency_job_id":null,"html_url":"https://github.com/yukiny0811/easy-node-editor","commit_stats":{"total_commits":64,"total_committers":1,"mean_commits":64.0,"dds":0.0,"last_synced_commit":"1f7b87bb78032f6043a3908f746efd7b2dd4b0d2"},"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yukiny0811%2Feasy-node-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yukiny0811%2Feasy-node-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yukiny0811%2Feasy-node-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yukiny0811%2Feasy-node-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yukiny0811","download_url":"https://codeload.github.com/yukiny0811/easy-node-editor/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248654094,"owners_count":21140236,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["easy-to-use","node-editor","swift-library","swift-package","swiftui"],"created_at":"2024-09-30T15:52:06.355Z","updated_at":"2025-04-13T02:13:22.715Z","avatar_url":"https://github.com/yukiny0811.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EasyNodeEditor\n\n[![CI](https://github.com/yukiny0811/easy-node-editor/actions/workflows/swift.yml/badge.svg?branch=main)](https://github.com/yukiny0811/easy-node-editor/actions/workflows/swift.yml)\n[![Release](https://img.shields.io/github/v/release/yukiny0811/easy-node-editor)](https://github.com/yukiny0811/easy-node-editor/releases/latest)\n[![Swift Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyukiny0811%2Feasy-node-editor%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/yukiny0811/easy-node-editor)\n[![Platform Compatibility](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fyukiny0811%2Feasy-node-editor%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/yukiny0811/easy-node-editor)\n[![License](https://img.shields.io/github/license/yukiny0811/easy-node-editor)](https://github.com/yukiny0811/easy-node-editor/blob/main/LICENSE)\n\n[English](https://github.com/yukiny0811/easy-node-editor/blob/main/README.md) / [Japanese](https://github.com/yukiny0811/easy-node-editor/blob/main/README_JAPANESE.md)\n\n**Still in alpha stage of development!**\n\nEasyNodeEditor is a library for creating node editors with SwiftUI. I am developing this library with the goal of showing as little internal complex code as possible, so that developers can concentrate as much as possible on node creation.\n\n\n## Demo\n\n(v0.1.0)    \n![GIF 2022-09-17 at 8 27 39 PM](https://user-images.githubusercontent.com/28947703/190854305-3e2bb603-fdab-4f53-b7f2-dd587ad39537.gif)\n\n(v0.1.4)    \n![GIF 2022-09-28 at 3 41 15 PM](https://user-images.githubusercontent.com/28947703/192706884-1942c998-88f5-4cbb-82f0-9141ad07e657.gif)\n\n## Usage1 - Standard output node\n\n### Step 1. Create your node\nCreate a class, and inherit it from NodeModelBase class.\n```.swift\nclass YourOutputNode: NodeModelBase {\n}\n```\n\n### Step 2. Create Outputs\nCreate output variables.     \nPut ```@Output``` for output variables.    \nMake sure you put ```@objc``` wrapper to all your output variables.    \nThere are no restrictions on the naming of the variables. Name the variables whatever you want, and the library will automatically use that name to display in the node.    \n```.swift\nclass YourOutputNode: NodeModelBase {\n    @objc @Output var output: Int = 3\n}\n```\n\n### Step 3. Register your node\nRegister your node when you instanciate EasyNodeEditor View.\n```.swift\nstruct ContentView: View {\n    var body: some View {\n        EasyNodeEditor(nodeTypes: [YourOutputNode.self])\n    }\n}\n```\n\n**This is it!**    \nThe EasyNodeEditor Library will create a node like this.\n\n\u003cimg width=\"286\" alt=\"image\" src=\"https://user-images.githubusercontent.com/28947703/190853209-7b8a1844-8bc8-4e20-8bfe-917cc88a2709.png\"\u003e\n\n## Usage2 - Standard input and output node\n\n### Step 1. Create your node\nCreate a class, and inherit it from NodeModelBase class.\n```.swift\nclass YourIONode: NodeModelBase {\n}\n```\n\n### Step 2. Create Inputs and Outputs\nCreate inputs and/or outputs.    \nPut ```@Input``` for input variables, and ```@Output``` for output variables.    \nMake sure you put ```@objc``` wrapper to all your input and output variables.     \nThere are no restrictions on the naming of the variables. Name the variables whatever you want, and the library will automatically use that name to display in the node.    \n```.swift\nclass YourIONode: NodeModelBase {\n    @objc @Input var input: Int = 0\n    @objc @Output var output: Int = 0\n}\n```\n\n### Step 3. Define what happens when input value changes\nOverride ```processOnChange()``` function, and define your process.    \nDon't change input value inside ```processOnChange()```. It will start infinite loop.    \n```.swift\nclass YourIONode: NodeModelBase {\n    @objc @Input var input: Int = 0\n    @objc @Output var output: Int = 0\n    override func processOnChange() {\n        output = input * 5\n    }\n}\n```\n\n### Step 4. Register your node\nRegister your node when you instanciate EasyNodeEditor View.\n```.swift\nstruct ContentView: View {\n    var body: some View {\n        EasyNodeEditor(nodeTypes: [YourOutputNode.self, YoutIONode.self])\n    }\n}\n```\n\n**Very easy!!**    \nThe EasyNodeEditor Library will create a node like this.\n\n\u003cimg width=\"319\" alt=\"image\" src=\"https://user-images.githubusercontent.com/28947703/190853336-2c347cb7-9528-483f-acde-6231a0b487f9.png\"\u003e\n\n## Usage 3 - Standard display node\n\n### Step 1. Create your node\nCreate a class, and inherit it from NodeModelBase class.\n```.swift\nclass YourDisplayNode: NodeModelBase {\n}\n```\n\n### Step 2. Create Inputs\nCreate inputs.  \nPut ```@Input``` for input variables.    \nMake sure you put ```@objc``` wrapper to all your input variables.     \nThere are no restrictions on the naming of the variables. Name the variables whatever you want, and the library will automatically use that name to display in the node.    \n```.swift\nclass YourDisplayNode: NodeModelBase {\n    @objc @Input var input: Int = 0\n}\n```\n\n### Step3. Create View\nOverride ```middleContent()``` function, and define your View.\n```.swift\nclass YourDisplayNode: NodeModelBase {\n    @objc @Input var input: Int = 0\n    override func middleContent() -\u003e any View {\n        Text(\"number is now -\u003e \\(input)\")\n    }\n}\n```\n\n### Step 4. Register your node\nRegister your node when you instanciate EasyNodeEditor View.\n```.swift\nstruct ContentView: View {\n    var body: some View {\n        EasyNodeEditor(nodeTypes: [YourOutputNode.self, YoutIONode.self, YourDisplayNode.self])\n    }\n}\n```\n\n**Amazing!!**    \nThe EasyNodeEditor Library will create a node like this.\n\n\u003cimg width=\"251\" alt=\"image\" src=\"https://user-images.githubusercontent.com/28947703/190853699-0bb3b421-fafb-45ea-a156-4bbec6080ace.png\"\u003e\n\n## Usage 4 - Standard Interactive Node\n\nI assume you have read Usage 1 ~ 3 here.    \nFor interactive nodes, EasyNodeEditor provides ```@Middle``` property wrapper.    \nWhenever the value of the variables with ```@Input``` or ```@Middle``` changes, ```processOnChange()``` function will fire.    \nIf you need a binding object for interaction, use ```binding``` method and pass the KeyPath to get binding object.  \nAfter finished making, register your node as usual.    \n```.swift\nclass YourInteractiveNode: NodeModelBase {\n    @objc @Input var input: Int = 0\n    @objc @Middle var count: Int = 0\n    @objc @Output var output: Int = 0\n    override func processOnChange() {\n        output = input * count\n    }\n    override func middleContent() -\u003e any View {\n        Group {\n            Slider(value: binding(\\YourInteractiveNode.count), in: 0...100)\n        }\n        .frame(minWidth: 200, maxWidth: 200)\n        .fixedSize()\n    }\n}\n```\n\n**Simple!!**    \nThe EasyNodeEditor Library will create a node like this.\n\n![GIF 2022-09-17 at 8 21 30 PM](https://user-images.githubusercontent.com/28947703/190854074-28cd9699-70a1-4dca-b480-6f69f9cb43f6.gif)\n\n## Full Sample Code\n\n```.swift\nimport SwiftUI\nimport EasyNodeEditor\n\nstruct ContentView: View {\n    var body: some View {\n        EasyNodeEditor(nodeTypes: [YourOutputNode.self, YourIONode.self, YourDisplayNode.self, YourInteractiveNode.self])\n    }\n}\n\nclass YourOutputNode: NodeModelBase {\n    @objc @Output var output: Int = 3\n}\n\nclass YourIONode: NodeModelBase {\n    @objc @Input var input: Int = 0\n    @objc @Output var output: Int = 0\n    override func processOnChange() {\n        output = input * 5\n    }\n}\n\nclass YourDisplayNode: NodeModelBase {\n    @objc @Input var input: Int = 0\n    override func middleContent() -\u003e any View {\n        Text(\"number is now -\u003e \\(input)\")\n    }\n}\n\nclass YourInteractiveNode: NodeModelBase {\n    @objc @Input var input: Int = 0\n    @objc @Middle var count: Int = 0\n    @objc @Output var output: Int = 0\n    override func processOnChange() {\n        output = input * count\n    }\n    override func middleContent() -\u003e any View {\n        Group {\n            Slider(value: binding(\\YourInteractiveNode.count), in: 0...100)\n        }\n        .frame(minWidth: 200, maxWidth: 200)\n        .fixedSize()\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyukiny0811%2Feasy-node-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyukiny0811%2Feasy-node-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyukiny0811%2Feasy-node-editor/lists"}