{"id":15873758,"url":"https://github.com/phronmophobic/membrane","last_synced_at":"2025-05-14T19:03:55.737Z","repository":{"id":37493564,"uuid":"246653386","full_name":"phronmophobic/membrane","owner":"phronmophobic","description":"A Simple UI Library That Runs Anywhere","archived":false,"fork":false,"pushed_at":"2025-03-23T21:52:20.000Z","size":33627,"stargazers_count":596,"open_issues_count":40,"forks_count":20,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-03-30T20:01:40.282Z","etag":null,"topics":["clojure","clojurescript","desktop","graphics","graphics-backends","gui","membrane","ui","user-interface","webgl"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/phronmophobic.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":"2020-03-11T18:44:29.000Z","updated_at":"2025-03-23T21:52:23.000Z","dependencies_parsed_at":"2023-10-16T13:55:36.462Z","dependency_job_id":"c86eb05a-92e4-48c2-8aac-fb255db80212","html_url":"https://github.com/phronmophobic/membrane","commit_stats":{"total_commits":935,"total_committers":6,"mean_commits":"155.83333333333334","dds":0.0117647058823529,"last_synced_commit":"f63681e9a519a949269a397ee34135d0c5acb7e3"},"previous_names":[],"tags_count":81,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fmembrane","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fmembrane/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fmembrane/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/phronmophobic%2Fmembrane/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/phronmophobic","download_url":"https://codeload.github.com/phronmophobic/membrane/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247550672,"owners_count":20956985,"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":["clojure","clojurescript","desktop","graphics","graphics-backends","gui","membrane","ui","user-interface","webgl"],"created_at":"2024-10-06T01:06:08.787Z","updated_at":"2025-04-06T21:03:21.501Z","avatar_url":"https://github.com/phronmophobic.png","language":"Clojure","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Membrane\n\n### A Simple UI Library That Runs Anywhere\n\n![Architecture Overview](/docs/overview-01.png?raw=true)\n\nMembrane provides all the tools you need to build a user interface. While all the pieces are built to work together, each piece is optional or can be mixed and matched with other implementations. For example, you could use [your favorite UI framework](https://github.com/phronmophobic/membrane-re-frame-example) and the other layers to reach another platform. Alternatively, you could provide your own ncurses graphics backend and leverage the ui framework and graphics model.\n\nThe three main pieces are:\n\n1. A **UI framework**, `membrane.component`, that provides state management for GUIs\n2. A platform agnostic **model** for graphics and events\n3. Multiple **graphics backends** that provide concrete implementations for #2\n\nFor membrane to run on a platform, the only requirements are:\n1) Drawing implementations for graphical primitives like shapes, text, and images\n2) An event loop that forwards events (eg. mouse clicks, key presses) to membrane and repaints\n\n#### Supported platforms:\n- Mac OSX\n- Linux\n- the web via WebGL\n\n#### Experimental platforms\n- Windows (see skija, swing, and javafx backends)\n- Terminal ([extra docs](/docs/terminal-uis.md),  [example project](https://github.com/phronmophobic/terminal-todo-mvc))\n- virtual dom\n- [skija](https://github.com/JetBrains/skija) (see [example project](https://github.com/phronmophobic/membrane-skija-example))\n- javafx via cljfx (see [example project](https://github.com/phronmophobic/reveal-treemap))\n- iOS via graalvm (see [example project](https://github.com/phronmophobic/grease))\n\n#### Experimental UI framework integrations\n- re-frame (see [example project](https://github.com/phronmophobic/membrane-re-frame-example))\n- fulcro (see [example project](https://github.com/phronmophobic/membrane-fulcro))\n\n#### Links\n\n[Tutorial](/docs/tutorial.md)  \n[API Reference](https://phronmophobic.github.io/membrane/api/)  \n[Documentation Organized by Topic](https://phronmophobic.github.io/membrane/membrane-topics.html)  \n[Styled Text](https://phronmophobic.github.io/membrane/styled-text/index.html)  \n[Examples](https://github.com/phronmophobic/membrane/tree/master/src/membrane/example)  \n[Background and Theory](https://blog.phronemophobic.com/what-is-a-user-interface.html)  \n[Distributing your desktop app](/docs/distribution.md)  \n[Targeting WebGL](/docs/webgl.md)  \nQuestions? Comments? Connect with us on clojurians slack in [#membrane](https://clojurians.slack.com/archives/CVB8K7V50) (join [here](http://clojurians.net/)) or discuss on [twitter](https://twitter.com/phronmophobic).\n\n\u003c!-- Guides   --\u003e\n\u003c!-- Design Philosophy   --\u003e\n\u003c!-- FAQ   --\u003e\n\n## Rationale\n\nMembrane was written because I wanted to build a desktop app with clojure, but I wanted all the cool functional features found in libraries targeting the browser, ie. react, reagent, re-frame, fulcro, etc.\n\nMembrane does not build on top of any existing ui toolkits like Swing, JavaFX, HTML, UIKit, GTK, etc. These toolkits are fundamentally based on an object oriented model and have a deep impedance mismatch with idiomatic clojure code.\n\nViews are values. Components and event handlers are pure functions.\n\nFor more info covering the design of membrane:  \n\n### Talks\n[![Simpler User Interfaces with Membrane](https://img.youtube.com/vi/Mjn92fODdaA/0.jpg)](https://www.youtube.com/watch?v=Mjn92fODdaA)  \n\n### Posts\n\n[What is a User Interface?](https://blog.phronemophobic.com/what-is-a-user-interface.html)  \n[Implementing a Functional UI Model](https://blog.phronemophobic.com/ui-model.html)  \n[Reusable UI Components](https://blog.phronemophobic.com/reusable-ui-components.html)\n\n### Videos\n\n[Interactive Programming with Clojure \u0026 Membrane](https://www.youtube.com/watch?v=ImBji-1bKkc) -  Peter Strömberg  \n\n## Usage\nLeiningen dependency:\n\n```clojure\n[com.phronemophobic/membrane \"0.14.4-beta\"]\n```\n\ndeps.edn dependency:\n\n```clojure\ncom.phronemophobic/membrane {:mvn/version \"0.14.4-beta\"}\n```\n\n### Skia Native Dependencies\n\nTo use the skia backend, the native dependencies that match your target platform are required. If multiple native dependencies are included, it will automatically choose the right one.\n\n```clojure\ncom.phronemophobic.membrane/skialib-macosx-x86-64 {:mvn/version \"0.14-beta\"}\ncom.phronemophobic.membrane/skialib-linux-x86-64 {:mvn/version \"0.14-beta\"}\ncom.phronemophobic.membrane/skialib-macosx-aarch64 {:mvn/version \"0.14-beta\"}\n```\n\n## Built With Membrane\n\n[membrane.term](https://github.com/phronmophobic/membrane.term) - A simple terminal emulator in clojure.  \n[snowball](https://github.com/phronmophobic/snowball) - View the sizes of your dependencies.  \n[grease](https://github.com/phronmophobic/grease) - An example of building a clojure library for iOS with graalvm native-image.  \n[htmltoimage](https://github.com/phronmophobic/clj-cef/tree/main/examples/htmltoimage) - Example of using clj-cef to convert a URL to an image.  \n[browser](https://github.com/phronmophobic/clj-cef/tree/main/examples/browser) - Example of building a very simplistic browser using membrane+skija.  \n[clj-media](https://github.com/phronmophobic/clj-media) - View or create videos and gifs with clojure.  \n[codetogif](https://github.com/phronmophobic/clj-media/tree/main/examples/codetogif) - A basic example of creating gifs using clj-media.  \n[viscous](https://github.com/phronmophobic/viscous) - A visual data inspector/explorer that runs in constant space, time, and screen space.  \n[treemap-clj](https://github.com/phronmophobic/treemap-clj) - An alternative to pprint for generically visualizing heterogeneous, hierarchical data. \n\n## Examples\n\n### A Simple Example without the UI Framework\n\nScreenshot:\n![simple counter](/docs/images/counter1.gif?raw=true)\n\n```clojure\n(ns counter\n  (:require [membrane.java2d :as java2d]\n            [membrane.ui :as ui\n             :refer [horizontal-layout\n                     button\n                     label\n                     spacer\n                     on]]))\n(defonce counter-state (atom 0))\n\n;; Display a \"more!\" button next to label showing num\n;; clicking on \"more!\" will increment the counter\n(defn counter [num]\n  (horizontal-layout\n   (on :mouse-down (fn [[mouse-x mouse-y]]\n                     (swap! counter-state inc)\n                     nil)\n       (button \"more!\"))\n   (spacer 5 0)\n   (label num (ui/font nil 19))))\n\n(comment\n  ;; pop up a window that shows our counter\n  (java2d/run #(counter @counter-state))\n  ,)\n\n```\n\n### Simple Example using `membrane.component` UI Framework\n\nScreenshot:\n![simple counter](/docs/images/counter2.gif?raw=true)\n\n```clojure\n(ns counter\n  (:require [membrane.java2d :as java2d]\n            [membrane.ui :as ui\n             :refer [horizontal-layout\n                     vertical-layout\n                     button\n                     label\n                     on]]\n            [membrane.component :as component\n             :refer [defui make-app defeffect]])\n  (:gen-class))\n\n\n;; Display a \"more!\" button next to label showing num\n;; clicking on \"more!\" will dispatch a ::counter-increment effect\n(defui counter [{:keys [num]}]\n  (horizontal-layout\n   (on :mouse-down (fn [[mouse-x mouse-y]]\n                     [[::counter-increment $num]])\n       (ui/button \"more!\"))\n   (ui/label num)))\n\n(defeffect ::counter-increment [$num]\n  (dispatch! :update $num inc))\n\n(comment\n  ;; pop up a window showing our counter with\n  ;; num initially set to 10\n  (java2d/run (make-app #'counter {:num 10}))\n  ,)\n```\n\nHere's an example of how you can use your `counter` component.\n\nScreenshot:\n![counting counter](/docs/images/counter3.gif?raw=true)\n\n```clojure\n;; Display an \"Add Counter\" button\n;; on top of a stack of counters\n;;\n;; clicking on the \"Add Counter\" button will\n;; add a new counter to the bottom of the stack\n;; \n;; clicking on the counters' \"more!\" buttons will\n;; update their respective numbers\n(defui counter-counter [{:keys [nums]}]\n  (apply\n   vertical-layout\n   (on :mouse-down (fn [[mx my]]\n                     [[::add-counter $nums]])\n       (ui/button \"Add Counter\"))\n   (for [num nums]\n     (counter {:num num}))))\n\n(defeffect ::add-counter [$nums]\n  (dispatch! :update $nums conj 0))\n\n(comment\n  ;; pop up a window showing our counter-counter\n  ;; with nums initially set to [0 1 2]\n  (java2d/run (make-app #'counter-counter {:nums [0 1 2]}))\n  ,)\n```\n\n## Fun Features\n\n\n```clojure\n;; graphical elements are values\n;; no need to attach elements to the dom to get layout info\n(ui/bounds (vertical-layout\n           (ui/label \"hello\")\n           (ui/checkbox true)))\n\u003e\u003e [30.79296875 27.0]\n\n\n;; events are pure functions that return intents which are also values\n(let [mpos [15 15]]\n  (ui/mouse-down\n   (ui/translate 10 10\n                 (on :mouse-down (fn [[mx my]]\n                                   ;;return a sequence of effects\n                                   [[:say-hello]])\n                     (ui/label \"Hello\")))\n   mpos))\n\u003e\u003e ([:say-hello])\n\n\n;; horizontal and vertical centering!\n(java2d/run #(let [rect (ui/with-style :membrane.ui/style-stroke\n                        (ui/rectangle 200 200))]\n             [rect\n              (ui/center (ui/label \"hello\") (ui/bounds rect))]) )\n\n\n;; save graphical elem as an image\n(let [todos [{:complete? false\n              :description \"first\"}\n             {:complete? false\n              :description \"second\"}\n             {:complete? true\n              :description \"third\"}]]\n  (java2d/save-image \"todoapp.png\"\n                   (todo-app {:todos todos :selected-filter :all})))\n\n;; use spec to generate images of variations of your app\n(doseq [[i todo-list] (map-indexed vector (gen/sample (s/gen ::todos)))]\n  (java2d/save-image (str \"todo\" i \".png\")\n                   (ui/vertical-layout\n                    (ui/label (with-out-str\n                                (clojure.pprint/pprint todo-list)))\n                    (ui/with-style :membrane.ui/style-stroke\n                      (ui/path [0 0] [400 0]))\n                    (todo-app {:todos todo-list :selected-filter :all}))))\n\n```\n## Screenshots\n\n![Overview](/docs/images/overview.gif?raw=true) \n\n## More Info\n\nThat's it! For more in-depth info, check out the [tutorial](/docs/tutorial.md).\n\n[Tutorial](/docs/tutorial.md)  \n[API Reference](https://phronmophobic.github.io/membrane/api/)  \n[Documentation Organized by Topic](https://phronmophobic.github.io/membrane/membrane-topics.html)  \n[Styled Text](https://phronmophobic.github.io/membrane/styled-text/index.html)  \n[Examples](https://github.com/phronmophobic/membrane/tree/master/src/membrane/example)  \n[Background and Theory](https://blog.phronemophobic.com/what-is-a-user-interface.html)  \n[Distributing your desktop app](/docs/distribution.md)  \n[Targeting WebGL](/docs/webgl.md)  \nQuestions? Comments? Connect with us on clojurians slack in [#membrane](https://clojurians.slack.com/archives/CVB8K7V50)\n\u003c!-- Guides   --\u003e\n\u003c!-- Design Philosophy   --\u003e\n\u003c!-- FAQ   --\u003e\n\n# License\n\nCopyright 2024 Adrian Smith. Membrane is licensed under Apache License v2.0.\n\n\n\n\n\n\n\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphronmophobic%2Fmembrane","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fphronmophobic%2Fmembrane","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fphronmophobic%2Fmembrane/lists"}