<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[Igor Clark]]></title><description><![CDATA[Technology projects by Igor Clark]]></description><link>https://portfolio.igorclark.net/</link><image><url>https://portfolio.igorclark.net/favicon.png</url><title>Igor Clark</title><link>https://portfolio.igorclark.net/</link></image><generator>Ghost 4.31</generator><lastBuildDate>Mon, 14 Sep 2026 18:34:27 GMT</lastBuildDate><atom:link href="https://portfolio.igorclark.net/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[LG: Radio Optimism]]></title><description><![CDATA[<p>An online radio station that allows visitors to create complete songs and scheduled shout-outs, just by typing in encouraging messages for their friends.</p><p>Working with TBWA\<a href="https://www.dotdotdash.io/">DotDotDash</a> out of NYC, I architected and tech-directed the entire system for this AI-driven campaign site for <a href="https://www.lg.com/">LG</a>. I also wrote a custom back-end</p>]]></description><link>https://portfolio.igorclark.net/projects/lg-radio-optimism/</link><guid isPermaLink="false">6911d42607a7ad0001d7219e</guid><category><![CDATA[DotDotDash]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Tue, 01 Jul 2025 13:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2025/11/lg-feature-image.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2025/11/lg-feature-image.jpg" alt="LG: Radio Optimism"><p>An online radio station that allows visitors to create complete songs and scheduled shout-outs, just by typing in encouraging messages for their friends.</p><p>Working with TBWA\<a href="https://www.dotdotdash.io/">DotDotDash</a> out of NYC, I architected and tech-directed the entire system for this AI-driven campaign site for <a href="https://www.lg.com/">LG</a>. I also wrote a custom back-end API using <a href="https://postgrest.org/">postgREST</a>, and designed &amp; implemented a complex off-line processing chain to generate the songs using <a href="https://aws.amazon.com/lambda/">AWS Lambda</a> functions.</p><p>The processing chain was orchestrated by a sequence of <a href="https://www.postgresql.org/">PostgreSQL</a> functions, each triggered by user inputs or outputs from peer processes, and kicking off the appropriate Lambda functions to build a song and its &quot;album cover&quot;.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/11/lg-track-page.jpg" class="kg-image" alt="LG: Radio Optimism" loading="lazy" width="1836" height="1480" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/11/lg-track-page.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/11/lg-track-page.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2025/11/lg-track-page.jpg 1600w, https://portfolio.igorclark.net/content/images/2025/11/lg-track-page.jpg 1836w" sizes="(min-width: 720px) 720px"><figcaption>AI-generated song &amp; album cover featured on Radio Optimism</figcaption></figure><p>Each step carried out a single task, from content moderation through prompt, lyrics, audio and image generation, and finally copyright filtering, storing its output back to the database - which then triggered the next step.</p><p>The Lambda functions were written in <a href="https://nodejs.org/">node.js</a> and communicated variously with 3rd-party AI services to create the songs and the artwork. These services included <a href="https://openai.com/">OpenAI</a> and <a href="https://replicate.com/">LlamaGuard on Replicate</a> for UGC moderation and sanitisation, <a href="https://www.controlla.xyz/">Controlla Audio</a> for song generation, <a href="https://www.adobe.com/products/firefly.html">Adobe Firefly</a> for images, and <a href="https://www.acrcloud.com/">ACR Cloud</a> for audio content fingerprinting.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/11/lg-application-flow-diagram.jpg" class="kg-image" alt="LG: Radio Optimism" loading="lazy" width="2000" height="1276" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/11/lg-application-flow-diagram.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/11/lg-application-flow-diagram.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2025/11/lg-application-flow-diagram.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2025/11/lg-application-flow-diagram.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>App execution flow diagram for Radio Optimism</figcaption></figure><p>As the services were all using AI, each step in the chain would take an unpredictable amount of time, and the overall delivery time for a user&apos;s song could be between 60-90 or even 120 seconds. This meant that the entire processing flow needed to be completely asynchronous. To this end I designed the system to work with a series of event-based actions and timeouts, rather than standard synchronous API calls, in order to be able to keep the user experience responsive and the back-end processing resources lightweight.</p><p>The complexity and timing of the song processing also meant that we had a fairly involved chain of actions, with a variety of possible execution paths. These all needed to be carefully monitored and tracked, to give us detailed observability of the processing flow during development, enable extensive integration and performance testing flows for the full API and 3rd-party services, and to help with any troubleshooting in production. We also needed to be able to &#xA0;generate large volumes of song requests in order to understand the scaling profile of the Lambda processing system.</p><p>To that end, I created a load/performance-testing and live monitoring tool, using <a href="https://www.erlang.org/">Erlang/OTP</a> for rapid development, very low latency and response times. The tool spawned large numbers of concurrent API clients via its web-based UI, using randomised user data to request a song generation for each one, and reported low-level information about all the steps taking place in the course of generating song&apos;s audio and imagery.</p><p>Every PostgreSQL <a href="https://www.postgresql.org/docs/current/sql-createtrigger.html">trigger</a> in the API database sent lightweight <a href="https://www.postgresql.org/docs/current/sql-notify.html">NOTIFY</a> messages to any listening monitor tools, containing metadata about each event. The monitor tool would then fan out these notifications in turn to any listening UI clients, and ultimately back to the mock API clients so that they&apos;d be able to complete their mock user journeys appropriately. This simulated realistic load for the song generation system, while providing real-time updates on the progress of individual and aggregate song generations via the monitor UI.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/11/lg-monitor-success-page.jpg" class="kg-image" alt="LG: Radio Optimism" loading="lazy" width="2000" height="853" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/11/lg-monitor-success-page.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/11/lg-monitor-success-page.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2025/11/lg-monitor-success-page.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2025/11/lg-monitor-success-page.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>Monitor tool showing a successful set of song generations</figcaption></figure><p>Showing all the currently-processing songs in a grid provided a really quick overview as to the overall health of the system and its partner services, as well as allowing a drilled-down view into very specific details of what was working out and what was having problems.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/11/lg-monitor-failure-page.jpg" class="kg-image" alt="LG: Radio Optimism" loading="lazy" width="2000" height="625" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/11/lg-monitor-failure-page.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/11/lg-monitor-failure-page.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2025/11/lg-monitor-failure-page.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2025/11/lg-monitor-failure-page.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>Monitor tool showing processing errors in song generation</figcaption></figure><p>This helped out enormously in development as well as providing a very detailed view for our LG deployment partners, giving them confidence about system visibility and immediate feedback on system performance as they rolled out the software into their regulated AWS environment.</p><p>The site&apos;s front-end and middleware were written in <a href="https://nextjs.org/">Next.js</a>, deployed via <a href="https://aws.amazon.com/cloudfront/">AWS Cloudfront</a> CDN and <a href="https://aws.amazon.com/fargate/">Fargate</a> serverless compute, and talked via an <a href="https://openresty.org/">OpenResty</a>/<a href="https://nginx.org/">nginx</a> proxy to the postgREST API. PostgreSQL functions (running in an <a href="https://aws.amazon.com/rds/postgresql/">AWS RDS</a> database) invoked Lambda functions asynchronously using the <a href="https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/PostgreSQL-Lambda.html">aws_lambda</a> extension (provided by AWS ), which communicated in turn with the various 3rd-party service APIs. Assets were all stored in <a href="https://aws.amazon.com/s3/">AWS S3</a>, also served behind a Cloudfront distribution.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/11/lg-tech-architecture-diagram.jpg" class="kg-image" alt="LG: Radio Optimism" loading="lazy" width="2000" height="792" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/11/lg-tech-architecture-diagram.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/11/lg-tech-architecture-diagram.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2025/11/lg-tech-architecture-diagram.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2025/11/lg-tech-architecture-diagram.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>System architecture for Radio Optimism</figcaption></figure><p>I directed a 3-strong tech team of front-end developers and dev-ops, which swelled to 6 at some of the busiest parts of the project, as requirements inevitably changed in the face of a static deadline. We managed all app code &amp; assets using <a href="https://www.github.com/">GitHub</a> &amp; <a href="https://aws.amazon.com/cloudformation/">AWS CloudFormation</a> for our internal CI/CD and converted the CloudFormation templates to <a href="https://developer.hashicorp.com/terraform">Terraform</a> for delivery to the deployment partner.</p><p>Here&apos;s a demo video of the load-test &amp; monitoring tool, which shows more detail about how it works. As often, developing a comprehensive testing tool in tandem with the system itself allowed for really intricate performance measurements, along with effective integration/regression testing during development, deployment, and into production.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/1093785704?h=1f78bf62ea&amp;app_id=122963" width="240" height="258" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write; encrypted-media; web-share" referrerpolicy="strict-origin-when-cross-origin"></iframe></figure>]]></content:encoded></item><item><title><![CDATA[Interactive LED basketball court]]></title><description><![CDATA[<p>For the 2024 All-Star weekend, NBA commissioned <a href="https://asbglassfloor.com">ASB GlassFloor</a> to create a series of interactive games for game stars to play on their game-certified LED floor at the <a href="https://en.wikipedia.org/wiki/Indiana_Pacers">Indiana Pacers</a>&apos; <a href="https://en.wikipedia.org/wiki/Gainbridge_Fieldhouse">Gainbridge Fieldhouse</a>.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/752_rIE53Tk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="Take a look at the LED court being used at NBA All-Star 2024"></iframe></figure><p>Players carried multiple tracking beacons including <a href="https://blacktrax.cast-soft.com">BlackTrax</a> and <a href="https://kinexon.com">Kinexon</a>, all of which transmitted position data to be</p>]]></description><link>https://portfolio.igorclark.net/projects/nba-all-star/</link><guid isPermaLink="false">66842db97ce6b60001c17d61</guid><category><![CDATA[NBA All-Stars]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Fri, 16 Feb 2024 17:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2024/07/72648067007-021724-all-star-saturday-night-0052-1.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2024/07/72648067007-021724-all-star-saturday-night-0052-1.jpg" alt="Interactive LED basketball court"><p>For the 2024 All-Star weekend, NBA commissioned <a href="https://asbglassfloor.com">ASB GlassFloor</a> to create a series of interactive games for game stars to play on their game-certified LED floor at the <a href="https://en.wikipedia.org/wiki/Indiana_Pacers">Indiana Pacers</a>&apos; <a href="https://en.wikipedia.org/wiki/Gainbridge_Fieldhouse">Gainbridge Fieldhouse</a>.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/752_rIE53Tk?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen title="Take a look at the LED court being used at NBA All-Star 2024"></iframe></figure><p>Players carried multiple tracking beacons including <a href="https://blacktrax.cast-soft.com">BlackTrax</a> and <a href="https://kinexon.com">Kinexon</a>, all of which transmitted position data to be collected and aggregated in close-to-real time, and streamed over the network to an <a href="https://www.unrealengine.com/">Unreal Engine</a> app which would compute and render the game graphics for the huge display.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2024/07/nba-as24-led-court-collage.jpg.webp" class="kg-image" alt="Interactive LED basketball court" loading="lazy" width="1400" height="788" srcset="https://portfolio.igorclark.net/content/images/size/w600/2024/07/nba-as24-led-court-collage.jpg.webp 600w, https://portfolio.igorclark.net/content/images/size/w1000/2024/07/nba-as24-led-court-collage.jpg.webp 1000w, https://portfolio.igorclark.net/content/images/2024/07/nba-as24-led-court-collage.jpg.webp 1400w" sizes="(min-width: 720px) 720px"></figure><p>I was asked to design and implement a data system to handle all the incoming tracking data via various <a href="https://en.wikipedia.org/wiki/User_Datagram_Protocol">UDP</a> app protocols, aggregating it into a common data format, storing it for fast time-based retrieval, providing access, recording and playback APIs for use by game logic apps to enable dynamic instant replays.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2024/07/IMG_5962.jpg" class="kg-image" alt="Interactive LED basketball court" loading="lazy" width="2000" height="1500" srcset="https://portfolio.igorclark.net/content/images/size/w600/2024/07/IMG_5962.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2024/07/IMG_5962.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2024/07/IMG_5962.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2024/07/IMG_5962.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>After some initial proof-of-concept work, prototyping and benchmarking, I settled on &quot;the simplest possible architecture that would work&quot;: a <a href="https://redis.io/">Redis</a> <a href="https://en.wikipedia.org/wiki/Publish&#x2013;subscribe_pattern">pub-sub</a> server and client and a <a href="https://mariadb.org">MariaDB</a> (MySQL) database, with <a href="https://nodejs.org/en">node.js</a> as a data-fusing &amp; routing engine.</p><p>The node.js app received BlackTrax, Kinexon, Unreal and <a href="https://mixondigital.com">Mixon</a> data over various <a href="https://rttrp.github.io/RTTrP-Wiki/RTTrPM.html">RTTrPM</a> and <a href="https://en.wikipedia.org/wiki/Open_Sound_Control">OSC</a> connections, packaging and publishing them to a Redis channel, providing a constant stream of current player positions. Two separate subscribed clients fetched new data on the channel, the first forwarding directly to game logic code, the second storing position frames to the database as part of specified game segments when requested.</p><p>A <code>PlaybackEngine</code> &#xA0;provided a mechanism for game logic to look up, select and request specific segments to be played back, at which point the engine would fetch the relevant data frames and re-transmit them via the live channel, so that app code could integrate instant replays into gameplay.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/974386043?h=a964c4f97c&amp;app_id=122963" width="240" height="252" frameborder="0" allow="autoplay; fullscreen; picture-in-picture; clipboard-write" title="NBA prototyping"></iframe></figure><p>As the project was on a tight deadline and there were a lot of unknowns relating to game content, much of the work needed to be done in parallel, and as close to the actual live environment as possible. Significant differences in behaviour between some of the data-stream simulator software and the real streaming hardware also meant that we needed to be testing code against the production rig as much as possible. This in turn meant firstly going to the ASB HQ near Munich, and then to a colossal warehouse outside Indiana where the full system was installed for development and testing in the weeks leading up to the game - both of which were in at least -5&#xBA;C temperatures!</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2024/07/IMG_6159-2.jpg" class="kg-image" alt="Interactive LED basketball court" loading="lazy" width="2000" height="2667" srcset="https://portfolio.igorclark.net/content/images/size/w600/2024/07/IMG_6159-2.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2024/07/IMG_6159-2.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2024/07/IMG_6159-2.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2024/07/IMG_6159-2.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>I wrapped up and handed over my work on the data service engine a week or two prior to the event, at which point the rest of the team pressed ahead finishing and polishing the game components for a successful and much-lauded display in Indianapolis on the live weekend.</p>]]></content:encoded></item><item><title><![CDATA[Parallel Processing Pipeline]]></title><description><![CDATA[<p>Since the successful reception of the <a href="https://portfolio.igorclark.net/projects/ntd-simulator/">Prevalence Simulator</a>, I&apos;ve continued to provide cloud consulting and development services for the <a href="https://www.ntdmodelling.org/">NTD Modelling Consortium</a> (NTDMC) via the epidemiology faculty at Oxford University&apos;s <a href="https://www.bdi.ox.ac.uk">Big Data Institute</a> (BDI). A big part of my work for the modelling team involves using</p>]]></description><link>https://portfolio.igorclark.net/projects/parallel-processing-pipeline/</link><guid isPermaLink="false">678238a6450a40000199f04e</guid><category><![CDATA[NTD Modelling Consortium]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Thu, 12 Oct 2023 21:05:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2024-08-25-at-22.31.24-copy-2-2Kpx.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2024-08-25-at-22.31.24-copy-2-2Kpx.jpg" alt="Parallel Processing Pipeline"><p>Since the successful reception of the <a href="https://portfolio.igorclark.net/projects/ntd-simulator/">Prevalence Simulator</a>, I&apos;ve continued to provide cloud consulting and development services for the <a href="https://www.ntdmodelling.org/">NTD Modelling Consortium</a> (NTDMC) via the epidemiology faculty at Oxford University&apos;s <a href="https://www.bdi.ox.ac.uk">Big Data Institute</a> (BDI). A big part of my work for the modelling team involves using tools and processes I&apos;ve developed to run large numbers of their data simulations in parallel, across many CPU cores on powerful cloud computers. Which is what&apos;s happening in the image: lots of simulations running on lots of CPUs.</p><p>Funded by the <a href="https://www.gatesfoundation.org/">Gates Foundation</a>, the NTDMC works on projecting effective approaches for eradicating a selection of <a href="https://en.wikipedia.org/wiki/Neglected_tropical_diseases">neglected tropical diseases</a>. With the help of <a href="https://researchsoftware.org/">Research Software Engineers</a> (RSEs) at the BDI, epidemiology researchers maintain and develop open-source <a href="https://github.com/NTD-Modelling-Consortium">software implementations</a> of their <a href="https://www.ncrm.ac.uk/news/show.php?article=5824">agent-based</a> statistical models to simulate multiple treatment scenarios for a variety of parasite-borne diseases until 2040. The scenarios usually include <a href="https://www.who.int/publications/m/item/mass-drug-administration-(mdas)--an-opportunity-for-community-engagement-and-social-behaviour-change">mass drug administration</a> (MDA) programs, and currently model worm and human-host life-cycles in sub-Saharan Africa, with future efforts potentially looking to regions of India.</p><p>Working with colleagues from <a href="https://opencultu.re/">OpenCulture</a>, I&apos;ve been helping with the development, orchestration and large-scale execution of the software models; managing the result data sets and coordinating with technical and scientific members of the BDI and other NTDMC partners at other universities; and shepherding the data all the way through to OpenCulture&apos;s visualisations for the NTDMC&apos;s research paper outputs. As part of the development work I&apos;ve liaised with, and helped hire, RSE staff at the BDI, as well as advising epidemiology researchers on software structure and modularisation.</p><p>Any one &quot;run&quot; of a particular model carries out a number (usually 200) of simulations, starting from a set of seed data pre-computed by other epidemiological tools. Each run uses a specific set of parameters for a scenario (e.g. MDA treatment type &amp; frequency, provision of protective bed nets, adherence to the program in a given population), and calculates outcomes for that scenario based on averages of all the simulation results.</p><p>I organise per-disease simulation runs and data management. Starting from the basic tooling I initially put in place for pre-computing the Prevalence Simulator&apos;s result sets, I&apos;ve extended and automated the approach, so that we can quickly and straightforwardly run large numbers of scenario simulations across multiple diseases, on many CPU cores across many virtual machines at a time, on an ad-hoc basis.</p><p>This may not be Google-scale &quot;big data&quot;, but it does generate tens to hundreds of gigabytes, across thousands of output files, for each of many simulation runs, all of which need to be managed, transmitted to partners, and post-processed for incorporation into intuitive visualisations of the outcomes. That&#x2019;s perhaps not enough to justify using enterprise-style data management products (or the associated price tags), but it definitely is enough to need some kind of structure and organisation. As the processing schedule is intertwined with the outputs of sometimes unpredictable research work, we have very bursty processing patterns: no processing might be needed for days or weeks, but then many thousands of simulations for a number of diseases will need to be quickly turned round all together.</p><p>The models work at the level of a given implementation unit (IU, an administrative designation usually representing a region of a country). Running 200 simulations for a given disease/scenario/IU combination can often be completed in a few minutes, though this can vary greatly depending on the complexity of the model, the extent to which a given disease is endemic in a particular IU, and other complicating factors. Providing statistically meaningful numbers of simulations &#xA0;requires running multiple scenarios for each disease across thousands of implementation units; scenarios and even modelling approaches can vary as a result of new field data or organisational change, requiring new sets of simulation runs across large geographical regions.</p><p>The software models are written variously in Python and &#xA0;C++, and are generally CPU-bound: i.e. they take up all the time of the CPU cores they&apos;re using at a given point. Some of the models are single-threaded and some use Python&apos;s &apos;<a href="https://docs.python.org/3/library/multiprocessing.html">multiprocessing</a>&apos; library to split the work across multiple cores. I use a combination of cloud virtual machine (VM) automation and Linux tooling to parallelise the tasks across worker processes as necessary according to their execution model and then further across multiple VMs.</p><p>I run all this on <a href="https://cloud.google.com/">Google Cloud Platform</a>. This gives us low-cost, easily managed data storage that can be organised hierarchically by disease and by scenario and shared with NTDMC partners. It also gives us a lot of flexibility in accessing processing power: we can quickly spin up large, multi-processor VMs, billed by the second, and switch them off immediately when the processing&#x2019;s done. I&apos;ve organised big enough usage quotas with GCP that we can access the processing power we need to run large jobs at will: the largest so far has been twelve 128-core machines running 1536 simulations at a time to project forward a range of <a href="https://www.who.int/news-room/fact-sheets/detail/onchocerciasis">epionchocerciasis</a> treatments across 19 countries.</p><p>I&apos;ve also independently created and presented a proof-of-concept for running agent-based worm life-cycle models in <a href="https://www.erlang.org/">Erlang/OTP</a>. Following my instinct about the work required to parallelise the existing model runs, my OpenCulture colleague and I identified and planned a potential new approach by which we could run simulations across much larger populations, with multiple diseases simultaneously. This wouldn&apos;t just be for efficiency purposes, though that&apos;s a key factor, but also to help account for the presence of (and interaction between) multiple parasites in a given human host. I wrote the Erlang POC to demonstrate how this could work.</p><p>My rationale was that the existing models&apos; implementation in Python and C++ has meant that while they can achieve very good sequential performance, single-threaded code has to be managed to use all the resource of a multi-core VM, scaling even multi-threaded code beyond the limits of a single machine will involve complex distribution mechanisms in code or tooling, and organising large simulation runs involves potentially brittle orchestration across multiple VMs (or containers, pods, etc).</p><p>Conversely, modelling worm life-cycles using Erlang&apos;s lightweight concurrency primitives means firstly that the <a href="https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)">BEAM</a> scheduler (sometimes with a bit of <a href="https://erlangforums.com/t/beam-on-128-core-linux-box-seeming-not-to-use-many-of-available-cores/3858">hinting</a>) can seamlessly spread the work across all the cores in a large multi-core machine; and secondly that the simulations can be scaled across multiple such machines straightforwardly using Erlang&apos;s built-in <a href="https://www.erlang.org/doc/system/distributed.html">distribution &amp; clustering mechanism</a>, with host and worm processes in a life-cycle system running on an Erlang cluster executing on separate machines while participating as peers in the overall simulation.</p><p>The prototype runs on a single machine so far, but clearly demonstrates the ability to run multi-disease simulations extremely efficiently across 128 cores in an environment providing powerful clustering tools:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2024-08-13-at-09.12.20.png" class="kg-image" alt="Parallel Processing Pipeline" loading="lazy" width="2000" height="242" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/01/Screenshot-2024-08-13-at-09.12.20.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/01/Screenshot-2024-08-13-at-09.12.20.png 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2025/01/Screenshot-2024-08-13-at-09.12.20.png 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2025/01/Screenshot-2024-08-13-at-09.12.20.png 2400w" sizes="(min-width: 720px) 720px"><figcaption>More terminal fun: prototype worm life-cycle software in Erlang distributed across 128 cores</figcaption></figure><p>The presentation was well received, and I&apos;m hopeful that once the current schedule has been completed there may be opportunities to further this work in partnership with NTDMC research scientists.</p><p></p>]]></content:encoded></item><item><title><![CDATA[Multiplayer llama world]]></title><description><![CDATA[<p>A boutique digital agency in LA asked if I could help out with some performance problems they&apos;d encountered on the time-sensitive, high-stakes, secret client project they were building for a large tech company. Covid had disrupted the client&apos;s annual all-hands meeting, so they&apos;d been</p>]]></description><link>https://portfolio.igorclark.net/projects/multiplayer-llama-world/</link><guid isPermaLink="false">6784f8757fb9ad00016f4b87</guid><category><![CDATA[Secret Squirrel Project]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Thu, 06 Jan 2022 18:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2025-01-13-at-11.29.41-smaller.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2025-01-13-at-11.29.41-smaller.jpg" alt="Multiplayer llama world"><p>A boutique digital agency in LA asked if I could help out with some performance problems they&apos;d encountered on the time-sensitive, high-stakes, secret client project they were building for a large tech company. Covid had disrupted the client&apos;s annual all-hands meeting, so they&apos;d been commissioned to build an online version where company staff could join in live, communicate with each other in virtual rooms (&quot;Worlds&quot;), watch C-suite presentations together on virtual in-world screens, and chat about them afterwards. All while manifesting in this custom 3D world as ... multi-coloured llamas. Who was I to argue?</p><p>The application was at a fairly late stage of development, with some lovely 3D animation work, as well as what looked like a very nicely organised, well-structured and neatly-written node.js backend application communicating with front-end clients over a websocket connection. Deployment process was solid, everything was in Kubernetes on AWS and managed very capably in <a href="https://www.terraform.io">Terraform</a>.</p><p>It all worked just fine - until they hit around 100 concurrent connected users. Everything slowed down after around 80, and pretty much fell apart near 100. Problem was, they needed to handle 6,000. Hence the agency devs needed urgent help on this kind of performance profile, as they only had a few weeks to make it work.</p><p>So I set about investigating how the application logic and comms worked, including what was in the database, what in memory, how the app flow worked, what messaging was being done, etc. Once I had a clear picture of all this, I built a testing tool which simulated the entire process of llama avatars spawning, moving, interacting in and leaving the virtual world, and allowed us to gradually increase the number of participants until we started to see problems.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2025-01-13-at-11.30.51-2.png" class="kg-image" alt="Multiplayer llama world" loading="lazy" width="1411" height="921" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/01/Screenshot-2025-01-13-at-11.30.51-2.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/01/Screenshot-2025-01-13-at-11.30.51-2.png 1000w, https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2025-01-13-at-11.30.51-2.png 1411w" sizes="(min-width: 720px) 720px"><figcaption>Simple UI for spawning, spawning and re-spawning virtual llamas</figcaption></figure><p>This showed up a few immediate obvious problems: some DB indexes could be tweaked, some redundant messages could be removed - but none of these was going to be a game-changer.</p><p>The main issue was fan-out of server-to-llama and inter-llama message notifications. Every time a llama did anything, it notified the server, which then notified all the other llamas, so of course the performance requirements scaled exponentially with the number of llamas.</p><p>On top of that, every time any client sent any message, the server was receiving it and then &quot;broadcasting&quot; it by sending it on to every other connected client in a tight loop. The application wasn&apos;t taking into account the explosion of CPU and I/O work necessary beyond a certain level, and the single-threaded node.js app was falling over under the volume of messaging, even on some of the larger pod types available.</p><p>The notion of re-writing the app to split it into multiple instances and somehow synchronise data between them at this stage in the game was understandably panic-inducing. So we needed a way to jack up the performance without going back to the drawing-board, by whatever means necessary. I knew we needed to get more CPU grunt in there, but the existing architecture made vertical scaling the only option, and taking that much further was looking difficult.</p><p>We discussed various approaches based not only on the compute/deploy resources available but also, importantly, the time and availability of key people. Given that there was still a fair amount of feature work to be completed in the application build, we decided to try to maximize the difference I could make in part by using my work to minimize the effort required from other team members.</p><p>To do this I proposed writing a simple websocket proxy that would run in <a href="https://kubernetes.io/docs/concepts/workloads/pods/sidecar-containers/">sidecar containers</a> for each World, taking most of the processing load away from the app server:</p><ul><li>The proxy would handle the establishment and maintenance of all the downstream websocket connections, manage all direct inter-llama messages in a given instance, and only communicate critical information (such as entries, exits, statuses and interactions) upstream to the node.js server.</li><li>That, along with its writer, would then be freed up to handle database/session management and further feature development.</li><li>Each proxy instance would maintain its client&apos;s upstream websocket connections to the node.js server, listening out for specific messages for that client as well as World-wide messages the server wanted to &quot;broadcast&quot; to all clients, and handling downstream comms in all these cases.</li><li>Rather than trying to shove through every outgoing message ad-hoc, the proxy would rationalise the messages by storing them in a memory-based data table and running a &quot;fetcher&quot; process. The fetcher would retrieve batches at a configurable/tunable rate and send them together, significantly reducing the numbers of calls.</li><li>I&apos;d write the proxy service in <a href="https://www.erlang.org/">Erlang/OTP</a>, as it has such a good async I/O story, meaning it can shovel large amounts of data in and out of large numbers of sockets really efficiently, and so is much better equipped to handle lots of really fast messaging.</li><li>Erlang&apos;s runtime (the <a href="https://en.wikipedia.org/wiki/BEAM_(Erlang_virtual_machine)">BEAM</a>) can also share larger data blobs efficiently between concurrent processes, passing references to socket handlers so there&apos;s a lot less data copying going on - so the batching mechanism meant we could shovel a lot of the data out to the clients with a lot less virtual blood, sweat and tears than the node.js app had had to expend.</li><li>Most importantly, unlike node.js, the Erlang platform could also take advantage of multi-core CPUs automatically. This meant we could get a lot more execution cycles into the mix, and so scale the performance a lot further without needing to re-architect the node.js app for multiple instances.</li></ul><p>I worked with the agency&apos;s backend developer to rationalise and streamline the message flows, and put together the simplest possible version of the proxy service I could, using <a href="https://github.com/ninenines/gun">cowboy</a> as the downstream websocket server, <a href="https://github.com/ninenines/gun">gun</a> as the upstream client, <a href="https://github.com/ostinelli/syn">syn</a> to manage client grouping and notification and <a href="https://github.com/davisp/jiffy">jiffy</a> for blazing fast JSON encoding &amp; decoding of messages.</p><p>Time spent upfront investigating and diagnosing the problems paid off when the core of the proxy only took a few days, with the main &quot;broadcast&quot; code hot-path moved to the new service, leaving unhandled messages passed through to the upstream for the time being. The effect was drastic:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2025/01/Screenshot-2025-01-13-at-11.07.59.png" class="kg-image" alt="Multiplayer llama world" loading="lazy" width="2000" height="1298" srcset="https://portfolio.igorclark.net/content/images/size/w600/2025/01/Screenshot-2025-01-13-at-11.07.59.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2025/01/Screenshot-2025-01-13-at-11.07.59.png 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2025/01/Screenshot-2025-01-13-at-11.07.59.png 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2025/01/Screenshot-2025-01-13-at-11.07.59.png 2400w" sizes="(min-width: 720px) 720px"><figcaption>Early demo of the proxy-enhanced service breaking previous the performance barrier</figcaption></figure><p>The performance anxiety was removed, allowing the node.js developer to focus on adding the remaining features using the new comms pattern, while I tweaked and tuned the system by gradually intercepting more and more of the message types in the proxy, and working with dev-ops on the proxy deployment story. We fine-tuned the batching interval to balance fluid-feeling UX and optimal batch size, and ended up doing what I call a &quot;whoompf&quot; (batch send to all interested parties) every 20ms.</p><p>The system was now able to support the full 6,000 users necessary across all the Worlds, and the llama event was a roaring (clucking? bleating?) success. Erlang to the rescue once more.</p>]]></content:encoded></item><item><title><![CDATA[RSC: Dream]]></title><description><![CDATA[<p>When the team at <a href="http://artistsandengineers.co.uk">Artists &amp; Engineers</a> got in touch to see if I&apos;d be able to help out on an interactive online experience for the <a href="https://www.rsc.org.uk">Royal Shakespeare Company</a>, I tried to play it cool for at least 5 seconds. Not sure how good a job I did</p>]]></description><link>https://portfolio.igorclark.net/projects/rsc-dream/</link><guid isPermaLink="false">617b0a7c0dc6fe0001ad1044</guid><category><![CDATA[Audience of the Future]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Erlang/OTP]]></category><category><![CDATA[Software development]]></category><category><![CDATA[Systems architecture]]></category><category><![CDATA[OpenResty]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Sat, 13 Mar 2021 20:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/12/IMG_7227.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/12/IMG_7227.jpg" alt="RSC: Dream"><p>When the team at <a href="http://artistsandengineers.co.uk">Artists &amp; Engineers</a> got in touch to see if I&apos;d be able to help out on an interactive online experience for the <a href="https://www.rsc.org.uk">Royal Shakespeare Company</a>, I tried to play it cool for at least 5 seconds. Not sure how good a job I did of it. </p><p>The project was <a href="https://audienceofthefuture.live/dream/">Dream</a>, a large-scale R&amp;D experiment led by &#xA0;<a href="https://www.marshmallowlaserfeast.com">Marshmallow Laser Feast</a> for the <a href="https://audienceofthefuture.live">Audience of the Future Consortium</a>, digging in detail into how live theatrical work might develop online - especially in the context of a COVID world where people had to experience it from their homes.</p><p>It was a highly creative and extremely ambitious piece, in which actors in motion-capture suits contributed position data to an <a href="https://www.unrealengine.com/en-US/">Unreal Engine</a> 3D scene, which took in and incorporated interaction data from a live audience representing thousands of fireflies in the scene, finally rendering and streaming it out as HD video to ... that same live audience.</p><figure class="kg-card kg-embed-card"><iframe width="200" height="113" src="https://www.youtube.com/embed/1UM69ygvtiA?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen></iframe></figure><p>The project had already been developing for a while and a lot of the 3D work was in progress already; the time had come to start working out how the audience interaction would work, both creatively and technically, and the team were very sensibly looking at using pre-built components to glue together.</p><p>I helped to assess a series of commercial systems which would synchronize the audience data with the 3D camera activity and the HD stream, but while a couple seemed very promising and certainly capable, none did exactly what we needed so we decided to ... do it ourselves.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/IMG_7111.jpg" class="kg-image" alt="RSC: Dream" loading="lazy" width="2000" height="1500" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/IMG_7111.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/IMG_7111.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2021/12/IMG_7111.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2021/12/IMG_7111.jpg 2400w" sizes="(min-width: 720px) 720px"></figure><p>I knew the success of the interaction would not only be heavily sensitive to data latency and throughput considerations, but it would also involve a lot of creative iteration. So, working in close collaboration with A&amp;E and <a href="http://allseeingeye.co">AllSeeingEye</a>, I built in parallel a data-streaming system - connecting the studio-side Unreal cluster with audience-client-side WebSocket code - and a stateful load-testing system allowing us to generate large volumes of meaningful robot clients, setting up and tearing down thousands of live WebSocket connections ad hoc and sending randomised but realistic client data across them to keep a constant eye on how the server would perform.</p><p>This meant that the creatives, the TD, the 3D team, the front-end developer and I could iterate together. We now had a test harness in place which would allow us to try out new features and functional changes and seeing what kind of impact each would have on the overall performance of the system, using realistic audience numbers.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://portfolio.igorclark.net/content/images/2021/12/IMG_7133.jpg" class="kg-image" alt="RSC: Dream" loading="lazy" width="2000" height="1500" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/IMG_7133.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/IMG_7133.jpg 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2021/12/IMG_7133.jpg 1600w, https://portfolio.igorclark.net/content/images/size/w2400/2021/12/IMG_7133.jpg 2400w" sizes="(min-width: 720px) 720px"><figcaption>Monitoring the system during a live performance</figcaption></figure><p>The target was to be able to hit 2000 live users per performance. Initially we were looking at sending live position data for all the fireflies, and the 3D scene was running at 60fps, so there could potentially be a lot of data. We needed to send the 3D camera positions and an aggregate of all the firefly positions to all the clients, so <a href="https://en.wikipedia.org/wiki/Fan-out_(software)">fan-out</a> was not going to be our friend.</p><p>I built the interaction server and the load test server in <a href="https://www.erlang.org">Erlang/OTP</a> (notably using <a href="https://github.com/ninenines/cowboy">Cowboy</a> HTTP/WS server, <a href="https://github.com/ninenines/gun">Gun</a> HTTP/WS client and <a href="https://github.com/ostinelli/syn">syn</a> process group manager), and implemented a dynamic batching mechanism to constrain the outgoing data figures.</p><p>I also created a web-based UI for the load-generation system. This enabled quick tweaking of firefly &quot;flock size&quot; and randomisation parameters for the flock, and with some simple system monitoring tools we could see exactly the efffect of the changes made in the tool.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/523004502?h=3cb885133c&amp;app_id=122963" width="310" height="240" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="dream-load-tester-demo-20210312a"></iframe></figure><p>Erlang&apos;s automatic multi-core scaling meant that I could reliably scale the server performance pretty high simply by bumping up the number of cores, and wouldn&apos;t need to worry about scaling the service horizontally. I still wanted to make sure we got the best performance out of the available resource though, so I implemented all the web client/server WebSocket conversations as <a href="https://developers.google.com/protocol-buffers">Protocol Buffer</a> messages, using a <a href="https://github.com/jg513/enif_protobuf">native protobufs implementation</a> on the server side and auto-generating a Javascript comms lib for the client-side as part of the build process. I also set up a comprehensive CI/CD pipeline which allowed team members to build and re-deploy the system independently during development, using <a href="https://bitbucket.org/product">Bitbucket</a> CI tools and <a href="https://aws.amazon.com/codedeploy/">AWS Code Deploy</a>.</p><p>Running the systems on large AWS multicore VMs, I managed to get upwards of 3000 clients running quite happily at a full 30fps in both directions, and was able to tweak the performance of the overall system by modifying the send rates for the camera frames on the Unreal side, the firefly positions on the client side, and the batching system on the interaction server, all on the fly while running thousands of live clients. Although the final result didn&apos;t require such a high level of throughput, this meant that we could freely experiment creatively throughout development, and maintain a high level of confidence that changes we made would work both in terms of functionality and performance.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/658383735?h=0151d4a230&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="RSC Dream: firefly interactions"></iframe></figure><p>Of course there were whole other aspects of the system required for a live, paid, ticketed audience event. It being also a timed event with a &quot;waiting room&quot; meant that we&apos;d be dealing with a large number of almost simultaneous connections to the interaction service, as all the audience for a given performance tried to join at the allotted time.</p><p>I worked with AOTF&apos;s marketing and ticketing partner <a href="https://fxdigital.uk/">FX Digital</a> to integrate the &quot;magic link&quot; and &quot;virtual lobby&quot; systems they&apos;d created to authenticate &amp; authorize audience members, and I implemented<strong> </strong>a queueing system in the interaction server to ensure the WebSocket connections were held safely while the server transacted with FX&apos;s ticketing API. I wrote code to manage upstream HTTP/2 connections dynamically, pipelining authorization requests across as few connections as possible, and helped FX in their load-testing to ensure their cloud deployment was tuned to handle the necessary volume of API requests.</p><p>Although it wasn&apos;t used in the final implementation, I also built on request a recording system which could store and play back camera and audience positions in real time, using Erlang&apos;s built-in soft-real-time database <a href="https://en.wikipedia.org/wiki/Mnesia">Mnesia</a>.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/508347889?h=835048319a&amp;app_id=122963" width="640" height="408" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="RSC Dream: firefly recorder (20210118)"></iframe></figure><p>Finally, &#xA0;I implemented a dynamically reverse-proxied redundant server setup (using <a href="https://openresty.org/en/">OpenResty</a>) to fail clients over to a backup interaction server in the event of catastrophic AWS host failure, built AWS AMIs for the load test tool using <a href="https://www.packer.io">Packer</a>, and deployed the whole system to AWS using <a href="https://www.terraform.io">Terraform</a>, including a <a href="https://aws.amazon.com/cloudfront/">CloudFront</a> CDN distribution, to serve all the static web assets and handle SSL termination.</p><p>Overall this was one of the most creatively and technically satisfying projects I&apos;ve worked on. Thanks, RSC, and thanks A&amp;E for pulling me in!</p><p>Press/media coverage in <a href="https://www.nytimes.com/2021/03/17/theater/review-dream-royal-shakespeare-company.html">New York Times</a>, <a href="https://www.theguardian.com/stage/2021/mar/17/rsc-a-midsummer-nights-dream">The Guardian</a>.</p>]]></content:encoded></item><item><title><![CDATA[NTD Prevalence Simulator]]></title><description><![CDATA[<p>I collaborated with colleagues from <a href="http://opencultu.re">Open Culture</a> and partners at the <a href="https://www.ntdmodelling.org">NTD Modelling Consortium</a> who were creating an epidemiological simulator for use by various health organisations including the <a href="https://www.who.int">WHO</a>. The simulator was organised at Oxford University and funded by the <a href="https://www.gatesfoundation.org/">Gates Foundation</a>. My part of the project was to help</p>]]></description><link>https://portfolio.igorclark.net/projects/ntd-simulator/</link><guid isPermaLink="false">61bf56d98f98c6000166d054</guid><category><![CDATA[OpenCultu.re]]></category><category><![CDATA[Big Data Modelling]]></category><category><![CDATA[Oxford University]]></category><category><![CDATA[Disease modelling]]></category><category><![CDATA[Epidemiology]]></category><category><![CDATA[NTD Modelling Consortium]]></category><category><![CDATA[Simulator]]></category><category><![CDATA[Cloud computing]]></category><category><![CDATA[Big data]]></category><category><![CDATA[Cloud Run]]></category><category><![CDATA[GCP]]></category><category><![CDATA[GCE]]></category><category><![CDATA[Compute Engine]]></category><category><![CDATA[python]]></category><category><![CDATA[flask]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Sun, 02 Aug 2020 11:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-16.47.30-1.png" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-16.47.30-1.png" alt="NTD Prevalence Simulator"><p>I collaborated with colleagues from <a href="http://opencultu.re">Open Culture</a> and partners at the <a href="https://www.ntdmodelling.org">NTD Modelling Consortium</a> who were creating an epidemiological simulator for use by various health organisations including the <a href="https://www.who.int">WHO</a>. The simulator was organised at Oxford University and funded by the <a href="https://www.gatesfoundation.org/">Gates Foundation</a>. My part of the project was to help boost client-side performance, and integrate large-scale server-side model computation with the UI application.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-17.53.23-1.png" class="kg-image" alt="NTD Prevalence Simulator" loading="lazy" width="1757" height="1411" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/Screenshot-2021-12-19-at-17.53.23-1.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/Screenshot-2021-12-19-at-17.53.23-1.png 1000w, https://portfolio.igorclark.net/content/images/size/w1600/2021/12/Screenshot-2021-12-19-at-17.53.23-1.png 1600w, https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-17.53.23-1.png 1757w" sizes="(min-width: 720px) 720px"></figure><p>The project had started as a data-viz prototype demonstrating the output of the Oxford University research team&apos;s predictive models, furnishing answers to the question of what happens to the spread of various sub-Saharan diseases in the face of treatment disruptions caused by funding problems and COVID. Users could tweak a wide variety of parameters such as mosquito net coverage, treatment frequency, drug regimen adherence and others across a period of years to get a fine-grained understanding of how funding issues could have direct real-world effects on the progress of treatments for these curable diseases.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-18.29.24.png" class="kg-image" alt="NTD Prevalence Simulator" loading="lazy" width="1324" height="1793" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/Screenshot-2021-12-19-at-18.29.24.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/Screenshot-2021-12-19-at-18.29.24.png 1000w, https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-18.29.24.png 1324w" sizes="(min-width: 720px) 720px"></figure><p>As the project developed, from a client-side-only prototype covering a single disease (<a href="https://www.cdc.gov/parasites/lymphaticfilariasis/index.html">Lymphatic Filariasis</a>) into a larger application providing analysis for several related strains of <a href="https://www.cdc.gov/globalhealth/ntd/">Neglected Tropical Diseases</a>, I came on board to help speed up and re-structure some of the state management code, and to integrate the necessary larger datasets and more complex, performance-intensive statistical models.</p><p>To start with I rewrote sections of the ReactJS application, improving performance of client-side session storage and reorganising some of the data access patterns. Then, as the brief expanded to take in various types of <a href="https://www.who.int/health-topics/soil-transmitted-helminthiases">soil-transmitted helminth</a> it became clear that some of the models would run too slowly to be effective in a purely JS implementation and needed to be converted into native code.</p><p>The research team had models running in various languages, ranging from R to C++, and there was work underway to port the core models into Python. I looked at various approaches to getting them integrated with the simulator, including using <a href="https://pyodide.org/en/stable/">Pyodide</a>, a WebAssembly implementation of the Python scientific stack, but while promising it had too many intermediate steps slowing down the performance, and so I turned to doing the processing on the server side.</p><p>Some of the Python models using numpy for the underlying math processing were sufficiently snappy to run as a back-end API, so I built a Flask API, allowing the simulator UI code to call out to the model with the appropriate parameter values, and deployed it as Docker containers to Google Cloud Run.</p><p>Other models were still far too slow to work as part of a UI system, taking up to several minutes to run even smaller simulations. The code was CPU-bound, but rewriting the models as GPU code was beyond the project scope and team experience, so I worked with NTD&apos;s research scientists to run thousands of sets of parameter permutations so that we could pre-calculate all the outputs for whatever parameters a simluator user might select.</p><p>The team pre-computed a series of prequisite historical data and relevant parameter combinations on the university&apos;s parallel compute clusters, which I then took and ran against the live models on a 1000-CPU compute-intensive VM setup I organised with Google Cloud Platform. I negotiated access to this large number of <a href="https://cloud.google.com/compute/docs/compute-optimized-machines">compute-optimised</a> machines with the GCP technical sales team, explaining the nature, motivation and funding of the project, and the reason for needing so many fast CPUs, and eventually got through enough layers of tech support to be able to get access to as many CPU-heavy VMs as we needed.</p><p>Having carried out many tens of thousands of runs of the models, we had all the data we needed to pre-populate the results for all the possible UI permutations, so I stored it all in Google Cloud Storage, and integrated with the simulator such that it would call out to the appropriate model for the selected disease, either running the model directly, calling out to a cloud API, or downloading a pre-computed result as necessary. I also implemented a storage-cache layer such that each run of the cloud API would add its output to the pre-computed result store, meaning the next access would be immediate and not require any back-end API usage.</p>]]></content:encoded></item><item><title><![CDATA[SKTel/Google: Changdeok ARirang]]></title><description><![CDATA[<p>Just before COVID hit the world, <a href="https://nexusstudios.com/">Nexus Studios</a> asked me to help out with a 5G-powered, AR-enhanced experience for <a href="https://nexusstudios.com/work/changdeok/">Changdeok Palace</a>, a UNESCO World Heritage site in South Korea.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/511573382?h=e9ce33c38b&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Nexus Studio x SK Telecom Present Changdeok ARirang (Case Study)"></iframe></figure><p>The project took advantage of the latest Google AR technologies (<a href="https://developers.google.com/ar">ARCore</a> and <a href="https://codelabs.developers.google.com/codelabs/arcore-cloud-anchors#0">Cloud Anchors</a>) to enable a rich mobile experience for</p>]]></description><link>https://portfolio.igorclark.net/projects/changdeok-arirang/</link><guid isPermaLink="false">61bf58788f98c6000166d05a</guid><category><![CDATA[Nexus Studios]]></category><category><![CDATA[Delivery]]></category><category><![CDATA[Deployment]]></category><category><![CDATA[GCP]]></category><category><![CDATA[Integration]]></category><category><![CDATA[nginx]]></category><category><![CDATA[Software development]]></category><category><![CDATA[Cloud Run]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Mon, 02 Mar 2020 12:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-16.45.46.png" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-16.45.46.png" alt="SKTel/Google: Changdeok ARirang"><p>Just before COVID hit the world, <a href="https://nexusstudios.com/">Nexus Studios</a> asked me to help out with a 5G-powered, AR-enhanced experience for <a href="https://nexusstudios.com/work/changdeok/">Changdeok Palace</a>, a UNESCO World Heritage site in South Korea.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/511573382?h=e9ce33c38b&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Nexus Studio x SK Telecom Present Changdeok ARirang (Case Study)"></iframe></figure><p>The project took advantage of the latest Google AR technologies (<a href="https://developers.google.com/ar">ARCore</a> and <a href="https://codelabs.developers.google.com/codelabs/arcore-cloud-anchors#0">Cloud Anchors</a>) to enable a rich mobile experience for both physical and virtual visitors to the site, bringing the location&apos;s history to life by conjuring AR versions of traditional Korean folklore characters.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Changdeok_At_Home-1400x788.jpg" class="kg-image" alt="SKTel/Google: Changdeok ARirang" loading="lazy" width="1400" height="788" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/Changdeok_At_Home-1400x788.jpg 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/Changdeok_At_Home-1400x788.jpg 1000w, https://portfolio.igorclark.net/content/images/2021/12/Changdeok_At_Home-1400x788.jpg 1400w" sizes="(min-width: 720px) 720px"></figure><p>Visitors to the site contributed their own personalised content in the form of virtual kites, saved into the scene using Cloud Anchors and stored in a remote backend API.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Changdeok_Web_1.gif" class="kg-image" alt="SKTel/Google: Changdeok ARirang" loading="lazy" width="492" height="369"></figure><p>As this was such a rich experience it required a large amount of volumetric 3D data to be transmitted to the users&apos; phones, but WiFI and phone availability at the site are limited. SKTel, the project&apos;s Korean telco co-sponsor, stepped in to provide 5G access, helping users get much faster downloads and hence much snappier response times in the application.</p><p>I worked with Nexus&apos;s 3D team to design and build the cloud API on <a href="https://cloud.google.com">Google Cloud Platform</a> infrastructure, and co-ordinated with SKTel&apos;s network teams, implementing a <a href="https://link.springer.com/chapter/10.1007/978-3-030-83944-4_3">Mobile Edge Cache</a> system providing a site-local, 5G-optimised data store, with assets smart-mirrored to edge servers, keeping them close to the end-user devices. This way SKTel 5G users would have the most streamlined experience, with data rates much faster than most WiFi.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Changdeok_At_Home_2.gif" class="kg-image" alt="SKTel/Google: Changdeok ARirang" loading="lazy" width="600" height="338"></figure><p>I wrote the backend API in <a href="https://nodejs.org/">node.js</a> from scratch in fairly short order, running on Google <a href="https://cloud.google.com/run">Cloud Run</a> and using the <a href="https://cloud.google.com/firestore">Firestore Native Database</a>, enabling realtime data updates during complex 3D development phases, and ensuring that the 247,000 virtual users who downloaded the app could enjoy the site experience remotely with similar performance to the 5G users at the real-world location.</p><p>I set up CI/CD using <a href="https://cloud.google.com/build">CloudBuild</a> in multiple test and production environments so that the 3D team could continue to tweak and iterate as necessary. COVID-19 happened at exactly the right time to mess up the installation plans, but I kept in touch with Nexus as they worked tirelessly over that time to ensure a smooth delivery later in the year when physical access was possible again.</p>]]></content:encoded></item><item><title><![CDATA[Samsung KX: Collage Me!]]></title><description><![CDATA[<p>My friends at <a href="https://rarevolume.com">Rare Volume</a> in NYC invited me to handle the tech implementation and installation for this <a href="https://rarevolume.com/work/samsung-kx/">self-contained interactive app</a>. Commissioned by their client <a href="https://www.samsung.com/">Samsung</a>, it was to be installed at the (then under-construction) Samsung KX space at <a href="https://www.coaldropsyard.com">Coal Drops Yard</a> in London&apos;s Kings Cross.</p><p>Showcasing the</p>]]></description><link>https://portfolio.igorclark.net/projects/samsung-kx-collage-me/</link><guid isPermaLink="false">617979850dc6fe0001ad0dc8</guid><category><![CDATA[Rare Volume]]></category><category><![CDATA[Android]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Deployment]]></category><category><![CDATA[Installation]]></category><category><![CDATA[node.js]]></category><category><![CDATA[Project management]]></category><category><![CDATA[React Native]]></category><category><![CDATA[Samsung]]></category><category><![CDATA[Software development]]></category><category><![CDATA[Systems architecture]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Tue, 01 Oct 2019 12:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/10/Screenshot-2021-10-27-at-17.28.35.png" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/10/Screenshot-2021-10-27-at-17.28.35.png" alt="Samsung KX: Collage Me!"><p>My friends at <a href="https://rarevolume.com">Rare Volume</a> in NYC invited me to handle the tech implementation and installation for this <a href="https://rarevolume.com/work/samsung-kx/">self-contained interactive app</a>. Commissioned by their client <a href="https://www.samsung.com/">Samsung</a>, it was to be installed at the (then under-construction) Samsung KX space at <a href="https://www.coaldropsyard.com">Coal Drops Yard</a> in London&apos;s Kings Cross.</p><p>Showcasing the flagship <a href="https://www.samsung.com/uk/smartphones/galaxy-s10/">Samsung Galaxy S10</a> phone, the installation would enable users to take a selfie with a provided S10 device, and incorporate it as the centrepiece of a London-themed collage on a Samsung 4K LED, using the S10 as a touch interface.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/639612753?h=72761a42b6&amp;app_id=122963" width="640" height="350" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Samsung KX: Collage Me!"></iframe></figure><p>I put together a 3-person team, consisting of a an <a href="https://www.artrabbit.com/">ArtRabbit</a> pal writing React Native UI, a friendly <a href="https://www.mazbox.com">graphics wizard</a> to write the big-screen display app, and me, to design, build and deploy the software solution. We created a custom kiosk-mode Android app which sent picture data, real-time path controls and various user information to a Windows Cinder app, which creates an appropriate colour scheme according to the selfie picture content and generates collage-style &quot;tears&quot; in the on-screen image, revealing sections of prepared imagery in real-time to fit with the scheme.</p><p>Once users have created their collage, the system prints out a copy on high-quality photographic paper and optionally sends them an electronic version to their email.</p><p>I architected the overall system, wrote the React Native networking code, created a client-testing harness in node.js providing a feature-complete mock back-end, integrated the Cinder app with Samsung&apos;s CRM APIs using a Python interface, and project-managed the development and delivery of the software. Alongside colleagues from Rare Volume I installed it on site, troubleshooting all technical aspects of the deployment, and working with them and the Samsung clients to manage several rounds of creative and functional changes to best fit the surroundings.</p>]]></content:encoded></item><item><title><![CDATA[MWC 2019: synchronized dioramas]]></title><description><![CDATA[<p>Google&apos;s NYC-based Hardware Marketing team came up with a really nice concept for a series of automated dynamic tableaux, showcasing various features of their product lineup at <a href="https://www.mwcbarcelona.com/">MWC</a> 2019 in Barcelona.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/658401254?h=ca9e8867df&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Google Hardware: MWC 2019"></iframe></figure><p>The displays included products ranging from Pixel phones and Slate tablets to Nest home automation lines, each</p>]]></description><link>https://portfolio.igorclark.net/projects/mwc-2019-synchronized-dioramas/</link><guid isPermaLink="false">61796d610dc6fe0001ad0d7c</guid><category><![CDATA[Google Hardware Marketing]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Software development]]></category><category><![CDATA[Systems architecture]]></category><category><![CDATA[Integration]]></category><category><![CDATA[Installation]]></category><category><![CDATA[Deployment]]></category><category><![CDATA[Erlang/OTP]]></category><category><![CDATA[Google]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Sun, 17 Feb 2019 12:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-15.43.08.png" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-15.43.08.png" alt="MWC 2019: synchronized dioramas"><p>Google&apos;s NYC-based Hardware Marketing team came up with a really nice concept for a series of automated dynamic tableaux, showcasing various features of their product lineup at <a href="https://www.mwcbarcelona.com/">MWC</a> 2019 in Barcelona.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/658401254?h=ca9e8867df&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Google Hardware: MWC 2019"></iframe></figure><p>The displays included products ranging from Pixel phones and Slate tablets to Nest home automation lines, each of which should display custom content on-device to highlight various product features out of the normal working context - in a physical installation with constraints making it impossible to use the normal software.</p><p>Synchronising multiple streams of activity, on multiple OSes and different products with physical display mechanisms and lighting systems, was proving challenging. So the team asked me to help co-ordinate the various systems and come up with solutions for reliably getting the right content to the right displays, on the right devices, at the right times.</p><p>Consulting with the creative, product and engineering teams to work out exactly what we could and couldn&apos;t do with the various devices, I quickly established that there was no way of getting custom OS builds for the Home Hub devices in the time available.</p><p>So I settled instead on a web-based display system using <a href="https://developers.google.com/cast">Google Cast</a> to send content to the Home Hubs, and an event-based messaging system using open Internet protocols to communicate with the products and physical display mechanisms.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/639912607?h=0c2173a9ac&amp;app_id=122963" width="360" height="640" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Google devices at MWC 2019"></iframe></figure><p><br>Included in the installation were:</p><ul><li>5 Pixel phones running a complete web-based mock-up of the Lens UI, mounted on a rotating carousel synced with the control server via UDP, &quot;recognising&quot; a pre-planned sequence of commercial products</li><li>A custom USB control mechanism to handle automated state changes on the Nest thermostat (with an SSH fallback in case the physical constraints made wiring impossible), synchronising lighting in the diorama by sending control messages to a Pharos lighting system</li><li>More UDP messaging with a revolving segment of a front-door controlling what to display via custom live streaming video from a display-mounted camera, Cast-ed to HTML content on a Home Hub video screen</li><li>Another Pixel mounted on a moving platform, alternately connecting and disconnecting to a wireless charger, sync&apos;ed via the control server to know when to display appropriate content depending on whether it was &quot;charging&quot; or not</li><li>A Home Hub displaying animated segments of the Home Hub UI as though in stop-motion animation Cast&apos;ed to the device and then sequenced via Websocket in time with the Pharos, to give the impression of a calendar day&apos;s events taking place</li><li>Marvel Universe content streaming to a Pixel Slate in an animatronic miniature movie theater</li></ul><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/639913410?h=e354f076e1&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Fake front door at MWC 2019"></iframe></figure><p>I took responsibility for the end-to-end design, build and delivery of all the software across the installation. I sourced and organised resource for front-end UI programming support, collaborated with the the hardware and lighting production companies, designed an overall system with a central control server synchronising everything, and got cracking.</p><p>Time was short so I wrote the control server in <a href="https://www.erlang.org/">Erlang/OTP</a>, which made it a lot quicker to get to a system that received and passed messages to and from the devices using the necessary mixture of UDP streams, Websocket and USB connections, and Web content.</p><p>I spec&apos;d and sourced redundant hardware servers to run and serve the control software using <a href="https://www.docker.com/">Docker</a>, built a test rig of the system at the production company&apos;s workshop in London, flew to Barcelona with the Google and production company teams, and installed and set up all the devices and software in situ at MWC.</p><p>Finally, I stayed on-site and kept an eye on all the systems through til the end of the event. Fortunately things went well enough that the last few days were pretty relaxed. Boring, even.</p><figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/639910625?h=655ff5e246&amp;app_id=122963" width="360" height="640" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="46593248504_a0d13bcb2f_vm.mov"></iframe></figure>]]></content:encoded></item><item><title><![CDATA[WebVR Experiments: Musical Forest]]></title><description><![CDATA[<figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/639634501?h=167482b19f&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Google WebVR Experiments: Musical Forest"></iframe></figure><p>Musical Forest is a WebVR Experiment by Google Creative Lab using &#x201C;co-presence&#x201D; - the synchronization of multiple people in a virtual space - to allow people to play music together in VR. All the players&#x2019; experiences are sync&#x2019;d in real-time using WebSocket connections.</p><p>A couple</p>]]></description><link>https://portfolio.igorclark.net/projects/webvr-experiments-musical-forest/</link><guid isPermaLink="false">617986640dc6fe0001ad0e5f</guid><category><![CDATA[Google Creative Lab]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Erlang/OTP]]></category><category><![CDATA[node.js]]></category><category><![CDATA[GCP]]></category><category><![CDATA[Software development]]></category><category><![CDATA[Systems architecture]]></category><category><![CDATA[Deployment]]></category><category><![CDATA[Google]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Mon, 10 Apr 2017 12:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/10/google-webvr-experiments-musical-forest-poster-image.jpg" medium="image"/><content:encoded><![CDATA[<figure class="kg-card kg-embed-card"><iframe src="https://player.vimeo.com/video/639634501?h=167482b19f&amp;app_id=122963" width="640" height="360" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen title="Google WebVR Experiments: Musical Forest"></iframe></figure><img src="https://portfolio.igorclark.net/content/images/2021/10/google-webvr-experiments-musical-forest-poster-image.jpg" alt="WebVR Experiments: Musical Forest"><p>Musical Forest is a WebVR Experiment by Google Creative Lab using &#x201C;co-presence&#x201D; - the synchronization of multiple people in a virtual space - to allow people to play music together in VR. All the players&#x2019; experiences are sync&#x2019;d in real-time using WebSocket connections.</p><p>A couple of years after I stopped working there full-time, Google Creative Lab in NY decided to get the band back together and asked me to create custom co-presence server software, enabling the participants to see each other&#x2019;s movements and share the musical experience in VR. I worked with the team at Google to make the smoothest connections possible and to ensure that the system would support tens of thousands of simultaneous users around the world.</p><p>I designed and built the entire <a href="https://github.com/googlecreativelab/webvr-musicalforest/tree/master/backend">server system</a>, writing the websocket server in <a href="https://nodejs.org/">node.js</a> (on request! &#x1F62C;) along with custom load testing software in <a href="http://www.erlang.org/">Erlang</a>. The system used <a href="https://cloud.google.com/pubsub/">Cloud Pub/Sub</a> and <a href="https://cloud.google.com/datastore/">Cloud Datastore</a> for client and horizontal server scaling synchronization, and I deployed it to Google&#x2019;s global cloud platform using <a href="https://www.docker.com/">Docker</a> and <a href="https://kubernetes.io/">Kubernetes</a> on <a href="https://cloud.google.com/container-engine/">Google Container Engine</a>, testing performance up to 7,500 concurrent users per region across USA, Europe and Asia.</p><p>Press/media coverage in <a href="https://thefwa.com/cases/the-musical-forest-a-webvr-experiment">The FWA</a>, <a href="http://www.thirst4beats.com/play-with-webvr-experiments/">Thirst4Beats</a>, <a href="https://www.androidheadlines.com/2017/04/google-outs-webvr-experiments-cardboard-support.html">Android Headlines</a>.</p>]]></content:encoded></item><item><title><![CDATA[ArtRabbit]]></title><description><![CDATA[<p><a href="https://www.artrabbit.com/">ArtRabbit</a> is a unique web + app guide to the contemporary art scene, connecting thousands of art spaces, exhibitions and events to artists, art professionals, collectors, students and art-interested people alike.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.33.45.png" class="kg-image" alt loading="lazy" width="1418" height="1634" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/Screenshot-2021-12-19-at-23.33.45.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/Screenshot-2021-12-19-at-23.33.45.png 1000w, https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.33.45.png 1418w" sizes="(min-width: 720px) 720px"></figure><p>The site runs on an open-submission model, enabling independent artists, curators and vendors to publicise their events, and working worldwide,</p>]]></description><link>https://portfolio.igorclark.net/projects/artrabbit/</link><guid isPermaLink="false">6179803a0dc6fe0001ad0e16</guid><category><![CDATA[ArtRabbit]]></category><category><![CDATA[Neo4J]]></category><category><![CDATA[Lua]]></category><category><![CDATA[OpenResty]]></category><category><![CDATA[nginx]]></category><category><![CDATA[Vagrant]]></category><category><![CDATA[React Native]]></category><category><![CDATA[GCP]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Wed, 16 Sep 2015 12:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/10/IMG_8720.jpg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/10/IMG_8720.jpg" alt="ArtRabbit"><p><a href="https://www.artrabbit.com/">ArtRabbit</a> is a unique web + app guide to the contemporary art scene, connecting thousands of art spaces, exhibitions and events to artists, art professionals, collectors, students and art-interested people alike.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.33.45.png" class="kg-image" alt="ArtRabbit" loading="lazy" width="1418" height="1634" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/Screenshot-2021-12-19-at-23.33.45.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/Screenshot-2021-12-19-at-23.33.45.png 1000w, https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.33.45.png 1418w" sizes="(min-width: 720px) 720px"></figure><p>The site runs on an open-submission model, enabling independent artists, curators and vendors to publicise their events, and working worldwide, but focusing on London, Berlin, NY and LA.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.39.31.png" class="kg-image" alt="ArtRabbit" loading="lazy" width="1409" height="1847" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/Screenshot-2021-12-19-at-23.39.31.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/Screenshot-2021-12-19-at-23.39.31.png 1000w, https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.39.31.png 1409w" sizes="(min-width: 720px) 720px"></figure><p>I co-conceived and co-created the iOS &amp; Android app along with a variety of new features and interactions on the site.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/IMG_7DCC532D9E42-1.jpeg" class="kg-image" alt="ArtRabbit" loading="lazy" width="400" height="866"></figure><p>I build and manage backend systems for the <a href="https://www.artrabbit.com/">site</a> and <a href="https://www.artrabbit.com/about/app">app</a>, including graph database design, programming and optimisation with <a href="https://neo4j.com/">Neo4J</a>; REST API design; development and deployment setups with <a href="https://www.vagrantup.com/">Vagrant</a> and <a href="https://cloud.google.com/">Google Cloud Platform</a>; client app development using <a href="https://github.com/reactjs/redux">Redux</a>/<a href="https://github.com/redux-saga/redux-saga">Sagas</a> for <a href="https://facebook.github.io/react-native/">React Native</a>; server side programming in <a href="http://www.lua.org/">Lua</a>/<a href="https://openresty.org/en/">OpenResty</a>, <a href="http://php.net/">PHP</a> and <a href="http://nginx.org/">nginx</a>; a custom high-performance caching image server and &#x2026; pretty much anything else that comes up.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.36.22.png" class="kg-image" alt="ArtRabbit" loading="lazy" width="1418" height="1336" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/12/Screenshot-2021-12-19-at-23.36.22.png 600w, https://portfolio.igorclark.net/content/images/size/w1000/2021/12/Screenshot-2021-12-19-at-23.36.22.png 1000w, https://portfolio.igorclark.net/content/images/2021/12/Screenshot-2021-12-19-at-23.36.22.png 1418w" sizes="(min-width: 720px) 720px"></figure>]]></content:encoded></item><item><title><![CDATA[Androidify]]></title><description><![CDATA[<p>As part of a global Android brand campaign, we created a cross-media digital campaign enabling users to create their own personalized Android characters on web or mobile, and have them take part in huge, real-time, interactive games on the biggest LED display in the world, in New York&#x2019;s</p>]]></description><link>https://portfolio.igorclark.net/projects/androidify/</link><guid isPermaLink="false">617a76cc0dc6fe0001ad0e75</guid><category><![CDATA[Google Creative Lab]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Technical direction]]></category><category><![CDATA[Systems architecture]]></category><category><![CDATA[Integration]]></category><category><![CDATA[Delivery]]></category><category><![CDATA[Google]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Tue, 25 Nov 2014 17:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/10/780x390.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/10/780x390.jpeg" alt="Androidify"><p>As part of a global Android brand campaign, we created a cross-media digital campaign enabling users to create their own personalized Android characters on web or mobile, and have them take part in huge, real-time, interactive games on the biggest LED display in the world, in New York&#x2019;s Times Square.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/600x450.jpeg" class="kg-image" alt="Androidify" loading="lazy" width="600" height="450" srcset="https://portfolio.igorclark.net/content/images/2021/10/600x450.jpeg 600w"></figure><p>Users made their individual characters using the <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.androidify">native Android app</a> or on the <a href="https://androidify.com/en/#/create">website</a>, sharing them to our custom AppEngine CMS and asset store.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/774x520.png" class="kg-image" alt="Androidify" loading="lazy" width="774" height="520" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/774x520.png 600w, https://portfolio.igorclark.net/content/images/2021/10/774x520.png 774w" sizes="(min-width: 720px) 720px"></figure><p>Games and character galleries were displayed on the Times Square board via Javascript/WebGL applications running from custom, local application servers. These co-ordinated with the upstream apps to retrieve remotely-generated Android characters from the asset store, and receive new ones created by visitors to the live installation. T-shirt and postcard stations also connected in and printed out personalised physical keepsakes for visitors to the event.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/780x519.jpeg" class="kg-image" alt="Androidify" loading="lazy" width="780" height="519" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/780x519.jpeg 600w, https://portfolio.igorclark.net/content/images/2021/10/780x519.jpeg 780w" sizes="(min-width: 720px) 720px"></figure><p></p><p>I directed the technology from inception to delivery, designing the overall architecture, choosing and managing specialist development vendors, managing and negotiating the project&#x2019;s progress through Google software processes, integrating our development efforts across all platforms, through to installation and launch on the giant board.</p><p>The timeline was extremely short - 2.5 months from start to launch. I designed and constructed the tech team from carefully picked partners, organised them into logical units to attack different components in parallel, worked with Google security teams, physical event and network management partners to get the on-site equipment set up, and even dug into diagnosing and providing fixes for low-level code issues in the Android app in the small hours before launch.</p><p>Finally, as a core part of the launch team I was on site for the entire duration of the event and made sure the tech side ran as smoothly as possible. We got <a href="https://www.google.com/search?&amp;q=google+androidify+times+square">some great coverage</a> and a huge amount of user feedback.</p><p><br>Press/media: <a href="http://www.theverge.com/2014/11/25/7283509/this-is-googles-massive-android-billboard-in-times-square">The Verge</a>, <a href="http://mashable.com/2014/11/24/google-interactive-billboard/#v.cyenriiOqR">Mashable</a>, <a href="http://gizmodo.com/this-google-android-billboard-in-times-square-is-freaki-1663246037">Gizmodo</a></p>]]></content:encoded></item><item><title><![CDATA[Big Web Quiz]]></title><description><![CDATA[<p>Using the power of Google <a href="https://www.google.com/intl/en_us/chrome/devices/chromecast/index.html">Chromecast</a>, up to 6 friends can compete to answer questions from their phones and tablets as the game plays out on the big screen. Questions are all generated by asking Google&#x2019;s <a href="http://www.google.com/insidesearch/features/search/knowledge.html">Knowledge Graph</a> about popular search terms and constructing quirky, unexpected trivia questions</p>]]></description><link>https://portfolio.igorclark.net/projects/big-web-quiz/</link><guid isPermaLink="false">617a79320dc6fe0001ad0ea8</guid><category><![CDATA[Google Creative Lab]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Systems architecture]]></category><category><![CDATA[Technical direction]]></category><category><![CDATA[Delivery]]></category><category><![CDATA[Google]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Thu, 01 May 2014 17:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/10/780x499.png" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/10/780x499.png" alt="Big Web Quiz"><p>Using the power of Google <a href="https://www.google.com/intl/en_us/chrome/devices/chromecast/index.html">Chromecast</a>, up to 6 friends can compete to answer questions from their phones and tablets as the game plays out on the big screen. Questions are all generated by asking Google&#x2019;s <a href="http://www.google.com/insidesearch/features/search/knowledge.html">Knowledge Graph</a> about popular search terms and constructing quirky, unexpected trivia questions by <a href="http://googleblog.blogspot.com/2012/05/introducing-knowledge-graph-things-not.html">traversing the relationships</a> stored in the graph.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/780x437.png" class="kg-image" alt="Big Web Quiz" loading="lazy" width="780" height="437" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/780x437.png 600w, https://portfolio.igorclark.net/content/images/2021/10/780x437.png 780w" sizes="(min-width: 720px) 720px"></figure><p>I pitched our original idea to Google&#x2019;s NY engineering team, and worked with them and our external application vendor to integrate the questions and answers with the native Android/iOS and <a href="https://cloud.google.com/appengine/">App Engine</a> applications.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/780x428.png" class="kg-image" alt="Big Web Quiz" loading="lazy" width="780" height="428" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/780x428.png 600w, https://portfolio.igorclark.net/content/images/2021/10/780x428.png 780w" sizes="(min-width: 720px) 720px"></figure><p>Players use native <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.bigwebquiz.app.prod">Android</a> and <a href="https://itunes.apple.com/us/app/big-web-quiz-for-chromecast/id904059716?ls=1&amp;mt=8">iOS</a> apps to launch the game on their Chromecast devices, which loads all the questions and the game server from an App Engine app. Gameplay, messaging and synchronisation happens via inter-device comms between the apps and the Chromecast using the <a href="https://developers.google.com/cast/">Cast SDK</a>.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/780x429.png" class="kg-image" alt="Big Web Quiz" loading="lazy" width="780" height="429" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/780x429.png 600w, https://portfolio.igorclark.net/content/images/2021/10/780x429.png 780w" sizes="(min-width: 720px) 720px"></figure><p>I co-ordinated between our development partner, the Knowledge Graph team and the Google internal Android team to complete, publish and launch the app. We showed off a custom version the app running on a large screen at Google I/O 2014 in San Francisco where it was one of the most popular stands in the show.</p><p>Press/media: <a href="http://thefwa.com/cases/big-web-quiz-for-chromecast?p=google-creative-lab">The FWA</a>, <a href="http://www.omgchrome.com/chromecast-games-android-big-screen-fun/">OMGChrome</a></p>]]></content:encoded></item><item><title><![CDATA[Photowall for Chromecast]]></title><description><![CDATA[<p>The launch of the Google Cast SDK and Chromecast means anyone can develop applications that take advantage of the biggest screen in the house - the TV.</p><p>We got excited about using the TV as a place for people to collaborate, so we started tinkering with ways for people to</p>]]></description><link>https://portfolio.igorclark.net/projects/photowall-for-chromecast/</link><guid isPermaLink="false">617a853e0dc6fe0001ad0edb</guid><category><![CDATA[Google Creative Lab]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Systems architecture]]></category><category><![CDATA[Technical direction]]></category><category><![CDATA[Delivery]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Mon, 24 Mar 2014 17:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/10/986x630.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/10/986x630.jpeg" alt="Photowall for Chromecast"><p>The launch of the Google Cast SDK and Chromecast means anyone can develop applications that take advantage of the biggest screen in the house - the TV.</p><p>We got excited about using the TV as a place for people to collaborate, so we started tinkering with ways for people to play with photos using their phones and tablets - like an interactive slideshow. The experiment became Photowall for Chromecast, a new Chrome Experiment that lets your friends collaborate and display images in real time on the TV.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/780x498.jpeg" class="kg-image" alt="Photowall for Chromecast" loading="lazy" width="780" height="498" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/780x498.jpeg 600w, https://portfolio.igorclark.net/content/images/2021/10/780x498.jpeg 780w" sizes="(min-width: 720px) 720px"></figure><p>I came up with the overall system concept and design, managed development between Google internal processes and our external vendor and delivered the overall project with my team-mates at Creative Lab. After the launch I wrote a <a href="http://googledevelopers.blogspot.com/2014/03/taking-chrome-experiments-to-tv.html">Google Developers Blog post</a> about the system, and took part in a <a href="http://youtu.be/rH0kG0iXN-s">live-streamed video interview</a> for Google&apos;s Developer Advocate team.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/780x498-1.jpeg" class="kg-image" alt="Photowall for Chromecast" loading="lazy" width="780" height="498" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/780x498-1.jpeg 600w, https://portfolio.igorclark.net/content/images/2021/10/780x498-1.jpeg 780w" sizes="(min-width: 720px) 720px"></figure><p>Users launch Photowalls using a dedicated <a href="https://play.google.com/store/apps/details?id=com.google.android.apps.photowall">Android</a> &amp; <a href="https://itunes.apple.com/us/app/photowall-for-chromecast/id814088518?mt=8">iOS</a> app, decorating and sending their photos to the wall via a desktop and mobile web interface to an <a href="https://cloud.google.com/appengine/">App Engine</a> application. Communication between browsers in the same &quot;rooms&quot; happens over a secure websocket connection, served from a dynamically-provisioned fleet of <a href="https://cloud.google.com/compute/">Compute Engine</a> VMs. If the user chooses, the system processes all the photos from the wall into a video and uploads it as a private keepsake in the user&apos;s YouTube account, once the wall has been closed.</p><p>Press/media coverage in <a href="https://www.engadget.com/2014/03/24/googles-photowall/">Engadget</a>, <a href="http://www.theverge.com/2014/3/24/5542108/google-photowall-app-interactive-photo-collage-chromecast">The Verge</a>, <a href="https://thenextweb.com/google/2014/03/24/google-launches-photowall-chromecast-app-lets-create-collaborative/#.tnw_x3pVzTne">The Next Web</a>.</p>]]></content:encoded></item><item><title><![CDATA[Coca-Cola: Polar Bowl]]></title><description><![CDATA[<p>W+K created a &quot;second-screen&quot; experience for Coke fans to enjoy during the 2012 Superbowl spot. Working with specialist partners Framestore and MLB Video, we created a way for fans to share the big game with Coke&apos;s signature polar bears. Animated and streamed to secondary devices,</p>]]></description><link>https://portfolio.igorclark.net/projects/coca-cola-polar-bowl/</link><guid isPermaLink="false">617a888a0dc6fe0001ad0f27</guid><category><![CDATA[W+K]]></category><category><![CDATA[Creative technology]]></category><category><![CDATA[Technical direction]]></category><category><![CDATA[Delivery]]></category><category><![CDATA[Coke]]></category><category><![CDATA[Coca-Cola]]></category><dc:creator><![CDATA[Igor Clark]]></dc:creator><pubDate>Sun, 05 Feb 2012 17:00:00 GMT</pubDate><media:content url="https://portfolio.igorclark.net/content/images/2021/10/720x406.jpeg" medium="image"/><content:encoded><![CDATA[<img src="https://portfolio.igorclark.net/content/images/2021/10/720x406.jpeg" alt="Coca-Cola: Polar Bowl"><p>W+K created a &quot;second-screen&quot; experience for Coke fans to enjoy during the 2012 Superbowl spot. Working with specialist partners Framestore and MLB Video, we created a way for fans to share the big game with Coke&apos;s signature polar bears. Animated and streamed to secondary devices, and controlled using a custom X-Box-based marionette system, they responded live to game events - and even competitors&apos; advertising.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/576x383.jpeg" class="kg-image" alt="Coca-Cola: Polar Bowl" loading="lazy" width="576" height="383"></figure><p>I directed the development and technical production teams in building social content channels, integrating with the streaming system, and negotiating with Coke&apos;s IT architecture board to build the system using J2EE/JBoss/Oracle. We deployed and delivered it using their preferred hosting environment and CDN (Savvis/Akamai).</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/484x462.jpeg" class="kg-image" alt="Coca-Cola: Polar Bowl" loading="lazy" width="484" height="462"></figure><p>Throughout the game 9 million consumers across various platforms checked in on the bears, and spent an unprecedented average dwell time of 28 minutes with the stream playing.</p><figure class="kg-card kg-image-card"><img src="https://portfolio.igorclark.net/content/images/2021/10/632x520.png" class="kg-image" alt="Coca-Cola: Polar Bowl" loading="lazy" width="632" height="520" srcset="https://portfolio.igorclark.net/content/images/size/w600/2021/10/632x520.png 600w, https://portfolio.igorclark.net/content/images/2021/10/632x520.png 632w"></figure><p>Press/media coverage in <a href="http://adage.com/article/special-report-social-tv-conference/coca-cola-polar-bowl-attracted-9-million-people/234645/">AdAge</a>, <a href="http://www.campaignlive.co.uk/article/coca-cola-coke-polar-bowl-wieden-kennedy-portland/1115676">Campaign</a>, <a href="http://www.fabawards.com/fab-entry/coca-cola-polar-bowl/">Fab Awards</a>, <a href="http://www.businessinsider.com/coca-colas-super-bowl-social-media-touchdown-polar-bears-will-watch-react-to-game-and-ads-live-2012-1?IR=T">Business Insider</a>.</p>]]></content:encoded></item></channel></rss>