<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>Donovan Montoya — Blog</title>
    <link>https://donovanmontoya.com/blog</link>
    <description>Write-ups on how projects and games were built, what held up, and what I&apos;d do differently.</description>
    <language>en-us</language>
    <managingEditor>contact@donovanmontoya.com (Donovan Montoya)</managingEditor>
    <lastBuildDate>Sat, 17 Oct 2026 00:00:00 GMT</lastBuildDate>
    <atom:link href="https://donovanmontoya.com/rss.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Trailhead, or why we record what players actually do</title>
      <link>https://donovanmontoya.com/blog/trailhead-session-replay</link>
      <guid isPermaLink="true">https://donovanmontoya.com/blog/trailhead-session-replay</guid>
      <pubDate>Sat, 17 Oct 2026 00:00:00 GMT</pubDate>
      <author>contact@donovanmontoya.com (Donovan Montoya)</author>
      <category>Trailhead</category>
      <category>Unity</category>
      <category>tools</category>
      <category>analytics</category>
      <description>A session recorder for 3D realtime environments. The design goal was to capture enough to replay a session in 3D without the recording ever getting in the way of the game loop.</description>
      <content:encoded><![CDATA[<p><img src="https://donovanmontoya.com/media/trailhead-replay.webp" alt="The Trailhead replay viewer playing back a Virtual Forest session, with rabbits scattered across the terrain and the session events listed on the left" /></p>
<p>Watching someone play a simulation tells you more than any survey. The
problem is that you cannot sit beside every student, and the interesting
moments in a field exercise are the ones nobody expected. Trailhead exists so
that a session can be replayed later, in 3D, by whoever needs to see it.</p>
<p>It was built for the Extended Reality team at Unity Environmental University
to replace a third-party recording service, first for Virtual Forest, where
students estimate rabbit populations and investigate the origin of a fire.
The questions instructors had were things like &quot;where did they go first&quot; and
&quot;did they ever look at the evidence&quot;. Those are spatial questions, and a
replay answers them directly.</p>
<h2 id="what-gets-recorded">What gets recorded</h2>
<p>A recording is a set of tracked subjects plus the events that happened around
them. In Virtual Forest that means the player, where they were looking, and
each rabbit. The gaze subject is a raycast from the camera, so the replay can
show not just where the player stood but what they were pointed at.</p>
<p>Each subject&#39;s transform is sampled ten times a second, and a sample is
skipped if the object has not moved more than a centimetre since the last
one. A rabbit sitting still costs almost nothing. Gameplay events such as a
rabbit being sighted or caught are stamped into the same timeline, either on
the recording as a whole or on the subject they belong to.</p>
<p>Alongside the samples, the game sets session and simulation metadata: the game
mode, time of day,weather, duration, average framerate, and the end-of-game stats. 
That metadata is what the gallery lists and searches, so nobody has to open a
payload to find the session they want.</p>
<h2 id="staying-out-of-the-game-loop">Staying out of the game loop</h2>
<p>The non-negotiable requirement was that recording never causes a frame hitch.
A simulation that stutters because it is being observed is not teaching what
it is supposed to teach.</p>
<p>The Unity client is a single component. Samples go into plain in-memory
arrays, and nothing is serialised until the session ends. Upload runs as a
coroutine with a short timeout, and the game carries on whether or not it
succeeds; on success the server returns a recording ID, and the post-game
screen shows a link to the replay. The API the game sees is small: start a
recording, add subjects, add events, set metadata, finish.</p>
<p>Browser builds get a different path. A WebGL page can be torn down at any
moment, so those clients upload compressed deltas as they go, and the server
appends each one to the recording. A closed tab loses the last few seconds
rather than the whole session.</p>
<h2 id="privacy">Privacy</h2>
<p>All user data is annonomized and obscured to prevent identifiability. User 
experiance and user trust are our most important assets. While we discuss 
data collection, its important to clearify the type of data collected. We 
never collect Personal Identifying Information. The only information we collect 
is directly related to the session events.</p>
<h2 id="where-it-goes">Where it goes</h2>
<p>Payloads travel to an ingest endpoint guarded by an API key. The server
writes the raw JSON to disk and indexes the game and metadata in
Postgres, so the dashboard can list, search, and sort recordings without
reading every file. Trailhead ships with a self-hosted sidecar 
Postgres and a Docker volume, which is all a single-host tool needs.</p>
<p>Summaries are also pushed into Summit, the analytics platform that holds
sessions, events, and performance samples. The push happens after the upload
has been acknowledged and never blocks it. The result is that an analytics
view of a session can link straight to its 3D replay, which closes the gap
between &quot;this number looks odd&quot; and &quot;here is what the player was doing when
it happened&quot;. Player feedback is entangled to their sessions, adding tangible 
evidence to close the loop.</p>
<h2 id="the-viewer">The viewer</h2>
<p>The replay viewer is a Next.js app with a React Three Fiber scene. It loads
the terrain, picks a skybox to match the session&#39;s time of day and weather,
places the tracked subjects with their models, and scrubs through the
timeline with the key events marked along it. The camera can fly freely,
follow a subject, or sit in the player&#39;s point of view. Stretches where
nothing was recorded are skipped automatically.</p>
<figure><img src="https://donovanmontoya.com/media/trailhead-heatmap.webp" alt="The replay viewer with the player's path shown as a heatmap over the Virtual Forest terrain" loading="lazy" /><figcaption>Any subject can be shown as a heatmap. This is one player's three-minute route through the forest.</figcaption></figure><p>Each subject can also be rendered as a heatmap, which turns a single session
into a picture of where a player spent their time. That view has done more to
answer &quot;where did they go first&quot; than any amount of scrubbing.</p>
<h2 id="what-i-would-keep">What I would keep</h2>
<p>Two decisions held up well and I would make them again on any similar tool.</p>
<p>Treat recording as a separate concern with a tiny surface area. The game
should be able to add a subject in one line and never think about it again.</p>
<p>Store the raw payload and the searchable summary separately. The summary is
what people browse; the payload is what they open once they have found the
session they care about. Mixing the two makes both slower.</p>
<p>Trailhead is an internal tool and the repository is private, but the general
shape is reusable for any real-time project that wants to know what players
did rather than guess.</p>
]]></content:encoded>
    </item>
  </channel>
</rss>
