It’s A Good Life Beta (Experiment)
It's A Good Life (Beta) is an experiment in building a complete hand-drawn-to-playable-game pipeline from scratch — pencil to SVG to Blender to Unity, entirely in one session.
The goal was to answer one question: how fast can an artist go from a drawing to something running in a browser? The answer turned out to be one day, with a working character, room, collision, camera follow, animation, music, and atmospheric audio — all sourced from hand-drawn art.
👇 Click each section below for more details.
🎨 The Pipeline — Pencil to Browser
The full chain runs: hand-drawn art → SVG → Blender (automated) → GLB export → Unity → WebGL build.
- SVG authoring: Shapes drawn in vector software with named groups. The parser reads group IDs to know what to build.
- Blender automation: A single Python script (
master_build.py) reads the SVGs and builds the entire 3D scene — room, chair, character billboard — without manual modelling. - GLB export: Three files land in an
export/folder: environment, props, sprites. Scale is 1 Blender unit = 1 Unity unit = 1 metre. - Unity import: GLTFast package handles GLB natively. Drag in, geometry and UVs transfer cleanly.
- WebGL build: Published to Unity Play for browser embedding.
The key design rule: every stage is replaceable. Redraw the SVG, re-run the script, reimport the GLB — the game updates. No manual 3D work, no rebinding.
🎮 Unity — What Was Built
- Character movement: WASD via Unity's New Input System. CharacterController handles collision. Y axis locked — no gravity, no jumping. Top-down diorama rules.
- Camera follow: Fixed offset tracking in LateUpdate. Smooth damp eases the follow so it never snaps.
- Room collision: Auto-generated Box Colliders per wall sourced from Blender face geometry data. Includes an invisible front barrier — the character can't walk out the open front of the diorama.
- Sprite animation: 18 hand-drawn idle frames swap on a timer via
SpriteAnimator.cs. One flat plane, one material slot, texture swap per frame. Paper Mario technique. - Scrolling pixel background: A Quad behind the room with a tiling Aseprite pixel art texture. UV offset increments each frame via
BackgroundScroll.cs. Wrap Mode Repeat makes it seamless. - Atmospheric audio: Background music runs through an Audio Low Pass Filter.
MusicMuffle.csreads the character's Z position and maps it to the filter cutoff — front of room sounds muffled, back wall sounds clear. Like music heard through a wall. - Mood lighting: Single Spot light above the room centre. Warm yellow-orange, low intensity. Dim apartment feel.
📓 What I Learned (Gotchas Log)
- Render Face → Both: Any interior mesh in Unity is invisible by default. Blender normals point inward — Unity culls back faces. Set Render Face to Both on every interior material.
- New Input System vs Old:
Input.GetAxis()throws an error if the New Input System package is active. UseKeyboard.current.wKey.isPressedinstead. - Mesh Colliders on thin walls: CharacterController slides up face normals on thin wall meshes. Box Colliders per wall are more reliable for room interiors.
- Play mode changes don't save: Any Inspector value changed during Play is discarded on Stop. Note values before stopping.
- Inspector lock for bulk frame assignment: Lock the Inspector (padlock icon), select all frames in Project panel, drag onto the array header — Unity fills all slots at once.
- Wrong scene in build: Build Profiles Scene List had the default empty SampleScene instead of the actual game scene. The build loaded a completely blank scene. Always verify the Scene List before building.
- WebGL audio policy: Browsers block audio autoplay until the user interacts with the page. Music won't start until the player clicks.
- AudioReverbZone properties locked by preset: ReverbPreset overrides manually set values at runtime. Switch to User preset and control Room and Reverb properties directly via script.
💻 Scripts Written
- SpriteAnimator.cs — PNG frame swap animation on a mesh plane. Frames array + fps timer.
- CameraFollow.cs — Fixed offset camera follow using SmoothDamp in LateUpdate.
- CharacterMovement.cs — WASD movement via New Input System. Y locked to floor.
- RoomWallColliders.cs — Auto-generates Box Colliders per wall from Blender face data. Includes invisible front barrier.
- ScenePlacement.cs — Code-driven asset positioning on Start. Reproducible layout.
- BackgroundScroll.cs — UV offset scroll on a Quad material. Mathf.Repeat for seamless loop.
- MusicMuffle.cs — Low pass filter cutoff mapped to character Z via InverseLerp. Position-based atmospheric audio.
- CameraSetup.cs — Forces camera clear flags to solid black on Awake. Prevents URP skybox bleed.
🔜 What's Next
- Sprite alpha clipping — remove the black background from the character plane
- Billboard behaviour — character sprite always faces the camera while moving
- Walk animation state — swap to walk cycle frames when WASD is pressed
- Wall and chair materials — PNG textures from the Blender pipeline
- Auto-reimport editor script — detects GLB changes and reimports automatically
- Expand the room — larger environment, additional props