š Dev Log: The Christmas Resurrection
(a.k.a. āStill No Halloween Resultsā)
Hello again, internet. Yes, Iām alive. Yes, itās almost Christmas. No, the Halloween Frontend Challenge results still havenāt been released. I assume the judges were eaten by CSS goblins. Happens.
Anyway. I am here to talk about why I vanished.
š 1. The Great Dev Log Hiatus
I fully intended to keep posting dev logs. I really did.
Then the challenge results never came out and my brain went:
āAh. Time to hibernate.ā
And so I did.
š§Ŗ 2. The Mini Game That Became a Monster
I started building a tiny miniāgame inside my main project.
I thought it was a "mini" game anyway , some fun collectable cards , maybe play again AI in my project, just a little side thing. A distraction. A palate cleanser.
Naturally, it mutated into its own ecosystem, a full blown 2nd project complete with:
its own UI
its own logic
its own lore
its own problems
its own identity crisis
Classic me.
š¦ 3. The Roblox Arc (a.k.a. My Exile)
Then I decided to ālearn Roblox scripting for fun.ā
Turns out roblox has it's own coding language , a version of Lua, specifically a customized version known as Luau.
I had never even heard of it , but the promise of free server hosting , and taking care of all the fiddly stuff, was enough for me to give it a try.
This was a mistake.
Within days ( or weeks ):
I got a warning
Then a 1āday ban
Then a 3āday ban
All because the AI moderation system decided that any amount of visible skin is a war crime.
I wasnāt even making anything weird. I was making a card game. A card Game where the main subject is ducks. Apparently elbows are forbidden, as are any ducks with 6 packs.
So I left Roblox like a disgraced wizard and returned to Unity while i await the banishment, like a peasant thrown from the village.
š§± 4. The Birth of This New Project
Out of the ashes of my Roblox exile came this new Unity project. ( side project )
It started simple:
Title screen
Credits panel
Settings panel
Then I blinked and suddenly I had:
A global audio engine
using UnityEngine;
using System.Collections;
namespace Audio
{
public class AudioManager : MonoBehaviour
{
public static AudioManager Instance;
[Header("Music")]
public AudioClip titleTheme;
private AudioSource musicSource;
[Header("SFX Looping")]
private AudioSource sfxLoopSource;
private bool hasFadedOut = false;
private float fadeDuration = 8f;
void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
DontDestroyOnLoad(gameObject);
// Create audio sources
musicSource = gameObject.AddComponent<AudioSource>();
musicSource.loop = true;
musicSource.playOnAwake = false;
sfxLoopSource = gameObject.AddComponent<AudioSource>();
sfxLoopSource.loop = true;
sfxLoopSource.playOnAwake = false;
ApplyVolumesFromOptions();
PlayTitleTheme();
}
public void ApplyVolumesFromOptions()
{
if (AudioOptionsManager.Instance != null)
{
AudioListener.volume = AudioOptionsManager.Instance.MasterVolume;
musicSource.volume = AudioOptionsManager.Instance.MusicVolume;
sfxLoopSource.volume = AudioOptionsManager.Instance.SFXVolume;
Debug.Log("[AudioManager] Volumes synced from AudioOptionsManager.");
}
}
public void PlayTitleTheme()
{
if (titleTheme != null && !hasFadedOut)
{
musicSource.clip = titleTheme;
musicSource.loop = true;
musicSource.Play();
}
}
public void StopMusic()
{
musicSource.Stop();
}
public void FadeOutMusic()
{
if (!hasFadedOut)
{
StartCoroutine(FadeOutRoutine());
}
}
private IEnumerator FadeOutRoutine()
{
hasFadedOut = true;
float startVolume = musicSource.volume;
musicSource.loop = false;
for (float t = 0; t < fadeDuration; t += Time.deltaTime)
{
musicSource.volume = Mathf.Lerp(startVolume, 0f, t / fadeDuration);
yield return null;
}
musicSource.volume = 0f;
musicSource.Stop();
}
public void PlayLoop(AudioClip clip, float volume = 1f)
{
if (clip == null)
{
Debug.LogWarning("[AudioManager] Tried to play null AudioClip.");
return;
}
sfxLoopSource.clip = clip;
sfxLoopSource.volume = Mathf.Clamp01(volume);
sfxLoopSource.loop = true;
sfxLoopSource.Play();
}
// Expose sources for external control
public AudioSource MusicSource => musicSource;
public AudioSource SFXLoopSource => sfxLoopSource;
}
}
using UnityEngine;
using UnityEngine.UI;
using Audio;
public class AudioOptionsManager : MonoBehaviour
{
public static AudioOptionsManager Instance { get; private set; }
[Header("UI")]
[SerializeField] private Slider masterSlider;
[SerializeField] private Slider musicSlider;
[SerializeField] private Slider sfxSlider;
[SerializeField] private Button resetButton;
[SerializeField] private Button closeButton;
[Header("Audio Sources")]
[SerializeField] private AudioSource musicSource;
[SerializeField] private AudioSource sfxLoopSource;
public const float DefaultMasterVolume = 0.75f;
public const float DefaultMusicVolume = 0.75f;
public const float DefaultSFXVolume = 0.75f;
private float masterVolume = DefaultMasterVolume;
private float musicVolume = DefaultMusicVolume;
private float sfxVolume = DefaultSFXVolume;
public float MasterVolume => masterVolume;
public float MusicVolume => musicVolume;
public float SFXVolume => sfxVolume;
private void Awake()
{
Instance = this;
}
private void Start()
{
// Auto-assign sources from AudioManager
if (AudioManager.Instance != null)
{
if (musicSource == null)
musicSource = AudioManager.Instance.MusicSource;
if (sfxLoopSource == null)
sfxLoopSource = AudioManager.Instance.SFXLoopSource;
}
// Wire UI
masterSlider.onValueChanged.AddListener(OnMasterVolumeChanged);
musicSlider.onValueChanged.AddListener(OnMusicVolumeChanged);
sfxSlider.onValueChanged.AddListener(OnSFXVolumeChanged);
resetButton.onClick.AddListener(OnResetAudio);
closeButton.onClick.AddListener(OnClosePressed);
// Initialize sliders
masterSlider.value = masterVolume;
musicSlider.value = musicVolume;
sfxSlider.value = sfxVolume;
ApplyVolumes();
}
private void OnMasterVolumeChanged(float value)
{
masterVolume = Mathf.Clamp01(value);
ApplyVolumes();
}
private void OnMusicVolumeChanged(float value)
{
musicVolume = Mathf.Clamp01(value);
ApplyVolumes();
}
private void OnSFXVolumeChanged(float value)
{
sfxVolume = Mathf.Clamp01(value);
ApplyVolumes();
}
private void OnResetAudio()
{
masterVolume = DefaultMasterVolume;
musicVolume = DefaultMusicVolume;
sfxVolume = DefaultSFXVolume;
masterSlider.value = masterVolume;
musicSlider.value = musicVolume;
sfxSlider.value = sfxVolume;
ApplyVolumes();
}
private void ApplyVolumes()
{
AudioListener.volume = masterVolume;
if (musicSource != null)
musicSource.volume = musicVolume;
if (sfxLoopSource != null)
sfxLoopSource.volume = sfxVolume;
}
private void OnClosePressed()
{
// MenuManager handles showing/hiding the panel
gameObject.SetActive(false);
}
}
A clean UI architecture
A proper menu flow
A credits panel that actually scrolls ( growth! )
Progress is faster this time because I actually know Unity now. I no longer open the editor, panic, and close it for two days.
Character development.
š§© 5. The PlayFab Signup
At some point I also signed up for PlayFab. ( Today )
Why? Because future me will need:
cloud saves
player data
inventory syncing
maybe multiplayer
maybe trading
maybe a full backend economy
Or maybe I just like dashboards. Hard to say.
š 6. The 310āCard Database
Yes. I imported 310 cards into Unity.
All with:
names
stats
rarities
factions
lore
effects
spreadsheetādriven data

This is the moment I realised:
āOh. This isnāt a miniāproject anymore.ā
This is a real game now.
A few Examples ..
and another 306 more !! ( i was still busy , sidetracked very much )
š§ 7. The Present Day
Right now the project has:
a clean title screen
a working settings panel
a scrolling credits panel
a global audio system
a database of 310 cards
a PlayFab backend ready to be used
a developer who is no longer afraid of Unity
and a dev log that has risen from the dead
š 8. Whatās Next
In no particular order:
UI transitions
Oneāshot SFX
Scene loading
Card binder
Card inspection
Gameplay prototype
More lore
More chaos
And maybe ā just maybe ā the Halloween challenge results.
Merry Christmas






Top comments (0)