Status
SteamPeaks
ChartsSalesUpcomingPatchesNewsCalculator
New on SteamEvery app, DLC and depot the minute Steam creates itAppsEvery app on Steam, newest change firstPackagesSubs and bundles, and what each containsDepotsDepots, manifests and install sizesTagsSteam's user tags and the games under themDevelopers & publishersCompanies and their cataloguesTechnologiesEngines, SDKs and anti-cheat found in the filesChange historyEvery PICS changelist as it lands
SignalsNineteen readings of the whole catalogueCompareAny games side by sideRecordsAll-time peaks and the days they were setReportsWeekly and monthly write-upsAlerts & newsroomWatch a game, get told when it movesSteam statusIs Steam up, right nowWeb API explorerTry the endpoints in the browser
NewsSteam's own announcements and the sales calendarCalculatorWhat a Steam account is worth, and its pile of shame
/
Sign in
/
SteamPeaks
The ultimate resource for Steam data.
ExploreChartsSalesSales and festsUpcomingPatchesNewsRecordsTrendingSignals
DatabaseAppsPackagesDepotsTagsDevelopersTechnologiesChange history
ToolsCalculatorCompareSearchAlertsSteam statusAPI
SiteMethodologyFAQDiscordSupportSign in via Steam
Not affiliated with Valve or Steam. Game names and artwork belong to their owners. All times UTC.
PrivacyCookiesFair useStatus
CottageCoreNewsCottageCore under the hood
Community

CottageCore under the hood

CottageCore · published 1 Oct 2026, 18:11 UTC

All newsPlayers around this dateRead on Steam

I’ve spent the past 12 years working on Babylon.js. CottageCore gives me a chance to use that experience from the other side of the engine: building a game where you can make a cottage, give someone a job, and watch a little village grow.A community member asked how a JavaScript game handles performance. For CottageCore, that starts with how I organize the game, share work between threads, and measure what happens during a frame.At 60 FPS, a frame has roughly 16.7 milliseconds. Small amounts of repeated work can add up quickly.The village and the pictureMost of CottageCore’s game code is TypeScript, which becomes JavaScript when the game is built. Rendering goes through Babylon Lite, using WebGPU. The Steam version wraps the game in Electron, so the web technology runs inside a desktop application.I keep a distinction between what happens in the village and how it looks on screen. A villager’s needs and movement belong to the simulation. Her visible pose belongs to the renderer.Creature simulation runs in a Web Worker, away from the main thread handling the interface and rendering. It advances in fixed time steps. The renderer interpolates between simulation snapshots, filling in the movement between them. The creature logic can keep its own cadence while the screen presents smoother motion.For creature state, I use SharedArrayBuffer. The worker and main thread can access the same block of numbers. Two state buffers and atomic checks coordinate which snapshot is ready to read. This reduces copied state messages; the renderer still copies snapshots into a short history for interpolation.That doesn’t put the whole game in a worker. Building tools, the interface and visual updates such as wind and lighting still have work to do on the main thread.Repeated scenery is another big part of the design. Trees use GPU instancing and GPU culling: placements share a model, with their own transforms and color information. A grove can reuse geometry instead of needing a separately cloned mesh for each tree.Building a frame, one task at a timeBabylon Lite organizes rendering through a frame graph. In the engine, that’s an ordered list of tasks. A task might draw the village, calculate an effect, or copy a result for the next frame. I arrange the order explicitly so each stage has the textures it needs.Here’s the map of the game’s rendering tasks, grouped by what they do. The exact graph depends on quality settings and the features in use. Some tasks stay in the graph but do no work while their effect is inactive.Getting the scene onto the GPU- shadow: renders the shadow maps used to work out where sunlight is blocked.
- ssao-normal: records surface directions and depth for ambient occlusion, which darkens sheltered areas.
- underwater-depth: records terrain and riverbed depth for the water’s shading and refraction.
- scene: draws the village and its environment. Its full-scene color and depth snapshots for water are handled here, separately from the terrain depth above.
- float-cloud-visible: draws the floating clouds in a separate pass after the scene on the postprocessing path. It keeps the scene’s color and depth; on the simpler path, clouds are part of scene.
- scene-depth-resolve: makes multisampled depth readable by later effects when scene MSAA is enabled.Shadows and the light between surfaces- shadow-compute: calculates sunlight visibility for pixels using scene depth and the shadow maps.
- shadow-blend: combines that shadow result with reprojected history to reduce shimmer.
- shadow-copy: saves the stabilized result for later frames. The scene’s materials read this shadow history on the following frame.
- ssao: estimates ambient occlusion from depth and surface directions.
- ssao-blur-h and ssao-blur-v: filter that result horizontally, then vertically, while respecting depth changes.
- ssao-blend: stabilizes the filtered occlusion across frames.
- ssao-copy: keeps its history for the next update.
- contact-shadow: looks for nearby surfaces blocking sunlight, adding small contact shadows.
- contact-shadow-blend: stabilizes those shadows over time.
- contact-shadow-copy: saves their history.
- ssgi: estimates color bleeding from nearby surfaces visible in the scene image, on the Ultra or Custom path.
- ssgi-blend: filters and accumulates that color estimate.
- ssgi-copy: preserves its history.Softening joins between objectsWhen mesh blending is enabled, these tasks help visible surfaces meet more softly:- mesh-blend-tags: records surface identities and depth so the effect can distinguish neighboring objects.
- mesh-blend-visibility: records a matching visibility depth when the scene uses MSAA.
- mesh-blend-visibility-resolve: makes that multisampled visibility depth available to the blending pass.
- mesh-blending: blends color near eligible surface contacts using those identities and depth information.Mist, glow and focus- dof-prebloom: adds the soft glow before depth-of-field processing, so the blur includes the glow too.
- ground-mist-march: samples low ground mist along the camera ray.
- ground-mist-resolve: reconstructs that lower-resolution mist result at screen resolution.
- dof-focus-probe: finds and smooths the focus distance from scene depth.
- dof-focus-history: stores that distance for the next frame.
- dof-coc: calculates how much blur each pixel needs from its distance to the focus plane.
- dof-bg: prepares a blurred background that the main blur can use around occluded areas.
- dof-march: gathers color across the camera aperture to create the depth-of-field blur.Putting the picture on screen- dof-present: combines the sharp and blurred image with the lighting effects. Color grading, the color lookup texture, fog and vignette are handled here rather than needing a separate task for each.
- smaa-present: smooths jagged edges and writes the final image to the screen (when msaa is off).
- selection-mask: draws the selected object’s silhouette when a selection needs highlighting.
- selection-outline: blends its outline over the finished image.The copy tasks may sound unexciting, but keeping history is what lets several effects settle across frames. The expensive part needs measuring too: adding a task means checking what it costs on the GPU, not just whether the image looks better.UI is HTMLThe main menus and dialogs are HTML and CSS, assembled in TypeScript. The wooden frames, icons, scroll areas and buttons are ordinary web elements underneath their game appearance.

Honestly this is the best perk when using web tech. We have such a powerful UI engine at our fingertips.Giving the garbage collector less workJavaScript reclaims unused memory through garbage collection. Creating lots of temporary objects gives that system more work, and can contribute to pauses. For a game, the awkward part is when a pause arrives while you’re dragging a house or moving the camera.In CottageCore’s animal renderer, instance matrices and colors live in typed arrays. Those arrays are allocated when the renderer is created, then their entries are updated as the animals move. Scratch storage is reused too. The scene’s frame phases also share one reusable context object.These are fairly simple choices: keep storage around when you know you’ll need it again, and update the numbers already in it. Typed arrays still allocate memory when you create them. Their value here is that I can reuse a compact block of data.There are still allocations in the game. I try to reduce unnecessary churn in frequently executed code, while keeping occasional work, such as opening a menu, straightforward.Measure, change, measure againMeasurement is part of the work throughout development. I look at frame times during camera and building interactions. An average FPS number can hide a hitch you feel immediately. And a hitch needs investigation: it could be JavaScript work, garbage collection, a graphics upload or shader compilation.Repeatable scenes and camera gestures help me check a change against the same situation. The tools also let me inspect draw calls, rendering passes and worker time. That gives me somewhere concrete to look when performance changes.For example, some house and tower rendering resources are prepared during startup so their pipelines can be compiled before the first visible frame. That tackles a different source of stutter from object allocation.I use a Mac mini for visual and performance checks, alongside the PC and the machines running the test suites. Keeping a smaller machine in the setup gives me another practical check on the cost of what I’m adding. I keep timings tied to the machine and settings used; one result doesn’t stand in for everyone’s hardware.Keeping the game smooth is ongoing work: measure a slow interaction, find what caused it, change that part, and measure it again. It matters most when you’re absorbed in building and the game lets you keep going.And that's pretty much it :)

More from CottageCore

Other announcements

All news
Community9 Oct 2026Russian joins the gladeCottageCore now supports Russian. A big thank you to Arsenii Pecherin for the Russian translation.Community2 Oct 2026CottageCore is also coming to macOS and LinuxGood news if you play on a Mac with Apple Silicon or on Linux! CottageCore is coming to both, alongside Windows, for its Steam release. Shape cottages and towers, welcome your villagers, and prepare your village for winter. The same little glade is coming to all three platforms. Thank you for the kind messages since the announcement. Add CottageCore to your Steam wishlist to follow what comes n…Community29 Sep 2026A new voice in the villageHello everyone! I’m currently working on a new villager for CottageCore: the journalist. From her newsroom, she’ll put together the Gazette, a little newspaper about life in your village. New arrivals, new buildings, changing seasons… and a little village gossip, of course. I want it to be another way to enjoy the stories unfolding in your glade, beyond the things you build. It’s still a work i…