{"id":50897316,"url":"https://github.com/themkat/shade-eval-print-loop","last_synced_at":"2026-06-16T01:03:58.353Z","repository":{"id":339270281,"uuid":"956967441","full_name":"themkat/shade-eval-print-loop","owner":"themkat","description":"SEPL. Inspired by Shadertoy, but powered by Scheme for settings. Dynamically set textures, variables, and other logic that affects the execution.","archived":false,"fork":false,"pushed_at":"2026-02-18T21:46:14.000Z","size":4060,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-02-19T02:13:56.652Z","etag":null,"topics":["glium","glsl","opengl","opengl-shading-language","rust","scheme","shaders"],"latest_commit_sha":null,"homepage":"","language":"Rust","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/themkat.png","metadata":{"files":{"readme":"README.org","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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-03-29T08:31:42.000Z","updated_at":"2026-02-18T21:46:18.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/themkat/shade-eval-print-loop","commit_stats":null,"previous_names":["themkat/shade-eval-print-loop"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/themkat/shade-eval-print-loop","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themkat%2Fshade-eval-print-loop","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themkat%2Fshade-eval-print-loop/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themkat%2Fshade-eval-print-loop/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themkat%2Fshade-eval-print-loop/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/themkat","download_url":"https://codeload.github.com/themkat/shade-eval-print-loop/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/themkat%2Fshade-eval-print-loop/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34386322,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-15T02:00:07.085Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["glium","glsl","opengl","opengl-shading-language","rust","scheme","shaders"],"created_at":"2026-06-16T01:03:56.678Z","updated_at":"2026-06-16T01:03:58.346Z","avatar_url":"https://github.com/themkat.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"[[https://github.com/themkat/shade-eval-print-loop/actions/workflows/build.yml][file:https://github.com/themkat/shade-eval-print-loop/actions/workflows/build.yml/badge.svg]]\n* Shade Eval Print Loop (SEPL)\n#+BEGIN_QUOTE\n[!NOTE]\n\nThis package is experimental, and will continue to evolve. Should be considered alpha quality software at the moment.\n#+END_QUOTE\n\nLive coding and prototyping environment for fragment shaders. Inspired by Shadertoy, but powered by Scheme for dynamically setting uniforms and other values. Dynamically set textures, variables, and other logic that affects the execution.\n\n\nEmacs is the only supported editor from my end, but the program should be able to support all editors that can connect to a process through TCP inferior-lisp style.\n\n[[./screenshot.gif]]\n(screenshot from an Emacs session where we see live reloading of shader, as well as error message printing)\n\n** Features\n- Live-reloading of fragment shaders. Useful for prototyping your materials, raymarching scenes and more.\n- Set uniforms and load textures with CPU side Scheme scripting.\n- Set uniforms that automatically update every 50 milliseconds (or close depending on your system specs). This can be elapsed time, or any other arbitrary code you may want to execute.\n- REPL (read-eval-print-loop) to interact with the shader runtime in Scheme.\n- Emacs mode using comint to easily interact with the running SEPL instance.\n\n  \nWhy not just use Shadertoy? Shadertoy is good, but I want the power of Scheme and Emacs in here as well. Configure it the way I want to. Make the uniforms the names I want to, so I can easily plug the shader into other projects once I'm done.\n\n*** Creators wishlist\nFeatures I might want to introduce:\n- [ ] Noise textures (Perlin noise)\n- [ ] Keyboard listener functions.\n- [ ] Mouse listener functions. Maybe position and/or click? The issue here is how to NOT overload the event input channels. Sending every mouse position without any delays or logic will probably do just that.\n\n** Usage\n*** Build\nNothing fancy.\n#+BEGIN_SRC bash\n  cargo build --release\n#+END_SRC\n\nIf this seems new to you: do you even Rust?\n\n*** Emacs modes install\nFirst, add the emacs directory to your load path. Then you can load =sepl-mode=:\n\n#+BEGIN_SRC emacs-lisp\n  (add-to-list 'load-path \"/path/to/shade-eval-print-loop/emacs/\")\n  (require 'sepl-mode)\n#+END_SRC\n\n*** Usage from Emacs\n**** Connect to running SEPL process\nYou first need to start a SEPL process yourself. This is done by simply running the program compiled above with your fragment shader path as an argument.\n\n\nOnce it is started, you can connect to this process directly from Emacs with =sepl-repl-connect=. Any errors are printed on screen in the SEPL window, but the full error log and outputs can be found in the =*SEPL-STDOUT*= buffer. \n\n**** Start SEPL process \"automatically\"\nYou first need to set the path to the SEPL executable. You will find it in your =target/release/= directory. Example: =/path/to/shade-eval-print-loop/target/release/shade-eval-print-loop=.\n\n#+BEGIN_SRC emacs-lisp\n  (setq sepl-program-bin \"/path/to/shade-eval-print-loop/target/release/shade-eval-print-loop\")\n#+END_SRC\n\nNow simply open your fragment shader of choice! Or an empty one. Simply run the command =M-x sepl-repl-start=. A new window will start, which will be your fragment shader instance. Any errors are printed on screen, but the full error log and outputs can be found in the =*SEPL-STDOUT*= buffer. There is also a Scheme REPL in =*SEPL REPL*= which can be used to evaluate scheme code to make new uniforms, load textures and similar operations. \n\n**** Interact with REPL from Scheme source files\nYou may have a scheme source file you wish to execute code from? Simply open your Scheme file and activate =sepl-mode=. You can now use =C-x C-e= to evaluate s-expression by s-expression, in any order you wish. Or evaluate the entire buffer with =M-x sepl-eval-buffer=. An example file is found in =example/myscheme.scm=.\n\n*** Scheme function interface\nThe SEPL interface provides a few Scheme functions:\n- =(screen-size)=: Get the screen size as a list of two numbers, width and height. (example: =(cadr (screen-size))= to get height).\n- =(matrix row1 row2 row3 row4)=: Creates a 4x4 matrix where each argument is a list of 4 numbers.\n- =(load-texture filename)=: Loads a texture from file. This will be a standard RGBA texture in memory, represented by 4 bytes in GPU memory. Other texture types are planned. Maybe a simple list of numbers could have converter methods for 1D textures? (to be used as lookup tables or arbitrary writes on modern hardware?). Or maybe 3D textures could be fun somehow?\n- =(set-uniform! name value)=: Sets the uniform with =name= (a string) to the value in =value=. SEPL will infer the type automatically. Floats, matrices and textures are currently supported.\n- =(set-dynamic-uniform! name closure)=: Same as for =set-uniform!=, but the value is re-calculated every 50 milliseconds or so (depending on your computer). In this version the argument is a function that takes 0 arguments. You can do arbitrary logic inside of it, but it should not be too compute intensive. Then the program will slow down a lot. You might even make your computer unresponsive until you quit the program, like I did to my Macbook Air M1...\n- =(delete-dynamic-uniform! name)=: Deletes a dynamic uniform. This can be used to free up CPU resources if you have added many uniforms with lots of calculations that are suddenly unused. \n\n\nIf you by any means are interested in this project, feel free to add wishlists in Issues \u003c3 \n\n** Architecture\nSEPL starts a group of threads to do work in parallel. The main thread is the render thread, which handles rendering using OpenGL (through Glium). In addition, a new thread is spawned for the Scheme interpreter logic. All communication with the Scheme interpreter (from outside the SEPL binary) happens through TCP. You can only run one SEPL process at a time, so the port number to connect to is deterministic. It's always 42069 (I'm an adult, lol).\n\n\nIn summary:\n- Main rendering thread\n- Scheme interpreter thread\n  - TCP server thread\n    - Client thread (one for each connecting client)\n\n\nAll communication between threads is done through channels. For evaluating Scheme code, [[https://github.com/mattwparas/steel][the Steel interpreter]] is used. This interpreter cannot be moved between threads. Therefore, each client thread sends the Scheme code to be evaluated via a channel, and receives the reply in a channel. For simplicity, these are simply strings.\n\n\nThe Scheme code has information on the rendering context through channels as well. Updates on screen size (and hopefully soon: key presses and mouse positions) are done this way.\n\n\n** Contributing\nDo you want to contribute (for some reason)? Great! Be kind and constructive, and it will be great to work together :) Feel free to send in PRs with smaller changes. If you have feature requests or want bigger changes, please start by making an issue. We then have a place to discuss it, and you may then work on it without too much wasted effort :) \n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemkat%2Fshade-eval-print-loop","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthemkat%2Fshade-eval-print-loop","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthemkat%2Fshade-eval-print-loop/lists"}