<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>ValueFactory Blog</title>
        <link>https://value.gay/blog/</link>
        <description>ValueFactory Blog</description>
        <lastBuildDate>Mon, 29 Jun 2026 00:00:00 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Furality Ultra Club A/V Writeup]]></title>
            <link>https://value.gay/blog/furality-ultra-av</link>
            <guid>https://value.gay/blog/furality-ultra-av</guid>
            <pubDate>Mon, 29 Jun 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Hi I'm Value. I'm one of the producers on the Furality A/V Team and I want to yap about A/V production leading up to Furality Ultra. This is not an official Furality writeup and does not represent any views or future plans Furality has. This is just me yapping and sharing the stuff I touched on and learned during the A/V production cycle this year.]]></description>
            <content:encoded><![CDATA[<p>Hi I'm Value. I'm one of the producers on the Furality A/V Team and I want to yap about A/V production leading up to Furality Ultra. This is not an official Furality writeup and does not represent any views or future plans Furality has. This is just me yapping and sharing the stuff I touched on and learned during the A/V production cycle this year.</p>
<p>This year I worked on producing sets, creating tooling, creating workflows, helping out put out fires and organize work.</p>
<p>I was not the one working on the world, that'd be Micca (and a lot of the other folks from the creative team). So anything relating to the club world might not be 100% accurate.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="terminology">Terminology<a href="https://value.gay/blog/furality-ultra-av#terminology" class="hash-link" aria-label="Direct link to Terminology" title="Direct link to Terminology">​</a></h3>
<ul>
<li><strong>"CRVF"</strong> - Club ready video file - the thing we play out that contains the DJ introduction, DJ set, visuals, lights, countdown etc.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="stage-tech">Stage Tech<a href="https://value.gay/blog/furality-ultra-av#stage-tech" class="hash-link" aria-label="Direct link to Stage Tech" title="Direct link to Stage Tech">​</a></h2>
<p>This year we streamed into the world at 2560x1440 30fps H.264 8Mbps via RTSP. VRCDN handled the broadcast delivery.
All the club programming came in through this video broadcast. So everything you saw happen was being controlled by this video.</p>
<p><img decoding="async" loading="lazy" alt="CRVF" src="https://value.gay/blog/assets/images/crvf-aded0faa4240e1027b67743847d745ed.png" width="2560" height="1440" class="img_ev3q"></p>
<p>This video is split up into various 'slices' that we can put content into.</p>
<p><img decoding="async" loading="lazy" alt="CRVF" src="https://value.gay/blog/assets/images/mapping-7cbcc9d1197334b61540caef3146dff4.png" width="1704" height="956" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="CRVF" src="https://value.gay/blog/assets/images/crvf-with-mapping-8ee8f40fa162c0557e2d51c08ba1e4fa.png" width="1706" height="959" class="img_ev3q"></p>
<p>The world cuts the video up into these slices and uses the slices around the various elements such as screens, hologram, DJ booth etc.</p>
<p>The "DMX" slice at the top contains DMX data encoded as binary using the MDMX system. Each white/black square is a 4x4 region of pixels that encode a single bit. Black regions are 0s and white regions are 1s. Each column contains 6 bytes of data with a 4 bit CRC for error checking at the end. So each column is <code>6*8+4=52</code> bits.
More information about MDMX can be found in the <a href="https://docs.google.com/spreadsheets/d/1Ja2MNUpNjJ7rvvbwJbI7oPJigNGIpVu1WQi0lew35io/edit?gid=394322462#gid=394322462" target="_blank" rel="noopener noreferrer">Stage Flight patch</a> and <a href="https://github.com/micksam7/VRC-MDMX" target="_blank" rel="noopener noreferrer">Micca's MDMX repo</a></p>
<p>We use <a href="https://github.com/furality/furality-grid-node" target="_blank" rel="noopener noreferrer">Furality Gridnode</a> to take in DMX from professional lighting software like grandMA3, MagicQ, QLC to Blender and other DMX outputting software. Fgrid then takes that DMX in and creates the binary gridnode that we can broadcast into the world.</p>
<p><img decoding="async" loading="lazy" alt="CRVF" src="https://value.gay/blog/assets/images/fgrid-20c08dfd4ca9d6d3c1119cd06b9d0d99.png" width="1165" height="288" class="img_ev3q"></p>
<p>Fgrid outputs this binary gridnode over Spout, so we can capture it in OBS and record it. We can also take screenshots of it.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="world-features">World Features<a href="https://value.gay/blog/furality-ultra-av#world-features" class="hash-link" aria-label="Direct link to World Features" title="Direct link to World Features">​</a></h3>
<p>This year the world had:</p>
<ul>
<li>8 screens with 6 DoF and 2 axis scale.</li>
<li>A particle screen with 6 DoF and scale.</li>
<li>A particle system</li>
<li>36 spot lights with pre-baked volumetric lights ("lutbeams") attached to light robots with 3 DoF</li>
<li>82 parcans throughout the world</li>
<li>20 2D lasers attached to FX robots with 6 DoF</li>
<li>Jill 😳 (the big creature)</li>
<li>Backdrops with multiple planets to choose from and an in-between warp mode.</li>
<li>Fireworks on the FX robots.</li>
</ul>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="screens">Screens<a href="https://value.gay/blog/furality-ultra-av#screens" class="hash-link" aria-label="Direct link to Screens" title="Direct link to Screens">​</a></h3>
<p>The screens were fun. Each screen was able to be moved and rotated <code>[-50;50]</code> cube and scaled between <code>[0;5.8]</code> units. Each screen could take from one of the 8 screen slices in the video map. Each screen could also choose which other screen acts as the mask for that screen, allowing us to do more complex shapes than just squares.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="dmx-programming">DMX Programming<a href="https://value.gay/blog/furality-ultra-av#dmx-programming" class="hash-link" aria-label="Direct link to DMX Programming" title="Direct link to DMX Programming">​</a></h3>
<p>Apart from the visual content, the rest of the world was programmed using DMX and streamed into the world via binary MDMX. We use a patch sheet to understand the capabilities of the club and to know what exactly to program. <a href="https://docs.google.com/spreadsheets/d/1Ja2MNUpNjJ7rvvbwJbI7oPJigNGIpVu1WQi0lew35io/edit?gid=0#gid=0" target="_blank" rel="noopener noreferrer">Here's the patch for Stage Flight as an example</a>. The patch outlines where the individual fixtures are located and their capabilities. We can then patch these into our DMX software and control the world.</p>
<p>For quick programming and preview of the DMX programming, we use <a href="https://github.com/micksam7/VRC-MIDIDMX" target="_blank" rel="noopener noreferrer">MIDIDMX</a>. It encodes DMX as MIDI and sends that into the VRChat client. The world reads this MIDI and lets us control the world with minimal latency.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="blender">Blender<a href="https://value.gay/blog/furality-ultra-av#blender" class="hash-link" aria-label="Direct link to Blender" title="Direct link to Blender">​</a></h2>
<p>Given the 6 DoF and scale controls for pretty much the whole club, we needed some way to control it all. We ended up using Blender and the <a href="https://github.com/Happyrobot33/blender-DMX-connector" target="_blank" rel="noopener noreferrer">DMX plugin by Happyrobot</a>.</p>
<p>I ended up patching in the rig into a blender file, creating instructions for setting it up and sharing it with the rest of the team.</p>
<p><img decoding="async" loading="lazy" alt="CRVF" src="https://value.gay/blog/assets/images/blender-839a88b213806bc237509392475c81b6.png" width="2560" height="1359" class="img_ev3q"></p>
<p>Each object represents a fixture and we have custom properties on these objects that control the channels of that fixture. For more complex channels like XYZ position, XYZ euler and scale, we use a text block property which runs a script that encodes the object transform into DMX.</p>
<p><img decoding="async" loading="lazy" alt="CRVF" src="https://value.gay/blog/assets/images/blender-script-6f5ea484e540f7c2a592227b1e37dd8a.png" width="929" height="779" class="img_ev3q"></p>
<p>So in the end we have the ability to control the screens and other things from blender!</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/blender-control.mp4"></video></p>
<p>This is how many collections I ended up having in my working blend file.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/blender-scene.mp4"></video></p>
<p>The workflow I ended up using is to separate each scene into its own collection, create linked duplicates of the reference fixtures that I needed for that scene and put them into the collection.</p>
<p>And because Blender has a whole animation tooling suite, we can do some fun and non-trivial things!</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="setup-guide">Setup Guide<a href="https://value.gay/blog/furality-ultra-av#setup-guide" class="hash-link" aria-label="Direct link to Setup Guide" title="Direct link to Setup Guide">​</a></h3>
<p>You can find the guide I wrote for how to set this blender tooling up (without the .blend file, sorry!) <a href="https://value.gay/blog/assets/files/F9_Blender_Plugin_Guide-9fa8a3b93b4856fdbe5b66a4e1d46804.pdf" target="_blank">here</a></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="constraints">Constraints<a href="https://value.gay/blog/furality-ultra-av#constraints" class="hash-link" aria-label="Direct link to Constraints" title="Direct link to Constraints">​</a></h3>
<p>We can make objects track other objects. For example this was used in Daxan's Jill UFO fight. Jill and the UFO both had FX drones with lasers that tracked each other. I had set up small rigs for the UFO to easily animate things as well so that the UFO can move and the FX drones on the UFO and the particle screen moves in unison with the root UFO object.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/daxan-jill-ufo.mp4"></video></p>
<p>The tracking was done using 'Track-to' constraints on the individual objects and I had them target a tracking object.</p>
<p><img decoding="async" loading="lazy" alt="Trackto" src="https://value.gay/blog/assets/images/track-to-0b1510dd3b857f4b937c584f77288ace.jpg" width="727" height="244" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="drivers">Drivers<a href="https://value.gay/blog/furality-ultra-av#drivers" class="hash-link" aria-label="Direct link to Drivers" title="Direct link to Drivers">​</a></h3>
<p>Drivers let us create relationships between individual channels on fixtures. For example I ended up using it to create a simple Jill tail rig:</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/drivers.mp4"></video></p>
<p>Tail 1 controls the tail fold and tail width for the other 4 tails.
Tail 5 wag is <code>1 - Tail 1 wag</code>
Tail 4 wag is <code>1 - Tail 2 wag</code></p>
<p>So drivers let us patch in these relationships rather easily.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="animations">Animations<a href="https://value.gay/blog/furality-ultra-av#animations" class="hash-link" aria-label="Direct link to Animations" title="Direct link to Animations">​</a></h3>
<p>Blender lets us keyframe stuff! So we can keyframe object transforms and custom properties!</p>
<p>Going back to the Daxan Jill vs UFO fight, that whole thing was done using animations. I ended up exporting out the audio for that part, putting it into the video editor timeline of Blender so that I have some music to timecode to, and then keyframed the action across a few scenes.</p>
<p>Here's the scene where Jill toys around with the UFO. Unmute the clip to hear the audio.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/jill-animation.mp4"></video></p>
<p><img decoding="async" loading="lazy" alt="Timeline" src="https://value.gay/blog/assets/images/blender-video-timeline-b1894271498c4a818dd0b334d5aee263.jpg" width="1624" height="891" class="img_ev3q"></p>
<p>Keep in mind this is just the DMX programming, so we're not seeing any of the visuals and the UFO. Putting in that visual content is done later in Davinci Resolve.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="video-playback">Video Playback<a href="https://value.gay/blog/furality-ultra-av#video-playback" class="hash-link" aria-label="Direct link to Video Playback" title="Direct link to Video Playback">​</a></h3>
<p>So while I didn't dare do video editing in Blender (it doesn't quite suit my needs), the video playback capabilities in Blender were VERY useful to be able to accurately timecode scenes. I mentioned above how I used the audio to timecode the Jill UFO fight, but we can also do the same with video.</p>
<p>For example I keyframed the intro animation using a reference video as a texture source and the audio in the video timeline. Each screen was properly UV unwrapped to sample from the incoming video broadcast the same way it would in the world, so all I had to do was make a new material, drag the intro video (produced by nullreff) into that material as a texture input, set up that node and assign that material to the screen objects. The audio was sourced separately by dragging in the video into the video editing tab and removing the video clip but keeping the audio.</p>
<p>Unmute the clip for audio.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/intro-animation.mp4"></video></p>
<p>So the result is that we have audio and video to keyframe to!</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="limitations">Limitations<a href="https://value.gay/blog/furality-ultra-av#limitations" class="hash-link" aria-label="Direct link to Limitations" title="Direct link to Limitations">​</a></h3>
<p>During the DMX recording of the club intro, I noticed that some of the frames were being dropped and that the captured DMX stuttered every now and then. Nullreff suggested we work around this by recording at 0.5x speed and speed it up 2x in Davinci. It worked out in the end but I don't think that will work for us in the future.</p>
<p>The exact cause of the stutter is unknown but I noticed that the more complex the scene, the more likely it will stutter. The intro had a bunch of objects and object transitions and it's likely Blender and it's python API couldn't keep up. Moving into the future I think setting up an "offline" render pipeline for the DMX data out of blender would help us avoid this issue.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="some-thoughts">Some Thoughts<a href="https://value.gay/blog/furality-ultra-av#some-thoughts" class="hash-link" aria-label="Direct link to Some Thoughts" title="Direct link to Some Thoughts">​</a></h3>
<p>I think we're barely scratching the surface of how Blender can help us in the VR A/V scene. I've been wondering what the strengths of VR shows are for a while and I've been very lucky to be able to work with talented people at Furality and Stage Flight to explore that. This 6 DoF + Blender stuff feels like that special sauce that makes VR shows unique. Nothing else can quite match the spectacle of seeing MeowMix or Daxan and the stage movements in those sets were only possible due to Blender's tooling.</p>
<p>VRSL's grayscale 16x16 blocks suffer from psycho-visual tuning that video encoders perform and MDMX is the solution to that data loss over this analog medium. The binary gridnode was one of the tech cornerstones of being able to properly transmit the programming we do in Blender and it would not have been possible without it. I was not the one working on MDMX, all the credit would have to go to Micca and Torvid (and maybe more people I'm forgetting, sorry!).</p>
<p>While all this Blender tooling is available right now for ya'll to mess with, I really hope we can put out MDMX for everyone to enjoy the benefits of!</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="davinci-resolve-tooling">Davinci Resolve Tooling<a href="https://value.gay/blog/furality-ultra-av#davinci-resolve-tooling" class="hash-link" aria-label="Direct link to Davinci Resolve Tooling" title="Direct link to Davinci Resolve Tooling">​</a></h2>
<p>A significant amount of time was spent doing composition or content programming in Davinci during Somna and Stage Flight. So investing time into making better tools for us there was a no-brainer.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mdmx-fixture">MDMX Fixture<a href="https://value.gay/blog/furality-ultra-av#mdmx-fixture" class="hash-link" aria-label="Direct link to MDMX Fixture" title="Direct link to MDMX Fixture">​</a></h3>
<p>I've been throwing around the idea of making DMX control software for myself but I'm lazy and want to do the least amount of work I can. So I ended up writing a Davinci Resolve plugin that can load fixtures and create keyframable parameters in the davinci timeline for me to program.</p>
<p>While we can control DMX in programs like Blender, QLC, grandMA3 etc, we have no way of directly programming DMX in Davinci Resolve and this plugin lets us do that. The plugin loads fixtures in a json format and exposes parameters for you to control then writes the values of those parameters directly into the video as a MDMX binary gridnode.</p>
<p><a href="https://github.com/valuef/mdmx-davinci" target="_blank" rel="noopener noreferrer">MDMX Fixture is open source and can be found here</a></p>
<p>For example this is the screen fixture definition I used for the screens:</p>
<details class="details_lb9f alert alert--info details_b_Ee" data-collapsed="true"><summary>F9 Screen V2.json</summary><div><div class="collapsibleContent_i85q"><div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">{</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "id" : "F9 Screen v2",</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "default_dmx_universe": 7,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "default_dmx_channel": 283,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "num_fixtures_in_sequence": 8,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  "controls": [</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "name": "Position", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "type": "pos_xyz_16", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "x_channel": 1,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "x_fine_channel": 2,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "y_channel": 3,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "y_fine_channel": 4,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "z_channel": 5,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "z_fine_channel": 6,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_min": -50, </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_max": 50</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "name": "Rotation", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "type": "euler_xyz_16", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_min": -270,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_max": 270,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "x_channel": 7,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "x_fine_channel": 8,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "y_channel": 9,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "y_fine_channel": 10,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "z_channel": 11,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "z_fine_channel": 12</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "name": "Size X", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "type": "float_16", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "channel": 13,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "channel_fine": 14,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "default_value": 0.7,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_min": 0,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_max": 5.6</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "name": "Size Y", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "type": "float_16", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "channel": 15,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "channel_fine": 16,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "default_value": 0.7,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_min": 0,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_max": 5.6</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "name": "Dimmer", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "type": "float", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "channel": 17,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "default_value": 1</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { "name": "Black as Alpha", "type": "float", "channel": 18 },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { "name": "Bloom", "type": "float", "channel": 19 },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "name": "Alpha Mask", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "type": "integer", </span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "channel": 20,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_min": 0,</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">      "display_max": 8</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { "name": "Hide Robot", "type": "toggle", "channel": 21 },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { "name": "Motion Speed", "type": "float", "channel": 22 },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { "name": "Rotation Speed", "type": "float", "channel": 23 },</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">    { "name": "Force Snap", "type": "toggle", "channel": 24 }</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">  ]</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">}</span><br></span></code></pre></div></div></div></div></details>
<p>Once we load it in the plugin, we have access to these parameters:</p>
<p><img decoding="async" loading="lazy" alt="Fixture" src="https://value.gay/blog/assets/images/mdmx-fixture-screen-92ca1624b7782c6f32d18b0019b010b9.jpg" width="410" height="999" class="img_ev3q"></p>
<p>So each of the fixture parameters can be keyframed in the Davinci timeline editor.</p>
<p>The "Write Mask" lets me choose which parameters are generated. If a parameter has the write mask unchecked, the MDMX pixels associated with that will not be emitted and will not overwrite anything previously there. So this also lets us poke values into the middle of fixtures that have been otherwise programmed earlier.</p>
<p>One caveat is that MDMX Fixture plugin does not calculate the CRC of the MDMX columns it outputs to. That's the next step.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mdmx-crc">MDMX CRC<a href="https://value.gay/blog/furality-ultra-av#mdmx-crc" class="hash-link" aria-label="Direct link to MDMX CRC" title="Direct link to MDMX CRC">​</a></h3>
<p>The MDMX gridnode is broken down into individual columns of 6 bytes. Each column has 4 bits at the end that contain the CRC of those 6 bytes. The 4 bits are there for a few bits of error checking, which considering we're transmitting this binary over what's effectively an analog medium, is very useful. If we catch errors, we can use the last known correct value.</p>
<p>But the existence of this CRC poses a problem: we can't easily poke values into the middle of a MDMX column. If we change any of the bytes in a column, the CRC needs to be recalculated.</p>
<p>On top of that, the MDMX Fixture plugin for Davinci doesn't calculate the CRC in the first place. So to be able to poke values and to use MDMX fixture plugin, we needed a way to be able to recalculate the CRC in a video editor.</p>
<p>I ended up writing the MDMX CRC Recalc davinci plugin to support this workflow. You can put it on an adjustment clip and set the resolution of the binary gridnode and it will take all the MDMX gridnode underneath the adjustment clip and recalculate the CRC for it.</p>
<p><a href="https://github.com/valuef/mdmx-davinci" target="_blank" rel="noopener noreferrer">MDMX CRC Recalc is open source and can be found here</a></p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/sf314/mdmx-crc.mp4"></video></p>
<p>It came in VERY useful. In fact we ended up using it during the final composite for the firework show to turn off some firework emitters as they were causing the video sound to crash. MDMX CRC recalc let us poke 0's into the firework fire channel without corrupting the CRC.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="videoremap">VideoRemap<a href="https://value.gay/blog/furality-ultra-av#videoremap" class="hash-link" aria-label="Direct link to VideoRemap" title="Direct link to VideoRemap">​</a></h3>
<p>The way we slice up videos into the video mapping typically is done using Resolume Arena. However Resolume Arena is geared for a realtime workflow as it doesn't have a timeline or anything to help us precisely switch mapping and to record remapped content as fast as possible.</p>
<p>That was REALLY annoying during Somna so I made <a href="https://videoremap.com/" target="_blank" rel="noopener noreferrer">VideoRemap</a> in-between Somna and Ultra. It's a Davinci Resolve plugin.</p>
<p>VideoRemap lets us define how to cut up an input video into different parts. We can define this mapping in Resolume Arena, then load it on an instance of VideoRemap on your video clip in the Davinci timeline and it will do that slicing for you. This means you can remap content "offline" and render it as fast as your machine allows instead of waiting for it to play out like before in Resolume.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/videoremap-ultra.mp4"></video></p>
<p>For fun, here's the same video mapped onto the peacock feathers from Somna:</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/videoremap-somna.mp4"></video></p>
<p>Without this tool I'm confident in saying that sets like Daxan and Birdbrain would not have been possible. There are hundreds of instances of this plugin active on those sets, mapping 16:9 content to various layouts of the screens. This tool was essential for me this year.</p>
<p><a href="https://videoremap.com/" target="_blank" rel="noopener noreferrer">VideoRemap is available here</a> for use in your own productions with are <a href="https://docs.videoremap.com/" target="_blank" rel="noopener noreferrer">documentation here</a>. You can use this tool on any VR club production (and maybe even outside of VR <!-- -->:O<!-- --> )</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="spout-output">Spout Output<a href="https://value.gay/blog/furality-ultra-av#spout-output" class="hash-link" aria-label="Direct link to Spout Output" title="Direct link to Spout Output">​</a></h3>
<p>Davinci Resolve doesn't provide any kind of easy to use monitoring output such as Spout or NDI. I ended up writing a plugin to output video over Spout as a stop-gap.</p>
<p><a href="https://github.com/valuef/davinci-spout-sender" target="_blank" rel="noopener noreferrer">Davinci Spout Sender is open source and can be found here</a></p>
<p>I use this thing in every production now. Slap it on an adjustment clip at the top of your timeline, receive it in OBS and flip. Then stream that out via VRCDN private or MediaMTX into world. The reason this is useful is so that I can preview the sequencing/programming I'm doing in Davinci. It removes the need for me to render out a clip into a video file as I can just play it out in world as it's playing out in my timeline. Ofc MediaMTX and VRCDN add their own latency, but maybe VRChat will add spout input support into the client at some point for us ;)</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="luma-glow-generation">Luma Glow Generation<a href="https://value.gay/blog/furality-ultra-av#luma-glow-generation" class="hash-link" aria-label="Direct link to Luma Glow Generation" title="Direct link to Luma Glow Generation">​</a></h3>
<p>This year we needed a way to generate luma glow and world gradients for about 31 sets. I cooked up a TouchDesigner file to do that. So the majority of the luma glow (and world gradients) was generated from a TouchDesigner file in an audio reactive way.</p>
<p>The TouchDesigner file generated</p>
<ul>
<li>4 Luma glow zone - (DMX out) - 3 band transient detection, 1 energy estimation.</li>
<li>3 Luma glow gradients - (Spout) - trailing luma glow zone data.</li>
<li>4 World gradients (Lasers 5,6,7,8) (Spout) - 1 energy estimation + low transient detection.</li>
</ul>
<p><img decoding="async" loading="lazy" alt="Daxan" src="https://value.gay/blog/assets/images/luma-overview-2c0d588aca78ea4e86edc7a4b3c04b0e.jpg" width="2207" height="1144" class="img_ev3q"></p>
<p>Transient detection was split into 3 bands: low, mid and highs.
Lows were tuned for kicks, mids were tuned for snares and highs were tuned for hi-hats.
Fundamentally the transient detection was done by generating a fast moving envelope and a slow moving envelope and then treating large deviations between the two envelopes as detected transients.Timing, filters and EQ for each of the bands was fine tuned.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/transient-detection.mp4"></video></p>
<p>The transient detection scrolls a gradient based off of the Ultra colors. For each luma zone, the color is sampled and multipled by a transient band and sent over DMX to Fgrid. Luma zones take that same data and trail it to generate a gradient image that's combined with the world gradient data. It's composited into the video map and gets sent out over Spout for capture in OBS.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/luma-zones.mp4"></video></p>
<p>World gradients were very similar. The energy estimator scrolls a gradient texture that's masked by that same energy estimator and the color is trailed to create a gradient. I also combined this gradient with a kick transient trail going in the opposite direction additively to give it a bit more energy. This gradient is then composited into lasers 5-8 and sent out over Spout.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/world-grad.mp4"></video></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="process">Process<a href="https://value.gay/blog/furality-ultra-av#process" class="hash-link" aria-label="Direct link to Process" title="Direct link to Process">​</a></h2>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="crvf-export-settings">CRVF Export Settings<a href="https://value.gay/blog/furality-ultra-av#crvf-export-settings" class="hash-link" aria-label="Direct link to CRVF Export Settings" title="Direct link to CRVF Export Settings">​</a></h3>
<p>Before production kicked off, I helped standardize on V1 of the the video editor export settings used to deliver the CRVF files. Our editors use Premiere pro, Davinci Resolve Free and Davinci Resolve Studio. So we had to have settings for all of these platforms.</p>
<ul>
<li>
<p>Premiere Pro</p>
<ul>
<li>Sequence settings<!-- -->
<ul>
<li>Frame Size - 2560x1440</li>
<li>Frame Rate - 30fps</li>
</ul>
</li>
<li>Export<!-- -->
<ul>
<li>Format - QuickTime</li>
<li>Video<!-- -->
<ul>
<li>Video Codec - H.264</li>
<li>Field Order - Progressive</li>
<li>Aspect - Square Pixels (1.0)</li>
<li>Use Maximum Render Quality - Yes</li>
<li>Bitrate Encoding - CBR</li>
<li>Target Bitrate - 16 Mbps</li>
<li>Key frame every 1 frames - Yes</li>
</ul>
</li>
<li>Audio<!-- -->
<ul>
<li>Match sample rate of original set audio. Default to 44100khz otherwise.</li>
<li>16 bit</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li>
<p>Davinci Resolve</p>
<ul>
<li>Timeline Settings<!-- -->
<ul>
<li>Resolution - 2560x1440 (1440p)</li>
<li>Framerate - 30 fps</li>
</ul>
</li>
<li>Export<!-- -->
<ul>
<li>Format - QuickTime (mov)</li>
<li>Video<!-- -->
<ul>
<li>Codec - H.264</li>
<li>Encoder - Native</li>
<li>Encoding Profile - high</li>
<li>Preset - Quality</li>
<li>Rate control - Constant Bitrate</li>
<li>Bitrate - 16000 kbps</li>
<li>Data levels - Full (changed to "video" later)</li>
</ul>
</li>
<li>Audio<!-- -->
<ul>
<li>Codec - Linear PCM</li>
<li>Sample Rate - Match original set audio. Default to 44100khz otherwise.</li>
<li>Bit depth - 16</li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
</ul>
<p>We learned a few things afterward:</p>
<ul>
<li>Our video playout stack assumes limited (or "video") data levels. Premiere pro already exports in limited range but Davinci did not and so that was going to cause issues. We switched to a Davinci export preset that used <code>Data Levels</code> set to "video" to force davinci to export in "limited" data levels (yuv420p as opposed to yuvj420p)</li>
<li>The H.264 Native encoder used on Davinci Resolve windows is BAD: during cuts to black, the video it encoded decodes with errors in VLC and Playdeck. During high bitrate scenes, it creates intra-frame smearing and destroys our content. We trialed HEVC for sets exhibiting these problems and had no issues with HEVC renders.</li>
</ul>
<p>If you're looking to use these settings as an example, I'd recommend using limited data levels and HEVC "Native" instead of H.264 for your final exports. Now you'll still be streaming H.264 out of OBS but that's fine if you use VideoLAN x264 as the encoder on OBS. That encoder did a really good job of preserving our content during encode.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="crvf-checklist">CRVF Checklist<a href="https://value.gay/blog/furality-ultra-av#crvf-checklist" class="hash-link" aria-label="Direct link to CRVF Checklist" title="Direct link to CRVF Checklist">​</a></h3>
<p>Last year I ended up producing a barebones text checklist for CRVFs that helped all the editors be on the same page. With the extra complexity in this year's club, I noticed that this simple text file checklist was getting cramped. I reached out to Roxy for some advice on how to organize it and he shared some insight which led us to make this proper checklist.</p>
<p><img decoding="async" loading="lazy" alt="Daxan" src="https://value.gay/blog/assets/images/crvf-checklist-603a26b6e8cafd0ef1410252aa286c70.jpg" width="1399" height="1177" class="img_ev3q"></p>
<p>Each checklist item has an associated resource linked to it so you can always find the resource you need to check that item off.</p>
<p>This ended up being very useful and is one of the reasons why we were on top of things. It let us have the confidence we're not missing anything and let editors get up to speed really quickly on what needed to be in the CRVF.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="being-a-producer">Being a producer<a href="https://value.gay/blog/furality-ultra-av#being-a-producer" class="hash-link" aria-label="Direct link to Being a producer" title="Direct link to Being a producer">​</a></h3>
<p>This year I was producing:</p>
<ul>
<li>Kadachii</li>
<li>Daratomic</li>
<li>Daxan</li>
<li>BirdBrain</li>
</ul>
<p>Each one of the DJs gets a pod of producer, VJ (visuals), LD (lighting) and editor.
The VJ does the visuals.
The LD does the lights.
The editor composites content.</p>
<p>The producer acts as the project manager and facilitator for all the work between the DJ and the pod.</p>
<p>So the general process I for me as a producer this year looked like this:</p>
<ul>
<li>
<p>Establish communication with the DJs.</p>
</li>
<li>
<p>Set up crabfits with DJs at the start to kick off production.</p>
</li>
<li>
<p>Have the production kickoff meeting. Talk about:</p>
<ul>
<li>Production: How involved do you want to be with the production pipeline?</li>
<li>Creative: What's the 'theme' of the set?</li>
<li>Creative: Are there any specific moments in the set that you'd like us to do something special for, or to focus on?</li>
<li>Misc: Anything to <em>NOT</em> do</li>
<li>Club: does the DJ need club clearance?</li>
</ul>
</li>
<li>
<p>Clear DJs for club access if needed.</p>
</li>
<li>
<p>Set up a second meeting to go through the set to figure out vis, lights, vis/light focus, any key points, notes etc and fill out the production tracking sheet.</p>
</li>
<li>
<p>Production is kicked off.</p>
<ul>
<li>Check in with LD/VJ to see if they have everything they need, if they're blocked or waiting or something. Also ask how they're feeling about the workload.</li>
<li>Put in my own work on working on key points, anything specific to the production that I need to do etc.</li>
<li>Share videos/pics with the DJ on any developments, updates to the rig.</li>
</ul>
</li>
<li>
<p>Schedule preview sessions once all the VJ and LD content is in and we have drafts.</p>
<ul>
<li>Take notes during these sessions for what needs to be fixed.</li>
</ul>
</li>
<li>
<p>QA the final drafts, ask for fixes if needed.</p>
</li>
<li>
<p>Sign off on the final CRVF (club ready video file).</p>
</li>
</ul>
<p>For my productions, we aim for an asynchronous workflow where we coordinate once very extensively and then work on our own parts individually. Our teammates are located all around the world with different schedules and timezones, so constantly being in sync is not that easy. On top of that, everyone is working on multiple different projects with their own sync requirements.</p>
<p>So the production sheet is the way we manage all this work. We lay out the ideas and things we want to keep track of so we're all on the same page and assign work in the sheets.</p>
<p>Here's a page out of the Daxan production sheet.</p>
<p><img decoding="async" loading="lazy" alt="Daxan" src="https://value.gay/blog/assets/images/daxan-sheet-5aef380fc16f3044283184da3de8b80f.jpg" width="2559" height="1188" class="img_ev3q"></p>
<p>This one took us around 8 hours spread across 4 meetings to fill out and properly understand. We're listening through the set during each meeting and trying to very clearly define the ideas that we're having, if we want to do them and how to precisely execute them.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="being-an-editor">Being an editor<a href="https://value.gay/blog/furality-ultra-av#being-an-editor" class="hash-link" aria-label="Direct link to Being an editor" title="Direct link to Being an editor">​</a></h3>
<p>I ended up being an editor for a few sets this year:</p>
<ul>
<li>Ashtalon</li>
<li>What the PUP!</li>
</ul>
<p>Being an editor involves taking various pieces of content and putting them all together. This year we were putting together:</p>
<ul>
<li>Credits</li>
<li>Production clock</li>
<li>"Johari" slice and A/V recruitment propaganda</li>
<li>DJ hologram</li>
<li>Luma glow + world gradients</li>
<li>World backdrop DMX</li>
<li>LD passes</li>
<li>VJ Passes</li>
<li>DJ logo</li>
<li>DJ Audio</li>
<li>Interview</li>
<li>Countdown</li>
</ul>
<p>We put all this stuff into a single timeline, sync it up with the audio, go through a checklist and render it out with a preset to create what we call a "club ready video file".</p>
<p>Here's What the PUP!'s timeline:</p>
<p><img decoding="async" loading="lazy" alt="Timeline" src="https://value.gay/blog/assets/images/wtp-timeline-356c88ceb04e9906b1eb76be119de57d.jpg" width="2461" height="826" class="img_ev3q"></p>
<p>I'd consider this one to be one of the simpler ones as the VJ and LD have set me up for success. Every DJ set ends up having its own unique editor timeline given the content that's coming in and the workflow that the production team is using and how fancy the editor wants to make it.</p>
<p>Here's the timeline for Ashtalon.</p>
<p><img decoding="async" loading="lazy" alt="Timeline" src="https://value.gay/blog/assets/images/ash-timeline-cfd1a3a9693aa5b021207d72fb1ffdde.jpg" width="2464" height="886" class="img_ev3q"></p>
<p>We decided to program in Jill last minute, I had to fix a slight bug with the VJ content spilling over into another screen and I added in fade-ins to the content at the beginning and end. The LD also had a hiccup during recording that we communicated on and had to fix. They also did a second pass on a few of the parts at the end. So a bit more going on here.</p>
<p>And then if you're like me and like to be a producer and editor for some sets, you get monsters like Daxan and Birdbrain.</p>
<p><img decoding="async" loading="lazy" alt="Timeline" src="https://value.gay/blog/assets/images/daxan-timeline-54b80cd45745ad6334cf20dcb9498cf7.jpg" width="2443" height="1190" class="img_ev3q"></p>
<p>The clips are color coded:</p>
<ul>
<li>Blue - 16:9 content</li>
<li>Tan - gobo</li>
<li>Green - static gridnode data</li>
<li>Purple - MDMX Fixture programming</li>
<li>White - LD pass</li>
<li>Brown - "place and forget" content.</li>
</ul>
<p>For Daxan, I received unmapped 16:9 that I used <a href="https://videoremap.com/" target="_blank" rel="noopener noreferrer">VideoRemap</a> to map out. A lot of the DMX programming and timecode sequencing happened in the timeline as well, hence the large amount of green and purple clips.</p>
<p>Birdbrain:
<img decoding="async" loading="lazy" alt="Timeline" src="https://value.gay/blog/assets/images/birdbrain-timeline-7c4503f744f9765f45cc3c471527f6ed.jpg" width="2461" height="1218" class="img_ev3q"></p>
<p>Birdbrain also provided 16:9 that I mapped with <a href="https://videoremap.com/" target="_blank" rel="noopener noreferrer">VideoRemap</a>. A lot of the scenes were static so I was able to take screenshots of the screen DMX gridnode and sequence them in, hence all the green clips.</p>
<p>The reason why Birdbrain and Daxan's timelines are so complicated is because as the producer and editor I have the ability to easily control the whole club and I do not have to coordinate with the VJ and LD. Both of the DJs provided their own footage so my role as producer and editor was more of a "stage movement" designer in which I control how the visuals show up and what they do. The timeline was my way of expressing these stage motions.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="qa">QA<a href="https://value.gay/blog/furality-ultra-av#qa" class="hash-link" aria-label="Direct link to QA" title="Direct link to QA">​</a></h3>
<p>This year we had enough time to do proper QA passes on each set. We're still figuring out exactly what this process will look like, but this is one of the reasons why we were so on top of the production this year and why there were minimal issues once the club was up and running.</p>
<p>Once a CRVF draft was submitted, we either did a QA pass on it or put out a request for someone to do a QA pass on it. QAing a set meant streaming the set into the world and watching it in the world, taking notes of any things that look weird, feel missing or are outright incorrect. We then posted these issues in the production channel for that set and had that set's decision makers decide on how to fix or not fix them.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="putting-out-fires">Putting out Fires<a href="https://value.gay/blog/furality-ultra-av#putting-out-fires" class="hash-link" aria-label="Direct link to Putting out Fires" title="Direct link to Putting out Fires">​</a></h3>
<p>The production cycle wasn't perfect. Some things fell through the cracks, especially on a rig this complicated. I jumped on to fix issues with sets found 16-8 hours before that set is supposed to air. This usually required me to download the CRVF draft so far, and fix issues outlined in the QA passes.</p>
<p>So this means that some of the sets had some generational loss as the hotfix process required us to render over an existing CRVF draft, encoding it again. We got lucky and didn't notice any perceptive generational loss in this process in the visuals or gridnode data.</p>
<p>Sets I ended up hot fixing:</p>
<ul>
<li>Hotfixing for Zenko</li>
<li>Hotfixing for DJK9</li>
<li>Hotfixing for EKKO</li>
</ul>
<p>A few of us ended up doing this hotfix process and it turned out great.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="individual-projects">Individual Projects<a href="https://value.gay/blog/furality-ultra-av#individual-projects" class="hash-link" aria-label="Direct link to Individual Projects" title="Direct link to Individual Projects">​</a></h2>
<p>Some interesting stories and things I did during the individual productions.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="screen-presets">Screen Presets<a href="https://value.gay/blog/furality-ultra-av#screen-presets" class="hash-link" aria-label="Direct link to Screen Presets" title="Direct link to Screen Presets">​</a></h3>
<p>I ended up making a bunch of screen presets for the team to use. It was unreasonable to expect everyone to make custom screen layouts so I had set aside a few days to make a package that contains Resolume mappings, gridnode screenshots and the blend file for a bunch of various screen presets that the team could drag and drop into their projects.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/presets.mp4"></video></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="daratomic">Daratomic<a href="https://value.gay/blog/furality-ultra-av#daratomic" class="hash-link" aria-label="Direct link to Daratomic" title="Direct link to Daratomic">​</a></h3>
<p>Dara's a good friend of mine and as much as I don't like hardstyle I still ended up working with him on the set. Dara, Raeschen, Pammematth and All Night were wonderfull to work with. Hitting the emotion during the intro and ending visuals programming was especially important and spent a good few days making sure we hit that right.</p>
<p>I'm selfisly happy that we got to reveal Jill with this set. How Raeschen programmed Jill during the laser moment ended up inspiring me to do better with how I had initially programmed Jill in Daxan's set and that ended up giving us the UFO vs Jill fight as we saw it during the convention.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="daxan">Daxan<a href="https://value.gay/blog/furality-ultra-av#daxan" class="hash-link" aria-label="Direct link to Daxan" title="Direct link to Daxan">​</a></h3>
<p>Daxan's set was crazy there's like 87 entries in the credits table for that set. Daxan and Tea++ took up the work of being external co-producers and organized all of the work that went into making the 16:9 "movie" content. I worked with them to figure out how to present it in the club and then do all the big stage movements you see like the table, Jill vs UFO fighting, the DONK TV etc.</p>
<p>Big ups to that whole team for being as crazy as they are with what they were trying to do. Matching that energy forced me to think creatively with the rig and do weird and funny things with it.</p>
<p>Thanks to Kat Food for jumping in last minute to help us out with lights.</p>
<p>Also got a chance to play with TD some more and make an audio-reactive DJ booth for the set <!-- -->:D</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/daxan-logo-td.mp4"></video></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="birdbrain">BirdBrain<a href="https://value.gay/blog/furality-ultra-av#birdbrain" class="hash-link" aria-label="Direct link to BirdBrain" title="Direct link to BirdBrain">​</a></h3>
<p>BirdBrain has a special handover from the set before it [NBN] where that set's countdown doesn't fade out. We hard cut from that set into BirdBrain. So we had to coordinate on that and make some special countdown material to make that happen and it worked out pretty well.</p>
<p>I ended up doing something silly with MDMX CRC recalc. I took Daratomic's binary gridnode and distorted it and ran it through the CRC recalc to create the lighting that you see in the beginning of the set. It's all messed up and the lights are going everywhere but that's intended as it fits the theme of the set.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/f9/birdbrain-gridnode.mp4"></video></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="fireworks">Fireworks<a href="https://value.gay/blog/furality-ultra-av#fireworks" class="hash-link" aria-label="Direct link to Fireworks" title="Direct link to Fireworks">​</a></h3>
<p>The fireworks team needed some help getting the final composite of the showfile ready. They sent me the individual clips and walked me through the show's cues and I put them all into a timeline and rendered them out.</p>
<p>The fireworks showfile was going to be delivered via HTTP on a CDN. So the thing I was rendering out was going to be played on everyones machines. And so, we had to render out in H.264 as that's the codec that we're guaranteed to have on all platforms. This meant using Davinci Native H.264 to render gridnode only video file.</p>
<p>The results were catastrophically bad.</p>
<p>The fireworks show video is all gridnode, most of it taken up by drones. Once the drones started moving, the H.264 native encoder completely gave up and had intra-frame smearing. On higher CBR bitrates it ended up being better, at the cost of a large video file. I'm not sure exactly what encoder "Native" is, but its seems like on windows it would be the <a href="https://forum.blackmagicdesign.com/viewtopic.php?f=21&amp;t=185356#p967399" target="_blank" rel="noopener noreferrer">WMF H.264 encoder</a></p>
<p>I know from experience that NVIDIA's encoder would also not be great as it has psycho-visual tuning and is optimized for real time encoding as opposed to mathematical accuracy. So that was off the table.</p>
<p>Something came to mind: what if we render out a ProRes 422 file and then transcode it to H.264 with VideoLAN x264 using Ffmpeg?</p>
<p>A few hours later we had a 213Mb H.264 show file with MINIMAL gridnode CRC decode errors.</p>
<p>This is the FFmpeg command line I ended up using to transcode:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">ffmpeg -i "Fireworks ProRes 422 Master V1.mov" -pix_fmt yuv420p -c:v libx264 -tune animation -profile:v high -preset slower -crf 23 -c:a copy "Fireworks x264 Master V1.mp4"</span><br></span></code></pre></div></div>
<ul>
<li>yuv420p to force a limited video color format to save on space.</li>
<li>Animation because idfk that's what was in my head at the time.</li>
<li>CRF 23 seemed to be okay (and turns out 20-23 is a good sweet spot for gridnode only data when <a href="https://www.desmos.com/calculator/3ofgoxdoty" target="_blank" rel="noopener noreferrer">measuring file size</a> and CRC error)</li>
<li>Profile high as all platforms we're targeting support it.</li>
<li>Preset slower since we had the time to sit there a bit longer for a higher quality file.</li>
</ul>
<p>After a bit of digging I found that there's an encoder pack that lets you use <a href="https://github.com/EdvinNilsson/ffmpeg_encoder_plugin" target="_blank" rel="noopener noreferrer">FFmpeg in Davinci</a>
We trialed it after the convention and found that for CRVFs it's about 3x slower but it still has good quality. It seems to break AV1 encoding on my machine though. This is a tad slow for us and I'd personally only use it if I had to encode more gridnode only content and not CRVFs that have a mixture of gridnode and visual content.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="closing">Closing<a href="https://value.gay/blog/furality-ultra-av#closing" class="hash-link" aria-label="Direct link to Closing" title="Direct link to Closing">​</a></h2>
<p>If you're interested in this kind of stuff, I encourage you to go get involved in helping run your favourite venue. Whether it's VR or at an IRL convention, talk to the people running the show and see if you can help out! While this kind of stuff is a lot of work, it's a space with an incredible amount of technical and creative overlap. If you're the kind of person searching for that, try it out!</p>]]></content:encoded>
            <category>av</category>
            <category>furality</category>
        </item>
        <item>
            <title><![CDATA[Stage Flight 3.14 Writeup]]></title>
            <link>https://value.gay/blog/stage-flight-314</link>
            <guid>https://value.gay/blog/stage-flight-314</guid>
            <pubDate>Tue, 10 Mar 2026 00:00:00 GMT</pubDate>
            <description><![CDATA[Quick technical and workflow writeup about some Stage Flight 3.14 stuff I've worked on.]]></description>
            <content:encoded><![CDATA[<p>Quick technical and workflow writeup about some Stage Flight 3.14 stuff I've worked on.
I only had time to touch on the Moonglow set for this iteration of SF.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="video-editing">Video Editing<a href="https://value.gay/blog/stage-flight-314#video-editing" class="hash-link" aria-label="Direct link to Video Editing" title="Direct link to Video Editing">​</a></h2>
<p><img decoding="async" loading="lazy" alt="Timeline" src="https://value.gay/blog/assets/images/videoediting-60d810033a743f6f850c654fab2a274d.png" width="2012" height="1000" class="img_ev3q"></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mdmx-tooling">MDMX Tooling<a href="https://value.gay/blog/stage-flight-314#mdmx-tooling" class="hash-link" aria-label="Direct link to MDMX Tooling" title="Direct link to MDMX Tooling">​</a></h3>
<p>I ended up developing tools to help control MDMX from Davinci Resolve.</p>
<p><a href="https://github.com/valuef/mdmx-davinci" target="_blank" rel="noopener noreferrer">Find it here</a></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mdmx-fixture">MDMX Fixture<a href="https://value.gay/blog/stage-flight-314#mdmx-fixture" class="hash-link" aria-label="Direct link to MDMX Fixture" title="Direct link to MDMX Fixture">​</a></h3>
<p>MDMX Fixture is a generator plugin that lets us define fixtures and load them on an instance of the plugin. Fixtures define controls which are then exposed to the user, which lets us control an animate various parts of the stage from within the Davinci Resolve timeline.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/sf314/mdmx-fixture.mp4"></video></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="mdmx-crc-recalc">MDMX CRC Recalc<a href="https://value.gay/blog/stage-flight-314#mdmx-crc-recalc" class="hash-link" aria-label="Direct link to MDMX CRC Recalc" title="Direct link to MDMX CRC Recalc">​</a></h3>
<p>MDMX CRC Recalc lets us recalculate the error checking CRC bits of the MDMX blade of the club ready file. If we were to add or modify MDMX data without this, the world would discard any of the data as the CRC that it calculates does not match the CRC bits on the MDMX data streamed in through the video. So this lets us add, composite, and generally change the MDMX data in Davinci Resolve.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/sf314/mdmx-crc.mp4"></video></p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="videoremap">VideoRemap<a href="https://value.gay/blog/stage-flight-314#videoremap" class="hash-link" aria-label="Direct link to VideoRemap" title="Direct link to VideoRemap">​</a></h2>
<p>This is probably the 3rd time I've used <a href="https://videoremap.com/" target="_blank" rel="noopener noreferrer">VideoRemap</a> on a Stage Flight project. I did some VJing for the Moonglow set.</p>
<p>I ended up trialing a new workflow for using VideoRemap that uses composite clips and it lets you map a whole timeline to one or more screens:</p>
<ul>
<li>Start with a "master timeline" that ends up containing all the mappped footage you'll use.</li>
<li>Create an adjustment clip that spans the range you want to prepare content for.</li>
<li>Convert that adjustment clip into a composite clip.</li>
<li>Copy over the part of the set audio that matches the start and end of that adjustment clip and paste it into the composite clip timeline.</li>
<li>Sync up footage with that audio in the composite clip.</li>
<li>Edit your footage in the composite clip.</li>
<li>Apply VideoRemap on the composite clip in the master timeline.</li>
</ul>
<p>Ended up working pretty well. Used it to map lyrics to the main screen and HAM particles and also the whole usual VR actor thing onto live cam and DJ booth screens.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/sf314/videoremap.mp4"></video></p>
<p>Pros:</p>
<ul>
<li>Lets you VideoRemap an arbitrarily complex timeline.</li>
<li>Lets you bake out that timeline with the ability to decompose it easily to make changes.</li>
</ul>
<p>Cons:</p>
<ul>
<li>Composite clips share the timeline size that they were created on, which is not always ideal. There's probably a analogous workflow by using child timelines where we explicitly set the resolution and them VideoRemap them in fusion to preserve that resolution.</li>
</ul>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="spout-output">Spout Output<a href="https://value.gay/blog/stage-flight-314#spout-output" class="hash-link" aria-label="Direct link to Spout Output" title="Direct link to Spout Output">​</a></h2>
<p>I end up dropping the <a href="https://github.com/valuef/davinci-spout-sender" target="_blank" rel="noopener noreferrer">spout output plugin</a> into every VJ project now. It's just incredibly useful to output directly to obs without having to capture a whole monitor or get a piece of hardware that davinci sends video out to.</p>
<h2 class="anchor anchorWithStickyNavbar_LWe7" id="world-dev">World Dev<a href="https://value.gay/blog/stage-flight-314#world-dev" class="hash-link" aria-label="Direct link to World Dev" title="Direct link to World Dev">​</a></h2>
<p>I ended up doing a bit of shader work for the Moonglow set.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="celestial-bodies">Celestial Bodies<a href="https://value.gay/blog/stage-flight-314#celestial-bodies" class="hash-link" aria-label="Direct link to Celestial Bodies" title="Direct link to Celestial Bodies">​</a></h3>
<p>A request came in to add a moon &amp; sun effects to the skybox.</p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="sun">Sun<a href="https://value.gay/blog/stage-flight-314#sun" class="hash-link" aria-label="Direct link to Sun" title="Direct link to Sun">​</a></h3>
<p>Doing the sun was going to be easy enough. The parameterization we settled on for both the moon and sun was in spherical coordinates without the radial component, giving us a (azimuth, polar) pair.</p>
<p>We can convert the spherical coordinates to a direction in which the sun is pointing:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">float3 sphere_dir;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sphere_dir.x = sin(body_polar) * cos(body_azimuth);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sphere_dir.y = sin(body_polar) * sin(body_azimuth);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sphere_dir.z = cos(body_polar);</span><br></span></code></pre></div></div>
<p>The skybox shader gives us a 3D view direction into the skybox.</p>
<p>We can take the dot product between this ray and sun direction to get the angle between the two which gives us enough to make the sun disk and glow.</p>
<p>To make the parameterization human friendly, I converted the cos angle to radians.</p>
<p>From there it's just a matter of expressing a mask for the disk and glow:</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">float body_size = 30./255.; // baked in after testing, in radians</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">float cos_angle = dot(sphere_dir, ray);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">float angle = acos(cos_angle);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">// https://www.desmos.com/calculator/umlhp8ps3j</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">float knee = 100;</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">float disk = saturate(1-(saturate(angle - body_size)*knee));</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">float bloom = saturate((1/(saturate(angle - body_size)*knee)) - (1/knee));</span><br></span></code></pre></div></div>
<p>And we have a sun! I wanted to make it a bit more interesting so I experimented with a crude approximation of reyleigh scattering.</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#F8F8F2;--prism-background-color:#282A36"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#F8F8F2;background-color:#282A36"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#F8F8F2"><span class="token plain">float rayleigh = pow(1-ray.y,4);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sun_color.r = exp(-rayleigh * 0);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sun_color.g = exp(-rayleigh * 3.1);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sun_color.b = exp(-rayleigh * 80.45);</span><br></span><span class="token-line" style="color:#F8F8F2"><span class="token plain">sun_color = saturate(sun_color);</span><br></span></code></pre></div></div>
<p>This just starts to remove from the green and blue components of the sun color as the sun starts to approach the horizon line, mimicking how wavelengths of light that tend toward violet have to scatter more and more as the sun approaches the horizon, whereas red light scatters the least.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/sf314/sun.mp4"></video></p>
<p><a href="https://www.desmos.com/calculator/xe5cf4sehm" target="_blank" rel="noopener noreferrer">https://www.desmos.com/calculator/xe5cf4sehm</a></p>
<p><a href="https://www.youtube.com/watch?v=DxfEbulyFcY" target="_blank" rel="noopener noreferrer">Sebastian Lague has a great explainer on modelling atmospheres</a></p>
<h3 class="anchor anchorWithStickyNavbar_LWe7" id="moon">Moon<a href="https://value.gay/blog/stage-flight-314#moon" class="hash-link" aria-label="Direct link to Moon" title="Direct link to Moon">​</a></h3>
<p>For the moon, I wanted texture mapping. Naturally that made things a bit more complicated.</p>
<p>After some experiments I landed on using a ray vs sphere intersection which would give me a latitude longitude pair to do texture mapping with. Dug up some old C++ code I wrote when I was doing raytracing and now we have a moon in the sky!</p>
<p>I experimented with normal mapping the moon and giving it a simple lighting model. We didn't end up needing it in the end but it looks pretty neat.</p>
<p><video style="max-width:100%;height:auto" autoplay="" loop="" muted="" controls="" playsinline="" src="/blog/img/sf314/moon-editor.mp4"></video></p>
<p>This looks massive in VR, desktop doesn't quite do it justice.</p>
<p>I ran into a issue where due to the raytracing math, I wasn't sure what the unit/relationship was between the provided radius and the size of the moon in the screen. We needed to know that as for the moon glow, the size was expressed in radians and had to match the size of the moon in the sky.</p>
<p>Instead of getting into the weeds with trying to math out the relationship, <a href="https://www.desmos.com/calculator/dyv88rjge5" target="_blank" rel="noopener noreferrer">ended up approximating the relationship function and moved on</a></p>
<p><img decoding="async" loading="lazy" alt="Moon" src="https://value.gay/blog/assets/images/moon-world-7a67075fa26cf0d92a871b678fddd29f.png" width="2083" height="1314" class="img_ev3q"></p>]]></content:encoded>
            <category>av</category>
            <category>stage-flight</category>
        </item>
    </channel>
</rss>