[id="C4276659642"] .page-layout { align-items: center; } [id="C4276659642"] .page-layout { align-items: center; }



Changelog👩🏻‍💻

 A narrative driven meta game about a fractured gamedev team

👥5 People
🕗 12 Months  
🛠️ Unity, C#, uGUI, Unity Timeline
🧢Programmer, Producer

[↗]🔗 View Full Changelog Repository on GitHub [↗] 📑 View Production Archive & Documentation



Changelog is a narrative puzzle game played through a fictional desktop interface, where players explore evolving builds of a cancelled student game. By examining chat logs, dev notes, and playable levels, they uncover how creative tensions and miscommunication unraveled a passionate team. The game centers themes of burnout, neurodivergence, and collaboration, offering a story-rich, introspective experience.

The game takes place inside a fake computer interface. You read devlogs, browse old builds, and search through an in-universe wiki to figure out what went wrong.
I built all systems that made that possible:

  • An in-editor wiki CMS for narrative content
  • A search system and indexer connecting secrets across builds
  • A progression manager unlocking new “semesters” of data
  • An inter-game loader that runs mini-games inside the main game
  • I also built the main menu you see above 😌

The Design Problem


We wanted the story to live inside the development tools themselves.
But working with CSV pipelines and Google Sheets made iteration slow. Every content change required a reimport and broke formatting.
We needed something fast, in-editor, and resilient enough for narrative work.

Technical Systems Breakdown


1. The Wiki System - Building Tools That Replaced Google Sheets
We began with Google Sheets → CSV → runtime imports for devlogs and chat logs.
It worked, but it was brittle, formatting broke, writers couldn’t preview content, and debugging took hours.
So I replaced it with a ScriptableObject-based CMS built directly in Unity.

📘 Core Wiki Page Structure
[CreateAssetMenu(fileName = "New Wiki Page", menuName = "Their Game/Wiki Page")]
public class WikiPageSO : ScriptableObject
{
    public WikiPageType PageType = WikiPageType.Devlog;
    public string Title;
    [TextArea(3, 4)] public string Subtitle;
    [TextArea(1, 35)] public string Content;
    public bool ContainsBuild;
    [ShowIf("@ContainsBuild")] public int BuildIndex;
    public List<string> AdditionalKeywords;
}
Writers could now create and edit devlogs, chats, and lore entries without ever leaving Unity. No reimports, no sync errors, instant preview.

↗ [View Code File on GitHub]

2. Chat Parsing : Making Raw Logs Readable
Writers wanted color-coded chat logs without learning any markup. I built a small parser that recognizes speaker names and formats them with colors automatically.

💬 Chat Color Parser
foreach (string line in Content.Split('\n'))
{
    if (line.StartsWith("-") || line.StartsWith("[")) continue;

    string name = line.Split(":")[0];
    string message = line.Split(":")[1];

    if (KentoAliasess.Contains(name))
        name = $"<color=#f5260f>{name}</color>";
    else if (RoseAliases.Contains(name))
        name = $"<color=#c002d1>{name}</color>";
    else if (ErenAliasess.Contains(name))
        name = $"<color=#0bd400>{name}</color>";

    formatted += $"<b>{name}:</b>{message}\n";
}
No markup, no tags, just raw dialogue. The parser auto-detects aliases and applies formatting dynamically.

↗ [View Code File on GitHub]

3. Wiki Indexing & Text Analysis
Once pages existed, I built the WikiIndexSO, a data brain for all entries. It powers in-game search and also includes an editor-only analysis function to inspect tone and keyword usage.

🧩 Word Frequency Analysis
Dictionary<string, int> FindMostCommonWords(List<string> sentences, int topN)
{
    var wordCount = new Dictionary<string, int>();
    var stopwords = new HashSet<string>{"is","a","the","and","to","of"};

    foreach (var sentence in sentences)
    {
        var words = Regex.Matches(sentence.ToLower(), @"\b\w+\b")
                         .Select(m => m.Value)
                         .Where(w => !stopwords.Contains(w));

        foreach (var word in words)
            wordCount[word] = wordCount.TryGetValue(word, out int v) ? v + 1 : 1;
    }

    return wordCount.OrderByDescending(kv => kv.Value)
                    .Take(topN)
                    .ToDictionary(kv => kv.Key, kv => kv.Value);
}
📊 In-Editor Text Analysis Tool
[Button]
public void RunAnalysis(int words)
{
    foreach (var word in FindMostCommonWords(
        WikiPages.Select(p => p.Content).ToList(), words))
    {
        Debug.Log($"{word.Key}: {word.Value}");
    }
}
Why this mattered: Writers could visualize word frequency, check for overused themes like “failure” or “trust,” and fine-tune tone, all without leaving Unity.
It turned the editor into a small narrative analytics lab.

↗ [View Code File on GitHub]

4. Knowledge Unlocks : The Wiki Search Manager
The WikiPageSearchManager connects everything. It tracks read pages, calculates progress, unlocks new semesters (Fall → Spring → Summer → Ending), and logs analytics with Aptabase.

🔓 Semester Unlock Logic
void Update()
{
    if (SpringUnlocked() && !hasShownSpringNotification)
    {
        NotificationManager.CreateNotification(notificationSprite,
            "New Database Available", "Spring", true);
        hasShownSpringNotification = true;
    }

    if (EndUnlocked() && !hasStartedEnding)
    {
        MetaNarrativeManager.Instance.TriggerStorytellerSequence("END_0");
        hasStartedEnding = true;
    }
}
🔍 Search & Progress Tracking
public void SetPageToLoad(WikiPageSO page)
{
    Aptabase.TrackEvent("page_visit", new Dictionary<string, object> {
        {"first_time", !visitedPages.Contains(page)},
        {"page", page.Title}
    });

    if (!visitedPages.Contains(page))
    {
        visitedPages.Add(page);
        Save();
    }

    LastFoundPageSO = page;
}
Each unlock triggers new UI notifications and fake OS behaviors, making the archive feel alive, like the system itself is recovering memory.


↗ [View Code File on GitHub]

5. The GameBuildManager : Running Mini-Games Inside the OS
Every “build” of Eren’s project is actually a separate Unity scene, launched and tracked by the main game.
The GameBuildManager acts like a tiny OS, spawning and unloading builds while remembering what’s been played.

🧠 Build Launch Logic
public void EnableGameBuild(int build)
{
    addedBuilds[build].SetActive(true);
    hasBuildBeenPlayed[build] = true;
    PlayerPrefs.SetInt($"PlayedBuild{build+1}", 1);

    if (!string.IsNullOrWhiteSpace(chatOnBuild[build]))
    {
        MetaNarrativeManager.Instance.TriggerStorytellerSequence(chatOnBuild[build]);
        chatOnBuild[build] = "";
    }
}
Every time the player opens a prototype, the wiki and chat systems react, revealing new pieces of story tied to that build.

↗ [View Code File on GitHub]

Production Results


SystemWhat It DoesImpact
Wiki SystemScriptableObject CMS for narrative dataReplaced Sheets; instant updates, no reimports
Chat ParserColor-coded dialogue formattingWriters could preview instantly in-engine
Wiki IndexerSearch + tone analysisGave writers insight into narrative patterns
Search ManagerProgression via knowledge trackingCreated data-driven story progression
GameBuildManagerIn-game build launcherLinked playable builds with devlog lore

Together, these systems made the fake OS feel alive. a machine that remembers, reacts, and falls apart with its creators.






thanks for visiting
made with 🩷and ☕ on a beautiful June afternoon🌻