Chris McCormick - News - clojure https://mccormick.cx/news/tags/clojure Chris McCormick - News - clojure en Copyright 2008- Chris McCormick 60 GMT chris@mccormick.cx mccormick.cx/news/ Replacing React With Preact in ClojureScript entries/replacing-react-with-preact-in-clojurescript https://mccormick.cx/news/entries/replacing-react-with-preact-in-clojurescript Today I put together a small test repo to check how much space is saved when replacing React with Preact in a ClojureScript project.

I used npm init shadowfront prtest to get a basic project up and running. This creates a simple one page Reagent app with a button you can click.

(ns prtest.core
  (:require
    [reagent.core :as r]
    [reagent.dom :as rdom]))

(defonce state (r/atom {}))

(defn component-main [_state]
  [:div
   [:h1 "prtest"]
   [:p "Welcome to the app!"]
   [:button {:on-click #(js/alert "Hello world!")}
            "click me"]])

(defn start {:dev/after-load true} []
  (rdom/render [component-main state]
               (js/document.getElementById "app")))

(defn init []
  (start))

I made a build to check the size of the resulting js binary. Then I uninstalled react and react-dom and installed preact@8 and preact-compat. Then I updated shadow-cljs.edn to add the following clause into the :app build:

:js-options {:resolve {"react" {:target :npm :require "preact-compat"}
                       "react-dom" {:target :npm :require "preact-compat"}}

This asks shadow-cljs to alias those React modules to the Preact compatibility layer throughout the whole stack.

I ran make to build the project before and after the change and got the following results:

  1. With React = 292k
    $ du -hs build/js/main.js 
    292K    build/js/main.js
  1. With Preact = 172k
    $ du -hs build/js/main.js 
    172K    build/js/main.js

A 41% size reduction (120k) for a simple one page app seems pretty good. Most of the remaining 172k would be ClojureScript core and libraries such as Reagent.

Update: shadow-cljs lets us generate a build report. Here's a build report with React and then Preact:

React ClojureScript build report

Package Weight %
react-dom @ npm: 18.2.0 128.22 KB 45.8 %
org.clojure/clojurescript @ mvn: 1.11.60 115.71 KB 41.4 %
reagent @ mvn: 1.1.0 22.93 KB 8.2 %
react @ npm: 18.2.0 6.49 KB 2.3 %
scheduler @ npm: 0.23.0 3.96 KB 1.4 %
org.clojure/google-closure-library @ mvn: 0.0-20230227-c7c0a541 1.12 KB 0.4 %
Generated Files 932 0.3 %
src 490 0.2 %

Preact ClojureScript build report

Package Weight %
org.clojure/clojurescript @ mvn: 1.11.60 115.61 KB 71.4 %
reagent @ mvn: 1.1.0 22.94 KB 14.2 %
preact-compat @ npm: 3.19.0 9.24 KB 5.7 %
preact @ npm: 8.5.3 8.18 KB 5.1 %
preact-context @ npm: 1.1.4 2.55 KB 1.6 %
org.clojure/google-closure-library @ mvn: 0.0-20230227-c7c0a541 1.12 KB 0.7 %
Generated Files 931 0.6 %
prop-types @ npm: 15.8.1 801 0.5 %
src 490 0.3 %
]]>
/tags/clojure Sun, 10 Sep 2023 00:42 GMT
ClojureScript UIs in 500 Bytes entries/clojurescript-uis-in-500-bytes https://mccormick.cx/news/entries/clojurescript-uis-in-500-bytes tl;dr: you can generate very small (less than 1k) JS artifacts from ClojureScript with some tradeoffs. I worked out a list of rules to follow and made the cljs-ultralight library to help with this.

Photograph of a glider in the air

Most of the web apps I build are rich front-end UIs with a lot of interactivity. Quite often they are generating audio in real time and performing other complicated multimedia activites. This is where ClojureScript and shadow-cljs really shine. All of the leverage of a powerful LISP with its many developer-friendly affordances (editor integration, hot-loading, interop, repl) brought to bear, allowing me to quickly iterate and build with fewer bugs.

On many projects I find myself also needing a small amount of JavaScript on a mostly static page. An example would be a static content page that has a form with a submit button that needs to be disabled until particular fields are filled. It seems a bit excessive to send a 100s of kilobyte JS file with the full power of Clojure's immutable datastructures and other language features just to change an attribute on one button.

In the past I resorted a tiny bit of vanilla JS to solve this problem. I have now discovered I can use ClojureScript carefully to get most of what is nice about the Clojure developer experience and still get a very small JS artifact.

Here's an example from the Jsfxr Pro accounts page. What this code does is check whether the user has changed a checkbox on the accounts page, and shows the "save" (submit) button if there are any changes.

(ns sfxrpro.ui.account)

(defn start {:dev/after-load true} []
  (let [input (.querySelector js/document "input#update-email")
        submit-button (.querySelector js/document "button[type='submit']")
        initial-value (-> input .-checked)]
    (aset submit-button "style" "display" "none")
    (aset input "onchange"
          (fn [ev]
            (let [checked (-> ev .-target .-checked)]
              (aset submit-button "style" "display"
                    (if (coercive-= checked initial-value)
                      "none"
                      "block")))))))

(defn main! []
  (start))

This code compiled to around 500 bytes. It has since been updated to do a bunch of different more complicated stuff and today it compiles to 900 bytes. I'll talk about some of the special weirdness and language tradeoffs in a second, but first here is the shadow-cljs config I used.

{:builds {:app {:target :browser
                :output-dir "public/js"
                :asset-path "/js"
                :modules {:main {:init-fn sfxrpro.ui/main!}}
                :devtools {:watch-dir "public"}
                :release {:output-dir "build/public/js"}}
          :ui {:target :browser
               :output-dir "public/js"
               :asset-path "/js"
               :modules {:account {:init-fn sfxrpro.ui.account/main!}}
               :devtools {:watch-dir "public"}
               :release {:output-dir "build/public/js"}}}

The first build target :app is for the main feature-rich app which does all the complicated stuff. I am fine with this being a larger artifact as it does a lot of things for the user including realtime generation of audio samples.

The second target :ui creates a file called account.js which is just 900 bytes. It gets loaded on the accounts page which is statically rendered. The reason for two completely separate build targets is otherwise the compiler will smoosh all of the code together and bloat your artifact size. It is easiest just to keep both codebases completely separate.

When compiling I found it useful to have a terminal open watching the file size of account.js so I could see real time when the size ballooned out and figure out which code was making that happen.

So what tricks do we have to use in the code to get the artifact size down? Here is a brief list of rules to follow to stay small. If you break any of these rules your artifact size will balloon.

  1. Do not use any native Clojure data types. Don't use vec or hash-map or list for example. Instead you have to use native JavaScript data structures at all times like #js {:question 42} and #js [1 2 3]. That also means you will have to use aget and aset instead of get and assoc. It means we are dropping immutablity and other data type features.
  2. Do not use Clojure's = operator. I know that sounds mad but what you can use instead is ClojureScript's coercive-=. This function does a native-style surface level JavaScript comparison. This means you have to give up the value based equality comparison you can use on deeply nested datastructures in Clojure.
  3. Do not use certain built-ins like partial. Other clever built-ins like juxt are probably going to be bad for file size too. As far as I can tell it's anything that uses immutable Clojure types under the hood. For the specific case of partial you can use #(...) instead to do what you need.
  4. Use js/console.log instead of print.
  5. Use (.map some-js-array some-func) instead of (map some-func some-js-array)

Generally as far as possible you should stick with native JavaScript calls and data types.

If all of this sounds onerous remember that the idea here is to only do this in situations where you have a small codebase giving the user some small amount of interactivity on a web page. So that's the tradeoff. You still get LISP syntax, editor integration, hot-loading, repl, and lots of other nice Cloure stuff, but you have to forgo immutable datastructures and language features like partial.

I have created a small library called cljs-ultralight to help with the UI side of things. It uses browser calls and returns JS data types. You can use it to perform common UI operations like attaching event handlers and selecting elements, without incurring too much overhead.

The library applied-science.js-interop also works with these techniques. Require it like this: [applied-science.js-interop :as j] and you can use j/assoc! and j/get and friends. Note if you use j/get-in or other functions that take a list argument, you should instead pass a JavaScript array which works well.

Also note that @borkdude has a couple of very interesting projects under way in this space. Check out squint and cherry for more details.

]]>
/tags/clojure Sun, 26 Mar 2023 12:15 GMT
PO Sync Pocket Operator Sync App entries/po-sync-pocket-operator-sync-app https://mccormick.cx/news/entries/po-sync-pocket-operator-sync-app My first app of the year is out, hooray! \o/ It's a simple app to sync pocket operator devices. It outputs a sync signal from your phone which you can plug into your pocket operator's left input to drive it using a 2.5mm male-to-male stereo audio cable. It works well with the p0k3t0 Sync Splitter.

You can get it for Android and iPhone:

PO Sync connected to a phone

This was a fun app to build. I made it because somebody left this review on one of my other apps on Google Play:

Using this for the PO sync feature. I like that most; everything else is okay... I think a great idea would be to make an app with just the PO sync feature and a tempo slider or wheel, plus an on/off

So I knew there was at least one person who wanted this app. It was simple to implement and I got to use my favourite programming languge, ClojureScript. I love it when people need software that I know I can put together quickly. You can get the source code here:

https://github.com/chr15m/PocketSync

2023 is going to be the year of pocket operator apps for Dopeloop and I. I hope to make at least 4 new music apps. I'll post back here when I release them (and also to newsletter + Dopeloop subscribers).

]]>
/tags/clojure Mon, 30 Jan 2023 10:20 GMT
Post An Image To Mastodon Using Nbb entries/post-an-image-to-mastodon-using-nbb https://mccormick.cx/news/entries/post-an-image-to-mastodon-using-nbb Mastodon is a real breeze to develop for. I was able to use nbb (Clojure scripting on Node.js) to post an image using the API in a few minutes. Here's how.

Step 1: Create a new Mastodon app.

Go to Preferences -> Development -> New Application, or visit /settings/applications/new on your Mastodon server.

screenshot.png

Step 2: Store the access token

Once that is done copy the "Access token" and your server's URL. Put them in an env file:

export MASTO_ACCESS_TOK=...
export MASTO_SERVER=...

Get these into your current environment (or use direnv etc.):

. ./env

Step 3: Set up nbb & libraries

echo {} > package.json
npm i nbb masto

Step 4: Create the code

In a file called post-image.cljs put the following code:

(ns post-image
  (:require
    [promesa.core :as p]
    [applied-science.js-interop :as j]
    ["fs" :refer [readFileSync]]
    ["process" :refer [env]]
    ["masto" :refer [login]]))

(p/let [masto (login #js {:url (j/get env :MASTO_SERVER) :accessToken (j/get env :MASTO_ACCESS_TOK)})
        attachment (j/call-in masto [:v2 :mediaAttachments :create] #js {:file (readFileSync (last argv))
                                                                         :description "Test image"})
        status (j/call-in masto [:v1 :statuses :create] #js {:status "Hello this is a test!"
                                                             :visibility "public"
                                                             :mediaIds #js [(j/get attachment :id)]})]
  (js/console.log status))

Step 5: Test it.

npx nbb post-image.cljs some-image.png

Congratulations, you now have an nbb script which can post images to Mastodon. Enjoy!

]]>
/tags/clojure Fri, 30 Dec 2022 01:08 GMT
Un-template Python HTML Library entries/un-template-python-html-library https://mccormick.cx/news/entries/un-template-python-html-library Un-template is a minimal Python library to modify and render HTML. The idea is to start with a pure HTML document, choose the bits you want to modify using CSS style selectors, and then change them using declarative Python datastructures. This means you can use pure Python to replace sections of HTML and do all of the "template logic", similar to how declarative front-end frameworks work.

Install it with pip install ntpl.

Here's an example. It's a Django view function that returns a web page. A file called index.html is loaded, two HTML tags with IDs content-title and content are replaced with new content. A link tag with ID home is replaced completely with a new link tag.

from ntpl import slurp, replace, replaceWith, render

template = slurp("index.html")
faqs = markdown(slurp("FAQ.md"))

def faq(request):
    html = template
    html = replace(html, "#content-title", "FAQ")
    html = replace(html, "#content", faqs)
    html = replaceWith(html, "a#home", render(["a", {"href": "/"}, "home"]))
    return HttpResponse(html)

That's basically all there is to it. You can use it like this instead of Django's native internal templating language.

You can get the source code on GitHub or install it with pip.

It is inspired by Clojure's Enlive and Hiccup, this library uses pyhiccup and Beautiful Soup to do its work.

]]>
/tags/clojure Tue, 02 Jun 2020 11:36 GMT
The Forest Moons of Yendor entries/the-forest-moons-of-yendor https://mccormick.cx/news/entries/the-forest-moons-of-yendor Last week I entered the 7 Day Roguelike Challenge. I used the the px3d game engine with Blender and ClojureScript to build a game prototype.

Screenshot of the game

forest-moon-bear.gif

Screenshot of the game

Screenshot of the game

]]>
/tags/clojure Sat, 14 Mar 2020 05:17 GMT
Linux Conf AU 2020 Talks entries/linux-conf-au-2020-talks https://mccormick.cx/news/entries/linux-conf-au-2020-talks Last week I was on the Gold Coast for Linux Conf AU. I gave two talks:

Piku: git push deployments to your own servers

px3d: a free software browser based pixel 3D nano-engine in ClojureScript

Other talks

I've compiled a list of talks I got a lot of value from which you can find on Twitter.

gold-coast.jpg

Enjoy!

]]>
/tags/clojure Wed, 22 Jan 2020 03:12 GMT
A Clojure-like Lisp That Runs In Bash entries/a-clojure-like-lisp-that-runs-in-bash https://mccormick.cx/news/entries/a-clojure-like-lisp-that-runs-in-bash wordmark.svg screencast.svg

Fleck is a Clojure-like LISP that runs wherever Bash is. Get it here.

This is a little experiment I hacked together from the amazing make-a-lisp project. My hard drive is littered with attempts to make this exact thing several times, and this was the first time I got it working properly.

My friend Crispin reminded me of this idea when we were discussing lightweight Clojure based scripting tools for domain specific tasks. He has made a fantastic Clojure static site generator called bootleg on top of GraalVM. We've both been inspired by the work of Michiel Borkent such as Small Clojure Intepereter and Babashka.

For more Clojure-likes check out awesome-clojure-likes.

Exciting times in the Clojure-verse!

]]>
/tags/clojure Sat, 30 Nov 2019 07:25 GMT
How I built an Excel add-in to export HTML tables entries/how-i-built-an-excel-add-in-to-export-html-tables https://mccormick.cx/news/entries/how-i-built-an-excel-add-in-to-export-html-tables An economist told me the worst part of her job is turning Excel data into HTML tables, so I built an add-in to fix it.

Many software developers probably don't realise that Microsoft Office add-ins these days are simply web pages which run inside of a panel in the UI. I suppose it was to be expected given the trend of the last couple of decades towards web based everything, but it still came as a surprise to me when I had to build one for a job. In my mind Office was still back in the world of COM objects and Delphi and DLLs.

After discovering how easy it is, I decided to do it again for this side project. Here is how I did it.

The plugin (whoops, "add-in") I built is called "Excel to HTML table" and does what it says on the tin. You make a selection of cells, click "copy", and you get a clipboard full of the corresponding HTML code that will render those cells. After that you can paste the code into your text editor and use it in a site's HTML.

Excel to HTML table screencast

Microsoft have some nodejs and yeoman projects to help you get up and running but I'm the sort of developer who likes to roll their own and keep things tight, tidy, and tiny. I like to build things from first principles so that I can understand what is going on at as low a level as possible. Here's what I discovered.

The Microsoft Tutorial has a lot of good info in it, but it's geared towards people using either Node + Yeoman or Visual Studio. If you're a text-editor-and-command-line person like me the best way to get started is just to grab the example .html, .css, and .js snippets from the Visual Studio version.

Get a dev server running

Any local HTTPS server will do. The difficult part is it must be HTTPS, even on localhost, or Word/Excel will refuse to load your add-in. My add-in is almost entirely client-side code and so I could get away with a small Python server using the built-in libraries like this:

from http.server import HTTPServer,SimpleHTTPRequestHandler
httpd = HTTPServer(address, SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, keyfile='selfsigned.key', certfile='selfsigned.cer', server_side=True)
httpd.serve_forever()

As you can see this looks for the .key and .cer files in the local dir, and you can create those with openssl:

openssl req -x509 -newkey rsa:4096 -keyout selfsigned.key -out selfsigned.cer -days 365 -nodes -subj "/C=US/ST=NY/O=localhost/OU=Localhost"

You can do the same thing in nodejs with express if that's your bag by passing the right options to https.createServer:

const server = https.createServer({
    key: fs.readFileSync('./selfsigned.key'),
    cert: fs.readFileSync('./selfsigned.pem')
}, app).listen(8000)

Before you can load your add-in you should make sure your browser has accepted the self-signed cert or the add-in won't load. Do this by browsing to your localhost:8000 server and bypassing the certificate warnings.

If you're debugging in the native Office app instead of Office Online, you will need to do this in Internet Explorer for it to work as far as I can tell.

Manifest validation

add-in.gif

Office finds out about the URL for your add-in using a "manifest" file. This file is XML and pretty fragile. You need to make sure it complies with the spec. Luckily Microsoft have a tool for verifying the add-in on the command line. Install the npm package "office-toolbox": "0.2.1" and then you can run a command like this:

./node_modules/.bin/office-toolbox validate -m ./path/to/manifest.xml

This will report most issues that come up.

In the manifest you can use https://localhost:8000/Home.html and it will point to your local dev server when running.

The Code

The code itself is basically web code. You can use libraries like React and jQuery in your UI. The exception of course is when calling the native APIs. These are exposed through an interface like Excel.run(...) and make heavy use of promises for async. You will often find yourself doing context.load() and then waiting for the promise to resolve before doing the next thing in the document. The API documentation is super useful for figuring out what is possible and how to do it.

Debugging

When it comes to iterating on your code and debugging, by far the easiest way is to use Office Online. This is because it is already in the web browser so debugging works the same way as you are used to - the add-in is just an iframe.

I was even able to do my dev & debugging right at home in Firefox on GNU/Linux!

At some point you will want to debug using an actual copy of Office running on Windows. I used Office 2016 on my wife's computer.

If you are not a Windows developer the following tip will save you a lot of time when it comes to debugging native. It's called "F12 Developer Tools" and it's buried deep inside a Windows subdirectory in C:\Windows\System32\F12\.

What this tool does is attach a "web console" type of debugger to your Office add-in instance running inside Office. You can do stuff like console.log and also see JavaScript errors which are thrown.

Ready to roll

8e9a6781754c869c84202121fb7a2fef.png

Once you've got those pieces in place you should have a basic add-in up and running. After that it's all about referencing the docs to figure out how to do the thing you want your add-in to do.

Submit

Finally when you're ready to ship, you submit your manifest.xml to the App Source "seller dashboard". Expect to wait a few days for the validation team to get back to you, and to have to fix things. This process was useful as they see the software with a fresh pair of eyes and give actionable feedback.

LISP madness

So finally I should mention my LISP obsession. I actually wrote all the code for this plugin in a LISP called Wisp. It's a Clojure-like that compiles to JavaScript and seems quite similar to ClojureScript but with three core differences:

  1. It lacks almost all of the great features & tooling of ClojureScript.
  2. It is closer to being "JavaScript with LISP syntax".
  3. It compiles down very small if you know what you are doing. How small? My final compiled .js bundle for this add-in is just 8.2k non-gzipped.

So that's about it. I hope you got something out of this article on building Microsoft Office plugins using web tech.

Now back to open source dev for me. :)

]]>
/tags/clojure Mon, 30 Sep 2019 12:25 GMT
How To Make Hy-lang More User-Friendly entries/how-to-make-hy-lang-more-user-friendly https://mccormick.cx/news/entries/how-to-make-hy-lang-more-user-friendly Hy(lang) is a LISP-family programming language built on top of Python. You get the rich Python language & library ecosystem, with a LISP syntax and many of the language conveniences of Clojure, such as reader macros for easy access to built in data types. What's not to love?

97bb1a75b5a52e8c6a0a8e7e68cd4b4f.png

I recently found out I have the most GitHub stars for projects written in Hy of any developer worldwide. With this admittedly ridiculous credential in hand I'd like to offer some opinions on the language.

I really like Hy a lot. I prefer writing code in Hy to writing code in Python, and I am writing this post because I want to see Hy do well. I originally wrote this as a list of things in Hy that could possibly be improved, from the perspective of an end user such as myself. Then my friend Crispin sent me this fantastic video by Adam Harvey: "What PHP learned from Python" and I realised that all of the issues I have with Hy stem from the same basic problem that Adam talks about.

Here is the crux of the problem: I've written a bunch of software in Hy over the past few years and often when I moved to a newer point-release of the language all my old code breaks. My hard drive is littered with projects which only run under a specific sub-version of Hy.

gilch[m] It might depend on the Hy version you're using.

I understand that the maintainers of the language, who are hard-working people doing a public service for which I'm deeply grateful, are concerned with making the language pure and clean and good. I understand that languages have to change to get better and they need to "move fast and break things" sometimes. That's all fine and good.

However, I think Adam Harvey's point stands. If you want users to use and love your language:

  • Break things cautiously
  • Maintain terrible things if it makes life better
  • Expand the zone of overlap [backwards compatibility between consecutive versions]

I think if you can maintain backwards compatability you should.

Almost all of the breakages I've experienced between Hy versions could have been avoided with aliasing and documentation. Not doing this backwards compatibility work basically tells your users "don't build things with this language, we don't care about you." I know that is almost certainly not the attitude of the maintainers (who are lovely, helpful people in my experience) but it is the way it comes across as an end user.

Here is a list of things which have changed between versions which blew up my Hy codebases each time I upgraded Hy:

  • Renaming true, false, and nil to the Python natives True, False, and None. These could have been aliased to maintain backwards compabitility.

  • Removing list-comp and dict-comp in favour of the excellent lfor, dfor, and friends. Again, small macros could have aliased the old versions to the new versions.

  • Removing def in favour of setv. A very small macro or maybe even an alias could have retained def as it is pretty much functionally identical from the perspective of an end user.

  • Removing apply, presumably in favour of #**. Support could have been retained for the functional apply. There are situations where a proper apply is favourable.

  • Removing the core macro let. It seems there was an issue where let would not behave correctly with generators and Python's yield statement. A more user-friendly solution than chopping the imperfect let from the default namespace and breaking everybody's code would have been to document the issue clearly for users and leave the imperfect let in. I know it is available in contrib. Moving it to contrib broke codebases.

Having your old code break each time you use a new version is frustrating. It makes it hard to justify using the language for new projects because the maintainance burden will be hy-er (sorry heh).

Some other minor nits I should mention which I think would vastly improve the language:

  • loop/recur should be core. Like let these are available in contrib, but that means you have to explicitly import them. Additionally it would be super nice if they were updated to support the vector-of-pairs declaration style of let and cond etc.

  • Why does assoc return None? This is completely unexpected. If there are performance issues then create an alternative which does what Python dict assignment does (aset?) but it seems unwise to break user expectations so fundamentally.

36583050842532df644f183cc62890e7.png

It is much easier to provide criticism than it is to write working code. I am sorry this is a blog post instead of a pull request, and I hope this criticism is seen as constructive. I want to thank everybody who has worked on hy. I am a huge fan of the language. It is an amazing piece of software and I am very grateful for your work.

]]>
/tags/clojure Thu, 26 Sep 2019 13:20 GMT
Speaking schedule 2019 and beyond entries/speaking-schedule-2019-and-beyond https://mccormick.cx/news/entries/speaking-schedule-2019-and-beyond I've got three conference talks coming up in Perth (Australia), London, and The Gold Coast (Australia). If you're nearby let me know - I would love to buy you a coffee/beer and hear what you're up to.

Security BSides

This Sunday, September 22nd, Perth, Western Australia.

I'm presenting "Bugout: practical decentralization on the modern web." It's a talk about the library I built on top of WebTorrent for building web based decentralized systems.

Bsides Perth Logo

Clojure eXchange

December 2nd-3rd, London, UK.

I'm giving a keynote: a show and tell of the multitude of strange things I've been building with the Clojure[Script] family of programming languages, and how Clojure enables the bad habit of starting way too many projects. I'll also give an update on Thumbelina, the tiny MIDI controller I've been working on with my friend Dimity.

Skills Matter Clojure eXchange

Linux.conf.au

January 13th-17th, Gold Coast, Australia.

I'm talking about Piku, and how it helps you do git push deployments to your own servers. I've made a bunch of contributions to this open source project in recent months. I've personally found a huge productivity gain from being able to deploy internet services without having to think too much, and I'm excited to show others this too.

Linux Australia Logo

]]>
/tags/clojure Wed, 18 Sep 2019 07:50 GMT
ClojureScript Pixel Game Engine With Blender Live-reloading entries/clojurescript-pixel-game-engine-with-blender-live-reloading https://mccormick.cx/news/entries/clojurescript-pixel-game-engine-with-blender-live-reloading Recently I've been hacking on a game engine for infinitelives called px3d.

around.gif

It's built on top of ClojureScript, Blender, and Three.js and it runs in the browser.

One feature I'm particularly happy with is the live-reloading of Blender assets into the game. You hit "save" in Blender and the updates appear in the running game a second later - no need to re-compile or re-load the game.

live-reloading.gif

The way this works is with a background script which watches the assets.blend file. It re-builds the assets.glb whenever it is modified, and writes the hash of the file into assets.cljs. Figwheel pushes changes to the compiled cljs files whenever they change, and there is another bit of code which tells three.js to re-load assets.glb if the hash has changed.

Infinitelives

Infinitelives is the vehicle me and my buddy Crispin use to make games and tooling, mostly for gamejams. The gamejam format is great because it is time-boxed, which means we can periodically do this self-indulgent thing we enjoy without taking too much family or work time.

Gamejams are typically only 48 hours long and so we have learned some good techniques for shipping working code under extreme constraints. A hardcore economy of time, resources, and scope is required.

ClojureScript & Figwheel are perfect for this with their hot-loading of modified code. I built the tight Blender re-load integration for the same reason. Hand drawn graphics consume a lot of time during jams and this should help us really level up on the content side of things.

cda02a53bdeea5ee13ac8d943761a42b.png

If you'd like to find out when we release games and new tools you can sign up to our release notifications on the infinitelives home page or follow us on Twitter.

If you liked this you might also like my Roguelike game web template which you can get on itch.io. Thanks for supporting my work!

]]>
/tags/clojure Sat, 17 Aug 2019 05:35 GMT
TOPLAP 15th Birthday Streamed Algorave entries/toplap-15th-birthday-streamed-algorave https://mccormick.cx/news/entries/toplap-15th-birthday-streamed-algorave As part of the TOPLAP 15th Birthday live-stream I live-coded some algorithmic rave music in Speccy:

Speccy is a browser based environment for live-coding 8-bit algorithmic rave music in ClojureScript.

You can watch the videos of everybody who participated here.

]]>
/tags/clojure Fri, 22 Feb 2019 09:05 GMT
Live-code 8-bit algorave music in the browser with Clojurescript entries/live-code-8-bit-algorave-music-in-browser-with-cljs https://mccormick.cx/news/entries/live-code-8-bit-algorave-music-in-browser-with-cljs

Speccy is a small utililty I built for live-coding chiptune music in the browser with Clojurescript.

You can copy sounds from sfxr.me and paste them in as synth definitions, using code to modify any parameter over time, or start from scratch by building a synth up from basic parameters.

You can paste the following examples into the online editor to try it out:

; blippy synth
(sfxr {:wave :square :env/decay 0.1 :note #(at % 32 {0 24 3 29 7 60 12 52 19 29 28 52})})

; donk bass
(sfxr "1111128F2i1nMgXwxZ1HMniZX45ZzoZaM9WBtcQMiZDBbD7rvq6mBCATySSmW7xJabfyy9xfh2aeeB1JPr4b7vKfXcZDbWJ7aMPbg45gBKUxMijaTNnvb2pw"
      {:note #(or
        (at % 57
          {5 35
           27 34})
        (at % 32
           {0 24
            6 29
            18 21
            26 12}))})

; hi hat
(sfxr {:wave :noise
       :env/sustain 0.05
       :env/decay 0.05
       :vol #(sq % [0.3 0.1 0.2 0.1])})

; snare
(sfxr "7BMHBGCKUHWi1mbucW62sVAYvTeotkd4qSZKy91kof8rASWsAx1ioV4EjrXb9AHhuKEprWr2D4u4YHJpYEzWrJd8iitvr23br2DCGu7zMqFmPyoSFtUEqiM64"
      {:note 36
       :vol #(at % 16
         {4 0.5
          12 0.5})})

The full source code and documentation is available at GitHub.

Enjoy!

]]>
/tags/clojure Fri, 03 Aug 2018 02:14 GMT
Frock: Clojure-flavoured PHP entries/frock-clojure-flavoured-php https://mccormick.cx/news/entries/frock-clojure-flavoured-php Frock is a little experimental tool for writing PHP scripts using Clojure-like LISP syntax.

If you want to see what the code looks like, here's an example which fetches and lists top news items from the Hacker News API.

Some Frock code

Frock could be interesting to you if you are LISP or Clojure programmer writing a web application which is mostly front-end code, but which needs some small amount of server side logic for e.g. proxying, authentication, data persistence etc. and you want this application to be easily deployable by semi-technical users on commodity hosting.

Basically if your target audience is graphic designers, you like Clojure, and your backend requirements are slim, then you might be interested.

Why?

Pythagoras says no to Fava beans

PHP is an old server-side web development language which is simultaneously loathed by software developers everywhere, and also wildly popular and widely deployed. To reconcile this paradox let's take a look at some pros and cons of PHP.

Cons:

  • Ugly language semantics & features.
  • Dubious security record.
  • Much awful legacy code lying around.

Pros:

  • User-friendly app deployments (simply copy files to server).
  • Widely available on internet servers.
  • Mature language and ecosystem.
  • Excellent documentation.
  • Much useful tech bundled ("batteries included").

The pros make PHP quite democratic. It's very easy to install PHP code on widely available, cheap, commodity hosting. It's easy to get started writing PHP applications; the PHP binary comes pre-installed on OSX for example. PHP contains a lot of capabilities by default: zipping files, opening sockets, encryption, command execution.

Frock exists to make the language semantics and features less of a con for brace wrangling LISP heads, whilst retaining the wide deployment surface and other democratic features of PHP.

]]>
/tags/clojure Wed, 27 Jun 2018 08:51 GMT
Frock: Clojure-flavoured PHP entries/frock-clojure-like-php https://mccormick.cx/news/entries/frock-clojure-like-php Frock is a little experimental tool for writing PHP scripts using Clojure-like LISP syntax.

If you want to see what the code looks like, here's an example which fetches and lists top news items from the Hacker News API.

Some Frock code

Frock could be interesting to you if you are LISP or Clojure programmer writing a web application which is mostly front-end code, but which needs some small amount of server side logic for e.g. proxying, authentication, data persistence etc. and you want this application to be easily deployable by semi-technical users on commodity hosting.

Basically if your target audience is graphic designers, you like Clojure, and your backend requirements are slim, then you might be interested.

Why?

Pythagoras says no to Fava beans

PHP is an old server-side web development language which is simultaneously loathed by software developers everywhere, and also wildly popular and widely deployed. To reconcile this paradox let's take a look at some pros and cons of PHP.

Cons:

  • Ugly language semantics & features.
  • Dubious security record.
  • Much awful legacy code lying around.

Pros:

  • User-friendly app deployments (simply copy files to server).
  • Widely available on internet servers.
  • Mature language and ecosystem.
  • Excellent documentation.
  • Much useful tech bundled ("batteries included").

The pros make PHP quite democratic. It's very easy to install PHP code on widely available, cheap, commodity hosting. It's easy to get started writing PHP applications; the PHP binary comes pre-installed on OSX for example. PHP contains a lot of capabilities by default: zipping files, opening sockets, encryption, command execution.

Frock exists to make the language semantics and features less of a con for brace wrangling LISP heads, whilst retaining the wide deployment surface and other democratic features of PHP.

]]>
/tags/clojure Wed, 27 Jun 2018 08:51 GMT
Browser Blockchain in ClojureScript entries/browser-blockchain-in-clojurescript https://mccormick.cx/news/entries/browser-blockchain-in-clojurescript I built a little blockchain-in-a-browser in ClojureScript to help understand the underlying algorithms.

You can simulate a network of peers by opening multiple browser tabs. Each peer can mine blocks and make transactions independently and the resulting blockchain will resolve conflicts correctly across all tabs.

A blockchain works by laying down a chain of blocks of transaction data.

Bitcoin whitepaper SPV

Each block in the chain contains a cryptographic hash with two important properties:

  • It proves a link to the previous block.
  • It proves that difficult computational work has been done.

The proof-of-work is accomplished by iteratively updating a nonce until a low-probability hash is discovered.

These two properties mean a blockchain is digital amber.

Insect embedded in amber

If somebody wants to modify a transaction deep inside the amber it would be very difficult because they would have to re-create every layer of the blockchain by doing as much work as the original process required.

In my browser blockchain the hashing is implemented like this:

(hash-object [timestamp transactions previous-hash nonce])

As you can see the previous block's hash is included in the current block.

The hashing is performed iteratively in a loop until a hash with at least one byte of leading zeroes is found:

(loop [c 0]
  (let [candidate-block (make-block (now) transactions previous-hash new-index (make-nonce))]
    (if (not= (aget (candidate-block :hash) 0) 0)
      (recur (inc c))
      candidate-block)))
]]>
/tags/clojure Wed, 13 Jun 2018 01:30 GMT
Lovelace Day 2017 entries/lovelace-day-2017 https://mccormick.cx/news/entries/lovelace-day-2017 A non-exhaustive list of technologies that I used this year which happen to be built by women:

I feel grateful to these people for enriching technology with their contributions.

]]>
/tags/clojure Wed, 11 Oct 2017 06:58 GMT
Sci Fi UIs in ClojureScript entries/sci-fi-uis-in-clojurescript https://mccormick.cx/news/entries/sci-fi-uis-in-clojurescript I built these sci fi user interfaces using ClojureScript, React, and SVG:

Tap or click to interact with them.

 

 

 

 

 

More here.

Source code here.

]]>
/tags/clojure Sun, 11 Sep 2016 07:13 GMT
OMG Not Another TODO List Application entries/omg-not-another-todo-list-application https://mccormick.cx/news/entries/omg-not-another-todo-list-application My wife and I needed a collaborative shopping list that we could update from our phones. There are proprietary solutions to this but after some research I was surprised to discover that there is no Free Software application that meets the following criteria:

  • Web based.
  • Easy to deploy.
  • Self-hosted & FLOSS.
  • Allows multiple people to update a list.
  • Simple text based format for easy editing.
  • Mobile friendly - "Add to Home Screen" webapp.
  • Satisfies the single use-case of collaborative TODO editing.

Of course I built one with ClojureScript.

Screenshot of 
OMGNATA

We've been using this "in production" for 3 months and so far it fills our need without issue.

  • Authentication can be accomplished with a .htaccess file or similar.
  • The text-file format is designed so that you can edit lists with a text-editor directly if you want to.
  • If you want to support multiple users you can set up two instances in two different folders and symlink the textfile of the list you want to share between them. Each folder can have its own authentication.
  • You can also do other textfile things like make a symlink into a Syncthing folder which enables you to modify your TODO lists on your laptop or server as well as through the web app.

The realtime updating is accomplished via long-polling. Primarily I used this instead of websockets because when it comes to browsers, older tech is more robust to different operating environments than newer tech.

I resorted to using PHP for a very lightweight server backend because it has the property that basically anybody with web hosting is able to upload a PHP script and I think it's good to give software as egalitarian a deployment surface as possible. Luckily it is only 150 lines of not-too-painful PHP.

Click here to get the source and download/install it.

]]>
/tags/clojure Sat, 28 May 2016 01:29 GMT
Zero Asset Game Engine entries/zero-asset-games https://mccormick.cx/news/entries/zero-asset-games Zero Asset Game Mockup

A "zero asset game" is a game that does not use any external art assets.

Game art is instead generated procedurally or by using artifacts of the rendering environment.

The following is a screenshot of a tiny game engine I built a little while ago in ClojureScript.

Tiny CLJS Game Engine Screenshot

The renderer runs on Facebook's React library so it is just a couple of lines of code.

I've spread it over several lines here for readability:

; DOM "scene grapher"
[:div {:id "game-board"}
  (doall
    (map
      (fn [[id e]]
        [:div {:class (str "sprite c" (:color e))
           :key id
           :style (compute-position-style e)
           :on-click (fn [ev] (sfx/play :blip))}
        (:symbol e)])
      (:entities @game-state)))]

The sprites are utf8 characters which are instantiated like this:

(make-entity {:symbol "◍"
              :color 0
              :pos [-20 300]
              :angle 0
              :behaviour behaviour-rock})

The function behaviour-rock here gets called once per frame and returns the new immutable entity-state for the next frame.

When you click on something the blip sound is generated procedurally in the browser using jsfxr.

]]>
/tags/clojure Fri, 11 Dec 2015 12:19 GMT
Fubbles entries/fubbles https://mccormick.cx/news/entries/fubbles Fubbles title screen

This is a video game I made for Scout to help her practice using a gamepad.

Play it! You'll need at least one gamepad and Firefox or Chrome.

  • It's hard to find nice games that fit the search "two player gamepad-enabled couch-co-op suitable for four year olds".

  • Game design for a four year old is quite nuanced. To make a fun game without all of the normal risk reward mechanics basically comes down to "make rude noises".

  • It's 360 lines of ClojureScript, rendered in the browser DOM with React. It took me a handful of evenings over a period of one month to develop.

  • I don't play many games, but the gamepad is probably my favourite human-computer interface.

Fubbles title screen

Source code: https://github.com/chr15m/fubbles/

Update

infinitelives Logo

Fubbles is the first game I have made using the new infinitelives ClojureScript library for game development that my friend Crispin and I have been building.

]]>
/tags/clojure Sun, 08 Nov 2015 11:43 GMT
miniCast web based podcast app entries/minicast-web-based-podcast-app https://mccormick.cx/news/entries/minicast-web-based-podcast-app screenshot.png

miniCast is a self-hosted web app for listening to podcasts.

I wrote it while learning ClojureScript. The back-end API is written in PHP. My friend George came up with the name and design.

]]>
/tags/clojure Sun, 25 Oct 2015 12:30 GMT
Live-coding Blender with Hy entries/live-coding-blender-with-hy https://mccormick.cx/news/entries/live-coding-blender-with-hy

Hy is a Clojure-like LISP that compiles to Python bytecode. Blender is a popular Free and Open Source 3d modelling program. This is a little livecoding experiment I put together with the two of them.

Source code is on GitHub.

]]>
/tags/clojure Wed, 17 Jun 2015 03:35 GMT
OMG Clojure entries/omg-clojure https://mccormick.cx/news/entries/omg-clojure Last weekend was Global GameJam. My buddy Crispin suggested we use Clojure, a non-traditional member of the LISP family running on the Java virtual machine, and its browser-friendly cousin ClojureScript.

Here is the game we built together, using graphics from Kenney.nl:


(click to play)

You can find the source code on GitHub.

A couple of weeks ago I installed Leiningen, the Clojure package/dependency manager, and the VIM plugins, and started practicing.

Literally every night for two weeks now I have been dreaming in parentheses. Writing code has never felt so comfortable. I think I may officially be a LISP convert.

]]>
/tags/clojure Thu, 29 Jan 2015 12:25 GMT