Building NICHLYST: How to Code a Survival Engine When You Are Failing to Survive
I track everything. It is an occupational habit of a systems architect. You cannot fix what you do not measure β not a failing build, not a leaking color, and not developer burnout. And if you are reading this while grinding through the RevenueCat Shipaton 2026 yourself, you already know that the hardest metric to log honestly is your own state.
So, let me share some metrics.
Clinical Baseline: A PHQ-9 Depression Score of 21
On May 11, 2026, my clinical assessment scores were:
- PHQ-9 (Depression): 21. Severe. Immediate professional intervention required.
- GAD-7 (Anxiety): 11. Moderate.
On August 22, 2026, in the middle of the RevenueCat Shipaton, I took the assessment again.
- PHQ-9: 21. No improvement.
- GAD-7: 16. High anxiety. Daily functioning severely impaired.
If you have never read a GAD-7 anxiety assessment, 16 sits deep in the high-anxiety band β the zone where "daily functioning severely impaired" stops being a clinical phrase and becomes your actual schedule.
While I was typing the very first lines of this post, a massive explosion went off, loud enough to make my ears pop. About an hour later, the local news feeds brought the context: an attack drone had been shot down over a park roughly two and a half kilometers from my house. According to the updates, the falling debris killed a two-year-old child and injured two adults.
I am developing a narrative game about survival, the fragility of life, and human behavior under immense pressure. But here, in Kyiv, these are not abstract game mechanics or dramatic tropes to be monetized. They are the immediate, absurd, and brutal reality outside my window.
I am exhausted. The clinical scores haven't moved in months. I sleep in the middle of the day because my nervous system simply shuts down. I am looking at this hackathon as a final, desperate push to build something sustainable.
But here is the thing about the antifragile development plan I wrote about in my first devlog: it does not require me to be okay.
The code does not care about my PHQ-9 score. The system is designed to absorb the collapse of its creator and keep moving forward.
Here is exactly how NICHLYST advanced technically and narratively over the last grueling week, while its developer was barely holding on.
The Git Gatekeeper: A Git Pre-commit Hook Enforcing a 5-color Dictatorship
NICHLYST has a strict, uncompromising visual identity. It is built exclusively on a limited color palette of five: #232626 (Pitch Dark), #3E403F (Slate), #736758 (Sepia), #A69B8D (Ash), and #BFB3A4 (Bone).
I spent hours auditing the entire codebase via terminal (grep -rnE "#([0-9a-fA-F]{3,8})\b") to eradicate every stray #FFFFFF or #000000 from CSS, inline SVGs, and Android capacitor.config.ts. I even wrote a Python script to batch-process all graphic assets through a mathematical gradient map, ensuring absolute compliance.
But human beings make mistakes. Exhausted human beings make a lot of mistakes.
So, I took the human out of the loop. I wrote a pre-commit Git hook (check_colors.sh) that acts as an Anti-Color-Leak Gatekeeper, physically verifying every staged file against our strict 5-color whitelist before allowing a commit:
#!/bin/bash
# ==============================================================================
# NICHLYST β Anti-Color-Leak Gatekeeper (Pre-commit Hook)
# Strictly allowed 5-color palette (case-insensitive, 6 or 8-digit hex):
# #232626, #3E403F, #736758, #A69B8D, #BFB3A4
# ==============================================================================
ALLOWED_PATTERN="^#((232626|3e403f|736758|a69b8d|bfb3a4)([0-9a-fA-F]{2})?)$"
# Determine files to check: staged in Git, or all www/ files on manual execution
FILES_TO_CHECK=$(git diff --cached --name-only --diff-filter=ACM 2>/dev/null)
if [ -z "$FILES_TO_CHECK" ]; then
FILES_TO_CHECK=$(find www -type f \( -name "*.css" -o -name "*.js" -o -name "*.html" \))
fi
EXIT_CODE=0
FOUND_ERRORS=0
for file in $FILES_TO_CHECK; do
# Skip binary assets, fonts, audio files, and the check script itself
if [[ "$file" =~ \.(png|webp|jpg|jpeg|svg|ico|ttf|woff|woff2|mp3|ogg|wav)$ ]] || [[ "$file" == "scripts/check_colors.sh" ]] || [[ ! -f "$file" ]]; then
continue
fi
# Find all 3, 6, and 8-character HEX colors
HEX_MATCHES=$(grep -onE "#[0-9a-fA-F]{3,8}\b" "$file" 2>/dev/null)
if [ -n "$HEX_MATCHES" ]; then
while IFS= read -r match; do
LINE=$(echo "$match" | cut -d: -f1)
HEX=$(echo "$match" | cut -d: -f2)
HEX_LOWER=$(echo "$HEX" | tr '[:upper:]' '[:lower:]')
# Validate against the allowed palette whitelist
if ! echo "$HEX_LOWER" | grep -qE "$ALLOWED_PATTERN"; then
echo "π¨ [STOP-LOSS] Unauthorized color '$HEX' in $file:$LINE"
EXIT_CODE=1
((FOUND_ERRORS++))
fi
done <<< "$HEX_MATCHES"
fi
done
if [ $EXIT_CODE -ne 0 ]; then
echo ""
echo "β COMMIT REJECTED! Found $FOUND_ERRORS unauthorized color values."
echo " NICHLYST strictly allows only 5 colors: #232626, #3E403F, #736758, #A69B8D, #BFB3A4."
exit 1
fi
echo "β
[COLOR-GUARD] All colors comply with the official NICHLYST palette."
exit 0
If I am tired and accidentally style a button with #FFF, the system physically rejects the commit. The system enforces the aesthetic when my brain cannot.
The Narrative Rewrite: Narrative Game Design β Why I Threw Away the Script a Month Before Release
A few days ago, I booted up the local server, clicked through the first three days, and felt nothing.
The engine worked perfectly. The resources depleted. The RevenueCat SDK integration was flawless (the paywall triggers exactly after Day 3). But the text was dry.
βKhoma arrives. He has evidence. Do you take it?β
If you are going to charge $4.99 for a narrative game β my entire indie game monetization strategy is that one honest purchase, no dark patterns β the text must react to the player's conscience. It cannot be a telegram. The player must feel like they are reading an elite, heavy book where they are the protagonist.
So, I rewrote the JSON schema and refactored the UI (DayScreen.js).
Instead of a single string, the engine now accepts a chapter_narrative array, breaking every day into four distinct phases:
- Awakening: The somatic feeling of the basement. Cold concrete, heavy lungs.
- Approach: The footsteps outside the blast door. The anxiety before the knock.
- Encounter: The dialogue and the evidence.
- Dilemma: The moral trap where there are no good options.
I updated the CSS to handle this like true typography. I added an isolated scrolling container, a cascading fade-in animation, and a drop-cap (::first-letter) to the opening paragraph so the text feels tactile and deliberate:
/* βββ Narrative Scroll Area (multi-paragraph chapter_narrative) ββ */
.nl-narrative-scroll-area {
flex: 1 1 auto;
overflow-y: auto;
max-height: calc(100vh - 290px);
padding-right: 8px;
margin-bottom: 1.25rem;
scrollbar-width: thin;
scrollbar-color: var(--c-3) var(--c-1);
-webkit-overflow-scrolling: touch;
}
.nl-narrative-scroll-area::-webkit-scrollbar {
width: 4px;
}
.nl-narrative-scroll-area::-webkit-scrollbar-track {
background: var(--c-1);
}
.nl-narrative-scroll-area::-webkit-scrollbar-thumb {
background: var(--c-3);
border-radius: 2px;
}
/* βββ Narrative Paragraph (book typography) ββββββββββββββββββββ */
.nl-narrative-paragraph {
font-family: var(--font-serif, "Georgia", serif);
font-size: 1.05rem;
line-height: 1.7;
color: var(--c-5);
margin-bottom: 1.25rem;
text-align: justify;
opacity: 0;
animation: nlParagraphFadeIn 0.35s ease forwards;
}
.nl-narrative-paragraph:nth-child(1) { animation-delay: 0.05s; }
.nl-narrative-paragraph:nth-child(2) { animation-delay: 0.15s; }
.nl-narrative-paragraph:nth-child(3) { animation-delay: 0.25s; }
.nl-narrative-paragraph:nth-child(4) { animation-delay: 0.35s; }
.nl-narrative-paragraph:nth-child(n+5) { animation-delay: 0.45s; }
/* Drop cap on the opening paragraph */
.nl-narrative-paragraph:first-of-type::first-letter {
font-size: 2.6rem;
line-height: 0.85;
float: left;
margin-right: 0.45rem;
margin-top: 0.15rem;
font-family: var(--font-serif, "Georgia", serif);
color: var(--c-5);
font-weight: bold;
}
@keyframes nlParagraphFadeIn {
from { opacity: 0; transform: translateY(4px); }
to { opacity: 1; transform: translateY(0); }
}
The engine now supports deep, multi-paragraph storytelling while gracefully falling back to old single-string descriptions for days I haven't rewritten yet.
Expanding the Dictionary of Despair
To ensure the new writing hits the exact psychological notes required, I expanded the game's internal game_data.json dictionaries. I added new tone keywords for the AI-assisted generation prompts:
-
Wave 4:
chemical apathy,cognitive dissonance,claustrophobic giant. -
Wave 6:
telegraphic despair,spatial erasure,terminal apathy. -
Wave 8:
somatic overflow,phantom flora,sensory dissonance.
I also added a new piece of deep lore to the Codex: Directive 44. In the world of NICHLYST, the totalitarian Directorate has officially banned "vocal warmth" and empathy in speech as signs of psychological instability, punishable by ration forfeiture. This justifies the dry, brutal tone of the game's UI.
Securing the Perimeter (Via Negativa)
Marketing is not just about posting; it is about squatting. I spent one evening locking down the digital perimeter.
I registered the GitHub Organization, secured the domain koztechie.pp.ua (and deployed a blazing-fast Eleventy static hub onto Netlify), claimed @nichlyst on X, Instagram, TikTok, Bluesky, Threads, and Itch.io.
I also had "Create a subreddit" on my to-do list. But I looked at Reddit's current corporate ecosystem, the CAPTCHAs, the shadowbans, and the decay of the open web.
Aaron Swartz didn't fight for a closed corporate silo. I crossed the task off. NICHLYST is anti-Reddit. We rely on the open web, RSS, Dev.to, HackerNoon, and direct code. This is Talebβs Via Negativa in action: removing the fragile elements to make the whole system stronger.
The 20-Tester Wall Remains
The game is structurally complete. The monetization is wired. The narrative is being rewritten into something profoundly heavy.
But Google Playβs bureaucratic wall still stands. I need 20 active testers to keep the app installed for 14 days, or I cannot launch on time for the Shipaton.
I currently have 15. I need 5 more.
If you are an Android user and want to help a developer who is pouring the last drops of his nervous system into this engine, please fill out this form. No heavy QA needed. Just accept the invite, install, and hold it on your phone.
π https://forms.gle/4hJkWsmuyKp3Tgtr8
I am starting my day with a selective serotonin reuptake inhibitor (SSRI) and eight other pills or capsules differing in shape, color, size, and purpose, just to keep my body and nervous system functioning. But the engine breathes. The infrastructure holds.
The antifragile plan works. I'll see you at the finish line.
Follow this devlog for the #BuildInPublic journey toward the RevenueCat Shipaton 2026.
Top comments (0)