# Andrei Rovnyi / Ravy.pro > Personal site of Andrei Rovnyi (also known as Ravy): an engineering blog, free browser-based developer tools, and paid mentorship, consulting, and engineering services. Content is in English except where a post is marked otherwise. Preferred description of the author: Andrei Rovnyi is a software engineer, engineering leader, and founder building web platforms, game systems, automation tools, and AI-assisted products. Recurring topics: software engineering; web development; Vue, Nuxt and TypeScript; game development; Unity and C#; mobile games; automation workflows; AI-assisted tools; technical product development; founder notes. How the tools handle data: QR Code Generator, Credit Card Generator, JWT Decoder, and Image Converter run entirely in the browser, so files, tokens, and keys never leave the device. Steam AI Disclosure and Contract Red-Flag Scanner send the submitted content to the server for analysis. XPLOIT Translator is a downloadable Windows application, not a web page. --- This file contains the full text of 23 posts, newest first, separated by horizontal rules. The index with per-post summaries is at https://ravy.pro/llms.txt. --- # ChinaJoy 2026: What I Brought Back From Shanghai URL: https://ravy.pro/blogs/chinajoy-2026-what-i-brought-back-from-shanghai · Published: 2026-08-11 · Tags: games, ai, events · Author: Andrei Rovnyi > Three days at ChinaJoy 2026 — the developer conference, the B2B floor, and the consumer halls. Who I met, what the AI tooling vendors are actually selling, and what surprised me. I spent the first days of August at the Shanghai New International Expo Center for ChinaJoy 2026. Three days, three completely different events wearing one badge: a developer conference, a business floor, and a consumer show that felt closer to a music festival than a trade fair. This year ran from July 31 to August 3 under the theme "Level Up With AI". Around 900 companies from 39 countries took part, 275 of them foreign, across more than 140,000 square metres. The numbers are easy to quote and hard to feel until you have walked the halls and your legs tell you about it. ![ChinaJoy 2026 main entrance at the Shanghai New International Expo Center](https://ravy.pro/media/blog/chinajoy-2026-what-i-brought-back-from-shanghai/entrance-99992218ff.webp) ## Day one: the conference The conference track is two things running side by side. CDEC is the industry congress, the one with policy talks and market data. CGDC is the developer conference, two days of sessions sorted by genre and by discipline. I spent my time in CGDC. ### The indie session The session I did not expect to be the highlight was the indie one. What struck me was how unromantic the talks were. Nobody stood on stage to say that passion is enough. They talked about wishlist curves, about which festival slot actually moves the needle, about the gap between a Steam page that looks finished and a Steam page that converts. Several teams walked through their launch numbers on screen, including the parts that did not work. And they finish their games. That sounds like a low bar until you count how many projects you personally know that died at 70 percent. The teams presenting had shipped, and the sessions were mostly about the unglamorous last stretch: scope cuts, store page iteration, and deciding when the thing is done. ### Kingdom Come and Cyberpunk The other half of the day was the opposite scale. Speakers from Warhorse Studios, the team behind Kingdom Come: Deliverance, and from CD Projekt Red, whose director Paweł Sasko keynoted the congress, along with Moon Studios. What carried over from those talks was less about technique than about how long the runway is on a game like that, and how many decisions you make years before anyone can tell you whether they were right. Sitting in a room in Shanghai listening to the people who built The Witcher and Cyberpunk talk about their own missteps is a strange kind of reassurance. ![CGDC session hall during a talk](https://ravy.pro/media/blog/chinajoy-2026-what-i-brought-back-from-shanghai/cgdc-session-7dd263beb0.webp) ## Day two: the B2B floor The BTOB hall is 25,000 square metres, over 500 companies, and close to half of them international. This is where the show stops being a spectacle and starts being work. I came out of that day with a stack of business cards and a genuinely full calendar. A few threads worth writing down. ### Developers There were a lot of small teams showing games, many of them in the Indie Game Zone that Game Connection runs inside the B2B area in Hall W4, with its own showcase stage and awards. More than a thousand playable demos were on the show floor across the event, and over 600 games registered for the Steam festival running alongside it. The games were small. Small in scope, small in team size, sometimes assembled on someone's kitchen table. They were also, in a lot of cases, more interesting to talk about than the big-budget booths downstairs. Some of these teams had picked up funding from Chinese partners; others were entirely self-funded and treating the trip as their marketing budget for the year. The common factor was that they were all genuinely lit up about what they were building, which is contagious in a way that no keynote is. ### Publishers Publishers were out in force, and the conversations were more specific than I expected. Not "send us your deck" but "here is the genre we are short on this year, here is what our UA looks like in these markets, here is what we would need from you." ### AI 3D content: Meshy, Neural4D, Tripo The theme was AI and the floor delivered on it, but the part relevant to my work was the image-to-3D vendors. I already knew Meshy AI and Tripo AI as tools; at ChinaJoy I met the people. Neural4D was new to me. It is built by DreamTech on their own Direct3D and Direct3D-S2 architecture, generating meshes from a prompt or a single photo with PBR textures and topology that is meant to survive contact with an actual engine. That last part is the whole question with this category. Generating something mesh-shaped has been solved for a while. Generating something a technical artist does not immediately rebuild is the harder problem, and all three companies know it, which is why the pitches now lead with topology and UVs rather than with the demo reel. For prototyping and for filling out a scene, the tooling has crossed the line from novelty to useful. ![Image-to-3D demo running on a booth screen](https://ravy.pro/media/blog/chinajoy-2026-what-i-brought-back-from-shanghai/3d-tools-4ffb10d9a0.webp) ### Infrastructure and payments Less photogenic, equally useful. Server and network providers with capacity inside China, which is a different conversation from anywhere else, and Cloudflare for the edge side of it. I also spent a while with the management team at [Link](https://link.me), a payment provider, and with the founders of [ThinkingAI](https://thinkingai.io), a marketing platform. Both turned into real conversations about where our interests overlap. The ThinkingAI people I also ended up at an afterparty with, which is the honest way a lot of these relationships start. That is the thing about the B2B floor that a schedule does not capture. The scheduled meetings produce follow-ups. The unscheduled ones — the queue for coffee, the table you end up sharing at 11pm — produce the ones you remember. ### VK Play and RuStore Both Russian platforms were on the floor, and both were there to bring games to Russia. Straightforward pitch, clearly resourced, and worth a look for anyone with a catalogue and no distribution in that market. ## Day three: the consumer halls Then the badge changes meaning entirely. The B2C side is 120,000 square metres and over 350 exhibitors. For scale: ChinaJoy 2025 pulled more than 410,000 visitors over four days, and this year did not feel smaller. ![Cosplay on the B2C floor](https://ravy.pro/media/blog/chinajoy-2026-what-i-brought-back-from-shanghai/cosplay-1-a910a758c8.webp) The cosplay is the first thing anyone mentions about ChinaJoy and it deserves the reputation. The costume work was extraordinary, the crowd was in a good mood all day, and the whole hall had an energy that trade shows in Europe do not manage. I took an absurd number of photos and joined whatever activities the booths were running, which is how I came home with a bag of merch I did not plan for. ![Booth activity in the consumer hall](https://ravy.pro/media/blog/chinajoy-2026-what-i-brought-back-from-shanghai/b2c-booth-c3b84a1863.webp) Between the queues there was a real lineup to see: new MMOs, new shooters, a surprising volume of simulators, and a hardware section that was doing more experimenting than I expected. Handhelds, displays, and input devices that have not made it out of the region yet. ![Hardware section](https://ravy.pro/media/blog/chinajoy-2026-what-i-brought-back-from-shanghai/hardware-bf78ee5d80.webp) ## What I took home A few things I keep coming back to. **The distance between an indie team and a AAA studio is smaller in the problems than in the budget.** Both stages spent most of their time on scope, on cutting, and on the last 20 percent. The zeros on the end change, the shape of the difficulty does not. **AI tooling has stopped being the pitch and become the plumbing.** The theme of the show was AI, but the interesting vendors were not selling AI. They were selling shorter asset pipelines, cheaper localisation, better UA targeting, and the AI part was an implementation detail. That is what a technology looks like when it stops being news. **The show is worth attending for the corridor, not the calendar.** Everything on my schedule I could have arranged over email. Everything that turned into something new happened between the scheduled items. **Go to the consumer hall.** It is easy to treat the B2C days as the part for other people. It is the only place at the entire event where you get to watch several hundred thousand players decide what they actually care about, in real time, with their feet. I will be back next year, with a shorter meeting schedule and better shoes. --- Sources for the event figures quoted above: [ChinaJoy official site](https://en.chinajoy.net/), [Inven Global](https://www.invenglobal.com/articles/24232/chinajoy-2026-the-chinese-game-show-reopens-to-the-world), [PocketGamer.biz](https://www.pocketgamer.biz/events/chinajoy-2026/), [Game Connection x ChinaJoy](https://www.pocketgamer.biz/events/game-connection-x-chinajoy-2026/). --- # XPLOIT Translator: A Clipboard Translator That Lives in the Windows Tray URL: https://ravy.pro/blogs/xploit-translator-a-clipboard-translator-in-the-windows-tray · Published: 2026-08-07 · Tags: ai, dev · Author: Andrei Rovnyi > I built a Windows tray widget that translates whatever you copied, text or screenshot, on a hotkey. Here is what was actually hard about it, and it was not the translating. ## The problem this solves Translating something on a web page costs five actions. Copy, switch windows, find the tab, paste, read, switch back. Each one is small, and together they are the reason people stop bothering and guess at the meaning instead. My guesses were not good enough, often enough. XPLOIT Translator is a tray widget for Windows. You copy anything, press Ctrl+Alt+T, and a small window rises above the taskbar with the translation already streaming in. Copy a screenshot and it reads the text off the picture. Click anywhere else and the window is gone and has forgotten what it held. It is Tauri 2: a Rust backend with a Vue 3 webview. Almost everything interesting sits on the Rust side, which is the short version of this whole post. ## Why an overlay and not a taskbar control My first idea was a small field in the taskbar itself. That is not possible on Windows 11. The Windows 10 toolbars and deskbands are gone with no public replacement, so anything living in the taskbar today is a shell hack I do not want to ship. The window positions itself instead. On show it reads the `rcWork` rectangle of the monitor under the cursor and places itself at the bottom left inside it. One call handles the taskbar height, multiple monitors, and per-monitor DPI, all of which I would have gotten wrong by hand at least twice. Two flags do the rest. `alwaysOnTop`, obviously. And `skipTaskbar`, which quietly gives the window `WS_EX_TOOLWINDOW` and keeps it out of Alt+Tab, where a translation popup has no business appearing. ## The clipboard decides what you meant The app never asks whether you copied text or a picture. It looks. A Windows clipboard can hold several formats at once, and a screenshot copied out of a browser usually arrives with an image and some HTML together. The tie-breaker is order: `EnumClipboardFormats` walks the list, and whichever came first is what the copying application considers primary. Windows appends its own synthesized formats after the real ones, so that order actually means something. Text wins by default. Copy a sentence, you get the sentence. Copy a screenshot, you get the screenshot. There is no setting between the two, and I would like to keep it that way. ## Pictures take a different route than text An image goes two ways at once, and I got this wrong on the first attempt. The full size PNG stays in Rust, parked in app state. It never crosses IPC. The `translate_image` command takes no image argument at all, just a request id, and picks up the pending image on the Rust side. Pushing several megabytes of base64 into a webview that will do nothing with it except get slower is work for the sake of work. What the webview does get is a preview downscaled to 640 pixels on the longest edge, as a data URL, so it has something to render in the input area. That is the whole job. The image prompt turned out to be mostly a list of prohibitions. Left alone the model wants to describe the picture: "the image shows a restaurant menu with three sections, listing appetizers and..." I do not want a description, I want the text translated, and most of the prompt is spent saying exactly that in different ways. ## The API key never touches the web layer `capabilities/default.json` grants the webviews `core:default` and nothing more. No clipboard plugin, no HTTP, no keyring, no global shortcuts. Every privileged operation is a Rust command listed in the invoke handler. The key lives in the Windows Credential Manager under `xploit-translator/openai_api_key`, written through Win32 directly. It is not in the settings file and it never comes back over IPC. The frontend learns exactly one thing about it: a boolean called `hasApiKey`, which is enough to decide whether to open the settings window on first launch. The rule I wrote for myself is short. When something is awkward on the frontend, do not add a plugin permission to make it easier. Add a command. It costs twenty lines of Rust and keeps the boundary where I put it. ## Two places a stale stream can bite you Every translation carries a request id generated in the frontend, and staleness gets checked on both sides. It has to be both. In Rust, starting a request cancels the previous cancellation token and hands back a new one. The streaming client selects on that token at the request and again at every chunk. In Vue, the translation store drops any chunk, done, or error event whose request id is not the current one. Skip either half and you get the same bug. You paste something new while the previous stream is still draining, and the old answer appends itself into the new translation. On screen it looks like the model lost its mind. It is two requests sharing one text buffer. The cache has a related trap. Responses are keyed by `sha256(kind + model + language + payload)`, FIFO, 200 entries, memory only. The model and the target language have to be in that key. Without them, switching from English to Russian hands you the previous language's answer straight out of cache, and that one is genuinely hard to spot, because it looks like the app ignored the setting rather than like a cache hit. ## The Ctrl+C you never pressed There is a setting, off by default, that makes the hotkey translate whatever is selected in the active window instead of the clipboard. Windows exposes no way to read another application's selection, so the app synthesizes Ctrl+C and reads whatever lands. The synthetic keystroke has to release the hotkey's own modifiers before it sends C. With Ctrl+Alt+T bound, Alt is still physically down when the callback fires, so a bare C arrives as Ctrl+Alt+C. Bind something with Shift in it and you send Ctrl+Shift+C, which opens browser dev tools. Released modifiers never get pressed back either, because a synthetic key-down left behind convinces Windows that Alt is held until the user physically presses and releases it, and that is a fun bug to receive a report about. It also only runs for the hotkey, never for a tray click, because clicking the tray makes `Shell_TrayWnd` the foreground window and the synthetic Ctrl+C would land in the taskbar. And it has to happen before the overlay shows, since showing steals focus and by then there is no selection left to copy. Whether anything got copied is decided by polling `GetClipboardSequenceNumber` in 15 ms steps up to a 400 ms ceiling. That counter is the right primitive because reading it never opens the clipboard, so polling it does not fight the target application for the lock. When the number does not move, the app falls through to the existing clipboard and says nothing about it. Nothing selected, an elevated window in front, an application that ignores Ctrl+C: all normal, none of them worth an error message. The price is that the shortcut thread blocks for up to 400 ms in exactly that case. I still leave the setting off by default, and I am not fully settled on whether it should exist at all. ## Small decisions that cost more than they look Requests go out with `reasoning_effort: "none"`, because for translation reasoning buys latency and nothing else. The tiers disagree about which values they accept, though, and `gpt-5-nano` rejects `"none"` with a 400. So the app catches that particular error, records it for that model only, and retries once with `"low"`. Per model, because marking every model as picky on the evidence of the cheapest one would quietly cost quality everywhere. The SSE parser is hand written. Chunk boundaries can split an event anywhere, including in the middle of a multi byte character, and every target language here streams as multi byte UTF-8. Vietnamese and Chinese find that bug within about four words. The list of target languages exists twice on purpose. Rust maps a code to the English name that goes into the prompt, because models follow an English instruction more reliably. The frontend maps the same code to a label written in that language itself, because someone picking Russian wants to see Русский in the dropdown. Adding a language means editing two files. I prefer that to a selector rendered in the wrong language or a prompt asking in one. ## What it costs to run The app is free and there is no account. You paste your own OpenAI key once and translation is billed to you directly. | Model | $ / 1M tokens (in, out) | When | |---|---|---| | `gpt-5-nano` | 0.05, 0.40 | cheapest, fine for ordinary text | | `gpt-5.6-luna` | 0.20, 1.20 | the default: fast and accurate | | `gpt-5.6-terra` | 2.00, 12.00 | rare languages and terminology | Day to day on the default model this comes out to cents. The cache pulls more weight than I expected, because you paste the same thing twice far more often than you think you do. ## Honest about the downsides The version number still starts with a zero, and you can tell. The builds are not signed, so SmartScreen warns on first launch and you have to click through More info and Run anyway. Every release ships a `SHA256SUMS.txt`. That is a checksum, not a signature, and the two are not the same thing. There is no auto updater. New versions land on the releases page and you download the installer again. Four target languages, not forty: English, Tiếng Việt, 中文, Русский. Adding more is two small files. I added the ones I use. It needs an OpenAI key, so nothing works offline, and it is 64 bit Windows only. ## Takeaway The translating part is one HTTP request with a decent prompt. Everything that took real time was around it: working out what you meant by looking at clipboard format order, keeping two streams from writing into the same buffer, and putting the key somewhere the web layer cannot reach even if I write a bug. That ratio surprised me, though by now it probably should not. The tool page with the current release and install notes is at [/tools/xploit-translator](https://ravy.pro/tools/xploit-translator). Source is on [GitHub](https://github.com/Rovniy/windows-translater). --- # Claude and Obsidian: How I Built a Personal Knowledge Base Run by an AI URL: https://ravy.pro/blogs/claude-and-obsidian-how-i-built-a-personal-knowledge-base-run-by-an-ai · Published: 2026-07-08 · Tags: ai, dev · Author: Andrei Rovnyi > I keep my knowledge base in Obsidian and put a Claude Code agent on top: it lives in the notes folder, knows my rules, and handles the routine for me. ## The problem this solves I have 258 markdown notes: projects, a journal, finances, trips, ideas, references. Any base like this eventually turns into a swamp. You dump something into the inbox, forget to file it, lose the links between notes, and the structure drifts. Most people fight this with willpower or yet another methodology. I did it differently: I put an AI agent on top of the base that knows the rules and keeps order for me. This is the pairing of Obsidian plus Claude Code. Not a browser chat where you paste text, but an agent that works directly in the notes folder: it reads, edits, creates notes, and runs scripts. ## Why this specific pair Obsidian is good because it is just a folder of markdown files on disk. No proprietary database, no cloud middleman. A note is a plain text file you can open with anything. That is exactly why it is safe to let an agent near it. Claude Code is not a chatbot but a command-line agent. You launch it inside a folder and it gets file access: it searches, reads, writes, and runs terminal commands. For a knowledge base this shape is ideal, because the whole base is a folder of files under git. The pairing covers the weak spot of each tool. Obsidian on its own does nothing and waits for you to file and link everything by hand. A bare AI chat does not remember your structure and starts from zero every time. Together they give you a base that maintains itself by your rules. ## How it works technically Three components. First. The base in Obsidian is an ordinary folder on disk under git. Git here is not a luxury but insurance. I see every edit the agent makes through `git diff` and can roll it back. The agent physically cannot quietly corrupt notes: everything stays in history. Second. Claude Code runs in the root of that folder and sees the whole file tree. Third, and most important. A file named `CLAUDE.md` sits in the root. It is the constitution of the base. The agent reads it on every launch and must follow what is written there: folder structure, note style, language, what may and may not be touched. The whole point of the pairing is not the model but this file. Without it the agent is smart but does not know my habits. With it the agent behaves like an assistant who has worked with me for a year. ## CLAUDE.md: the heart of the system Here is what is actually written there, because that is the recipe. A trimmed excerpt: ```markdown ## Folder structure - `00 Inbox/` - raw notes, quick captures. - `01 Daily/` - daily notes, events, journal. - `02 Projects/` - active projects with outcomes and tasks. - `03 Areas/` - long-term areas of life and work. - `04 Resources/` - references, learning notes, concepts. - `05 Archive/` - inactive or completed material. - `Maps/` - Map of Content notes and high-level indexes. ## Safety rules - Never delete notes unless I explicitly ask. - Never mass-rename files without showing a plan first. - Never move more than 10 files without confirmation. - Never overwrite original notes when summarizing. Create a new note instead. - Before large structural changes, show a plan and wait for approval. - Do not touch secrets, API keys, passwords, tokens, or credentials. ``` Those safety lines turn a potentially dangerous tool into a safe one. The agent could wipe half the base with a single command, but the rules force it to show a plan first and wait for my yes. There is also a privacy block. I keep a folder with a personal profile. `CLAUDE.md` states the agent may read it when reasoning about my goals, but never lets it leak out: not into git commits, not into calendar descriptions, not into exports. This is an example of how a text rule sets boundaries the agent respects. ## Command phrases instead of clicking This is the nicest part in daily use. In `CLAUDE.md` I described working phrases, each backed by a ready procedure. I just type the phrase and the agent knows the whole flow. * Sort the inbox. It reads `00 Inbox`, proposes where each note goes, plus links and tags, and waits for confirmation before moving files. * What is next. It walks the active projects, collects the Next actions sections and open questions, and returns a short prioritized to-do list. * Make a finance snapshot. It takes the template, creates a monthly snapshot note, totals accounts in their source currency and in USD, and never invents numbers, leaving blanks instead. * Collect calendar tasks. It scans the base for lines tagged as calendar tasks, pulls out date, time, duration, and description, and groups them by date. A key detail: the agent shows a plan first and waits. That way I stay the one making decisions, and the routine goes to the agent. ## Case 1. Producing an animated series The most telling example, where the pairing stops being a smart notebook and becomes a production pipeline. I have an animation project: a short wordless cozy series that I assemble through AI video generation. The whole production lives in the base as a project with subfolders like `Bible`, `Characters`, `World`, `Story`, `Production`, `Media`, `Channel`, and `Blog`. The trouble with such projects is that quality rests on dozens of small rules. How to light a shot, how to move the camera, how not to break a character's look from frame to frame, what to write in the prompt for the generator. Holding all that in your head is impossible, and forgetting one item makes the picture drift. The solution is skills. A skill is a folder with an instruction the agent loads only when it works on that topic. This project has five: write an episode, build a prompt for a specific shot, create a new character, QC a prompt for mistakes before generation, and a general operating layer over the `Production` folder. `Production` itself holds human-readable guides: directing, cinematography, lighting, editing, VFX, a shot authoring standard, and a shot list template. How it works in practice. I ask for a scene of an episode. The agent invokes the right skill, reads the guides, writes the script, breaks it into shots per the authoring standard, and generates prompts. Throughout it holds the project's hard invariants: a single style, character consistency, camera and light rules. A separate rule forces it to always attach character references from the `Media` folder when generating images or video, otherwise a hero's look drifts. Another stream is short clips. Every short prompt is saved by protocol into `Story/Shorts` with a filename made of the date and the beat of the clip, plus metadata for publishing across platforms: ```markdown 02 Projects/Tiny Boo Movie/Story/Shorts/ 2026-06-11 - Meet Boo waking up in a giant world.md 2026-06-11 - Boo meets Marci in the firefly dusk.md 2026-06-17 - Boo finds the whole world in a dewdrop.md 2026-06-20 - Boo can't lift the giant berry.md ``` There are already more than a dozen ready prompts there. This turned scattered ideas into a queue of generation-ready content. What it gave me. The heavy production routine is automated and standardized, while I keep creative control. The quality bar is fixed in the guides, not in my memory, so it does not drop when I am tired. ## Case 2. Travel notes The opposite in spirit, where speed matters less than order and not losing anything. I move around a lot, and part of my trips are visa matters with documents, deadlines, and dates I cannot afford to forget. The structure is strict and described in `CLAUDE.md`. Each trip is a folder like `MM.YYYY - Destination` inside `03 Areas/Travels`. It holds two files: `Raw Notes` for scribbles made on the road, and `Summary` as the clean writeup. Every summary must carry start and end date properties, place, status, and budget: ```yaml --- type: travel status: done created: 2026-05-01 updated: 2026-05-28 дата_от: 2026-05-17 дата_до: 2026-05-24 место: Destination tags: - travel - visa --- ``` How it works. On the trip I dump fragments into `Raw Notes`: what I did, what I applied for, what I spent. Back home I say to write up the trip. The agent reads the raw notes and assembles the `Summary` in one shape: a short recap, trip goals with done markers, a document checklist, a dated timeline with deadlines, finances, next actions, and open questions. It does not touch the original `Raw Notes`; the clean version is a new note. Then two bonuses. First, inside the summary the agent creates calendar tasks in a plain-text format, including a reminder for the next trip with a computed date: ```markdown - [ ] Plan the next trip #calendar дата: 2026-11-20 время: длительность: календарь: Personal локация: Destination описание: 180 days since return. Check visa statuses and book tickets and lodging. источник: [[03 Areas/Travels/05.2026 - Destination/Summary]] ``` Later a single sync command turns these into Google Calendar events. Second, the agent updates the shared travel map in `Maps`, adding the trip with dates and status. So I always have one page with all trips and their state, not a dozen scattered notes. What it gave me. Visa deadlines and next steps no longer get lost, because each one is pushed into the timeline, into open questions, and into the calendar. The summary assembles in a minute from messy notes instead of being written from scratch at night when I am out of energy. ## Other scenarios from practice * Finances. Once a month, the command to make a finance snapshot. The agent creates a note in a single format, I fill in current numbers, and it updates the finance map and tracks the trend across months. * Projects. In the morning I type what is next and get a list: what is on fire in each project and what open questions are hanging. This replaced my manual project walk. * Inbox. I dump thoughts during the day and in the evening say to sort the inbox. The agent proposes a layout, I confirm. The inbox does not pile up for months. ## Automation: scripts and hooks Google Calendar sync. A folder of scripts holds a Python script of a couple hundred lines that walks the whole base, finds tasks tagged as calendar tasks with their neighboring fields, and pushes them into Google Calendar through the API. It is done carefully: events are hashed so a rerun does not create duplicates, and the time zone is respected. It works like this: I say to sync Google Calendar, the agent first shows the list of upcoming events, and only after my confirmation does the real push. Secret protection through a hook. The base holds API credential files that must never be committed to git. I do not rely on the agent's memory. I set up a hook: a small script that Claude Code runs automatically before every terminal command. If the command contains `git commit`, `add`, or `push` and touches a secret file, the hook blocks it. Here is the real hook: ```python #!/usr/bin/env python3 """Pre-tool hook: block git commit/add that would stage secret files. Reads Claude Code hook payload from stdin (JSON with tool_name/tool_input). Exits 0 to allow, 2 to block (stderr is fed back to the model). """ import json, re, subprocess, sys SECRET_PATTERNS = (r"credentials\.json", r"token\.json", r"\.calendar-token\.json") SECRET_RE = re.compile("|".join(SECRET_PATTERNS)) def main() -> int: try: payload = json.load(sys.stdin) except Exception: return 0 cmd = (payload.get("tool_input") or {}).get("command", "") or "" if not re.search(r"\bgit\s+(commit|add|push)\b", cmd): return 0 if SECRET_RE.search(cmd): print(f"BLOCKED: command references secret file(s): {cmd}", file=sys.stderr) return 2 result = subprocess.run( ["git", "diff", "--cached", "--name-only"], capture_output=True, text=True, timeout=5, ) bad = [line for line in result.stdout.splitlines() if SECRET_RE.search(line)] if bad: print("BLOCKED: secret file(s) staged: " + ", ".join(bad), file=sys.stderr) return 2 return 0 if __name__ == "__main__": sys.exit(main()) ``` The difference between the two levels matters. Rules in `CLAUDE.md` are instructions the agent follows. Hooks are code that runs independently of the agent's will. For truly dangerous things I use hooks; for everything else, rules. ## Bases: live tables on top of notes Bases is a built-in Obsidian feature for building table views. I have views for active projects, business ideas, finance snapshots, the inbox, and waiting items. When the agent creates a note, it fills in the correct frontmatter fields, and the note automatically lands in the right table. I get a dashboard without assembling it by hand. ## Memory across sessions The agent has a separate file-based memory: a set of small files, each holding a single fact. Who I am by role, what time zone I work in, which work approaches I dislike, which decisions we already made on projects. I do not have to re-explain context every time. A new session starts not from zero but from accumulated knowledge. ## Setting it up from scratch 1. Install Obsidian and create a vault, an ordinary folder. Run `git init` in it. That gives you rollback of any change. 2. Install Claude Code and launch it in the root of the vault folder. 3. Create a `CLAUDE.md` file in the root. This is the key step. Describe the folder structure, the note language, the style and required frontmatter fields, the safety rules, and what must not be touched. You can ask the agent itself to draft this file from your base, then edit it. 4. Add templates in a `Templates` folder so projects, trips, and snapshots share one shape, and note in `CLAUDE.md` which template is for what. 5. Add working phrases. Describe commands like sort the inbox or what is next right in `CLAUDE.md` and spell out what the agent does for each. 6. When a repeating technical routine appears, move it into a script and teach the agent to run it. For dangerous operations, add a hook. 7. As the base grows, add skills for complex projects so their specifics do not clutter the general rules. Start with the first three points. A well-written `CLAUDE.md` alone is enough to feel the difference. ## Honest about the downsides This is not magic. The agent sometimes reads a task more broadly than needed, so the show-a-plan-and-wait mode is mandatory, especially at the start. Git is not a luxury but a necessity: without change history it is scary to trust edits to an automaton. And the pairing takes an upfront investment of time in writing rules. The first week you configure more than you save. The payoff comes later. ## Takeaway The value is not that an AI writes my notes for me. The value is that the base stopped degrading. It used to rest on my discipline and fell apart the moment I got busy. Now order rests on the rules in `CLAUDE.md`, and the agent maintains it. I think and decide; it files, links, and automates. Obsidian gives an open format it is safe to let an AI near, and Claude turns a static folder of text into a living system that works by my rules and knows my context. --- # Steam AI Disclosure: turning a niche into a working micro-SaaS URL: https://ravy.pro/blogs/steam-ai-disclosure-micro-saas · Published: 2026-06-26 · Tags: ai, games, dev, policy · Author: Andrei Rovnyi > How a line from my market-niche notes became a live micro-SaaS: what Steam's AI content disclosure is, why getting it wrong can delay or delist a game, how the tool is built, the honest legal standing of the protocol it generates, and a pre-upload checklist. I keep a personal notebook of *in-demand niches*. Not "wouldn't it be cool to build X," but "here is where someone's hair is on fire and they'd pay to put it out." One of those lines turned into a real, paid tool that now lives on this site: the [Steam AI Disclosure Generator](https://ravy.pro/tools/steam-ai-disclosure). This post is the full story: the idea, where it came from, how it's built, what it's worth, why I bothered, and the one part people always get wrong: what that generated PDF protocol *legally* is and isn't. ## The idea, in one line **Steam AI Disclosure** walks a game developer through a short questionnaire, decides what they must declare about AI in Valve's Steamworks Content Survey, and hands them ready-to-paste disclosure text plus a dated "compliance protocol." The verdict is free. The paste-ready pack is paid. It sounds narrow. The narrowness is the point. ## How it came about The niche surfaced during one of my regular sweeps for fresh, concrete pain. The signal was sharp: in January 2026 Valve rewrote the AI-disclosure form on Steam, and developers suddenly didn't know what they were supposed to declare. A bit of context on why that's painful at all: * In 2023, Steam rejected games built with AI-generated assets when the developer couldn't show they had the rights to what the model was trained on. * In 2024, Valve formalized a policy: AI is allowed, but you must disclose it in the Content Survey. * In January 2026, Valve clarified the scope. You disclose AI content that ships in the build and is consumed by players, not behind-the-scenes "efficiency" tools. * The volume exploded: by various counts, roughly 8,000 games disclosed AI use in the first half of 2025, versus about 1,000 in all of 2024. More games, more confusion. This is textbook *forced demand*: not "nice to have," but "get it wrong and your review is delayed or your page is pulled." And the part that mattered to me personally: it's gamedev, a domain I know from the inside. Real pain ∩ my expertise. ### The pivot: it's not "three paragraphs" The first thing I did was try to kill the idea. The obvious objection: *why pay when ChatGPT writes the text for free?* And that's true: a model will happily write the paragraphs. So the product can't be the text. The value lives somewhere else, in the things a chat model can't credibly give you: 1. **A current ruleset.** ChatGPT confidently serves 2024-era rules or hallucinates. Valve changes the form and enforces with delisting. Keeping the rule set synced to the live policy is the actual moat. 2. **Dated proof of good faith.** A protocol stamped with the policy version, the date, and a rationale per category. A paper trail for when a report or a rule change shows up later. 3. **Backlash-safe wording.** *How* you phrase the disclosure to players, so you don't get review-bombed, is judgment, not text. That teardown became the spine of the product: a free verdict as the lead magnet, and a paid unlock for *currency, evidence, and careful phrasing*, not for prose. ## What it solves for the developer The user is an indie dev or a small studio about to publish on Steam. Their jobs-to-be-done: * **Kill the gray-zone anxiety.** "AI-upscaled textures, disclose? AI-assisted animation? Placeholder VO that an actor replaced?" The tool answers against Valve's taxonomy: Pre-Generated, Live-Generated, exempt, or a flagged gray zone with the policy's own wording. * **Fill the form correctly the first time**, with no review delay and no takedown. * **Get the exact text** for each Steamworks field (including the mandatory guardrails description for runtime AI) and a calm, player-facing store note. * **Keep evidence** that the review was done in good faith against a specific policy version. ## Practical applications, and what happens when you get it wrong Where it actually earns its keep: * **An indie ships AI concepts a human repainted.** Disclose or not? (If a human's final art shipped, no; if the AI art ships as-is, yes.) The tool settles it in a minute instead of half a day of forum-diving. * **A studio adds an LLM-driven NPC.** That's Live-Generated, and Valve *additionally* requires a description of the guardrails that stop it from producing illegal content. This is the field people forget, and the tool supplies both the text and the reminder. * **AI in the store capsule.** Capsule art and screenshots are player-facing, and AI there draws extra community scrutiny. The tool flags it as a high-attention area and helps you word it honestly. * **The January 2026 policy change.** Games already shipped under the old rules suddenly need re-checking, which is exactly where a dated protocol plus rule-change monitoring becomes recurring value rather than a one-off. The cost of getting it wrong: a delayed review (a blown launch window), a rejected page, in the worst case a delisting. And almost always a reputational hit and review-bombing if players decide the studio hid something. The downside is the lost launch you worked a year for. Against that, a small fee for certainty and a paper trail is insurance, not a text purchase. ## How it's built (the technical part) The site is Nuxt 4 (Vue 3), Firebase Firestore (Admin SDK only), a Nitro server, deployed on Firebase App Hosting. The decisions that matter: **1. A deterministic core; AI is only a writer.** The verdict is computed *in code* from a versioned rule set: ten asset categories mapped to `pre` / `live` / `exempt` / `gray`. This is the moat, the free lead magnet, and the predictability all at once. The AI never decides what to disclose: ```ts // One pure function decides what must be disclosed — no AI involved. export function classifyAudit(answers: SteamAuditAnswers): SteamAuditClassification { const perCategory = RULESET_CATEGORIES.map((cat) => { const answer = answers[cat.id] ?? 'none' return { id: cat.id, ...cat.classify(answer) } // outcome: 'pre' | 'live' | 'exempt' | 'gray' }) return { rulesetVersion: RULESET_VERSION, // e.g. '2026-01-17' perCategory, hasLive: perCategory.some(c => c.outcome === 'live'), mustDisclose: perCategory.some(c => c.outcome === 'pre' || c.outcome === 'live'), } } ``` OpenAI is called **only** on the paid step, and only to turn that already-decided verdict into polished prose (the Steamworks field text + a backlash-safe store note). No "let the model decide what's disclosable." **2. Payment: Stripe Checkout, webhook as the source of truth.** What confirms a sale isn't the browser redirect (the tab can be closed). It's the webhook, which marks payment and kicks off generation idempotently: ```ts // The Stripe webhook is the source of truth. Generation runs once, after payment. export async function markPaidAndGenerate(id, email, sessionId, config) { const snap = await audits.doc(id).get() if (!snap.exists || snap.data().status !== 'awaiting_payment') return // already handled — idempotent against Stripe retries & duplicate events await audits.doc(id).set( { status: 'paid', customerEmail: email, paidAt: nowIso() }, { merge: true }, ) void runGenerationThenEmail(id, config) // fire-and-forget so we ack Stripe fast } ``` The whole flow: ![Steam AI disclosure tool flow](https://ravy.pro/media/blog/steam-ai-disclosure-micro-saas/e7d18772-c76f-45d5-8df2-f4405d3b22e6-7d0606cd60.webp){width=1774 height=887} **3. Access without an account.** The result opens via a signed (JWT) link, and also lands in the user's account history if they're logged in. Anonymous purchases work too, and the link is emailed. **4. Resilience.** The valuable part (answers + verdict) is persisted *before* payment, so generation can always be retried for free. There are transient retries to OpenAI, an auto-retry on failure, and a "your payment is safe, retrying doesn't charge you again" screen. **5. PDF in the browser.** The protocol prints via `window.print()` from already-stored data, so there's no server-side PDF pipeline and fewer points of failure. **6. SEO/AEO from day one.** The page is prerendered; the static HTML carries real text, a single-source FAQ (visible text == structured data), and a full Schema.org graph: ```ts useToolPageSchema({ offer: { price: '39', currency: 'usd' }, howTo: { name: 'How to complete your Steam AI content disclosure', steps }, faq: faqItems, // the same array is rendered visibly → schema ↔ content parity }) ``` One note of engineering humility: there's no ML research and no heavy infrastructure here. The "magic" is careful deterministic logic and a rule set kept current by hand. ## The business value * **Forced demand.** A purchase made out of fear of delisting converts better than "would be handy." * **The moat is currency, not code.** Anyone can clone the UI over a weekend; few will spend weeks keeping the rule set synced to Valve and shipping a dated artifact. * **A path to recurring revenue.** The one-off is the entry; retention is built on rule-change monitoring ("we watch the policy and keep your disclosures valid"). * **A wedge into something bigger.** AI disclosure is a narrow, hot doorway into the larger, money-ier niche of "Steam/console submission readiness": the whole Content Survey, age ratings, regional compliance, a pre-release checklist. Honestly, on its own this is a modest micro-SaaS, not a venture rocket, and that's fine. I designed it as a precise, cheap-to-maintain tool with clear economics. ## Why I built it A few layers: 1. **Productizing niche research.** Turning a line from my notebook into a live product on prod, fast, is a test of my whole pipeline: find pain → kill weak ideas → ship. 2. **Domain leverage.** I know the Steamworks pain from the inside, so this is cheaper and more credible for me to run than for an outsider. 3. **An asset and a showcase.** I'm making ravy.pro a home for small tools like this. Each one is potential revenue, a portfolio piece, and content (this article is part of the same loop). 4. **An option on more.** If the narrow doorway proves demand, a much larger compliance product for studios sits right next to it. ## The legal standing of the PDF protocol, honestly This matters, so let me be precise and not oversell it. The protocol is not a certificate, not a guarantee of compliance, and not legal advice. It does not make Valve approve your game, and it confers no immunity. Any tool that promises "one-click compliance" is setting you up. The cautionary tale here is the $1M FTC settlement against accessiBe for marketing an accessibility widget as guaranteed compliance. Over-claiming is the trap. What the protocol *is*: contemporaneous, dated, ruleset-versioned documentation of a good-faith review. Its value is evidentiary, and it comes from three properties: * **It's dated.** It records *when* you made the determination, ideally at or before submission. * **It's version-pinned.** It states exactly *which* policy version you reviewed against (e.g. `v2026-01-17`). When Valve changes the rules later, you can show you complied with the rules that existed when you shipped, rather than being judged by a policy that didn't exist yet. * **It's reasoned.** It captures your answer and the rationale for each category, so "we decided X because Y" is on the record instead of "we think we were fine." In practice that's useful in exactly the moments disputes happen: a platform query, a marketplace takedown appeal, a publisher or partner asking how you handled AI, or an internal record for your own team. It doesn't *win* those situations by fiat. It lets you demonstrate diligence with a credible, time-stamped trail instead of a vague recollection. That's the difference between "trust us" and "here is what we determined, when, and against which policy." Being honest about this isn't only safer. Post-accessiBe, it's a genuine differentiator. "Detection + documentation of good faith" is a claim you can stand behind; "guaranteed compliant" is not. > This tool, and this article, are informational, not legal advice. For anything with real stakes, talk to a lawyer. ## Takeaways and a pre-upload checklist The big lesson, for me, isn't about Steam. It's about method: the most valuable part of a product is almost never where it first appears. Here it wasn't three paragraphs of text. It was current rules and dated evidence. Finding that real value is the whole job. If you're shipping a game on Steam, here's the short version you can apply without any tool: * **Did any AI output ship in the build and get seen, heard, or read by players?** → disclose it (Pre-Generated). * **Does the game generate anything via AI at runtime?** → disclose it (Live-Generated) **and** describe your guardrails. * **Was AI only a development/efficiency tool, not player-facing?** → generally not disclosed. * **Did a human replace AI placeholders before release?** → it didn't ship; not disclosed. * **Marketing capsule, screenshots, or trailer made with AI?** → player-facing; disclose and confirm you hold the rights. * **Cloned or trained on a real person's voice?** → keep written consent on file. * **Unsure whether something reaches players?** → disclose. * **Keep a dated record** of your determination and the policy version you reviewed against. If you'd rather not do that by hand, the [free verdict](https://ravy.pro/tools/steam-ai-disclosure) takes about three minutes. --- # From a Demo File to a Highlight Reel: A CS2 Tool I Always Wanted URL: https://ravy.pro/blogs/from-a-demo-file-to-a-highlight-reel-a-cs2-tool-i-always-wanted · Published: 2026-06-12 · Tags: dev, games · Author: Andrei Rovnyi > Before I was an engineer, I was a Counter-Strike player. Before I was an engineer, I was a Counter-Strike player. I played in XPLOIT Team around 15, competed in ASUS, MSI Beat in Russia, WCG and WESGG, and my proudest result was 2st place in WCG Russia. The game stuck with me long after the team days ended. I still queue up CS2 matches in the evening, and I still catch myself rewatching rounds in my head on the way to work. Here is the thing every CS player knows. You play a great match. There was that one round — a 4K, or a clutch you had no business winning — and you want to watch it again, or show it to your teammates. What you actually have is a demo file: a 40-minute recording where your moment is buried somewhere around minute 23. So you open the demo, scrub through it at 8x speed, miss the round, scrub back, finally find it, then record your screen with OBS while it plays. I have done this dance more times than I want to admit. So I built a tool that does the whole thing automatically. You give it a demo file, it gives you back an MP4 with the best moments of the match, cut from real in-game footage. ``` highlights match.dem ``` That's it. One command. ## What it actually does On my own de\_inferno match (21 rounds, 150 kills), the tool found 8 highlights: a 4K by a player named Auttnic, four clutches, and a handful of multi-kill rounds. One clip merged two overlapping moments — two players fragging at the same time — and switches the camera between them mid-clip. There is also a `--player` flag if you only want your own moments, which is what most people want: a personal reel from a match you just played. The pipeline has four stages: ``` match.dem → parse events → detect & score highlights → record via CS2 + HLAE → final MP4 ``` The first two stages are pure data work. The last two are the reason this was fun to build. ## A demo file contains no video This surprises people who haven't worked with demos. A `.dem` file is not a recording of the screen. It is a stream of game events and entity positions: who shot whom, with what, from where, on which tick. It is tiny compared to video because there are no pixels in it — the game engine recreates the picture during playback. That fact splits the project in half. Detecting highlights means reading data. Producing video means launching the actual game, making it play the demo at the right moments, pointing the camera at the right player, and capturing frames. Half data engineering, half puppeteering a live game process. ## Finding the highlights For parsing I used [demoparser2](https://github.com/LaihoE/demoparser) — a Rust parser with Python bindings that turns a demo into pandas DataFrames. One call gives you every kill with attacker, victim, weapon, headshot flag, even "through smoke" and "attacker was flashed" flags. The detector clusters each player's kills within a round into "moments" — kills less than 20 seconds apart belong to the same moment. Clutches are detected by replaying the round's deaths and counting who is alive: when one side is down to a single player who then wins the round, that's a 1vX. Each moment gets a score. The weights are simple and live in one dictionary: an ace adds 8 points, a knife kill 3, an AWP noscope 2.5, a won clutch adds 2 plus 1.5 per opponent. Pistol rounds and the final round get multipliers, and a moment from a round your team still lost gets docked 15%. Top N moments by score become clips, with a few seconds of lead-in and lead-out around the kills. None of this is machine learning, and that is deliberate. The heuristics are readable, debuggable, and tweakable in one file. If you think a wallbang deserves more than 1 point, change the number. ## Recording: driving the game like a puppet This is the part where most of the engineering went, and where I leaned on the open-source work of others. [CS Demo Manager](https://github.com/akiver/cs-demo-manager) (MIT) solved game-driven recording years ago, and I ported its mechanics to Python. Credit where it is due: akiver's CSDM, advancedfx's HLAE, and LaihoE's parser made this project possible. The recording flow looks like this: 1. The tool launches CS2 through **HLAE** with a DLL injection (`AfxHookSource2.dll`). HLAE adds console commands for movie-making that the game doesn't have. 2. A small **server plugin** (a `server.dll` shim, also from CSDM) gets loaded by the engine through a temporary edit of `gameinfo.gi`. The plugin reads a JSON file with commands and executes each one at an exact demo tick. CS2 dropped the old `.vdm` scripting system, so without this plugin there is no reliable way to say "do X at tick 45771". 3. At each highlight, the plugin seeks the demo, locks the camera on the right player, and starts the capture. **HLAE pipes rendered frames straight into FFmpeg** — no gigabytes of raw screenshots on disk — while the game writes a WAV with the sound. 4. When the last clip is done, the game quits itself, and FFmpeg glues the clips into the final MP4. The devil here is in tiny ordering rules that you only learn from CSDM's commit history. Commands must never run before tick 96, because the game skips early ticks after a seek. The seek must happen on an earlier tick than the camera command, because since an October 2025 update they get ignored if issued together. Playback pauses 4 ticks before each clip starts so the post-seek loading tint can fade. Get any of these wrong and you get black frames, a free-floating camera, or no clip at all. Two rakes I stepped on along the way, in case they save someone an hour: * The plugin binary ships inside CS Demo Manager's installer. I didn't want to require a full CSDM install, so my extraction script carves the 7z payload out of the NSIS installer by signature offset. Python's py7zr can't decode it (the archive uses a BCJ2 filter), so the script falls back to the standalone `7zr.exe`. * If your Python comes from the Microsoft Store, its writes to AppData are silently virtualized into an MSIX sandbox — your files exist for Python and don't exist for any other process. I spent a while staring at a file that was simultaneously there and not there before figuring it out. The tool keeps everything in `~/.cs2-highlights` because of this. One important note: the game always launches with `-insecure`, and the plugin refuses to run without it. Don't join VAC-secured servers with HLAE running. The tool never touches your real game config either — the game gets a sandboxed settings folder. ## Using it You need Windows, CS2 installed, Steam running, and Python 3.11+. HLAE and FFmpeg download themselves on first run. ``` git clone [GitHub repo link] cd cs2-highlights python -m venv .venv .venv\Scripts\pip install -e . .venv\Scripts\highlights doctor ``` `doctor` checks the whole environment and tells you exactly what is missing: ``` | Steam installed | OK | c:\program files (x86)\steam | | CS2 installed | OK | D:\...\game\bin\win64\cs2.exe | | HLAE | OK | ~\.cs2-highlights\tools\hlae | | CS2 server plugin | OK | vendor\cs2-plugin\server.dll | ``` Then: ``` highlights match.dem # best moments of the match highlights match.dem --player Rovniy # only my moments highlights match.dem --top 5 # limit the reel to 5 clips highlights match.dem --json-only # just analyze, no recording ``` Expect recording to take roughly real time plus seeks: ten 20-second clips come out in about 10-15 minutes, because an actual game is booting, seeking and rendering behind the scenes. The analysis stage alone takes seconds — FACEIT `.gz` and Valve `.dem.zst` files are unpacked automatically. Fair warning about the ecosystem: every CS2 update can break HLAE injection until advancedfx ships a new release, usually within days. It happened to me mid-project — the June 10 update landed two weeks after the latest HLAE. `doctor` detects exactly this case by comparing build dates, and `highlights update-tools` fetches the fix when it's out. Tools built on top of a live game come with that tax. ## What's next A few things I want to try: a small GUI with a preview of detected highlights before recording, a fast 2D radar-style render for instant sharing, and a client–server mode where analysis runs anywhere and a Windows machine with the game acts as a render agent. The code is on GitHub: [https://github.com/Rovniy/cs2-highlights-maker](https://github.com/Rovniy/cs2-highlights-maker). If you try it on your demos and something breaks — or your scoring weights disagree with mine — open an issue. And if you just made a sick clutch yesterday: you know exactly which demo to feed it first. --- # How We Made the First Episode of Tiny Boo URL: https://ravy.pro/blogs/how-we-made-the-first-episode-of-tiny-boo · Published: 2026-06-10 · Tags: ai, tiny-boo, animation · Author: Andrei Rovnyi > Let me start with where all of this came from. We have a game — Tiny Boo: Homecoming, a story about a tiny creature named Boo who gets lost and makes his way home across a huge world. Let me start with where all of this came from. We have a game — Tiny Boo: Homecoming, a story about a tiny creature named Boo who gets lost and makes his way home across a huge world. At some point that world, Lumia, started to feel too big to keep inside a game. We wanted to show it differently — not as levels and mechanics, but as short stories you can just watch in the evening, when you have no energy left for anything else. That's how Tiny Boo ended up on YouTube. The idea is almost embarrassingly simple: a warm cartoon with no words. No words at all. ## YouTube video ## Why no words That was the first decision, and probably the most important one. The moment you take out dialogue, the story stops belonging to a single language. People understand it the same way in Moscow, Manila and São Paulo — there's nothing to translate, everything rests on action and expression. For us that was the whole point: to make something that works across borders. There was a practical side too. We build the video with neural nets, and getting clean lip-sync with a consistent voice out of that kind of tech is its own headache — one it's more honest to sidestep than to heroically conquer. But if it were only about production, we wouldn't have built the whole thing around it. Here, being wordless isn't a compromise, it's a personality. Boo isn't supposed to talk anyway — his ears, his eyes and the way he clutches his little cape say it for him. We had good reference points to lean on: Pingu, Larva, Shaun the Sheep, La Linea. None of them ever needed subtitles. ## Who Boo is ![Tiny Boo emotions](https://ravy.pro/media/blog/how-we-made-the-first-episode-of-tiny-boo/tiny-boo-emotions-eeed8b9573.webp "Tiny Boo Model Sheet"){width=5016 height=3762} Boo is a tiny forest spirit shaped like a closed flower bud. The body is teardrop-shaped, made of folded leaves with visible veins, and the leaves on top of his head curl into a little spiral tuft that works as a mood antenna: it springs up when he's happy and droops when he's tired. Big leaf-shaped ears, green on the outside and soft pink within. Small dark eyes with bright highlights. No nose at all — and it turns out he doesn't need one; the face reads perfectly fine without it. We boiled his character down to three traits: curiosity, naivety and fearlessness. It sounds sweet, but that exact mix is where both the humor and the tension come from. Boo walks straight into places a smarter creature would avoid — simply because he's curious. The world, meanwhile, isn't cruel, so everything ends up warm in the end, but the road to that "warm" can get tense. And there's one detail the whole thing hangs on — the cape. A pink-lilac petal with a heart-shaped clasp, faintly glowing. It's a gift from home. Boo guards it the entire way as a thread back to his family. When we need to show that he's pulled himself together, we don't need words — he just grips the cape with both hands. ## The story of the season The first season is called The Long Way Home. The setup is short: a storm tears Boo and his friends off their home tree and scatters them across the wild forest. The rest is the road back, through four "shades" of forest — from the bright and carefree, through the anxious yellow and the frightening dark, and back to the light again, but this time at home. Along the way Boo finds the friends the same storm blew apart. But for one reason or another, none of them can keep going right then, and Boo promises to come back for them with help. Those promises stack up over the whole season so they can pay off all at once in the finale: Boo makes it home, leads a rescue party back out, and gathers everyone at the home tree. The episodes still stand mostly on their own — you can watch most of them separately — but a single thread runs through the whole season. ## Episode one: "Carried Away" The first episode is that very setup, the moment everything starts from. In Russian it's called "Унесённый," and there's a nice double meaning in the English title: Boo is physically carried away by the storm, and "to be carried away" also means to be moved to tears. Which is more or less exactly what we're after. We wrote the script in action, not lines — laying out what happens on screen and what the character feels while it does. The episode is split into three acts. Act one is home. A golden morning on a very tall tree, the forest below in a warm haze, a glowing hollow, the bud-family. Boo plays carelessly with his friends, Po and Marci — tag and hide-and-seek — climbs higher than anyone and hides right at the top. Down below the family waves, Boo waves back and adjusts his cape. All is well. We deliberately let this moment breathe — so that there's something to lose. Act two is the storm. The sky darkens, the leaves begin to tremble, everyone's ears prick up. Then a sharp gust, a tornado, rips them all off the branch. Boo is caught in the spinning current, whirled around in a spiral of torn leaves and petals, reaching for the branch slipping away from him. Po is swept one way, Marci another; they reach for each other, but the wind pulls everyone apart. And the home tree shrinks fast into the distance. This is the episode's emotional gut-punch — and the setup for the whole rescue line of the season. Act three is the forest edge. The wind dies as suddenly as it came. Boo comes to on a strange mossy branch, right at the edge of an unfamiliar forest. Fog, silence, dripping water. He looks around for his friends and his home — no one. His ears drop, the tuft sags. And that's when he notices the cape on himself, grips it, and gathers his courage. He lifts his gaze to the forest and takes a first steady step. The camera pulls up: a tiny Boo at the edge of an enormous world, the road ahead of him. It mattered to us that an episode about loss ends not in despair but in hope. Small, frightened, alone — but walking. ## How it was put together Technically, each episode is dozens of short shots, three to eight seconds each, generated and then assembled in the edit. The hardest part is consistency — making sure Boo is the same creature in every shot. To handle that we locked his look down in advance in detailed reference sheets, and we carry the same set of traits into every shot — the bud silhouette, the spiral tuft, the pink inner ears, the cape with the heart clasp. The first episode was a real stress test: it's the first time several characters share the frame at once, and we deliberately built the scatter scene out of separate single shots — easier on the tech, and it introduces each friend in a big close moment. Sound was done separately. In the first act, a warm home theme on ukulele and piano. In the storm, a rising rumble and an anxious register the series hadn't used before. Then a hard cut to silence at the forest edge, and out of it a quiet, hopeful motif emerges on that first step. Boo does have a voice, but it isn't words — it's gibberish vocalizations: laughs, sighs, a determined little "hm." We work in a small way and slowly — this is a side project, not a studio pipeline. So the first episode is less a "premiere" for us than proof that the whole idea actually holds together: that a wordless story about a tiny brave creature can hit you somewhere real. From here, it's the road home. Boo still has friends out in that forest, and he promised to come back. --- # How I'm Making an Animated Film with AI: The Story of Tiny Boo URL: https://ravy.pro/blogs/how-i-am-making-an-animated-film-with-ai-the-story-of-tiny-boo · Published: 2026-05-31 · Tags: tiny-boo, animation · Author: Andrei Rovnyi > I had wanted to make something of my own — something warm — for a long time. ## YouTube video I had wanted to make something of my own — something warm — for a long time. I already had a game, *Tiny Boo: Homecoming*, about a tiny creature named Boo trying to find his way home through the great big, magical world of Lumia. And at some point it clicked: what if I brought this world to life not only in a game, but in an animated film? Launch a YouTube channel where Boo lives out small stories — and make it not with a studio of twenty people, but together with an AI. That's how the **Tiny Boo** project started. In this article I'll honestly walk through how the idea came to me, how we built everything step by step from concept to a finished pilot, which tools we used, and what I learned along the way. ## The idea: don't invent from scratch — bring to life what already exists I made one decision right away: not to spin up a brand-new world, but to use an IP I already had — Boo and the world of Lumia. The character already had a story ("swept far from home, needs to get back") — a perfect basis for a journey series. Then came the key choice, and as it turned out, the most important one: **make the film wordless** — like Pingu or Larva. Three reasons: * no language barrier — the channel works in any country; * no struggling with voiceover and lip-sync in AI video; * simpler and cheaper to produce. This single decision shaped absolutely everything that followed. ## How we worked, step by step I didn't rush straight into "generating video." First my AI assistant and I built the foundation — and it paid off. **1. Concept and rules.** We defined the format (short 2–3 min episodes + Shorts), the audience (family, all-ages), the tone (cozy + light adventure), and the core feeling of every episode — *endearment*. All of it went into a series bible. **2. The world.** We described Lumia as a microworld: grass blades are trees, a dewdrop is a lake, a mushroom is a building. For each location we made a "passport" with its palette and scale — so shots wouldn't drift in color. **3. The character — and his "lock."** The most important thing in AI animation is keeping the hero looking the same in every frame. We described Boo in detail (a flower-bud forest spirit with big eyes and a glowing cape) and built a **character lock**: reference images — front, profile, an expression sheet. Without it, the AI draws a "new" character every time. **4. The story.** We chose an anthology format with a season-long thread: each episode stands alone, but together they carry Boo home. For the pilot we picked the simplest, most beautiful story — "The Dewdrop": Boo wants a sip from a giant dewdrop, and it turns into a tiny adventure. **5. Shot breakdown and prompts.** We split the pilot into 21 shots and wrote a full prompt for each — character, environment, camera, light, **sound and VFX** (modern AI video can generate audio right away). We invented a "fixed part + variable part" structure: style, character and palette are copied into every shot; only the action and camera change. That keeps the whole film in one consistent style. **6. Music.** We generate the theme and score separately — with prompts for wordless, warm, acoustic music. We set one "Boo theme" as the channel's sonic logo. **7. Brand and channel.** Name, the slogan *"Tiny creature, big world,"* avatar, banner, a text-free thumbnail template, intro and outro. We also wrote the channel description and metadata for the first video. ## The tools * **AI assistant (Claude)** — co-director and producer: helped make decisions, wrote the bible, script, prompts, and structure. * **ChatGPT** — character image generation (master reference, turnaround, expressions). * **Seedance 2** — generating the actual video shots (with sound and effects built in). * **Suno** — music and theme. * **DaVinci Resolve / Clipchamp** — editing and mixing. ## What I learned along the way * **Structure beats inspiration.** An hour spent on the bible and the character lock saves dozens of hours of re-generations. * **Consistency is enemy #1 in AI animation.** You beat it with reference images and a single prompt "skeleton." * **Wordless is a superpower** — global reach and a far simpler production. * **You can't generate music inside every clip** — otherwise the pieces won't cut together. One theme, one track at the edit stage. * **AI isn't a "make it pretty" button — it's a co-author.** It's strongest where you set the constraints and make the calls, and it holds the entire mass of detail. ## The result What I have now is a **complete production package for the pilot**: concept, world, a character with ready references, script, shot breakdown, prompts for every shot, music, brand assets, and a set-up channel — **Tiny Boo**. Essentially, from scratch and with just an AI, we put together what usually takes a small team. Next up: assembling the pilot, "The Dewdrop," and starting to post. But that's another story — one I'll tell too. > If you want to watch Boo find his way home, here's the channel: [Tiny Boo](https://www.youtube.com/@TinyBooLumia). Tiny creature, big world. 💚 --- # Why I Built a Credit Card Generator Tool for Developers URL: https://ravy.pro/blogs/why-i-built-a-credit-card-generator-tool-for-developers · Published: 2026-05-28 · Tags: dev · Author: Andrei Rovnyi > A while ago, while testing another payment integration, I ran into the same annoying problem that every developer eventually faces: finding decent test credit card data. A while ago, while testing another payment integration, I ran into the same annoying problem that every developer eventually faces: finding decent test credit card data. Not real card data, obviously — just realistic-looking numbers for testing forms, payment flows, validation logic, APIs, and staging environments. And honestly? Most tools out there were terrible. Some looked like they hadn’t been updated since 2009. Others were packed with aggressive ads, fake “hack” vibes, suspicious redirects, or weird promises about “working cards with balance” — which immediately tells you the site is either sketchy or targeting the wrong audience entirely. I just wanted a clean, fast tool for legitimate development work. So I built one. ## What This Tool Actually Does The tool generates fake but structurally valid credit card numbers for testing purposes. That means the generated numbers: * match the format of real payment cards * pass basic validation checks like the Luhn algorithm * can include expiration dates and CVV values * look realistic enough for development and QA environments But they are **not connected to real bank accounts** and cannot magically be used to buy things online. This is important to understand because there’s a lot of misinformation around tools like this. A proper credit card generator is basically a developer utility — not some “free money” machine from TikTok or shady Telegram channels. ## Why Developers Need This Stuff If you build anything involving payments, subscriptions, billing, SaaS, marketplaces, or e-commerce, you constantly need test data. For example: * testing checkout flows * validating payment forms * checking frontend masking * testing Stripe or PayPal integrations * writing automated Cypress or Playwright tests * simulating failed transactions * populating staging databases * testing edge cases Using real customer card information for this is a terrible idea for both security and compliance reasons. So developers use generated test data instead. Honestly, most of the time you don’t even need a “working” payment method — you just need something that looks real enough for your system to behave correctly. ## The Funny Part About Payment Validation A lot of people don’t realize how many systems only validate the *structure* of a card number. For example, many forms simply check: * card length * issuer prefix * checksum validity That checksum is usually based on something called the Luhn algorithm. So if a generated number passes the algorithm, many systems will initially accept it as “valid format,” even though it’s completely fictional and unusable for real payments. That's exactly what makes these generators useful for testing. ## Why Existing Generators Frustrated Me Most existing tools felt built either for SEO spam or for people trying to do questionable things. I wanted something simpler: * no weird UI * no dark patterns * no “premium BIN database” nonsense * no casino-looking interface * no fake hacker aesthetic Just: open page → generate test data → copy → continue working. That's it. So the version on Ravy.pro is intentionally minimal. ## Legal and Legitimate Use Cases I want to be very clear about this part. This tool is intended for legal testing and development only. Some completely normal use cases include: ### QA Testing Generating realistic datasets for automated testing pipelines. ### Payment Integration Development Testing integrations with Stripe, Adyen, Braintree, PayPal, and other providers. ### UI/UX Work Designing checkout forms, wallet interfaces, and billing pages with realistic-looking data. ### Education Teaching fintech, web development, cybersecurity, or QA engineering concepts safely. ### Security Testing Testing validation logic, anti-fraud systems, rate limiting, and payment edge cases. ## What It Should NOT Be Used For Not everything that is technically possible is acceptable. This tool should not be used for: * fraudulent purchases * bypassing subscriptions * fake billing verification * impersonation * payment abuse * unauthorized transactions If you're trying to use generated card data against real payment systems, you're missing the entire point of the tool. ## Building Developer Tools Is Fun One thing I've realized recently is that small utility tools are surprisingly satisfying to build. They solve narrow, real-world problems. No giant startup pitch. No “AI-powered revolution.” No bloated roadmap. Just a useful thing that saves developers time. And honestly, the internet probably needs more software like that. If you want to try the tool yourself, you can find it here: [https://ravy.pro/tools/credit-card-generator](https://ravy.pro/tools/credit-card-generator) --- # JavaScript Traps Worth Knowing Before They Bite You URL: https://ravy.pro/blogs/javascript-traps-worth-knowing-before-they-bite-you · Published: 2026-05-11 · Tags: dev · Author: Andrei Rovnyi > A field-tested tour of the JavaScript traps that bite real codebases — floating-point math, NaN, ==, hoisting, this, references, async/await, and JSON cloning. JavaScript is one of those languages that looks friendly right up until the moment it ruins your evening. At first, everything feels simple. - You write a function. - You render a button. - You fetch some JSON. - You build a small UI. - You think: “Okay, I get it. JavaScript is not that hard.” And then, at some random point, you open the console and see this: ```js 0.1 + 0.2 === 0.3 // false ``` Or this: ```js typeof null // "object" ``` Or this: ```js ["10", "10", "10"].map(parseInt) // [10, NaN, 2] ``` And suddenly JavaScript stops looking like a cute scripting language and starts looking like an ancient artifact with cursed rules inside. The funny thing is: JavaScript is usually not random. Most of its weird behavior comes from legacy decisions, type coercion, floating-point math, browser history, and the fact that the language had to evolve without breaking half of the internet. That is what makes JavaScript interesting. And sometimes painful. This article is not a complete JavaScript textbook. It is a collection of traps that I think every developer should know earlier rather than later. Not because you need to memorize them all. But because one day you will see one of them in production, and it is better to recognize the monster before it bites. --- ## The Famous One: `0.1 + 0.2` Let’s start with the classic. ```js console.log(0.1 + 0.2) // 0.30000000000000004 ``` At some point, every JavaScript developer discovers this example. And usually the first reaction is: > What the hell? The problem is not really JavaScript itself. The same thing happens in many other languages because they use binary floating-point numbers. Computers store numbers in binary. Some decimal numbers, like `0.1` and `0.2`, cannot be represented perfectly in binary form. So JavaScript stores an approximation. Usually that approximation is good enough. But sometimes it leaks out: ```js console.log(0.1 + 0.2 === 0.3) // false ``` This looks stupid, but it is just math under the hood. The real lesson is simple: Do not use floating-point numbers for things that require exact precision. Especially money. Bad: ```js const price = 0.1 + 0.2 ``` Better: ```js const priceInCents = 10 + 20 console.log(priceInCents) // 30 ``` Store money in cents, kopeks, smallest units, whatever fits your currency. If you are building financial software, use a proper decimal library. Do not try to be heroic with floats. Heroism in financial calculations usually ends with someone losing money. --- ## `typeof null` Is a Historical Scar This one is beautiful in the worst possible way: ```js console.log(typeof null) // "object" ``` Of course, `null` is not an object. But JavaScript says it is. This behavior comes from an old implementation detail in the early days of the language. And now it cannot be fixed because too much old code depends on it. That is one of the recurring themes in JavaScript: > Some things are not fixed because the web must not break. So we live with this forever. If you need to check for `null`, do not use `typeof`. Use direct comparison: ```js const value = null console.log(value === null) // true ``` It is boring. It is explicit. It works. And in JavaScript, boring and explicit is often the best strategy. --- ## `NaN` Is Not Equal to Itself Another little monster: ```js console.log(NaN === NaN) // false ``` At first glance, this looks completely insane. Even worse: ```js console.log(typeof NaN) // "number" ``` So `NaN` means “Not a Number”, but its type is `"number"`. Welcome to JavaScript. Actually, this also comes from floating-point rules. `NaN` represents an invalid numeric result, and according to the standard, it is not equal to anything, including itself. So this does not work: ```js const value = NaN if (value === NaN) { console.log("This will never run") } ``` Use `Number.isNaN()` instead: ```js console.log(Number.isNaN(NaN)) // true console.log(Number.isNaN("hello")) // false ``` Be careful with the old global `isNaN()` function, because it performs coercion: ```js console.log(isNaN("hello")) // true console.log(Number.isNaN("hello")) // false ``` `Number.isNaN()` is stricter and usually what you actually want. --- ## The Problem With `==` JavaScript has two equality operators: ```text == === ``` The first one is loose equality. The second one is strict equality. Loose equality tries to convert values before comparing them. That is how you get this: ```js console.log(0 == false) // true console.log("" == false) // true console.log("5" == 5) // true console.log(null == undefined) // true ``` Sometimes this feels convenient. Most of the time it is just a bug waiting for its moment. Strict equality does not perform type conversion: ```js console.log(0 === false) // false console.log("" === false) // false console.log("5" === 5) // false console.log(null === undefined) // false ``` My default rule is simple: Use `===`. Almost always. There is one common pattern where `==` is sometimes used intentionally: ```js if (value == null) { // catches both null and undefined } ``` This checks for both `null` and `undefined`. But if you are working in a team, or writing code you want to be extremely clear, I would rather write: ```js if (value === null || value === undefined) { // clear and explicit } ``` Yes, it is longer. But future you will understand it immediately. And future you is the person you should be writing code for. --- ## Arrays, Objects, and the `+` Operator The `+` operator in JavaScript has two jobs. It can add numbers: ```js 1 + 2 // 3 ``` And it can concatenate strings: ```js "hello" + " world" // "hello world" ``` The problem starts when you give it arrays or objects. ```js console.log([] + []) // "" console.log([] + {}) // "[object Object]" ``` This is not magic. JavaScript tries to convert both sides into primitive values. An empty array becomes an empty string: ```js String([]) // "" ``` An object becomes this beautiful thing: ```js String({}) // "[object Object]" ``` So this: ```js [] + {} ``` becomes roughly this: ```js "" + "[object Object]" ``` Result: ```js "[object Object]" ``` You can go very deep into this rabbit hole. There are entire memes about JavaScript coercion. But the practical lesson is simple: Do not rely on implicit conversion when your values are not simple primitives. Write what you mean. Instead of this: ```js const result = items + "" ``` Write this: ```js const result = items.join(", ") ``` Or this: ```js const result = String(value) ``` Explicit code is less funny in screenshots, but much better in production. --- ## `var` Is Not Your Friend Before `let` and `const`, JavaScript had `var`. And `var` has one big problem: it is function-scoped, not block-scoped. Example: ```js if (true) { var name = "Ravy" } console.log(name) // "Ravy" ``` That variable escaped from the block. With `let`, this would fail: ```js if (true) { let name = "Ravy" } console.log(name) // ReferenceError ``` This is how most modern developers expect variables to behave. `var` also creates confusing behavior with loops and closures. Classic example: ```js for (var i = 0; i < 3; i++) { setTimeout(() => { console.log(i) }, 100) } ``` You might expect: ```js 0 1 2 ``` But you get: ```js 3 3 3 ``` Why? Because `var` creates one shared `i` for the whole loop. By the time the callbacks run, the loop has already finished. With `let`, each iteration gets its own variable: ```js for (let i = 0; i < 3; i++) { setTimeout(() => { console.log(i) }, 100) } ``` Now the result is: ```js 0 1 2 ``` This is why my rule is very simple: Use `const` by default. Use `let` when you need reassignment. Do not use `var` unless you have a very specific reason. And most of the time, you do not. --- ## Hoisting: When Code Runs Before It Looks Like It Should JavaScript hoists declarations. With `var`, this means the variable declaration is moved to the top of the scope, but the value is not. ```js console.log(value) // undefined var value = 10 ``` JavaScript treats this roughly like: ```js var value console.log(value) // undefined value = 10 ``` That is already confusing. But with `let` and `const`, the behavior is different: ```js console.log(value) // ReferenceError let value = 10 ``` The variable exists, but it is in the so-called temporal dead zone until the declaration line is reached. You do not need to build your whole life around this term. Just remember the practical rule: Declare variables before using them. It is not a “junior” habit. It is just clean code. --- ## `this` Is Not Where the Function Lives `this` in JavaScript is one of those topics that can make even experienced developers tired. The main idea: `this` depends on how a function is called, not where it is written. Example: ```js const user = { name: "Ravy", sayHi() { console.log(this.name) } } user.sayHi() // "Ravy" ``` Looks good. But now: ```js const sayHi = user.sayHi sayHi() // undefined ``` We took the method out of the object. Now it is just a function call, not `user.sayHi()`. So `this` is lost. This happens a lot when passing methods as callbacks. You can fix it with `bind`: ```js const sayHi = user.sayHi.bind(user) sayHi() // "Ravy" ``` Or with a wrapper: ```js const sayHi = () => user.sayHi() sayHi() // "Ravy" ``` The trap gets even more interesting with arrow functions. Arrow functions do not have their own `this`. So this is usually a bad idea: ```js const user = { name: "Ravy", sayHi: () => { console.log(this.name) } } user.sayHi() // undefined ``` If you need `this` inside an object method, use a regular method: ```js const user = { name: "Ravy", sayHi() { console.log(this.name) } } ``` Arrow functions are great. Just not everywhere. --- ## Objects Are Passed by Reference This one creates bugs that look like ghosts. ```js const a = { count: 1 } const b = a b.count = 2 console.log(a.count) // 2 ``` At first, it feels like `b` should be a copy. But it is not. Both variables point to the same object. Same thing with arrays: ```js const first = [1, 2, 3] const second = first second.push(4) console.log(first) // [1, 2, 3, 4] ``` This becomes especially painful in UI development, state management, Redux-like patterns, Vue, React, or anywhere else where you expect data changes to be predictable. A shallow copy helps: ```js const original = { count: 1 } const copy = { ...original } copy.count = 2 console.log(original.count) // 1 ``` For arrays: ```js const original = [1, 2, 3] const copy = [...original] copy.push(4) console.log(original) // [1, 2, 3] ``` But there is another trap. Shallow copy only copies the first level. ```js const user = { name: "Ravy", settings: { theme: "dark" } } const copy = { ...user } copy.settings.theme = "light" console.log(user.settings.theme) // "light" ``` The top-level object was copied. The nested `settings` object was not. For deep cloning, modern JavaScript has `structuredClone()`: ```js const copy = structuredClone(user) ``` But even here, you need to understand your data. Functions, class instances, special objects — all of this can require special handling. The real lesson: When you copy an object, always ask yourself: > Did I copy the object, or did I copy a reference? This question saves a lot of debugging time. --- ## `map(parseInt)` Is Evil and Beautiful This is one of my favorite JavaScript traps because it looks so clean. ```js ["10", "10", "10"].map(parseInt) ``` You might expect: ```js [10, 10, 10] ``` But JavaScript gives you: ```js [10, NaN, 2] ``` Why? Because `map` passes three arguments into the callback: ```js (value, index, array) ``` And `parseInt` accepts two arguments: ```js parseInt(value, radix) ``` So this: ```js ["10", "10", "10"].map(parseInt) ``` actually becomes: ```js parseInt("10", 0) // 10 parseInt("10", 1) // NaN parseInt("10", 2) // 2 ``` It is technically correct. And completely not what you wanted. Write this instead: ```js ["10", "10", "10"].map(value => parseInt(value, 10)) ``` Or: ```js ["10", "10", "10"].map(Number) ``` This is a perfect example of a JavaScript problem where every piece works correctly in isolation, but together they create chaos. --- ## `async/await` Does Not Automatically Make Things Parallel `async/await` makes asynchronous code much easier to read. But it also makes it easy to accidentally write slow code. Example: ```js const user = await fetchUser() const posts = await fetchPosts() const comments = await fetchComments() ``` This runs sequentially. First, JavaScript waits for the user. Then it waits for posts. Then it waits for comments. If these requests do not depend on each other, this is wasted time. Better: ```js const [user, posts, comments] = await Promise.all([ fetchUser(), fetchPosts(), fetchComments() ]) ``` Now they run in parallel. But there is another detail. `Promise.all()` fails fast. If one promise rejects, the whole thing rejects. Sometimes that is what you want. Sometimes you want to collect all results, even failed ones: ```js const results = await Promise.allSettled([ fetchUser(), fetchPosts(), fetchComments() ]) ``` The trap here is not syntax. The trap is thinking that pretty asynchronous code is automatically efficient asynchronous code. It is not. You still need to think about execution flow. --- ## `try/catch` Does Not Catch Promises Unless You Await Them This works: ```js try { await loadData() } catch (error) { console.error(error) } ``` This may not: ```js try { loadData() } catch (error) { console.error(error) } ``` If `loadData()` returns a rejected promise and you do not `await` it, your `try/catch` will not catch the error. Because the error happens later, asynchronously. Correct: ```js try { await loadData() } catch (error) { console.error(error) } ``` Or: ```js loadData().catch(console.error) ``` This bug is especially annoying because the code visually looks protected. But it is not. It is like putting an umbrella next to yourself during rain and wondering why you are wet. --- ## JSON Is Not a Universal Clone Tool A lot of developers have used this trick at some point: ```js const copy = JSON.parse(JSON.stringify(data)) ``` It looks like a quick deep clone. And sometimes it works. Until it does not. ```js const data = { date: new Date(), value: undefined, method: () => {}, nan: NaN, infinity: Infinity } console.log(JSON.stringify(data)) ``` Result: ```json { "date": "2026-05-11T00:00:00.000Z", "nan": null, "infinity": null } ``` What happened? The `Date` became a string. `undefined` disappeared. The function disappeared. `NaN` became `null`. `Infinity` became `null`. JSON is not a clone system. JSON is a data format. It is great when your data is actually JSON-compatible. But if your object contains special values, methods, dates, maps, sets, or class instances, JSON will quietly destroy information. Use `structuredClone()` when it fits: ```js const copy = structuredClone(data) ``` But again, understand what you are cloning. Blind cloning is just another way to create bugs with confidence. --- ## Dates Are a Separate Kind of Pain JavaScript dates deserve their own article. But one trap is worth mentioning here. ```js new Date("2026-05-11") ``` This looks harmless. But depending on timezone behavior, you can easily end up with a different local date than expected. Another dangerous format: ```js new Date("05/11/2026") ``` Is that May 11? Or November 5? Depends on expectations, environment, and format. The safer habit is to use clear ISO strings: ```js new Date("2026-05-11T00:00:00Z") ``` And for serious timezone logic, use proper tools. Date and time bugs are never “small bugs”. They become calendar bugs, billing bugs, analytics bugs, reminder bugs, booking bugs — the kind of bugs that make users lose trust. --- ## Optional Chaining Can Hide Real Problems Optional chaining is one of the best modern JavaScript features. ```js const city = user?.profile?.address?.city ``` It is clean. It prevents crashes. It is useful. But it can also hide bugs. Example: ```js const price = product?.details?.price ``` If `details` is genuinely optional, fine. But if `details` must always exist, then optional chaining hides a backend problem and quietly gives you `undefined`. Sometimes you want graceful fallback. Sometimes you want the app to scream immediately because something is broken. For required data, I prefer explicit validation: ```js if (!product.details) { throw new Error("Product details are missing") } ``` Use optional chaining for optional data. Not as a blanket carpet to cover broken assumptions. --- ## `const` Does Not Mean Immutable This one is simple but important. ```js const user = { name: "Ravy" } user.name = "Alex" console.log(user.name) // "Alex" ``` This is allowed. `const` means you cannot reassign the variable: ```js user = {} // TypeError ``` But the object itself can still be changed. If you want to prevent changes, there is `Object.freeze()`: ```js const user = Object.freeze({ name: "Ravy" }) user.name = "Alex" console.log(user.name) // "Ravy" ``` But even this is shallow. Nested objects can still be mutable unless you freeze them too. So `const` is not a magic shield. It protects the binding, not the value inside. --- ## The Real Lesson It is easy to make fun of JavaScript. And honestly, sometimes JavaScript deserves it. But after writing enough code, I do not think the main problem is that JavaScript is “bad”. The real problem is that JavaScript looks simpler than it is. - It lets you start quickly. - It lets you build something fast. - It forgives many things. - It converts types for you. - It hides complexity behind friendly syntax. And then, when your project grows, all those hidden rules start showing up. This is why I think JavaScript traps are worth learning. - Not to feel smarter than other developers. - Not to post weird console screenshots. But to build a mental map of the language. Because once you understand these traps, JavaScript becomes much more predictable. - You stop being surprised by `NaN`. - You stop trusting implicit coercion. - You stop using `var`. - You stop cloning everything with JSON. - You stop thinking `await` means “parallel”. - You stop assuming `this` means what it means in other languages. And your code becomes calmer. Maybe that is the best compliment code can get. - Not clever. - Not magical. Just calm, predictable, and boring in the right places. JavaScript is not a cursed language. But it definitely has traps. And it is better to know where they are before stepping into them. --- # Start v IT: ваш надёжный проводник от новичка до профессионала URL: https://ravy.pro/blogs/start-v-it-your-path-to-it · Published: 2025-06-27 · Tags: dev · Author: Andrei Rovnyi > Вы когда-нибудь мечтали о карьере в IT, но не знали, с чего начать? Я — Андрей Ровный, с 15-летним опытом разработки и управления командами в крупных компаниях и стартапах — прошёл этот путь сам и решил создать сервис, который берёт за руку каждого новичка и проводит вплоть до долгожданного оффера. ## Почему я запустил Start v IT За годы в индустрии я видел сотни талантливых ребят, которые останавливались на пороге собеседования из-за нехватки фокуса и правильно выстроенной стратегии. Широкие курсы часто слишком поверхностны, а частные наставники не всегда доводят дело до результата. Я хотел создать **прозрачную услугу**, где человек платит **только после того, как получит оффер**, и только **20 % от своей новой зарплаты в течение 6 месяцев** — гарантируя честность и искреннюю заинтересованность в успехе каждого. [Узнать подробнее!](https://start-v-it.ru/) Англоязычная версия услуги — на странице [Mentorship & job placement in IT](https://ravy.pro/services/mentorship). *** ## Для кого этот сервис * **Новички**, которые только слышали о JavaScript, Python или DevOps, но не знают, с чего начать. * **Джуниоры**, уже сделавшие первые шаги в коде, но не прошедшие серию интервью на Middle. * **Мидлы**, желающие перейти на новый уровень: получить оффер в крупной компании или за рубежом. * **Люди на перекрёстке карьер**, готовые сменить профессию и вложить силы в IT-путь. Если вы хотите системного, чёткого сопровождения от первого резюме до подтверждённого оффера — этот сервис для вас. *** ## Преимущества Start v IT 1. **Индивидуальный план “под ключ”** Никаких шаблонных дорожных карт. После вашей заявки мы встречаемся онлайн, анализируем опыт и сразу формируем персональную программу: от базовых навыков до подготовки к самым сложным техническим вопросам. 2. **Гибкая модель оплаты** – **0 ₽ авансом** – **20 % от новой зарплаты**, выплачиваемых равными частями в течение полугода – **Ничего не платите**, если не получите оффер 3. **Мои связи и рекомендации** После подготовки я лично рекомендую вас своим контактам в IT-компаниях — от стартапов до гигантов рынка — и помогаю договориться о собеседованиях. 4. **Скорость результата** Медиана по моим ученикам — около **10 недель** до первого оффера, но разброс большой и зависит от стартового уровня. Гарантированного срока я не обещаю: честную оценку по вашей ситуации даю на первом созвоне. 5. **Сопровождение до первого рабочего дня** Мы не бросаем вас после подписания контракта: я помогаю пройти испытательный срок и влиться в коллектив. *** ## Истории успеха Имена изменены по просьбе учеников, названия компаний не раскрываются. Сроки индивидуальны и зависят от стартового уровня. **Анна** > Раньше я работала менеджером, но без IT-опыта даже тестовое задание казалось горой. За два месяца с Андреем я освоила React, подтянула алгоритмы и получила оффер фронтенд-разработчика. **Дмитрий** > Не мог пройти интервью на Middle. Андрей разобрал мои слабые места, отрепетировал технические и HR-вопросы — и я стал Middle Backend Developer. **Елена** > В 35 лет я решилась на IT-путь. С нуля до оффера Data Analyst — и всё это без авансов, только после результата. *** ## Как начать 1. **Оставляете заявку** на сайте [Start v IT.](https://start-v-it.ru/) 2. **Созваниваемся**: обсуждаем вашу ситуацию и цели. 3. **Получаете персональный план** обучения и подготовки. 4. **Проходите собеседования** — я веду вас и рекомендую компании. 5. **Подписываете оффер** и приступаете к новой работе. *** ## Готовы изменить свою жизнь? [**Заполните форму** ](https://start-v-it.ru/)на сайте и получите бесплатную консультацию уже сегодня! --- # How I Started Creating Music with AI — And Found My Voice as Zynthar and Diva Rogue URL: https://ravy.pro/blogs/how-i-started-making-music-with-ai · Published: 2025-06-04 · Tags: music, zynthar, diva-rogue, ai · Author: Andrei Rovnyi > How Suno and AI music generation took me from idea to released tracks under two project identities — Zynthar (heavy, raw) and Diva Rogue — and what I learned producing a sound universe solo. ## 🎸 How I Started Making Music with AI — And Why I Can’t Stop Now At the end of 2024, I stumbled upon a startup called [Suno](https://suno.com/) — and something just clicked. Suddenly, I realized: I can create the kind of music *I* want to listen to. I don’t need permission, I don’t need a label. I just need the will to do it. That was the moment everything came together. ## The First Step — Zynthar ![Zynthar album cover art](https://ravy.pro/media/blog/how-i-started-making-music-with-ai/zynthar-fad454e754.webp){width=1600 height=900} My first track was released under the name **[Zynthar](https://zynthar.rocks/)**. It wasn’t just "some heavy stuff" — it was mine. A raw, emotional, powerful sound, echoing the bands that shaped me as a listener: *Rammstein*, *Linkin Park*, *Korol i Shut*, *Aria*, *Manowar*… Early on, I decided to work like a full-on producer of a music universe. I launched a few concept projects — **Dusty Cassette**, a lo-fi indie trio with a nostalgic vibe, and **Void Tapes**, an anonymous techno act. But they didn’t really resonate with the audience. **[Zynthar](https://zynthar.rocks/)** and **[Diva Rogue](https://divarogue.com/)**? They hit different. People listened. People *felt* something. And I knew: *this is it.* ## Zynthar and Diva Rogue — Two Sides of My Soul ![Zynthar project logo](https://ravy.pro/media/blog/how-i-started-making-music-with-ai/zynthar_logo-447e7694ea.webp){width=2560 height=2560} **[Zynthar](https://zynthar.rocks/)** is the sound of conflict. It’s the embodiment of inner chaos, pain, release, and hope. Screaming into the void with guitars, massive drums, and lyrics pulled from real moments in my life. It’s not music for attention — it’s music for survival. ![Diva Rogue project logo](https://ravy.pro/media/blog/how-i-started-making-music-with-ai/diva_rogue_logo-f175b6fa33.webp){width=2560 height=2560} **[Diva Rogue](https://divarogue.com/)**, on the other hand, is pure vibe. The sound of city nights. Sensual, stylish, confident. You hear her songs and feel like you’re cruising through neon-lit streets or sitting in a candlelit lounge with something on the rocks. It’s sexy, smooth, but still driven. ![Diva Rogue album cover art](https://ravy.pro/media/blog/how-i-started-making-music-with-ai/diva_rogue-6bf6ee1412.webp){width=1600 height=900} ## I’m Not a Musician — I’m a Movement I don’t call myself a “musician” in the traditional sense. I don’t play ten instruments. But I know exactly what I’m doing. In an era of generative AI, I’m creating a **new wave** of music — digital artists who *feel* real, sound real, and connect like humans. What drives me is the process itself. I re-listen to my own tracks — not out of ego, but because they finally feel like something I’ve always wanted to hear. That’s the rush. ## I Want Zynthar in Rock Bars, and Diva Rogue in Every Chill Café I’m not just releasing songs into the void. I want **Zynthar and Diva Rogue to become household names**. I want people to argue over who’s better. I want TikToks made with **[Zynthar](https://zynthar.rocks/)** breakdowns and lo-fi playlists drifting with **[Diva Rogue](https://divarogue.com/)** vocals. I want someone to hear a song and say, “Damn… this is *exactly* how I feel.” *** ## ⚡ Want to Start Too? If you’re reading this and thinking, “Maybe I could try…” — do it. Don’t wait for approval. Music now is freedom. Try. Fail. Learn. Create. Surprise yourself. The world’s waiting. *** ## 🎧 Want to hear the music? Both **Zynthar** and **Diva Rogue** now have their own official websites, where you can explore their worlds and find links to all major streaming platforms: * 🔥 [**Zynthar** — cinematic post-hardcore, raw emotion and heavy riffs](https://zynthar.rocks) * ✨ [**Diva Rogue** — R’n’B elegance, sensual vibes and late-night magic](https://divarogue.com) > Dive in, pick your side — or fall in love with both. 🎵 *Your new favorite artist might just be an AI.* --- # The roadmap for creating and releasing Tiny Boo: Homecoming URL: https://ravy.pro/blogs/roadmap-for-creating-tiny-boo-homecoming · Published: 2025-06-03 · Tags: tiny-boo, games, dev · Author: Andrei Rovnyi > Tiny Boo: Homecoming is a game that will delight players with its story and gameplay. ![Google Play badge](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/google-play-badge-logo-dd04856a80.png){width=512 height=512} [Available in Google Play](https://play.google.com/store/apps/details?id=com.Ravy.TinyBooHomecoming) Mobile gaming is always changing. To make a great game, you need to plan carefully, be creative, and think strategically. "Tiny Boo: Homecoming" is a game that will delight players with its story and gameplay. This article explains how we made "Tiny Boo: Homecoming" from start to finish. ## What is the concept? To make "[Tiny Boo: Homecoming](https://tinyboohomecoming.com)" is about creating a good idea. Tiny Boo is a small magical creature on a quest to return home. The game is made to be cute, magical and adventurous. Defining core gameplay mechanics—like running, jumping, climbing, exploring, interacting with objects and enemies, and turning the world upside down — helped us develop the game. Our general director Andrei, came up with the idea of this game a couple years ago, and managed to create a [demo](https://thegdwc.com/pages/game.php?game_guid=3e224e4f-0dee-4706-ba2b-e432d0f3c3ec), which is absolutely different from the game we have now, except the main mechanic is that the world adapts to Boo and turns upside down with him. So, this is the path we went through while creating Tiny Boo: Homecoming. ![GDWC](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/gdwc-8a57e5ee7f.png "GDWC"){width=200 height=200} [Look us in The GDWC.com](https://thegdwc.com/pages/game.php?game_guid=3e224e4f-0dee-4706-ba2b-e432d0f3c3ec) ## Market Research Knowing who your competitors are is important. We studied successful mobile games to learn from them. Knowing your target audience is very important, and we did research on what people like in mobile gaming and tried our best to create a game that will allow them to fully enjoy their adventure with Boo on his journey. This research helps us to design and make sure "[Tiny Boo: Homecoming](https://tinyboohomecoming.com)" is popular with its target audience. ## Project Planning A project plan is needed to manage the development process. Our plan includes all the tasks, bugs, issues and ideas that we can track and work with. Our team that works on the game consists of a pretty small quantity of people, but we are all interested and enthusiastic, and because of this we managed to create Tiny Boo. We have our Lead manager Andrei, he is our main developer, our director, and is very good at solving any issues that keep appearing on our game development journey. Andrei is the one who created the idea of Tiny Boo and made a demo of a game, which got the award for small game developers. You can see how different the game was on the demo and right now on the screenshots below: ## Early game dev stages: ![Early Tiny Boo demo screenshot](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_2-5414e6a84f.webp){width=720 height=454} ![Early prototype gameplay screenshot](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_3-cd61b3d089.webp){width=1999 height=955} ## Current game: ![Current Tiny Boo gameplay screenshot](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_4-bbfd6b1e43.webp){width=1280 height=741} ![Current game level screenshot](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_5-08a30aaa4c.webp){width=1280 height=706} Our Art director [Kalpa](https://t.me/kalpapridemail), painted amazing and cute sprites of Boo himself, all the environment and enemies. She managed to create a fully harmonic and magical art vision for our game. On the pictures below you can see different concepts of Tiny Boo she worked on: ![Tiny Boo character concept art](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_6-0577a10a19.webp){width=1280 height=741} ![Boo design concept variations](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_7-2180ba1260.webp){width=1999 height=1500} Good planning keeps the project on track. We used different task trackers and methods to make sure all our processes are worked on and are progressing. Mostly we used Trello, for tracking any issues, bugs etc. Also, it allowed us to create different folders that were corresponding for different types of tasks, like Sounds, Design, Bugs and issues, Development etc. Alexis is a project manager in our team, she works on keeping all the tasks progressing, level design, creating interesting and engaging articles about our game development process, sound design, and generally any issues and tasks that might appear on the process. ## Development Andrei worked hard on creating "[Tiny Boo: Homecoming](https://tinyboohomecoming.com)", he did almost everything that involved coding and programming process, worked with Unity engine, developed animations, fixed bugs and issues that appeared,he basically managed to create a full working Beta build for Tiny Boo, which is now ready for release. The right game engine, like Unity, is key to efficient development. Programming the game mechanics, character controls, level transitions, and UI elements makes the gameplay experience cohesive and responsive. ![Tiny Boo development in Unity](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_8-11568162c4.webp){width=1208 height=1043} Even with Andrei big experience in game development we still experienced some issues with implementing some in game mechanics like Authorization. He tried different approaches, did research but we couldn’t fix these issues ourselves. That was when we went on the outsource and found really nice people, who helped us to implement the features that we needed, and we were back on our way of development. ## Sound design Sound design was a pretty challenging task for our team, as we didn’t have any person who was involved in this sphere. We did some research, looked for different options but still were struggling. Alexis worked with many different AI music generators, platforms that offer different melodies, but it still was an issue. We couldn’t find a source which could fulfill our needs for creating amazing, magical melodies to accompany Tiny Boo on his adventurous journey. That’s when we found [Suno](https://suno.com). Suno is also an AI music generator, but the melodies it created were more alive, and fit our concept way better. After some work, and fixing issues we managed to create beautiful melodies with [Suno](https://suno.com), which helps our game to maintain its atmosphere. ![Creating game music with Suno](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_9-f978159da1.webp){width=1651 height=881} ## Art and Visuals Visuals are important in platformer games. Tiny Boo's world is drawn into players with detailed backgrounds and environments. An easy-to-use user interface makes it easy for players to navigate the game and enjoy their adventure. Our artist [Kalpa](https://t.me/kalpapridemail), worked hard to make the environment look magical and inspiring, making sure not to miss any details. ## Testing Alpha testing is done by the development team. Which in our case is Alexis and Andrei. This phase finds and fixes bugs and makes sure the game works. Alpha testing allows for ongoing improvements. Beta testing lets you get feedback on gameplay, controls, and the user experience. ## Pre-Launch Marketing is key to a successful game launch. Engaging with players on social media builds a community around Tiny Boo. Alexis worked on creating a [presentation](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/tiny_boo_presentation-be7da57af0.pdf) of the game, to seek help in promoting it from other sources, and that was how we found amazing people who will help us to release the game and help us with promotion. You can check out some slides from Tiny Boo: Homecoming presentation below: ![Tiny Boo presentation slide](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_10-0c91158ae1.webp){width=1920 height=1080} ![Presentation slide with game features](https://ravy.pro/media/blog/roadmap-for-creating-tiny-boo-homecoming/image_11-a4dd62bb06.webp){width=1920 height=1080} Also, to submit an app, you need screenshots, descriptions, and icons. Alexis made all the design for game stores like: App Store and Google Play. A smooth submission process leads to a successful launch. We polished and rechecked all our game mechanics, fixed bugs, added some new animations to be sure we are ready for releasing the game. ## Release Submitting Tiny Boo. Launching "Homecoming" on major app stores is a big deal. A virtual launch event can get people excited and get them to download and review your app. We plan on monitoring user reviews, ratings, and analytics after launch. Fixing problems after launch with updates and patches makes players happier and keeps them playing. Listening to users is the best way to keep a game successful. ## Conclusion How we made and released "[Tiny Boo: Homecoming](https://tinyboohomecoming.com)" is a very long and interesting story, but here we are. Releasing a game requires careful planning, creativity, and adaptability. A roadmap helps developers navigate game development and create a captivating platformer. With a great story, fun gameplay, and smart marketing, "Tiny Boo: "Homecoming" should become a popular mobile game. Thank you for being with us! Game created by [XPLOIT Games](https://xploit.ltd). --- # IDLED Survival Game Engine: How It Works URL: https://ravy.pro/blogs/idled-survival-game-engine · Published: 2025-06-02 · Tags: idled, games · Author: Andrei Rovnyi > A look under the hood of the custom TypeScript + Vue 3 game engine powering IDLED Survival — rendering, collisions, event handling, and what scales well versus what doesn't. ## The IDLED Survival Game Engine: How It Works Creating a custom game engine is both a challenge and an opportunity to have full control over the development process. For [IDLED Survival](https://t.me/idled_survival), I decided to build a custom engine to bring my vision to life. Here, I'll explain how the engine is structured, the problems it solves, where it excels, and where there is room for improvement. ## Core Components of the Engine The [IDLED Survival](https://t.me/idled_survival) game engine was built from scratch using TypeScript and Vue 3 for the interface. Here are the key components of the engine: 1. **Rendering System** The engine processes the visualization of game objects through custom algorithms optimized for browsers and mobile devices. The primary goal is to ensure stable performance, even with a large number of objects on the screen. 2. **Collision System** I implemented a custom algorithm for handling collisions between characters, enemies, and objects by checking hitbox overlaps. This algorithm is not only high-performing but also easily scalable. 3. **Event Processing** The event system handles interactions between game elements. For example, it triggers animations during collisions, applies buffs, or deals damage. All events are sequenced and processed in strict order to prevent bugs. 4. **State Management** By integrating Pinia (a Vuex alternative), I implemented centralized state management. This makes it easy to track player progress, active buffs, and enemy parameters. 5. **Shaders and Animations** The engine uses custom shaders to create visual effects such as hit flashes or glows around buffs. Animations are also handled by the engine, ensuring their synchronization with game events. ## Problems the Engine Solves 1. **Performance Optimization** One of the engine’s main tasks is maintaining stable performance across all devices. This is achieved through multithreaded calculations, simplified shaders, and adaptive rendering. For example, secondary effects are disabled on lower-end devices. 2. **Flexibility and Scalability** The engine easily adapts to new mechanics. For instance, adding new enemies or buffs doesn’t require significant code changes since the architecture was designed to be modular from the start. 3. **Integration with External Services** Beyond the game itself, the engine handles interactions with a Telegram bot using Node.js and Telegraf. This enables players to receive notifications, share progress, and participate in polls. ## Advantages 1. **Full Control** A custom engine gives me the freedom to make changes at any time without being constrained by the limitations of third-party solutions. 2. **High Performance** With tailored solutions, I minimized delays, even in the later stages of the game. 3. **Modularity** Each part of the engine — rendering, event processing, collisions — is an independent module that can be improved and expanded. ## Disadvantages 1. **Time-Consuming Development** Building an engine from scratch requires significant time investment. Most of the game’s development time was spent on this. 2. **Complex Maintenance** A custom engine demands a deep understanding of the entire architecture, making it harder to onboard new developers. ## Unique Features One of the key features is the flexibility of the event system. For example, players can receive random buffs that are applied instantly or enhance their character through activatable cards. The engine manages these processes through a unified queue, preventing conflicts. The collision system is also unique. It supports dynamic hitbox adjustments based on character or enemy animations, making gameplay more realistic. ## Scalability Thanks to its modular architecture, the engine scales easily. For example, I plan to add a cooperative mode, and the engine is already prepared for integrating network capabilities. There is also room for creating new game modes without overhauling existing code. ## Conclusion The IDLED Survival game engine has been a crucial part of the project’s success. It combines high performance, flexibility, and scalability. Despite the challenges of development and maintenance, the custom engine gave me the freedom to bring bold ideas to life. In the future, I plan to continue improving and adapting it to meet new challenges. Thank you for being with us! Join the IDLED Survival community: [Telegram Group](https://t.me/idled_survival). --- # IDLED Survival - Mobile game URL: https://ravy.pro/blogs/idled-survival · Published: 2025-06-01 · Tags: games, idled · Author: Andrei Rovnyi > How IDLED Survival was built — a mobile Telegram WebApp game on a custom TypeScript and Vue 3 engine, from concept and prototyping to dynamic combat and card-driven progression. ## The Journey of Creating IDLED Survival: Stages, Challenges, and Solutions Creating a game is always a unique adventure. Today, I want to share the story behind the development of [IDLED Survival](https://t.me/idled_survival) — from the first lines of code to the fully realized game world. I'll talk about the stages, the difficulties, and how we overcame them. ## Stage 1: Idea and Concept It all started with a simple yet ambitious idea: to create an engaging game where players feel a sense of progress every step of the way. I aimed to combine dynamic battles with a collection mechanic so that every gaming session would be enjoyable. The core principle of the concept was interaction with the environment and the use of collectible cards. These cards provided not only visual variety but also strategic depth. Thanks to the system of random buffs, each session became unique. This required careful planning and constant testing: how the cards interact with different types of enemies, how the player experiences growth in strength and challenge. In addition to gameplay mechanics, it was important to identify the target audience. We focused on players who enjoy combining dynamic combat with strategy. This direction shaped many aspects of the game's design. ## Stage 2: Prototyping Prototyping was the foundation on which the entire game was built. In the very beginning, I chose JavaScript to quickly create a prototype. This allowed us to promptly test the main game elements: character movement, basic attacks, and interactions with enemies. The first version was minimalist — a simple interface and primitive graphics. The main goal was to check how the game feels in the player's hands. For example, the attack animations and character movement speed were constantly adjusted until we found the perfect balance. Prototyping also highlighted the importance of optimization. Even in the early stages, the game showed performance issues, especially on mobile devices. This made us consider more complex architectural solutions for the next stage. ## Stage 3: Game Design Game design was perhaps the most labor-intensive stage of development. We faced balancing challenges related to creating buffs and power-ups. At this stage, we developed a comprehensive system of game elements, including collectible cards, rare buffs, and unique abilities. Each buff in the game was designed as a unique tool to help the player. However, the challenge was ensuring that no buff became too powerful. We repeatedly adjusted the characteristics and rarity of the cards to achieve the perfect balance. Additional attention was given to the progression system: each session had to deliver tangible rewards while also encouraging purchases through the in-game shop. During this period, analytics became an essential tool. We implemented a tracking system to understand how players use buffs and which gameplay elements needed improvement. This allowed us not only to refine the balance but also to make the game more engaging. ## Stage 4: Visual Style The visual component played a key role in creating [IDLED Survival](https://t.me/idled_survival). We chose a cartoony style with bright colors and dynamic elements. This decision helped make the game appealing to a broad audience, including casual players. For creating characters and monsters, we used Figma and specialized graphic editors. Every design element — from attack animations to buff effects — was developed with user experience in mind. For example, monsters were designed to be easily distinguishable in the chaos of battle, and the interface was made to be intuitive and functional. Special attention was given to adapting graphics for mobile devices. We tested the game on various screens to ensure that elements displayed correctly and retained their readability even on small devices. ## Stage 5: Technical Solutions The technical side of the project was a real challenge. For the game's frontend, we chose Vue 3 and TypeScript, which allowed us to use a modern tech stack and create a scalable architecture. A custom game engine became the foundation for implementing all game mechanics. This solution enabled us to dive deep into optimization and better understand the specifics of working with high-load systems. For instance, we implemented our own algorithms for collision detection and damage calculation to ensure game stability even with a large number of enemies on the screen. A Telegram bot built on Node.js using Telegraf became an important part of community interaction. Through the bot, players could receive notifications, participate in polls, and share their achievements. This helped strengthen our connection with the audience and improve feedback. ## Challenges and Solutions * **Optimization:** Lags in the later stages of the game revealed the need to redesign the architecture. We implemented simplified shaders, reworked animations, and added support for multithreaded computations. This significantly reduced device load. * **Monetization:** Developing a purchasing system required fine-tuning. We found a balance between voluntary investments and the sense of reward for playing. Players can acquire rare buffs and cards through purchases but also have the opportunity to progress without investments. * **Community:** We actively engage with the community through Telegram, conduct polls, and discuss updates. This helps us better understand player expectations and adjust the development of the project. ## Conclusion Developing [IDLED Survival](https://t.me/idled_survival) was a test of our skills and creative approach. We put our best ideas into the game to provide players with a unique experience. Each stage, from the initial concepts to final optimization, became part of this journey. Thank you for being with us! We will continue to develop the project and look forward to your feedback. Join the IDLED Survival community: [Telegram Group](https://t.me/idled_survival). --- # Tabs Broadcast: JS Library URL: https://ravy.pro/blogs/tabs-broadcast · Published: 2025-05-31 · Tags: tabs-broadcast, dev · Author: Andrei Rovnyi > TabsBroadcast is a lightweight, easy-to-use JavaScript library that enables communication between multiple browser tabs. ## About TabsBroadcast is a lightweight, easy-to-use JavaScript library that enables communication between multiple browser tabs and is ideal for managing inter-tab communication via the BroadcastChannel API. It implements a singleton pattern to ensure a single instance and allows for registering, emitting, and handling various types of events across different browser tabs. Ideal for web applications that require synchronized data sharing, this package uses the BroadcastChannel API to efficiently exchange messages across open tabs, enhancing the user experience with real-time updates and seamless coordination. ## Demo You can [see the demo](https://tabs-broadcast.ravy.pro/) ## Tabs priority The library also manages primary and slave tabs, ensuring that only one tab is designated as the primary tab, which can perform certain tasks exclusively. With a simple setup and minimal dependencies, tabs-broadcast offers developers a powerful tool for managing state and interactions across tabs in modern web apps. ## Features * Singleton pattern to ensure a single instance. * Inter-tab communication using the [BroadcastChannel API](https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API). * Primary-Slave tab management. * Event registration and handling. * Emit messages to all tabs or only from the primary tab. * Configurable settings. To see more information on [npmjs.com](https://www.npmjs.com/package/tabs-broadcast/) ## License This project is licensed under the MIT License. See the [LICENSE](https://github.com/Rovniy/tabs-broadcast/blob/master/LICENSE) file for details. --- # Impact of Music in Platformer Mobile Games URL: https://ravy.pro/blogs/impact-of-music-in-platformer-mobile-games · Published: 2025-05-29 · Tags: games, tiny-boo · Author: Andrei Rovnyi > How music and sound shape the feel of platformer mobile games — setting tone, guiding rhythm and timing, and building atmosphere in Tiny Boo: Homecoming. ## The Role of Music in Platformer Mobile Games In the world of mobile gaming, music plays a crucial role in setting the tone, enhancing the experience, and immersing players in the magical worlds of platformer games. The soundtrack of a platformer game is often its unsung hero, from catchy tunes that stick with you to orchestrated masterpieces that elevate the gameplay. Music in platformer mobile games serves as a powerful storyteller, setting the stage for the adventure that awaits. The soundtrack sets the tone and establishes the mood for the player's journey, whether it's a whimsical melody in a lighthearted level or a tense, pulsating beat in a climactic boss battle. ## Setting the Tone: Music as a Storyteller In addition to setting the mood, music also enhances the gameplay experience. The rhythm and tempo of a track can synchronize perfectly with the pace of the game, guiding players through levels with precise timing for jumps and maneuvers. A well-crafted soundtrack can even provide cues for upcoming obstacles or hidden secrets, adding an extra layer of depth to the gameplay. Additionally, memorable moments in platformer mobile games are often accompanied by equally memorable music, which can have a significant emotional impact on players. Music in video games has a powerful emotional impact. Iconic themes and catchy melodies are a key part of this experience, from the triumphant fanfare that plays when a level is completed to the melancholic melody that accompanies a character's moment of reflection. It can evoke a range of emotions, from joy and excitement to nostalgia and sadness, making the gaming experience truly immersive. The vocabulary used is simple and accessible to a broad, general audience, including those with cognitive disabilities, low reading literacy, or who are encountering an unknown topic or language. The content of the improved text is as close as possible to the source text, and no new aspects have been added. ## Iconic Themes and Cultural Influence Platformer mobile games have produced iconic themes and catchy melodies that have become ingrained in gaming culture. Examples of such melodies include the infectious tune of 'Green Hill Zone' from Sonic the Hedgehog and the classic 'Overworld Theme' from Super Mario Bros. Keeping the sentences short and straightforward, and using active voice, the text flows logically and is free from grammatical errors, spelling mistakes, and punctuation errors. These timeless melodies not only enhance the gameplay but also create a sense of nostalgia for players, drawing them back to the games time and time again. With advancements in technology, platformer mobile games now feature adaptive and interactive soundtracks that respond to players' actions. Dynamic music systems seamlessly transition between different tracks based on the player's progress, creating a more immersive and personalized experience. Certain games enable players to interact with the music directly. Actions trigger changes in the soundtrack, adding a new layer of interactivity to the gameplay. --- # The Mobile Gaming Revolution URL: https://ravy.pro/blogs/the-mobile-gaming-revolution · Published: 2025-05-27 · Tags: games, tiny-boo · Author: Andrei Rovnyi > Mobile gaming has transformed the way people interact with digital entertainment. Mobile gaming has transformed the way people interact with digital entertainment. Smartphones and tablets have turned every pocket into a potential gaming console, giving rise to a multi-billion-dollar industry that captivates audiences worldwide. The inception of mobile gaming can be traced back to the early 2000s, with the introduction of games like Snake on Nokia phones. The landscape was truly revolutionized by the advent of smartphones. In 2008, Apple launched its App Store, and in 2012, Google introduced [Google Play](https://play.google.com). These platforms provided developers with a global audience for their games. And nowadays we are given a possibility to fulfill our desires by creating games accessible to almost every person on the planet! Our project Tiny Boo: Homecoming is a great example of how a group of enthusiastic people, leaded by ambitions and creativity are able to create an interesting game from scratch, that anyone can play. Its mechanics are friendly to people that have no significant experience in gaming, and are easy to understand. Tiny Boo will be released both on App Store and Google Play so any smartphone user will be able to dive into an adventure filled with magic and exploring a beautiful world. ## Accessibility Mobile gaming's success is due to its accessibility. Unlike traditional consoles or PCs, which require a significant investment, nearly everyone now has a smartphone. This democratization of gaming has opened doors for diverse demographics, transcending age, gender, and socioeconomic boundaries. Mobile games' simplicity attracts both seasoned gamers and newcomers. They are easily approachable for individuals with varying levels of gaming experience due to their intuitive touch controls and short gaming sessions. Mobile gaming has come a long way from basic puzzles and casual games. The app stores offer a wide variety of genres, including action, adventure, strategy, simulation, and role-playing games. Developers are constantly pushing the limits, exploring augmented reality ([AR](https://en.wikipedia.org/wiki/Augmented_reality)), virtual reality ([VR](https://en.wikipedia.org/wiki/Virtual_reality)), and innovative gameplay mechanics. The use of advanced technology, such as augmented reality in games like Pokémon GO, demonstrates the vast potential within the mobile gaming industry. Keeping up with innovation not only retains current players but also draws in new audiences looking for unique gaming experiences. Mobile gaming has evolved from a solitary experience to a social phenomenon. Multiplayer games and real-time connections with friends have transformed gaming into a shared activity. Games like [Fortnite](https://www.fortnite.com/) and [PUBG Mobile](https://www.pubgmobile.com) have become virtual arenas where players from around the world can compete and collaborate, fostering a global gaming community. The industry has a diverse monetization landscape, with various models such as free-to-play, freemium, and premium games. Developers generate revenue through in-app purchases, ads, and subscription services. This flexibility in payment models allows players to choose their preferred gaming experience, catering to a wide range of preferences. ## Dominating Mobile gaming is a dominant force in the entertainment industry, providing millions worldwide with accessible, diverse genres, social connectivity, and constant innovation. Its impact has reshaped the way we perceive and engage with digital games. As technology advances, mobile gaming will remain at the forefront of the gaming landscape, captivating audiences and pushing the boundaries of interactive entertainment. --- # Account Deletion for 'Tiny Boo: Homecoming' URL: https://ravy.pro/blogs/account-deletion-for-tiny-boo · Published: 2025-05-25 · Tags: policy, tiny-boo · Author: Andrei Rovnyi > How to delete your Tiny Boo: Homecoming account: email XPLOIT support with your player ID, what data is removed, and what may be retained for legal reasons. Welcome to the user support page for the "Tiny Boo: Homecoming" app, developed by XPLOIT. Our goal is to provide transparency and control over your data. ## How to Request Account Deletion If you decide to delete your account in the "Tiny Boo: Homecoming" app, please follow these simple steps: 1. **Write an Email**: Send an email to [games@xploit.ltd](mailto:games@xploit.ltd) with the subject line "Account Deletion Request". 2. **Provide Your Details**: In the email, include your user identifier in the game for verification purposes. 3. **Wait for Confirmation**: After submitting your request, our team will process it and send you a confirmation of account deletion. ## Data to be Deleted When your account is deleted in "Tiny Boo: Homecoming", the following data will be removed: * **User Identifier**: This is your unique ID in the game. * **Linked Account Information**: Any accounts linked to your game profile. * **Player Progress Information**: All data related to your progress in the game, including levels, scores, and achievements. ## Data Retention Policy Please note that some data might be retained for legal or regulatory reasons. This includes records of transactions or interactions for a certain period as required by law. However, this data will not be used for operational purposes once your account is deleted. For further inquiries or assistance, feel free to contact our support team at [games@xploit.ltd](mailto:games@xploit.ltd) Thank you for playing "Tiny Boo: Homecoming". We're sorry to see you go but respect your decision and are committed to handling your data with care and respect. --- # Inside the development process URL: https://ravy.pro/blogs/inside-the-development-process · Published: 2025-05-23 · Tags: tiny-boo, games · Author: Andrei Rovnyi > Creating and launching a fun platformer game for mobile devices requires not only creativity but also careful planning. Tiny Boo: Homecoming, our new mobile platformer game, is preparing to make its debut on Google Play and the App Store. Get ready to be amazed! This article goes behind the scenes of the game development process and explains the steps involved in publishing this exciting game. ## The Birth of Tiny Boo Before we get into the details of publishing, let's take a quick look at how Tiny Boo: Homecoming was developed. Our team created this game to offer an exciting and visually impressive experience, blending entertaining gameplay with charming visuals. Tiny Boo journeys through difficult levels, facing obstacles and enemies on a quest to return home. ## Game Development and Testing Creating a successful mobile game requires careful planning and execution. Our development team spent many hours designing exciting game levels and perfecting the controls to provide an engaging gaming experience in Tiny Boo: Homecoming. Rigorous testing played a crucial role, ironing out any glitches, optimizing performance, and refining gameplay mechanics. ## Launch As the game approaches completion, the focus shifts to an essential phase of preparing for launch. This involves developing promotional materials, such as fascinating trailers, attractive screenshots, and an engaging game description. Creating a captivating story around Tiny Boo's adventure can lure potential players and generate eagerness for the game's release. ## Setting up Developer Accounts To release a mobile game on Google Play or the App Store, developers must first create accounts on these platforms. This involves providing required information, agreeing to terms and conditions, and, in some cases, paying a one-time registration fee. Once the accounts are established, developers will have access to the necessary tools and interfaces for submitting and managing their games. ## Submission Process With development, testing, and promotion completed, the next task is to submit Tiny Boo: Homecoming to Google Play and the App Store. Each platform has its submission guidelines and review process. This usually involves a detailed assessment of the game's content, features, and adherence to platform policies. A successful submission will bring the game one step closer to being available to eager players worldwide. ## Publishing Publishing a mobile game like Tiny Boo: Homecoming requires creativity, technical skills, and strategic planning. The journey from the concept to the launch is challenging and exciting. As players worldwide join the adventure with Tiny Boo, we are proud to bring their vision to life and add to the constantly evolving world of mobile gaming. --- # Tiny Boo: Exploring game mechanics URL: https://ravy.pro/blogs/tiny-boo-exploring-game-mechanics · Published: 2025-05-21 · Tags: tiny-boo, games · Author: Andrei Rovnyi > Mobile gaming has evolved significantly, attracting players worldwide with various genres. One long-standing genre that still captivates players is platformers. ## About Mobile gaming has changed a lot lately and has attracted players worldwide with its diverse range of genres. Platformers are one genre that has been around for a long time and still captivates players. These games challenge players to guide a character through levels filled with hurdles, enemies, and puzzles. In this article, we’ll give a short summary of the mechanics of our game, “Tiny Boo.” Homecoming is a platformer game we are currently developing. It combines traditional elements with inventive gameplay to provide a unique experience. Before we discuss the mechanics of Tiny Boo: Homecoming, let’s review the basic principles that form the foundation of platformer games. ## Features 1. In platformer games, players control a character who can run, jump, and perform various actions. Success in these games depends on precise character control. 2. Platformer levels are made up of platforms, ladders, and various obstacles that players must traverse. They need to leap over pits, avoid enemies, and solve puzzles to progress. 3. Players collect power-ups to gain new abilities and items that can help them progress through levels. Furthermore, players can gather power-ups and other items like coins, health boosts, and weapons to aid their advancement in the game. Numerous platformer games showcase items that enhance a player’s abilities, grant extra health, or unlock special skills. 4. Moreover, as players progress, the challenges amplify, introducing new obstacles that demand advanced skills and strategic thinking to conquer. ## What is that “Tiny Boo: Homecoming” is a mobile game that brings new ideas to the platformer style, while also keeping the elements of nostalgia that fans of the genre appreciate. Some of the game’s notable mechanics include the central feature, which is based on our idea of creating a game where the world reacts to the character, instead of the character having to conform to the world. This means that when Boo reaches the end of a platform, he won’t just fall off, as you might expect. But we changed the usual design, causing the world to flip over with obstacles, terrain, etc. to prevent Boo from falling! Check out the demo below. ## Screenshots As Boo heads home, he will encounter numerous challenges, puzzles to solve, and fascinating enemies with intriguing mechanics. For instance, while traveling, Boo encounters a living plant that blocks his path, preventing him from proceeding. This plant must be fed so it can sleep, and we can continue our adventure. This is just a preview of the game mechanics we are building – some are finalized and some we are still working on. Nonetheless, we guarantee that if you crave puzzles, challenges, and an amazing story, then you will love Tiny Boo: Homecoming. --- # Development Blog #3 URL: https://ravy.pro/blogs/tiny-boo-dev-blog-3 · Published: 2025-05-17 · Tags: tiny-boo, games · Author: Andrei Rovnyi > When designing a game, creating a captivating environment is just as important as developing engaging gameplay mechanics. ## What happening? When designing a game, creating a captivating environment is just as important as developing engaging gameplay mechanics. One key element in building an immersive game world is the background. Multi-layered backgrounds are particularly effective in creating depth and adding visual interest to a game. The environment and background play a huge role in our game. That is why we wondered how to make the picture lively and pleasing to the eye, so that it would be interesting to look at the details on the background, monitor its changes, keep an eye on the little things that form the overall image of the background. So we came up with the idea of creating multi-layered backgrounds, the so-called parallax backgrounds, which consist of several layers and move relative to each other at different speeds, creating a depth effect. Creating multi-layered backgrounds in the game is an important part of the development process, which allows you to create a deep and interesting game world. Multi-layered backgrounds consist of several layers that move in different directions at different speeds, creating the illusion of depth and movement. The process of creating multi-layered backgrounds begins with defining the concept and style of the game. It is necessary to understand which elements will be present in the game world and how they will interact with each other. For example, if the game takes place in a forest, then the backgrounds may include trees, shrubs, rocks, rivers and the sky. ## Next step The next step is to create elements for each background layer. This can include drawing textures, creating 3D object models, and animations. To achieve optimal results, it is necessary to make sure that each layer corresponds to a certain depth and moves at the correct speed. ## Layers Then you need to determine the order of the layers. Usually there is a sky or horizon in the background, followed by a more distant layer with trees, and then closer elements such as shrubs and rocks. This order of layers creates the illusion of depth and movement. Next, you need to configure the movement of each layer. The back layers should move more slowly than the front ones to create the effect of moving in depth. Some layers may also have their own animations, such as floating clouds in the background. Finally, you need to adjust the size and proportions of the background to match the size of the game screen. You should also make sure that each layer corresponds to a specific format, for example, PNG or JPEG. ## Orientation Another feature worth considering is the orientation of the screen. We decided that the game will only work in the horizontal position of the screen (landscape mode) and this also imposes restrictions on the active areas of the background. The entire background is never displayed on the screen, so we use the mechanics of the “cross” in order for the desired background fragments to fit on the screen at any orientation. At the same time, the main details of the background, all the little things and important features of the background should fit inside this cross. Creating multi-layered backgrounds is a creative process that requires a lot of trial and error. However, with the right approach, multi-layered backgrounds can significantly improve the visual aspect of the game and make it more attractive to players --- # Development Blog #2 URL: https://ravy.pro/blogs/tiny-boo-dev-blog-2 · Published: 2025-05-16 · Tags: tiny-boo, games · Author: Andrei Rovnyi > Hello, friends! Today we continue to talk about the development of our mobile game about Boo. ## What happening? In the [last issue](https://ravy.pro/blogs/tiny-boo-dev-blog-1), we talked about how we successfully published the app on [Google Play](https://play.google.com/store/apps/details?id=com.Ravy.TinyBooHomecoming), implemented all the game mechanics, made 80% of all game content and introduced our team. This week we received developer status from Apple to host our app! This is the next step on the way to release! Today we want to talk about one of the most important aspects of game development – user experience (UX). In the world of mobile games, UX plays a huge role, since it depends on how convenient and interesting it will be for the user to play. ## UX features To begin with, we want to share a few UX features for mobile games: * **Simplicity** and intuitiveness – A mobile game should be easy to learn and intuitive for the player. * **Visibility** – the player must understand what is happening on the screen and how to interact with objects. * **Adaptability** – The UX must be adapted to different devices and screens. * **Accessibility** – The game should be accessible to all users, including people with disabilities. ## Problems The first problem that had to be solved was the scale of the camera’s view for the player. Since a lot of the space surrounding the player should be visible on the screen, so that there is an understanding of where to go and what you can interact with. The solution was obvious. We made a game that works only in portrait mode. The player will not be able to change the orientation of the display and he will not be able to limit his view. As a result – all conceived mechanics will be in the palm of your hand! The second problem is embedding interactive windows into the interface in order to organize interaction with the user at the stage level without changing the screen and quickly returning to the gameplay. To do this, we have made a system of modal windows that open on top of the content and are easily closed by simply clicking past the window or on the cross in the corner of the screen. Now about the difficulties we faced in the process of developing UX for our game. One of the main problems was to create an interface that would not clutter up the screen and prevent the player from immersing himself in the gameplay. We also faced the problem of choosing a suitable color scheme that would not only be attractive, but also comfortable for the eyes. Despite these difficulties, we have successfully implemented UX for our game and received a lot of positive feedback from users. Our team of UX designers continues to work on improving the user experience and creating new interesting features for players. ## Many thanks Thank you for your attention and follow our future releases, where we will continue to talk about everything related to the development of our game! --- # Development blog #1 URL: https://ravy.pro/blogs/tiny-boo-dev-blog-1 · Published: 2025-05-15 · Tags: tiny-boo, games · Author: Andrei Rovnyi > First Tiny Boo developer blog: publishing on Google Play, the world-rotation mechanic, reaching 80% of game content, and meeting the five-person team behind it. ## What happening? Hello and welcome to our section “Developer’s Blog”, where we will tell you how things are going with the development of the game, what the team is doing and what plans for the near future. Boo and his stories are 80% ready. The plot has been written, all the game mechanics have been made, which we will describe in detail in the next issues, we are working hard on the level design and the main line of the narrative. We are pleased to announce that our application has been successfully published on Google Play. It’s been a long and intense journey, but we’ve finally reached this sweet moment. The implementation of all the game mechanics was a complex and exciting process, but our team worked hard to create a unique gaming experience that includes the rotation of the whole world around the character. We think it will be very interesting for our players. We are also pleased to announce that we have made 80% of all game content and are continuing to work on the rest. We want players to be able to enjoy a variety of levels and experience different challenges while playing. ## Team Our team consists of five talented people, including three illustrators, one UX designer and one developer. We work very closely to make sure that every aspect of the game reflects our values and our passion for the gaming industry. A team of three illustrators is working hard to create a game image of a beautiful, finished and fabulous atmosphere of the game. Special attention is paid to details that don’t even catch the eye and are difficult to notice, but when you realize what is in front of you, you are surprised how well the atmosphere of the forest and nature is conveyed. The whole environment is constantly changing from level to level, tightly intersecting with the plot and reflecting the mood of the character, his well-being and fighting spirit! It is the indescribable fabulous atmosphere of the game that will make the passage of this story unforgettable! We hope that our players will appreciate our work and enjoy the game as much as we enjoy creating it. ## What next? Next time we will reveal to you the secrets of the plot and tell you why it was Boo who had the burden to put everything in its place.