<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>PraxisLIVE</title>
    <description>hybrid visual live programming - rethinking general purpose and creative coding</description>
    <link>https://www.praxislive.org/</link>
    <atom:link href="https://www.praxislive.org/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Wed, 04 Feb 2026 10:40:35 +0000</pubDate>
    <lastBuildDate>Wed, 04 Feb 2026 10:40:35 +0000</lastBuildDate>
    <generator>Jekyll v4.3.3</generator>
    
      <item>
        <title>OPENRNDR in PraxisLIVE</title>
        <description>&lt;p&gt;A lot of focus in recent releases of PraxisLIVE has been on support for custom
roots and base components. This allows for building out a range of components
to use with third-party libraries, all within the context of an individual project.
And this being PraxisLIVE, all aspects being live recodeable as you do so!&lt;/p&gt;

&lt;p&gt;Over the last few weeks, I’ve been exploring &lt;a href=&quot;https://openrndr.org/&quot;&gt;OPENRNDR&lt;/a&gt; -
a fantastic open source creative coding framework that offers an alternative to
the built-in support for Processing inside PraxisLIVE.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/pl-openrndr.png&quot; data-lightbox=&quot;pl-openrndr&quot; data-title=&quot;Live coding OPENRNDR in PraxisLIVE&quot;&gt;&lt;img alt=&quot;Live coding OPENRNDR in PraxisLIVE&quot; src=&quot;/assets/pl-openrndr-sm.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OPENRNDR maps well to a node graph based on similar principles to the core Processing
support, and makes use of a number of libraries already in PraxisCORE. At the same
time, it is written in Kotlin so throws up some interesting challenges for
using it from a Java context (the page on
&lt;a href=&quot;https://kotlinlang.org/docs/java-to-kotlin-interop.html&quot;&gt;Calling Kotlin from Java&lt;/a&gt;
is very useful!).&lt;/p&gt;

&lt;p&gt;I’ve uploaded a repository with the example code discussed here, that can also be
used as a template for exploration. Aside from the logo image, everything is
contained within the two source files for the project and root.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/codelerity/pl-openrndr/&quot;&gt;https://github.com/codelerity/pl-openrndr/&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;All seems to be working well on Linux and Windows at the moment. I’m working on
a fix for the image nodes that seem to be causing issues on macOS. This is also
using OPENRNDR 0.4.4 for now, due to another issue with the latest alphas.&lt;/p&gt;

&lt;h2 id=&quot;project-definition&quot;&gt;Project definition&lt;/h2&gt;

&lt;p&gt;The first file in the project is the
&lt;a href=&quot;https://github.com/codelerity/pl-openrndr/blob/main/OPENRNDR/project.pxp&quot;&gt;project.pxp&lt;/a&gt;
file. In the IDE, this file is edited via the project properties. There are two
key changes for the hub and libraries. The hub definition is changed to load all
roots in a separate JVM launched with the same necessary Java options for the
OpenGL support as in the built-in Processing (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;root:video&lt;/code&gt;) support.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;java-options {
  -XstartOnFirstThread
  -XX:+IgnoreUnrecognizedVMOptions
  -Djava.awt.headless=true
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The libraries section adds three PackageURLs for OPENRNDR artefacts on Maven
Central. These will automatically be resolved and downloaded when you run the
project, using the &lt;a href=&quot;https://github.com/maveniverse/mima&quot;&gt;MIMA&lt;/a&gt; support built in
to PraxisCORE. The various LWJGL dependencies required by OPENRNDR are already
in the runtime and will be resolved from there.&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;libraries {
  &quot;pkg:maven/org.jetbrains.kotlin/kotlin-stdlib@2.1.10&quot;
  &quot;pkg:maven/org.openrndr/openrndr-application-jvm@0.4.4&quot;
  &quot;pkg:maven/org.openrndr/openrndr-gl3-jvm@0.4.4&quot;
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Within the IDE, libraries can be added to a project using the project properties.
See more at &lt;a href=&quot;https://docs.praxislive.org/coding-libraries/&quot;&gt;https://docs.praxislive.org/coding-libraries/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;custom-root-graph&quot;&gt;Custom root graph&lt;/h2&gt;

&lt;p&gt;The second file is the
&lt;a href=&quot;https://github.com/codelerity/pl-openrndr/blob/main/OPENRNDR/openrndr.pxr&quot;&gt;openrndr.pxr&lt;/a&gt;
root graph. All of the integration code to work with OPENRNDR is in this file.
Within the IDE, look at the Shared Code files, the root code (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Edit Code&lt;/code&gt; in the
graph background popup), as well as the code of individual nodes.&lt;/p&gt;

&lt;p&gt;I’m not going to go into every aspect of the integration, but some key things to
look for include -&lt;/p&gt;

&lt;h3 id=&quot;driver-proxy&quot;&gt;Driver proxy&lt;/h3&gt;

&lt;p&gt;A key integration point between OPENRNDR and PraxisCORE happens in the root code
at -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Driver&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Consumer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Boolean&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;processor&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(!&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;active&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;tell&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;self&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;stop&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;c1&quot;&gt;// call graph and render to window&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;RenderTarget&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getRenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDrawer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;colorBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;releaseRenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The &lt;a href=&quot;https://javadoc.io/static/org.praxislive/praxiscore/6.2.0/org.praxislive.code/org/praxislive/code/CodeRootDelegate.Driver.html&quot;&gt;@Driver&lt;/a&gt;
annotation works similarly to &lt;a href=&quot;https://javadoc.io/doc/org.praxislive/praxiscore/latest/org.praxislive.code/org/praxislive/code/userapi/Proxy.html&quot;&gt;@Proxy&lt;/a&gt;
but can only be applied to an interface implementation in a root. PraxisCORE uses
a kind of wrapper injection to wrap the field value in a proxy implementation which
drives the root graph every time a call is made. This way the OPENRNDR rendering
thread can drive the component graph.&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;processor&lt;/code&gt; wrapper (now the value of this field) is passed into the very simple
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHARED.RNDRProgram&lt;/code&gt; implementation of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Program&lt;/code&gt; and called on every render. This
interface could have been &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Runnable&lt;/code&gt; except that we also want to call it when the
rendering exits due to the window closing. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RNDRProgram&lt;/code&gt; is passed to the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;MainThread&lt;/code&gt; executor, ensuring it runs on the startup thread of the JVM,
required for OpenGL rendering on some platforms.&lt;/p&gt;

&lt;h3 id=&quot;data-pipes&quot;&gt;Data pipes&lt;/h3&gt;

&lt;p&gt;The next key integration point is the use of
&lt;a href=&quot;https://javadoc.io/doc/org.praxislive/praxiscore/latest/org.praxislive.code/org/praxislive/code/userapi/Data.html&quot;&gt;Data Pipes&lt;/a&gt;
to pass OPENRNDR’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RenderTarget&lt;/code&gt; surfaces through the node graph. The root code
includes -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@Ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Publish&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Inject&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Pipe&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Inject&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nl&quot;&gt;Data:&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;identity&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;onCreate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;getRenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;onClear&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;clearColor&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;CLEAR&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;onAccumulate&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;DrawerKt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isolatedWithTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDrawer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDrawStyle&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;setBlendMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;BlendMode&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;ADD&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;image&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;src&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;colorBuffer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;));&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}));&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;dst&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;onDispose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;releaseRenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;rt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sink&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ref&lt;/code&gt; to publish an input that can be picked up and connected to by our
output nodes. This in turn is connected to a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Data.Sink&lt;/code&gt; configured to create,
clear and add together render surfaces. Aside from the cache of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RenderTarget&lt;/code&gt;
held elsewhere in the code, this is all that is required to enable a data graph
that includes support for adding multiple inputs and feedback paths.&lt;/p&gt;

&lt;p&gt;The image in the header was created by adding a feedback path through a mix
component on the mouse driven circle -&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/pl-openrndr-feedback.png&quot; alt=&quot;OPENRNDR feedback path&quot; /&gt;&lt;/p&gt;

&lt;h3 id=&quot;custom-component-registration&quot;&gt;Custom component registration&lt;/h3&gt;

&lt;p&gt;The various custom component types defined in Shared Code are registered inside
the root code -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@SupportedTypes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;custom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@CustomType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;openrndr:draw&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDRDraw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDRDraw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TEMPLATE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@CustomType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;openrndr:composite&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDRComposite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;n&quot;&gt;template&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDRComposite&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;TEMPLATE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@CustomType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;openrndr:image&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDRImage&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@CustomType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;openrndr:mix&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDRMix&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@CustomType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;openrndr:out&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDROut&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All the custom component types are defined in Shared Code, and so are fully live
recodeable. The components that are designed to be extended with custom behaviour
have a defined code template as a starting point.&lt;/p&gt;

&lt;p&gt;A cut down version of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;RNDRDraw&lt;/code&gt; type shows how these are defined as subtypes
of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CodeCodeDelegate&lt;/code&gt;. You can see how the data pipe configuration is handled
within the base type, allowing for user nodes to just draw on the surface with
the provided &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Drawer&lt;/code&gt;.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;RNDRDraw&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;CoreCodeDelegate&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;final&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;TEMPLATE&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;
            &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;
              import org.openrndr.*;
              import org.openrndr.draw.*;
              import static SHARED.OPENRNDR.*;

                  @Override
                  public void draw(Drawer d) {
                     \s
                  }
              &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@In&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;In&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RenderTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Subscribe&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;@Inject&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Ref&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Program&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;programRef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Program&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;link&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Data&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;with&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;private&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;process&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;RenderTarget&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;program&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;programRef&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;get&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;();&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;DrawerKt&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;isolatedWithTarget&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;program&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getDrawer&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frame&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;unit&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
                    &lt;span class=&quot;n&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;});&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

    &lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;Drawer&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;

&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Also note the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHARED.OPENRNDR&lt;/code&gt; utilities that are statically imported into the
template. These are used for simple, directly callable functions where OPENRNDR’s 
API is complex to use from Java. It is also used to simplify other aspects of
the Kotlin interaction - eg. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;unit(..)&lt;/code&gt; to wrap consumers that need to return
Kotlin’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Unit.INSTANCE&lt;/code&gt;.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;Currently I’m looking at stabilising some aspects of this and then adding it to
the standard available project templates. In many ways, custom integrations like
this, doing more within projects while keeping the core lightweight, is the future
direction of PraxisLIVE.&lt;/p&gt;

&lt;p&gt;I’m also looking at a different custom library integration with
&lt;a href=&quot;https://avaje.io/jex/&quot;&gt;Avaje Jex&lt;/a&gt; and &lt;a href=&quot;https://htmx.org/&quot;&gt;HTMX&lt;/a&gt;, as a possible
replacement GUI … or even the basis of a fully recodeable editor.&lt;/p&gt;

&lt;p&gt;Any thoughts or questions, please do jump in on the PraxisLIVE discussions at
&lt;a href=&quot;https://github.com/orgs/praxis-live/discussions&quot;&gt;https://github.com/orgs/praxis-live/discussions&lt;/a&gt;,
or reach out some other way.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;
</description>
        <pubDate>Wed, 07 May 2025 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/exploring-openrndr/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/exploring-openrndr/</guid>
        
        
      </item>
    
      <item>
        <title>On Watch</title>
        <description>&lt;p&gt;PraxisLIVE v6.1 saw the first introduction of Watch functions into PraxisCORE,
along with basic UI support in the PraxisLIVE graph editor. These saw further
enhancement in the v6.2 release, and still more is planned.&lt;/p&gt;

&lt;p&gt;A Watch function is a function control for accessing information about a component.
They are somewhat similar to read-only properties, but for data that should only
be calculated on demand, and perhaps asynchronously. They also support extended
metadata, and the option of query arguments to request specific information. Watch
functions are somewhat analogous to watch expressions in a debugger, but within
the context of an active real-time re-codeable system. They can be rewritten as
necessary to explore and expose the state of the running system, while having
minimal overhead when not in use.&lt;/p&gt;

&lt;p&gt;The only required metadata for a Watch function is the media (MIME) type of the
returned data, which is used to select a suitable viewer. The function should also
respond with the data type specified by the media type - usually String for
text-based formats, and PBytes for binary ones. The graph component inside
PraxisLIVE currently provides viewers for PNG and SVG images, as well as plain
text.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/assets/on-watch.png&quot; data-lightbox=&quot;on-watch&quot; data-title=&quot;Various watches in the graph editor&quot;&gt;&lt;img alt=&quot;Various watches in the graph editor&quot; src=&quot;/assets/on-watch-sm.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;defining-watches&quot;&gt;Defining Watches&lt;/h2&gt;

&lt;p&gt;Watch functions can be defined in code using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FN.Watch&lt;/code&gt; annotation. This works
similarly to the generic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@FN&lt;/code&gt; annotation (and under the hood uses the same control
binding), with additional fields for defining the necessary metadata.&lt;/p&gt;

&lt;p&gt;A simple text watch could be defined using -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@FN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Watch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MIME_TEXT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello Watcher!&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;- although as this returns the same text each time, it’s not the most useful of
watches! The watch can be exposed on the graph editor in the IDE using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Expose&lt;/code&gt;
sub-menu in the component popup. The expose feature also supports other types of
control, such as properties. To expose any watch or control by default, use the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@Config.Expose&lt;/code&gt; annotation.&lt;/p&gt;

&lt;p&gt;Another supported media type for watches is SVG. The SVG data should be returned
from the control as a String, and in a format suitable for embedding in HTML5
(the IDE doesn’t use HTML, but other future contexts will). We can write a
component that highlights the state of a boolean property, and relate the watch
to the port, using -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@P&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;boolean&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Config&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Expose&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;watch&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@FN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Watch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MIME_SVG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relatedPort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;status&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;watch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&quot;&quot;
        &amp;lt;svg width=&quot;64&quot; height=&quot;64&quot;&amp;gt;
           &amp;lt;circle cx=&quot;32&quot; cy=&quot;32&quot; r=&quot;32&quot; fill=&quot;COLOUR&quot; /&amp;gt;
        &amp;lt;/svg&amp;gt;
        &quot;&quot;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;replace&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;COLOUR&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;status&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;?&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;green&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;red&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;async-responses&quot;&gt;Async responses&lt;/h2&gt;

&lt;p&gt;Also added in v6.1 was support for asynchronous returns from function controls,
which are very useful for Watches. Asynchronous values in component code are
represented using the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Async&amp;lt;T&amp;gt;&lt;/code&gt; type. An Async is somewhat similar to a standard
Java Future, however it is neither thread-safe nor blocking. It is not possible
to wait on the value, which will be completed by a future actor call. Function
response calls will automatically be generated and sent when the returned Async
completes.&lt;/p&gt;

&lt;p&gt;We might use the standard &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ask()&lt;/code&gt; function to send a call to another control and
return its result, or use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;async()&lt;/code&gt; to generate a response, or manage
internally using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Async&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Async.Queue&lt;/code&gt; fields.&lt;/p&gt;

&lt;p&gt;In the code below we create a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;video:custom&lt;/code&gt; component that can be used to watch
video frames moving through the pipeline. This is a reduced version of the code in
the built-in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;video:composite&lt;/code&gt;. In the watch function itself we return an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Async&amp;lt;PBytes&amp;gt;&lt;/code&gt;
that has been wrapped by the timeout function - this will complete the Async with
error if nothing else does so within the specified time. We cannot initiate the
encoding of the input itself until &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw()&lt;/code&gt; is called. During the drawing method,
a check is made to see if a watch result is pending. A scaled down PNG encoding of
the input is started using &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;write()&lt;/code&gt; which also returns an Async value. The pending
Async is bound to the PNG result and then the field cleared.&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@In&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;PImage&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Persist&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Async&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;PBytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@Override&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;draw&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;!=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mf&quot;&gt;0.25&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Async&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;PBytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;png&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;MIME_PNG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;scale&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;nc&quot;&gt;Async&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;bind&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;png&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;release&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@FN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Watch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MIME_PNG&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;relatedPort&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;in&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nc&quot;&gt;Async&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;PBytes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;watchIn&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;null&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;||&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;failed&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;())&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;timeout&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Async&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&amp;gt;());&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;watchInResponse&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;chaining-queries-and-future-moldability&quot;&gt;Chaining, queries and future moldability&lt;/h2&gt;

&lt;p&gt;Watch functions can accept optional or required queries in the form of maps,
although this feature is not yet exposed in the IDE interface.&lt;/p&gt;

&lt;p&gt;For example, the first text example might be changed to -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@FN&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;Watch&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;mime&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;no&quot;&gt;MIME_TEXT&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;text&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nc&quot;&gt;PMap&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Hello &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getString&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;name&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;&amp;lt;UNKNOWN&amp;gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The Output window in the IDE can be used to call this function -&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&amp;gt; /root/component.text [map name John]
--- Hello John
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Queries will be used in future to support a range of feature such as data ranges
and other formats.&lt;/p&gt;

&lt;p&gt;Another future plan is to support chaining watches, using re-codeable watches in
other components or embedded within the IDE to transform data, to highlight certain
features or adapt media types. Watches are also designed to be used in other contexts
away from the PraxisLIVE IDE, such as in a HTML-based UI or notebook-like interface.&lt;/p&gt;

&lt;p&gt;All in all, Watches provide an open-ended way to explore, understand and
represent what is going on inside your projects as they are running.&lt;/p&gt;
</description>
        <pubDate>Wed, 02 Apr 2025 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/on-watch/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/on-watch/</guid>
        
        
      </item>
    
      <item>
        <title>PraxisCORE / PraxisLIVE v6</title>
        <description>&lt;p&gt;I’m pleased to announce that this month saw the first version 6 release of PraxisCORE
and PraxisLIVE. Somewhat longer in gestation than originally planned (due to things
unrelated to the project), version 6 is a substantial rewrite of some key aspects of how
PraxisCORE works. Expect some rough edges! These will improve as version 6 update
releases happen over the coming months.&lt;/p&gt;

&lt;h2 id=&quot;key-changes&quot;&gt;Key changes&lt;/h2&gt;

&lt;p&gt;Many deprecated and legacy features have been removed, removing things that were 
hindering development of some key new features. With existing projects, make
sure to check for and correct use of deprecated features and code in the latest
version 5 release before attempting to open a project in version 6. Also check the
following section about removed root types.&lt;/p&gt;

&lt;p&gt;The IDE and core now require minimum Java 21. Installers with bundled JDK will now
ship with the latest JDK version as standard. Networked hubs now use &lt;a href=&quot;https://netty.io/&quot;&gt;Netty&lt;/a&gt;
and &lt;a href=&quot;https://github.com/amazon-ion&quot;&gt;Ion&lt;/a&gt; to provide a more robust and structured
communication protocol than was possible with the previous OSC implementation. Much
of the project saving and execution has moved directly into PraxisCORE, which means
that much more of the IDE functionality works by calling Pcl commands. This also opens up
the possibility of alternative editors, or even one day the IDE will be a PraxisCORE
project!&lt;/p&gt;

&lt;p&gt;Other libraries have been updated, including our &lt;a href=&quot;https://github.com/praxis-live/libp5x&quot;&gt;libP5X&lt;/a&gt;
updated to &lt;a href=&quot;https://processing.org/&quot;&gt;Processing 4&lt;/a&gt;. Runtime dependency management
is now based on &lt;a href=&quot;https://github.com/maveniverse/mima&quot;&gt;MiMa&lt;/a&gt; rather than Ivy.&lt;/p&gt;

&lt;p&gt;There are a bunch of other useful changes. Custom roots can now specify use of table
editing rather than the graph editor (we can now make fully recodeable MIDI editors, etc.)
Containers can filter allowed child types and even specify custom types. The weight
parameter on annotations is now optional - eg. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@P int x,y,z;&lt;/code&gt; is now legal syntax! The
ordering is in alphabetical order by default. Examples and custom components are being
updated and added showing the new features.&lt;/p&gt;

&lt;p&gt;The most obvious visual change is the new vector logo, window background actions, and
revamped dashboard. The background actions and dashboard support were contributed to
Apache NetBeans a few months ago, but were really written for PraxisLIVE!&lt;/p&gt;

&lt;p&gt;Finally, the IDE build system has been moved to Maven to match PraxisCORE. Most of the
IDE modules are now published to the central repository as well, allowing use of PraxisCORE
and PraxisLIVE as a platform for other projects. One of which is currently in the works.&lt;/p&gt;

&lt;h2 id=&quot;root-templates--or-wheres-my-osc-midi-tinkerforge-support&quot;&gt;Root templates .. or where’s my OSC, MIDI, TinkerForge support?&lt;/h2&gt;

&lt;p&gt;Version 6 sees the removal of the built-in support for OSC, MIDI and TinkerForge roots.
These features will be supported by using custom root templates and (where necessary)
external libraries in future. A MIDI root template is already included in the custom
components repository. OSC and TinkerForge examples will be added soon. Automatic
migration from old root types is not currently available.&lt;/p&gt;

&lt;p&gt;To use the MIDI template, make sure to install custom components from the dashboard
display. Then use the popup menu on the project, select &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;New / Other...&lt;/code&gt;, and find
the MIDI template in the Roots category.&lt;/p&gt;

&lt;p&gt;If you have any audio, video or other root graph that you want to use in other projects,
you can also use the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Save as Template...&lt;/code&gt; action on any &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.pxr&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/praxis-live/components/blob/master/Roots/MIDI.pxr&quot;&gt;custom MIDI component&lt;/a&gt;
also offers a good demonstration of the new annotations for registering table editing
and custom components - in particular here, where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ControllerComponent&lt;/code&gt; is a subclass of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;CoreCodeDelegate&lt;/code&gt; in the shared code -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@SupportedTypes&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;system&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;kc&quot;&gt;false&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;custom&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nd&quot;&gt;@CustomType&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;type&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;midi:controller&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;base&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;ControllerComponent&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@DisplayTable&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;properties&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;channel&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;controller&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;binding&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;})&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;init&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h2 id=&quot;towards-introspection-and-moldability&quot;&gt;Towards introspection and moldability&lt;/h2&gt;

&lt;p&gt;Over the next few months I’ll be working on various improvements within PraxisCORE and
PraxisLIVE related to introspection, and improved visualization and control over what
is happening in the underlying system. This in part comes from an interest in exploring
how aspects of &lt;a href=&quot;https://moldabledevelopment.com/&quot;&gt;moldable development&lt;/a&gt; and
&lt;a href=&quot;https://clerk.vision/&quot;&gt;live moldable notebooks&lt;/a&gt; can work within the
cyber-physical coding context of PraxisLIVE. Watch this space …&lt;/p&gt;

&lt;p&gt;In the meantime, &lt;a href=&quot;/download/&quot;&gt;download PraxisLIVE v6&lt;/a&gt; and get discovering!&lt;/p&gt;
</description>
        <pubDate>Wed, 27 Nov 2024 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/praxislive-v6/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/praxislive-v6/</guid>
        
        
      </item>
    
      <item>
        <title>ClassLoader trees</title>
        <description>&lt;p&gt;&lt;em&gt;…exploring ClassLoader trees in the &lt;a href=&quot;/blog/a-forest-of-actors/&quot;&gt;forest of actors&lt;/a&gt;…&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;PraxisCORE v5.2 added the ability to share code and types across components (actors)
in a graph. This is a feature that’s been requested for a while, but took some
thinking to work out how to implement. And it’s a key ingredient in how
&lt;a href=&quot;https://www.codelerity.com&quot;&gt;Codelerity&lt;/a&gt; is supporting general purpose programming
usage of the PraxisLIVE suite of tools.&lt;/p&gt;

&lt;p&gt;It’s been possible to add compiled libraries to PraxisCORE projects for a while,
even at runtime, and v5.1 added the ability to
&lt;a href=&quot;https://docs.praxislive.org/coding-libraries/&quot;&gt;include dependencies from Maven Central&lt;/a&gt;.
However, such pre-compiled code is not editable. With the shared code feature
we want to allow components to share features and types, while still allowing that
code to be rewritable safely at runtime like the code of individual components.&lt;/p&gt;

&lt;h2 id=&quot;sharing-code&quot;&gt;Sharing code&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/assets/shared-code.png&quot; data-lightbox=&quot;shared-code&quot;&gt;&lt;img alt=&quot;Shared code in the graph&quot; src=&quot;/assets/shared-code-sm.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Here we have a simple example of shared code usage in PraxisLIVE v5.2 (click to
enlarge). We have a shared &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID&lt;/code&gt; type passed between two components, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-source&lt;/code&gt; and
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-consumer&lt;/code&gt; using data ports. This is somewhat contrived as data ports are usually
used for packets of continuous data. We also have a shared &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Utils&lt;/code&gt; class for utility
methods that can be static imported into our component code.&lt;/p&gt;

&lt;p&gt;The problem to be solved was allowing the shared code to be edited and recompiled
at any point, while ensuring that at any instant, all components in the graph are
linked to the same shared type. We also want to ensure that any changes to shared
code are always valid - not removing types or methods in use by any component.&lt;/p&gt;

&lt;p&gt;Part of addressing these concerns is the limitation that shared code is only shared
across the components within a single graph / root. As within our forest of actors
architecture each root is guaranteed to be only active on a single thread at any
time, we can ensure atomic replacement. It also shields us from having to deal with
the problem of some roots being local and others remote. Shared code is currently
stored as a property of the root component, although in theory we could also support
shared code on sub-containers.&lt;/p&gt;

&lt;p&gt;Implementing shared code involved some rethinking of the ClassLoader hierarchy used
for dynamic code in components, as well as significant changes to the compiler service
and other services used in the updating of component code.&lt;/p&gt;

&lt;h2 id=&quot;a-classloader-tree&quot;&gt;A ClassLoader tree&lt;/h2&gt;

&lt;p&gt;In versions of PraxisCORE prior to v5.2, we have the following (truncated) hierarchy
of ClassLoaders for each component.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;System ClassLoader(s)&lt;/li&gt;
  &lt;li&gt;Library ClassLoader&lt;/li&gt;
  &lt;li&gt;Code delegate ClassLoaders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The system ClassLoaders are obviously the JDK and modules that make up the PraxisCORE
runtime, on modulepath or classpath. The library ClassLoader is used for adding
pre-compiled libraries to a project, or strictly to the RootHub - this is currently
a subclass of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;URLClassLoader&lt;/code&gt; that allows for dynamic addition (not removal), and
there is a single instance that exists for the lifetime of each hub.&lt;/p&gt;

&lt;p&gt;Finally, the code delegate ClassLoaders are lightweight in-memory ClassLoaders that
contain a single iteration of one component’s code. Every code update involves replacing
this ClassLoader and the classes it contains. There can be many active code delegate
ClassLoaders at any one time - one for every component in the graph that has customized
code.&lt;/p&gt;

&lt;p&gt;For more on the use of code delegates to support real-time programming / code hotswap
see the related post on &lt;a href=&quot;/blog/just-in-time-programming&quot;&gt;Just-in-Time Programming&lt;/a&gt;
systems in Java.&lt;/p&gt;

&lt;p&gt;From v5.2 this ClassLoader tree has changed - we now have a shared code
ClassLoader inserted in the hierarchy.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;System ClassLoader(s)&lt;/li&gt;
  &lt;li&gt;Library ClassLoader&lt;/li&gt;
  &lt;li&gt;&lt;em&gt;Shared code ClassLoader&lt;/em&gt;&lt;/li&gt;
  &lt;li&gt;Code delegate ClassLoaders&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That is, &lt;em&gt;some&lt;/em&gt; component ClassLoaders may now have the shared code ClassLoader as a
parent. As mentioned, shared code is currently attached to each root, so we now
have a ClassLoader tree that roughly follows our forest of actors hierarchy -
system (process) → library (root hub) → shared code (root) → code delegate (component).&lt;/p&gt;

&lt;p&gt;Like the code delegate ClassLoaders, the shared code ClassLoader is lightweight and
in-memory (in fact the same type, wrapping a PMap of PByte). Whenever any shared
code type is updated, we have to recompile all the shared code types, and create
a new ClassLoader. This also means that we need to recompile and create new
ClassLoaders for every dependent code delegate - we cannot just reload the delegate
bytecode in a new ClassLoader or we run the risk of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NoSuchMethodError&lt;/code&gt; and other
problems when the shared code changes incompatibly.&lt;/p&gt;

&lt;p&gt;Because of the overhead of recompilation and atomic replacement, the shared code
ClassLoader is kept as an optional element of the hierarchy - only components that
require linking to shared code types have this ClassLoader as a parent. Likewise,
because the code delegate ClassLoader remains separate and has the shared code
ClassLoader as a parent, we can update component code without needing to recompile
and reload any shared code. So, the shared code addition has minimal impact on
runtime code updates that were possible prior to v5.2.&lt;/p&gt;

&lt;h2 id=&quot;compiler-and-context-service-rewrites&quot;&gt;Compiler and context service rewrites&lt;/h2&gt;

&lt;p&gt;PraxisCORE has the concept of Protocols, akin to interfaces exposed by actors, and
Services that are Protocol implementations that can be registered and located by
other actors. There are two services involved in runtime code updates - a service
that can create new CodeContexts (wrappers for CodeDelegate instances loaded from
the above mentioned ClassLoaders) and a service that exposes the Java compiler. Both
work with source and bytecode in memory rather than on disk.&lt;/p&gt;

&lt;p&gt;The context service deals with actual Java references so must be in the same process
(so one will exist in each PraxisCORE process across a distributed hub). The compiler
service can run in a separate process, or even on a separate machine, so there will
usually only be one.&lt;/p&gt;

&lt;p&gt;Prior to v5.2, the compiler service accepted a single Java class body (ie. no
imports, class definition, etc.) and the class name of a type that could be used
to assist in wrapping the class body into valid Java source for compilation. A
legacy of an earlier iteration of compilation where everything was handled in-process,
this had the limitation of not working for full Java sources, or multiple classes.
For v5.2 the compiler service was extended to accept a map of Java sources to compile.
It can also accept an optional map of pre-existing classes to compile against.&lt;/p&gt;

&lt;p&gt;The context service had to be rewritten to handle the wrapping of class bodies itself,
as well as extended to provide a shared code context service that also handles
recompilation and reloading of all dependent component code. This also required
changes to how classes are identified. Assume a component with the following action -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@T&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;logClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;log&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;no&quot;&gt;INFO&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;Class : &quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;getClass&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;().&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;getName&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;());&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In versions prior to v5.2, if you trigger that action you will see -&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;INFO : /data/custom
Class : $
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;From v5.2 you will see something like -&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;INFO : /data/custom
Class : CODEa255.data.custom.code.$
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Every component with custom code prior to v5.2 was backed by a delegate class named
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$&lt;/code&gt; in the default package. This was fine, because a class is actually identified
by both its name and the ClassLoader that loaded it. However, now we want to support
compiling multiple components’ code at the same time, along with our shared code,
we have a problem. Instead, we switch to a package name based on the component address,
with a partially randomized root package (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;a255&lt;/code&gt; here is random hex).&lt;/p&gt;

&lt;p&gt;Going back to the basic patch shown in our image above, whenever the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.code&lt;/code&gt; property
on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-source&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-consumer&lt;/code&gt; receives a new iteration of code, that code will be
sent to the code context service actor. That actor will wrap the code in its context,
adding default imports, package location (eg. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;package CODExxxx.data.id_source.code;&lt;/code&gt;),
and class definition (eg. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;class $ extends CoreCodeDelegate&lt;/code&gt;). This source will
then be passed to the compiler service, along with the previously compiled bytecode
for the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHARED&lt;/code&gt; package. On successful response, the compiled code delegate is
created, wrapped, and passed back to the component.&lt;/p&gt;

&lt;p&gt;On the other hand, when the code of either &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Utils&lt;/code&gt; is updated, the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.shared-code&lt;/code&gt; property will collect all shared code dependent components (in this
case both &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-source&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;id-consumer&lt;/code&gt;) and pass their source along in a task for the
code context service. The service will wrap all component code as before, and add
to a source code map along with all shared code, for passing to the compiler. On
successful receipt, the returned bytecode map is partitioned to create the shared
code parent ClassLoader and each individual delegate ClassLoader. Delegates are
created, wrapped, and passed back in one message for atomic replacement. As the
process is asynchronous, the response is validated against the current graph before
each component is updated.&lt;/p&gt;

&lt;p&gt;Whether or not a component is compiled and loaded against code from the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHARED&lt;/code&gt;
package is currently triggered by a search for the String &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;SHARED.&quot;&lt;/code&gt; in the source
code. This obviously has the possibility for false positives - it might change in
future!&lt;/p&gt;

&lt;h2 id=&quot;a-note-on-data&quot;&gt;A note on Data&lt;/h2&gt;

&lt;p&gt;Data ports allow for continuous data packets to be passed from one component to
another. They are typed by their generic signature, and if that changes then the
configuration is invalidated and all connections are removed. Because class identity
is actually a product of name and ClassLoader, this would have caused all &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID&lt;/code&gt; ports
to be disconnected on every shared code change. In v5.2 data ports have been updated
to retain connections where the type is in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;SHARED&lt;/code&gt; package and has the same
name - atomic code replacement ensures that an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ID.class&lt;/code&gt; reference is always
identical across all components at any one time.&lt;/p&gt;

&lt;h2 id=&quot;inside-the-praxislive-ide&quot;&gt;Inside the PraxisLIVE IDE&lt;/h2&gt;

&lt;p&gt;The PraxisLIVE IDE has been updated to support shared code editing - right-click
on the graph editor to show / add shared types. PraxisLIVE uses Apache NetBeans’
memory file system to allow editing of shared types in the same way as used for
component code. The shared code memory file system is separate to the ones used
for components, but added in to the IDE’s class path support in a similar
hierarchy as used in PraxisCORE for class loading. One difference is that shared
code is always included in the class path, so that completion and code navigation
works, whether the code currently references shared code or not. Imports will be
correctly added on code completion if required, and CTRL-click on shared types or
their members will open them in the editor.&lt;/p&gt;

&lt;h2 id=&quot;next-steps&quot;&gt;Next steps&lt;/h2&gt;

&lt;p&gt;As you might gather from the length of this post, finding the right way to
implement shared code was complicated and took time to get right.
However, it really opens some interesting options for the future as we expand
general purpose coding support in PraxisCORE.&lt;/p&gt;

&lt;p&gt;One initial thing currently being looked at is using shared code to support component
prototypes - effectively a way for multiple components to share the same code, but
keeping some ability to override at a component level.&lt;/p&gt;

&lt;p&gt;Keep an eye on the
&lt;a href=&quot;https://docs.praxislive.org/coding-shared/&quot;&gt;docs for shared code&lt;/a&gt; as these
features evolve.&lt;/p&gt;

&lt;p&gt;If you’re interested in the actual implementations of the processes outlined above,
check out
&lt;a href=&quot;https://github.com/praxis-live/praxiscore/blob/master/praxiscore-code/src/main/java/org/praxislive/code/CodeProperty.java&quot;&gt;CodeProperty&lt;/a&gt;,
&lt;a href=&quot;https://github.com/praxis-live/praxiscore/blob/master/praxiscore-code/src/main/java/org/praxislive/code/SharedCodeContext.java&quot;&gt;SharedCodeContext&lt;/a&gt;,
&lt;a href=&quot;https://github.com/praxis-live/praxiscore/blob/master/praxiscore-code/src/main/java/org/praxislive/code/SharedCodeProperty.java&quot;&gt;SharedCodeProperty&lt;/a&gt;,
&lt;a href=&quot;https://github.com/praxis-live/praxiscore/blob/master/praxiscore-code-services/src/main/java/org/praxislive/code/services/DefaultCodeFactoryService.java&quot;&gt;DefaultCodeFactoryService&lt;/a&gt;,
and
&lt;a href=&quot;https://github.com/praxis-live/praxiscore/blob/master/praxiscore-code-services/src/main/java/org/praxislive/code/services/DefaultCompilerService.java&quot;&gt;DefaultCompilerService&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Thanks for reading!&lt;/p&gt;
</description>
        <pubDate>Mon, 14 Jun 2021 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/classloader-trees/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/classloader-trees/</guid>
        
        
      </item>
    
      <item>
        <title>PraxisCORE / PraxisLIVE v5</title>
        <description>&lt;p&gt;PraxisLIVE and PraxisCORE v5.0 were finally released on September 21st, after a
number of earlier beta releases. This was a few months later than originally
scheduled, but then 2020 really hasn’t been a great year for best laid plans!&lt;/p&gt;

&lt;h2 id=&quot;radical-changes&quot;&gt;Radical changes&lt;/h2&gt;

&lt;p&gt;Version 5 is the most radical change to PraxisLIVE since the move to full
re-codeability between v1 and v2. The extra months afforded by the 2020 lockdown
and postponement of some work have been used to fully implement and extend the
changes discussed in the &lt;a href=&quot;/blog/2020-vision/&quot;&gt;2020 Vision&lt;/a&gt; post.&lt;/p&gt;

&lt;p&gt;There has been a major rewrite of both the core runtime and the IDE. Much legacy
and deprecated functionality has been removed. All of PraxisCORE has now been
rewritten around the new base actor system introduced in part in 4.4.0.
PraxisCORE is now built on top of the Java module system, rather than the 
NetBeans platform (the PraxisLIVE IDE is still based on
&lt;a href=&quot;https://netbeans.apache.org/&quot;&gt;Apache NetBeans&lt;/a&gt;). The build for PraxisCORE has
been moved to Maven, and individual modules are deployed to central for re-use
from other projects.&lt;/p&gt;

&lt;p&gt;Both PraxisLIVE and PraxisCORE now require at least Java 11, and fully embrace
newer Java features. An open-source Java 11 JDK from
&lt;a href=&quot;https://adoptopenjdk.net/&quot;&gt;AdoptOpenJDK&lt;/a&gt; is now included in all binary bundles,
including in the new AppImage for Linux, although the standalone zip is still
available.&lt;/p&gt;

&lt;p&gt;PraxisLIVE now supports running multiple projects at once. Distributed hub
support has moved from the IDE into PraxisCORE, and is configured separately for
each project - the default configuration will run audio and video roots
in separate Java processes. Additional processes are now started when required
rather than automatically. The master/slave terminology has been removed, both
because it’s problematic and because it no longer fully reflects the technical
roles different processes can play.
&lt;a href=&quot;https://docs.praxislive.org/projects/#hub-configuration&quot;&gt;Read more about configuring project hubs&lt;/a&gt;
in the docs.&lt;/p&gt;

&lt;p&gt;The PraxisCORE runtime is now included in the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;praxiscore&lt;/code&gt; folder inside the
IDE installation. It can be copied out and run from the CLI for networking or
project running, or embedded inside a project to make it standalone.&lt;/p&gt;

&lt;p&gt;Video / OpenGL visualization is now based on
&lt;a href=&quot;https://github.com/praxis-live/libp5x/&quot;&gt;libp5x&lt;/a&gt;, our modularized fork of
Processing that uses &lt;a href=&quot;https://www.lwjgl.org/&quot;&gt;LWJGL&lt;/a&gt; for rendering. Audio
support has now moved to our &lt;a href=&quot;https://github.com/jaudiolibs/pipes&quot;&gt;Pipes v2&lt;/a&gt;
library, which includes all the unit generators previously in PraxisLIVE itself.
Both of these libraries are published separately via Maven for use elsewhere.&lt;/p&gt;

&lt;h2 id=&quot;rethinking-coding&quot;&gt;Rethinking coding&lt;/h2&gt;

&lt;p&gt;One thing you might notice on the website and elsewhere is a new tagline for the
overall project - &lt;em&gt;rethinking general purpose and creative coding&lt;/em&gt;. PraxisLIVE
will always aim to be a great programming system for creative coding, but one
key aspect of founding &lt;a href=&quot;https://www.codelerity.com/&quot;&gt;Codelerity&lt;/a&gt; to support
PraxisLIVE’s development is to explore opportunities for use outside of this
sector.&lt;/p&gt;

&lt;p&gt;PraxisCORE’s move to Java modules and the publishing of individual modules is a
part of this. Version 5 also lays the groundwork for a range of additional
features to come over the next months that will benefit everyone. These include
proper dependency management for improving third-party library usage (such as Maven
dependencies), support for shared (and still editable) code across components,
better support for working with embedded boards and electronics (and Raspberry
Pi), and improving CLI and code editing support away from the IDE.&lt;/p&gt;

&lt;p&gt;By version 6 it may be that all specific features (audio, video, etc.) get
automatically downloaded only when required. But throughout version 5 expect
additions that concentrate on what PraxisCORE and PraxisLIVE do best -
rethinking the coding process, and bringing the best aspects of Erlang,
Smalltalk and Extempore into the Java world.&lt;/p&gt;

&lt;p&gt;Get it while it’s hot - &lt;a href=&quot;/download/&quot;&gt;download PraxisLIVE v5&lt;/a&gt; now!&lt;/p&gt;
</description>
        <pubDate>Fri, 02 Oct 2020 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/praxislive-v5/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/praxislive-v5/</guid>
        
        
      </item>
    
      <item>
        <title>2020 Vision</title>
        <description>&lt;p&gt;So, with a pun too obvious to ignore (if ironic given my eyesight!), let’s take a
look ahead at 2020 plans for PraxisLIVE and PraxisCORE. As well as talk a little
about the founding of Codelerity Ltd.&lt;/p&gt;

&lt;h2 id=&quot;objects-in-the-rear-view-mirror&quot;&gt;Objects in the rear view mirror&lt;/h2&gt;

&lt;p&gt;In some ways, 2019 seemed a quiet year on the PraxisLIVE front. We had
&lt;a href=&quot;https://github.com/praxis-live/praxis-live/releases&quot;&gt;three minor releases&lt;/a&gt;
which brought some useful new features, including support for Java 11. But there
were no major changes, at least on the surface. Behind the scenes, however, some
big changes have been afoot as preparations have been made for the upcoming v5.&lt;/p&gt;

&lt;p&gt;2019 had some enjoyable PraxisLIVE related talks and workshops too, including trips
to ICLC in Madrid, FOSDEM in Brussels, and LGM in Saarbrucken; JUG talks in
Birmingham, Manchester, Dublin and London; and the really fun &lt;em&gt;Code2Create&lt;/em&gt;
workshop in Andover.&lt;/p&gt;

&lt;p&gt;During 2019 I was also involved as a PMC member of the 
&lt;a href=&quot;https://netbeans.apache.org/&quot;&gt;Apache NetBeans&lt;/a&gt; community, fleshing out the new 
quarterly release plan, and release managing two Apache NetBeans releases (11.1
and 11.2). NetBeans is an essential part of PraxisLIVE, which is now based on
Apache NetBeans 11.1 - an update that has allowed us to run on and support
Java 11+.&lt;/p&gt;

&lt;h2 id=&quot;jump-to-light-speed&quot;&gt;Jump to light speed&lt;/h2&gt;

&lt;p&gt;Aside from occasional paid projects and workshops, PraxisLIVE has mostly been a
spare-time (if sometimes all consuming) pursuit. In the decade leading up to 2017,
most of my paid work was, like many others, in web applications and services.
Since 2017 I’ve been trying to concentrate more on work related directly to
PraxisLIVE in order to spend more time on it, the majority of which to-date has
been related to GStreamer.&lt;/p&gt;

&lt;p&gt;In mid-2019 I set up &lt;a href=&quot;https://www.codelerity.com/&quot;&gt;Codelerity Ltd.&lt;/a&gt;. We will be
offering consultancy and development work around real-time systems, real-time
programming, media, embedded and tools on the JVM. This will expand on the recent
consultancy work I have been doing, as well as investing in other use cases for
aspects of PraxisCORE and PraxisLIVE. For example, we’ve recently been looking
at low-latency video in machine learning, as well as development for embedded
devices. If you think we might be able to help with something,
&lt;a href=&quot;https://www.codelerity.com/contact/&quot;&gt;get in touch&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;/community/&quot;&gt;Donations to support PraxisLIVE development&lt;/a&gt; are, and will remain,
much appreciated. However, they are not enough to sustain the amount of time I’d
like to be putting in. Assuming all goes to plan, Codelerity will allow me to
spend more time investing in PraxisLIVE development, while ensuring it remains
free, and continues with its creative and innovative approach to coding.&lt;/p&gt;

&lt;h2 id=&quot;number-5s-alive-ish&quot;&gt;Number 5’s alive(-ish)&lt;/h2&gt;

&lt;p&gt;PraxisLIVE, or more specifically the PraxisCORE runtime, is undergoing some
radical restructuring for v5. So radical we’ve switched to a completely
&lt;a href=&quot;https://github.com/praxis-live/praxiscore&quot;&gt;new repo&lt;/a&gt;! We’re moving away from
the NetBeans module system and fully embracing Java modules, and Java 11 will be
the baseline supported Java version. We’re also moving to the Maven build system,
and all modules that make up PraxisCORE will be published to Maven Central for
reuse in other projects.&lt;/p&gt;

&lt;p&gt;A new, simplified actor and component base was added in 
&lt;a href=&quot;https://github.com/praxis-live/praxis-live/releases/tag/v4.4.0&quot;&gt;v4.4.0&lt;/a&gt;,
initially just for data roots and some of the built-in Hub services. These will
now form the basis for other modules, allowing a large amount of legacy code
from the v1 days to be removed. The code is also being restructured to remove
unwanted dependencies between modules, remove the need for Processing except in
the OpenGL renderer, and replace all NetBeans usage in PraxisCORE. Many of these
changes support Codelerity’s plans for other use cases for these modules, while
also offering key benefits in PraxisLIVE.&lt;/p&gt;

&lt;p&gt;Unfortunately, Processing still has some issues with Java 11, as does JOGL, so
I’m currently working on forking Processing and tidying up the
&lt;a href=&quot;https://www.lwjgl.org/&quot;&gt;LWJGL&lt;/a&gt;-based OpenGL renderer. These changes should give
us a better performing OpenGL pipeline, and the forked modules will also be
published to Maven Central for other projects to make use of. Of course, I’d
prefer to see those changes accepted upstream, but we shall see.&lt;/p&gt;

&lt;p&gt;Changes in the PraxisLIVE IDE for v5 will not be as radical, but there will be
some key changes to support changes in the runtime. Projects will now run in
separate processes from the IDE, and there will be a Hub per project. This will
allow multiple projects to be run independently, removing a confusion for new
users. Distributed hub settings will also be moved to each project, and also
be taken into account when the project is run from the command line or as a
standalone application. Support for exporting standalone applications will also
be improved.&lt;/p&gt;

&lt;p&gt;PraxisLIVE v5 should be released sometime in the next few months, although as
with all these things we’ll release when it’s ready! Not every change is
decided yet - if you have things you’d like to see then
&lt;a href=&quot;https://github.com/praxis-live/support/issues&quot;&gt;open an issue&lt;/a&gt;, or
&lt;a href=&quot;/community/&quot;&gt;join in the conversation&lt;/a&gt;.&lt;/p&gt;
</description>
        <pubDate>Thu, 09 Jan 2020 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/2020-vision/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/2020-vision/</guid>
        
        
      </item>
    
      <item>
        <title>Just-in-Time Programming</title>
        <description>&lt;p&gt;So, a few thoughts on the trials and tribulations of building a just-in-time programming
system in Java. But wait, isn’t Java a JIT-compiled language anyway? Job done … 
next post … no, wait.&lt;/p&gt;

&lt;p&gt;Firstly, let’s be clear, Java isn’t a JIT-compiled language, otherwise what’s javac for?!
It (usually) has JIT-compiled bytecode, and that makes it a useful tool for this
endeavour, but that doesn’t get us from source code to running code.
And anyway, there’s far more to a useful just-in-time programming system
than just getting code running. Let’s be clear about some requirements here.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;we want a system that allows us to write and rewrite code as it’s running, at
any point in the lifecycle (no development vs production distinction)&lt;/li&gt;
  &lt;li&gt;we want a system that allows us to replace code atomically &lt;em&gt;at the right time&lt;/em&gt;
in order to provide glitch-free updates during real-time processing&lt;/li&gt;
  &lt;li&gt;we want a system that allows us to easily and correctly manage resources added
 or removed at runtime&lt;/li&gt;
  &lt;li&gt;we want a system that handles errors gracefully and carries on running while we fix
the problem&lt;/li&gt;
  &lt;li&gt;and, we want a system that can persist its current state so that we can carry 
on running from where we left off at at a later date.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id=&quot;code-as-data&quot;&gt;Code as Data&lt;/h2&gt;

&lt;p&gt;PraxisCORE is a &lt;a href=&quot;/blog/a-forest-of-actors/&quot;&gt;forest-of-actors runtime&lt;/a&gt; for real-time
programming, designed to bring aspects of Erlang, SmallTalk and Extempore into the
Java world. Like Erlang, it allows for the code of individual actors to be hot replaced
at runtime. Unlike Erlang, and as far as I know unique amongst at least Java actor
frameworks, is that actors accept their new behaviour as a message containing Java
source code. This is great for providing SmallTalk like introspection and persistence,
ensuring formatting and comments remain part of the persisted image. It also gives
us a form of code as data - not full-on Lisp like homoiconicity, but still giving
us powerful metaprogramming capabilities.&lt;/p&gt;

&lt;h2 id=&quot;got-code-now-what-no-right-of-repl&quot;&gt;Got code, now what? No right of REPL.&lt;/h2&gt;

&lt;p&gt;Some people who’ve seen PraxisLIVE in action assume the runtime uses a form of hot code
reloading like the JVM’s built-in agent based HotSwap mechanism; others that it’s
using JShell, the Java REPL. The truth is that neither are suitable or can meet
all of the requirements outlined above.&lt;/p&gt;

&lt;p&gt;Java’s built-in HotSwap mechanism allows for reloading classes at runtime. However,
it is limited to changes to code inside method bodies, without allowing for structural
changes such as adding/removing methods, fields, or (often) lambdas. There are a
number of projects that remove some of those limitations, such as
&lt;a href=&quot;https://zeroturnaround.com/software/jrebel/&quot;&gt;JRebel&lt;/a&gt; and
&lt;a href=&quot;http://hotswapagent.org/&quot;&gt;HotSwapAgent/DCEVM&lt;/a&gt;, but they’re a bit hacky, and in the latter
case require a patched JVM. They offer some utility in development, but not the level
of stability we’re looking for. And there’s part of me that thinks that if it’s not
stable enough for production use, it’s not &lt;em&gt;really&lt;/em&gt; stable enough for development.&lt;/p&gt;

&lt;p&gt;Reloading classes with these HotSwap mechanisms has other problems that don’t meet
our requirements above. Firstly we need to control exactly when the code change
occurs (not in the middle of processing something), and hook in to the code change to
correctly manage resources that are added or removed. But another problem is handling
our requirement for a system that can persist its current state. It is too easy with
this technique to remove code that is required, such as code that initializes 
a field. You get to a point where the project is running great, but when you stop
and re-run it, it all goes boom!&lt;/p&gt;

&lt;p&gt;So, the PraxisCORE runtime eschews class reloading, in fact for something much simpler.
It’s actually not hard to compile and execute new bytecode in a running Java application
by using a compiler interface and a custom classloader, and there are various
applications that do this. A (perceived) downside of this approach is that a class
in Java is defined not only by its name, but also the classloader that loads it.
Using this approach we are not changing an existing class but creating a whole new one.
But by careful use of our actor framework, and other common Java patterns like dependency
injection, we can turn this limitation to our advantage in delivering our requirements.&lt;/p&gt;

&lt;p&gt;The JShell Java REPL also bears some similarity with how PraxisCORE works, including
similar contextual wrapping of Java source code in a class context with additional
imports. However, PraxisCORE does not use this either, and not only because it predates
JShell! A problem with REPLs is that they embed an iterative design process, and
potentially the only way to get back to a guaranteed state is to rerun the entire code
history. The PraxisCORE runtime and API is designed such that &lt;em&gt;code replacement is
transactional&lt;/em&gt;, where the code and data at any point forms the entire picture.&lt;/p&gt;

&lt;h2 id=&quot;behaviour--state--identity&quot;&gt;Behaviour | State | Identity&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/assets/code-objects.png&quot; alt=&quot;Diagram of CodeComponent, CodeContext and CodeDelegate&quot; /&gt;&lt;/p&gt;

&lt;p&gt;A standard Java object generally combines three things - behaviour, state and identity.
A re-codeable actor in PraxisCORE needs to breaks these things apart, with a separate
class for each.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;CodeDelegate&lt;/strong&gt; is the base class that the user’s code (automatically) extends, providing
the behaviour aspect of actor. There are different CodeDelegate base classes for most
base actor types, providing access to useful functions and fields, as well as optional
or required method hooks (eg. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;init()&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;update()&lt;/code&gt;).&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CodeContext&lt;/strong&gt; is the class that manages state for our actor. There are currently
different CodeContext subtypes for each CodeDelegate subtype, and an instance of 
a CodeContext wraps each CodeDelegate instance. The CodeContext connects annotated
fields and methods in the CodeDelegate to the wider actor system, injecting state
and managing resources across context changes and for persistence. NB. this means
that although the CodeContext manages state, the schema for that state along with
internal updates are controlled by the user’s code.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CodeComponent&lt;/strong&gt; is the simplest of the three, and provides the identity functionality.
It is the one class that exists throughout the lifecycle of an actor. It wraps
a CodeContext and a mechanism for replacing it, but otherwise delegates all aspects
of the component (actor) interface to the installed context. Unlike the other classes,
there is currently only one type of CodeComponent used for all actors.&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;CodeConnector&lt;/strong&gt; is an auxillary class, again currently one per CodeDelegate
type, that separates out the functionality of introspecting on the user’s code 
and writing the “recipe” for the CodeContext.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The above allows a basic &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;core:custom&lt;/code&gt; actor to accept the following simple snippet of code
and transform itself into an actor capable of adding a value to numbers it receives, as
well as automatically persisting that value -&lt;/p&gt;

&lt;div class=&quot;language-java highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;nd&quot;&gt;@P&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;nd&quot;&gt;@Out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;nc&quot;&gt;Output&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;;&lt;/span&gt;

&lt;span class=&quot;nd&quot;&gt;@In&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;in&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;double&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;out&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;na&quot;&gt;send&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;x&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Full information on writing custom components (actors), and all the base types and 
annotations available, is at &lt;a href=&quot;https://docs.praxislive.org/coding/&quot;&gt;https://docs.praxislive.org/coding/&lt;/a&gt;&lt;/p&gt;

&lt;h2 id=&quot;compiler-as-a-service&quot;&gt;Compiler as a service&lt;/h2&gt;

&lt;p&gt;The PraxisCORE actor framework provides a service discovery mechanism, by which
actors can request the addresses of other actors providing particular services.
When an actor receives new source code, it does not handle turning this into a
CodeContext itself. This is definitely not a real-time safe operation! Instead it
looks up a service that can instantiate a CodeContext for it, based on the provided
source code and base type.&lt;/p&gt;

&lt;p&gt;If the CodeContext service does not have previously compiled bytecode for this source
and base type, it may look up another service that provides access to the Java
compiler. The compiler service was split out from the CodeContext service in
PraxisLIVE v3 so that the compiler part can optionally be run in a separate process, or
even on a different machine, using the
&lt;a href=&quot;https://docs.praxislive.org/distributed-hubs/&quot;&gt;distributed hubs&lt;/a&gt; functionality.
This is particularly useful where garbage collection is an issue for low latency
pipelines.&lt;/p&gt;

&lt;p&gt;The CodeContext service handles all introspection on the user’s code, and a possible
previous iteration, which may include instantiating necessary resources or creating
the instructions to migrate from one iteration of code to the next. A key benefit of not
changing the existing class (eg. HotSwap) is that we can achieve all this in the
background while the existing code continues to execute.&lt;/p&gt;

&lt;p&gt;When the CodeContext is ready, it is returned within an actor system message. The context
is already in such a state that it can be atomically replaced inside the CodeComponent with
minimal overhead, even in a low-latency pipeline (eg. real-time DSP). And despite
the various different services involved, possibly across processes, the efficiency
of the messaging system and the use of a memory-based filesystem for the
compiler (source and bytecode never on disk) means that the time between enacting
a change in the editor and that change being apparent is almost imperceptible.&lt;/p&gt;

&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Hopefully this has been a useful brief(ish) exposition of how &lt;a href=&quot;/core&quot;&gt;PraxisCORE&lt;/a&gt; achieves
its goal of being a just-in-time programming runtime. If you’ve got any questions,
jump on the &lt;a href=&quot;/community&quot;&gt;mailing list, chat or otherwise send me a message&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Otherwise, go have fun with it or come get involved …&lt;/p&gt;

&lt;p&gt;… and &lt;a href=&quot;https://donorbox.org/praxislive&quot;&gt;donations (Donorbox with PayPal or card)&lt;/a&gt;
are always appreciated!&lt;/p&gt;
</description>
        <pubDate>Mon, 31 Dec 2018 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/just-in-time-programming/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/just-in-time-programming/</guid>
        
        
      </item>
    
      <item>
        <title>A Forest of Actors</title>
        <description>&lt;p&gt;The recent release of PraxisLIVE v4 saw a focus on relicensing the &lt;a href=&quot;/core/&quot;&gt;PraxisCORE&lt;/a&gt; runtime, and promoting its standalone usage as a platform for media processing, data visualisation, sensors, robotics, IoT, and lots more. PraxisCORE is a modular runtime for cyberphysical programming, supporting the real-time coding of real-time systems. Absolutely essential to this is its asynchronous, shared-nothing message-passing system - a forest-of-actors evolution of the standard &lt;a href=&quot;http://en.wikipedia.org/wiki/Actor_model&quot;&gt;actor model&lt;/a&gt; with the needs of real-time processing in mind.&lt;/p&gt;

&lt;h2 id=&quot;whats-the-problem&quot;&gt;What’s the problem?&lt;/h2&gt;

&lt;p&gt;While the PraxisCORE architecture can be used for processing any type of data, it was initially designed with the needs for working with multiple real-time media streams in mind. For example, my &lt;a href=&quot;https://www.neilcsmith.net&quot;&gt;creative work&lt;/a&gt; often involves working with audio and video together, or a low frame-rate camera doing motion detection and controlling a high frame-rate projection. Sometimes you might be working with video working at 60 fps and audio processing at 750 fps (PraxisCORE uses an internal 64 sample buffer).  How do we process events in those pipelines and allow them to talk to each other &lt;em&gt;without interfering with each other&lt;/em&gt;?  Now add in the principle of &lt;em&gt;edit everything live&lt;/em&gt; where we want to be able to insert new components, live compile code, or load resources, all without pausing or glitching.&lt;/p&gt;

&lt;p&gt;Solving this problem was probably my initial reason for developing PraxisCORE.  There’s some great software out there for working with audio or with graphics / video.  However, there’s not a lot that I consider works well with both at the same time.  For example, I think &lt;a href=&quot;https://www.processing.org/&quot;&gt;Processing&lt;/a&gt; is a great project - the live video coding API in PraxisCORE is based on it for a reason! But as a system for working with multiple media it is frustratingly lacking. This is not due to a lack of libraries for audio, etc. but because the underlying architecture is fundamentally tied to a single frame-rate based model.&lt;/p&gt;

&lt;h2 id=&quot;whats-wrong-with-synchronization--everything&quot;&gt;What’s wrong with synchronization? … Everything!&lt;/h2&gt;

&lt;p&gt;Working with different media in this way is analogous to working with &lt;a href=&quot;http://en.wikipedia.org/wiki/Thread_%28computing%29&quot;&gt;threads&lt;/a&gt;. In fact, in most cases this is exactly what we’re doing. Now a common way of handling communication between threads in a Java program is to use a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;synchronized&lt;/code&gt; block, or other form of locking. Unfortunately, these are terrible ways of dealing with this problem.&lt;/p&gt;

&lt;h3 id=&quot;time-waits-for-nothing&quot;&gt;Time waits for nothing&lt;/h3&gt;

&lt;p&gt;There’s a great article by Ross Bencina (author of &lt;a href=&quot;http://www.audiomulch.com/&quot;&gt;AudioMulch&lt;/a&gt;) called &lt;a href=&quot;http://www.rossbencina.com/code/real-time-audio-programming-101-time-waits-for-nothing&quot;&gt;Real-time audio programming 101: time waits for nothing&lt;/a&gt;. It discusses in some detail the reason not to use mutexes and other common threading constructs when programming real-time audio. I’d consider it a &lt;em&gt;must-read&lt;/em&gt; for anyone doing audio coding, and useful for anyone working with real-time requirements.&lt;/p&gt;

&lt;p&gt;Remember &lt;em&gt;your media thread is for processing media&lt;/em&gt;! You need to be aware of all the code that is running in that thread, and the maximum &lt;em&gt;potential&lt;/em&gt; execution time of that code, to ensure your data is processed in time. If you start adding in locks, then besides the overhead of synchronization and putting your code at the mercy of the scheduler, you add in the possibility of contention with other code that is now &lt;em&gt;effectively running in your real-time thread&lt;/em&gt; but might not be able to meet your real-time deadlines.&lt;/p&gt;

&lt;h3 id=&quot;optimization&quot;&gt;Optimization&lt;/h3&gt;

&lt;p&gt;There’s another problem with locks, and that is working out how coarse-grained they should be – how much code they should cover. You might expect that for best performance you’d want to keep the lock as fine as possible, only covering the minimal required code in an individual component. Besides being a bad idea as mentioned above, it also inhibits a more important performance optimization that happens in the PraxisCORE code. Audio, video and data pipelines switch off processing of sections of the graph where they can prove the output is not required.  To achieve this, they need to be sure that changes can only happen at a particular point of each processing cycle.  However, to achieve this using mutexes would massively increase the chances of contention.&lt;/p&gt;

&lt;h3 id=&quot;atomicity&quot;&gt;Atomicity&lt;/h3&gt;

&lt;p&gt;Another problem with synchronization is one of misapprehension, but one I’ve seen on multiple occasions. Imagine for a moment you have an audio sample player type, and on that type is a synchronized &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;play()&lt;/code&gt; method.  From your control thread (maybe Processing’s &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;draw()&lt;/code&gt; method) you call play, and the sample plays fine and all is well.  Now imagine you decide to play 4 samples together, so you call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;play()&lt;/code&gt; 4 times in succession and all is well .. actually, no it isn’t, because there’s no guarantee that those 4 samples will play together.  This is another issue with using locks – how can the user ensure that a series of events happen atomically?&lt;/p&gt;

&lt;h2 id=&quot;the-praxiscore-architecture&quot;&gt;The PraxisCORE architecture&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;/assets/PL4-new-graph.png&quot; data-lightbox=&quot;pl4-graph&quot;&gt;&lt;img src=&quot;/assets/PL4-new-graph-sm.png&quot; /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;One (probably &lt;em&gt;the&lt;/em&gt;) way to deal with the issues above is to pass events into your media process using a non-blocking queue or ring-buffer. I’ve written a variety of code in the past that used variations on these methods, and I’ve used a variety of other “non-blocking” concepts (such as &lt;a href=&quot;http://en.wikipedia.org/wiki/Future_(programming)&quot;&gt;Futures&lt;/a&gt;) for dealing with resource loading, etc. However, mixing different techniques for different requirements can be problematic! PraxisCORE began life as an experiment to build an architecture based entirely around a single, uniform message-passing model. It is inspired by the actor model, with some notable divergences.&lt;/p&gt;

&lt;h3 id=&quot;a-forest-not-a-tree&quot;&gt;A forest not a tree&lt;/h3&gt;

&lt;p&gt;Components (actors) in PraxisCORE are arranged in trees. Each component has an address in a familiar slash-delimited format (eg. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/audio/filter&lt;/code&gt; ). There is no single root - &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/&lt;/code&gt; has no meaning. Instead, the first element of the address refers to the root component, of which there can be many - a hub of roots creating a forest of actors. Roots generally, but not always, encompass a thread of execution.&lt;/p&gt;

&lt;p&gt;Diverging from the typical actor model, components do not maintain their own queue for incoming messages. Mailbox functionality is handled by each root, with external messages being delivered through a single lock-free queue, putting the root component in charge of all scheduling. Messages also have a time stamp. Each root maintains a clock relative to an overall hub clock, ensuring messages are dispatched at the correct time.&lt;/p&gt;

&lt;p&gt;Each component has zero or more controls, which act as end points for messages and are addressed in a form that echoes function calls (eg. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/audio/filter.frequency&lt;/code&gt;). Controls may wrap simple properties and actions, or complex functions that set off a chain of further messages. PraxisCORE adheres to a principle of no shared state between components, and control call communication uses a simple immutable type system. Even the code of each component is backed by a control - source code received as data to a component sets off a chain of messages that compile the code and inject the new behaviour atomically.&lt;/p&gt;

&lt;p&gt;As well as controls, components can have input and output ports, sometimes reflecting the same data. Ports provide a lightweight way for sibling components to communicate, and it is port connections that are reflected in the visual dataflow editor. Port communication itself is synchronous, although components can create or delay onward port messages, or use them to trigger asynchronous control calls. Port communication uses the same immutable type system, but extends this with the ability to pass mutable &lt;em&gt;data&lt;/em&gt; such as audio buffers and video frames. This provides the ability to process real-time data in a lightweight and lock-free way across a series of components, while maintaining the strong encapsulation of the actor model.&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/assets/audio-player.png&quot; alt=&quot;Audio player component in the PraxisLIVE IDE&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Here you can see an example of an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;audio:player&lt;/code&gt; component from within the PraxisLIVE editor. Ports can be seen on the graph node itself, and controls within the open editor dialog. Note the correlation between them. Manipulating values within the editor dialog sends control messages to the component. Note also the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ready&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;error&lt;/code&gt; ports - because loading a sample file is not real-time safe, the sample port triggers an asynchronous control message, with port messaging continuing on response.&lt;/p&gt;

&lt;h3 id=&quot;at-your-service&quot;&gt;At your service&lt;/h3&gt;

&lt;p&gt;&lt;img src=&quot;/assets/hub-manager.png&quot; alt=&quot;PraxisLIVE Hub Manager with system roots visible&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Alongside an unlimited number of user root components, there are various system-defined roots. Here you can see the Hub Manager inside the PraxisLIVE IDE with the system roots toggle active. Some of these roots provide services such as the compiler or resource loader. The runtime is modularized and decoupled, and a service discovery mechanism is used by components to find the addresses of services they require. Another of these system roots might be the PraxisLIVE IDE itself. The IDE can only communicate with the runtime via message passing, and other components have no knowledge of the IDE, making it easy to disconnect it, or swap in another editor that represents the underlying model in a different way.&lt;/p&gt;

&lt;h3 id=&quot;distributed-root-hubs&quot;&gt;Distributed root hubs&lt;/h3&gt;

&lt;p&gt;A key advantage of this architecture is its ability to work transparently with roots running in separate processes, literally at the flick of a switch. This makes it possible to edit code and dataflow across multiple machines. It also allows a project to run across multiple local processes, perhaps to improve real-time performance by mitigating garbage collection effects across pipelines. Or to improve resilience by automatically restarting a root in case of failure.&lt;/p&gt;

&lt;h2 id=&quot;in-a-pcl&quot;&gt;In a Pcl&lt;/h2&gt;

&lt;p&gt;While it is perfectly possible to control the PraxisCORE system from Java code using callbacks, in a continuation passing style, the recommended way to interact with the system is via the PraxisLIVE IDE. This provides live visual editing of the actor graph, as well as strong introspection facilities. And it supports the editing of code fragments stored in controls on components, with full syntax highlighting and completion (based on top of the &lt;a href=&quot;https://netbeans.apache.org&quot;&gt;Apache NetBeans IDE&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;PraxisCORE also has a simple text based command language. The syntax of this is loosely based on &lt;a href=&quot;http://en.wikipedia.org/wiki/Tcl&quot;&gt;Tcl&lt;/a&gt; - and if that is pronounced &lt;em&gt;tickle&lt;/em&gt; then Pcl must be &lt;em&gt;Pickle&lt;/em&gt;! It is the language used inside the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Terminal&lt;/code&gt; component in the PraxisLIVE IDE, and also the syntax of all the files used in projects.&lt;/p&gt;

&lt;p&gt;Two common commands, with symbolic aliases, are &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; (at) and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;~&lt;/code&gt; (connect). &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;@&lt;/code&gt; takes a component address, an optional component type (used to construct a new component) and a script (that will be run within the context of the address, allowing nested hierarchies. This simple language hides the complexity of working within the PraxisCORE message-passing system, the interpreter automatically handling the sending and receiving of messages.&lt;/p&gt;

&lt;p&gt;This is a simple script used to create a simple graph identical to the Hello World example in the examples download – it is similar to the the contents of the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;video.pxr&lt;/code&gt; file from the graph editor.  There are actually 5 different roots (threads) involved in the execution of this script, potentially split across up to 3 processes!&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-Tcl&quot;&gt;@ /video root:video {
    .width 400
    .height 300
    .fps 20

    @ ./noise video:source:noise {}

    @ ./image video:still {
        .image [file &quot;resources/hello world.png&quot;]
    }

    @ ./window video:output {
        .title &quot;Hello World!&quot;
    }

    ~ ./noise!out ./image!in
    ~ ./image!out ./window!in
}

/video.start
&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id=&quot;in-practice-in-praxis&quot;&gt;In practice in Praxis&lt;/h2&gt;

&lt;blockquote&gt;
  &lt;p&gt;&lt;strong&gt;Praxis&lt;/strong&gt; (from Ancient Greek: πρᾶξις, translit. praxis) is the process by which a theory, lesson, or skill is enacted, embodied, or realized. &lt;a href=&quot;https://en.wikipedia.org/wiki/Praxis_(process)&quot;&gt;(Wikipedia)&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;What began life as an experiment into a message-passing actor system for real-time use has now matured into a robust and resilient runtime. The initial complexity of building a general purpose system in this way has paid dividends over the years in the ease of working with almost any library on the JVM. And with lock-free messaging and strong encapsulation it has proven to be an ideal and natural architecture for supporting real-time hot code reloading in Java.&lt;/p&gt;

&lt;p&gt;Come get involved in the next exciting steps for PraxisCORE, bringing the best aspects of Erlang, Smalltalk and Extempore into the Java world.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post is based on a much earlier 2012 blog post at &lt;a href=&quot;https://praxisintermedia.wordpress.com/2012/07/26/the-influence-of-the-actor-model/&quot;&gt;The Influence of the Actor Model&lt;/a&gt;, updated (and abridged, honestly!) with snippets from my ICLC conference paper on PraxisLIVE and other more recent aspects of PraxisCORE.&lt;/em&gt;&lt;/p&gt;

</description>
        <pubDate>Wed, 01 Aug 2018 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/a-forest-of-actors/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/a-forest-of-actors/</guid>
        
        
      </item>
    
      <item>
        <title>Welcome!</title>
        <description>&lt;p&gt;Welcome to the new PraxisLIVE blog, now hosted as part of a revamped website. The
&lt;a href=&quot;https://praxisintermedia.wordpress.com&quot; target=&quot;_blank&quot;&gt;old WordPress blog&lt;/a&gt; will be left as an
archive but no new posts added - some old but still relevant information will be
updated and reposted here.&lt;/p&gt;

&lt;p&gt;This coincides with the recent release of PraxisLIVE v4, and the restructuring and
relicensing of the &lt;a href=&quot;/core/&quot;&gt;PraxisCORE runtime&lt;/a&gt;, which now has its own dedicated page.
Separate pages have been added for &lt;a href=&quot;/download/&quot;&gt;downloads&lt;/a&gt; and &lt;a href=&quot;/community/&quot;&gt;community&lt;/a&gt;,
with links to the relatively new &lt;a href=&quot;https://gitter.im/praxis-live&quot; target=&quot;_blank&quot;&gt;Gitter chat&lt;/a&gt; and
&lt;a href=&quot;https://donorbox.org/praxislive&quot; target=&quot;_blank&quot;&gt;DonorBox donations&lt;/a&gt;. And the documentation has been
re-hosted and given a new UI at &lt;a href=&quot;https://docs.praxislive.org&quot; target=&quot;_blank&quot;&gt;https://docs.praxislive.org&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;There are lots of exciting things in the pipeline for PraxisLIVE over the summer months
so please keep an eye here for updates!&lt;/p&gt;

</description>
        <pubDate>Fri, 22 Jun 2018 00:00:00 +0000</pubDate>
        <link>https://www.praxislive.org/blog/welcome/</link>
        <guid isPermaLink="true">https://www.praxislive.org/blog/welcome/</guid>
        
        
      </item>
    
  </channel>
</rss>
