Asset CloudedStudio/LevelProto2dMetroidvania URP Editor + Runtime

Level Proto 2D Metroidvania

A Scene View–integrated toolkit for rapidly blocking out 2D metroidvania levels with editable polygon shapes, grid-aware movement feedback, area labels, and data-driven PNG/JSON export — no hand-placed cube sprites required.

Introduction

Overview

Level Proto replaces the usual "resize a bunch of white cubes" blockout workflow with a single component, ProtoShape2D, that you draw and edit directly in the Scene View — arbitrary polygons, not just boxes — plus a runtime grid material so flat areas still give you a sense of scale and movement while playtesting.

Draw & edit freely

Click to draw new shapes, drag vertices and edges, insert or delete points, extrude new sections from an edge — all with full Undo.

Stay aligned

Grid snapping and axis-angle snapping keep edges level unless you intend a slope, backed by a numbered Scene View ruler.

Feel the scale

A hand-written URP shader draws a major/minor grid with ruler-style tick marks in world space, visible in Play Mode and builds.

Export the data

Render the whole prototype to PNG (grid included, no camera capture) or dump it to JSON for another tool's pipeline.

Getting Started

Installation

This asset is distributed as a plain Assets-folder package, following the Unity Asset Store's required layout — everything lives under a single folder named after the asset, not under Packages/.

  1. Import the .unitypackage (or copy this folder) into your project — it installs under Assets/CloudedStudio/LevelProto2dMetroidvania.
  2. Confirm your project uses Universal Render Pipeline (both the standard Universal Renderer and the 2D Renderer are supported by the runtime grid shader).
  3. Confirm the Input System package is installed (required by Proto Player's PlayerInput component).
Dependencies

Only com.unity.render-pipelines.universal and com.unity.modules.physics2d are required — no Shader Graph, no third-party packages.

Getting Started

Demo Scene

Open Demo/Level Proto 2D - Material Showcase.unity for a self-contained, playable tour of the asset. It compares Proto Grid, Cavern Stone, and Mossy Ruins side by side using real Proto Shapes rather than screenshots.

Representative geometry

Inspect floors, floating platforms, slopes, masonry steps, decorative backgrounds, Proto Shape Groups, and Proto Labels.

Playable traversal

Enter Play Mode, move with A/D or the arrow keys, and jump with Space using the configured Proto Player.

Build Settings

The demo scene is intentionally not added to Build Settings automatically. Add it only when you want to create a standalone demo build.

Getting Started

Quick Start

  1. Create a shape Use GameObject > 2D Object > Proto Shape for a default quad, or select the Draw Proto Shape tool in the Scene View toolbar and click out a custom outline (click the first point again, or press Enter, to close it).
  2. Shape it With the shape selected, drag any vertex or edge directly in the Scene View. Click an edge (without dragging) to insert a new point there; hover a vertex and press Delete to remove it.
  3. Grow it Switch the Inspector's Scene View Edit Mode to Extrude Edge, then drag an edge outward to push out a new section. Hold Shift to drag freely instead of snapping to the edge normal.
  4. Mark areas Add GameObject > 2D Object > Proto Label for callouts like "Boss Arena" — it's a normal Transform, so the built-in Move tool repositions it.
  5. Export Use Tools > Level Proto > Export PNG or Export JSON to hand the whole prototype off — to an artist, a design doc, or another tool.
Core Concepts

Proto Shape 2D

ProtoShape2D is a local-space polygon: a list of Vector2 vertices that drives a generated Mesh (filled with Fill Color) and, optionally, a matching PolygonCollider2D. It auto-adds MeshFilter/MeshRenderer and manages its own mesh lifecycle — you never need to touch those directly.

Inspector fields
FieldTypeDescription
Fill ColorColorPer-shape base color, applied via a MaterialPropertyBlock so shapes can share one material instance.
OutlineboolExplicitly enables the boundary outline for any bundled Visual Style.
Outline / ColorColorOutline color and opacity. Defaults to solid black.
Outline / ThicknessfloatHow far the outline extends inward, in local units.
Inner ShadowboolEnables an inward shadow along every boundary edge for any bundled Visual Style.
Inner Shadow / ColorColorShadow color and opacity.
Inner Shadow / Blend ModeenumMultiply (default), Normal, Additive, or Screen.
Inner Shadow / Choke0–1Controls how much of the shadow remains solid before fading.
Inner Shadow / SizefloatHow far the shadow extends inward, in local units.
Generate ColliderboolToggles a PolygonCollider2D matching the current vertices. Turned off for purely visual/marker shapes.
Sorting OrderintPassed straight through to the MeshRenderer.
TagsstringFree-form text, not used by the package itself - carried straight through to JSON export for downstream tooling/integrations.
Remove Redundant Vertices

Removes any vertex that sits exactly on the straight line between its two neighbors - e.g. a stray point left in the middle of an otherwise straight edge from a mid-edge insert or an extrude - since it doesn't actually change the outline. Real corners are always kept, and the shape never drops below 3 vertices.

Self-intersecting shapes

If a shape's edges cross themselves, the outline turns red in the Scene View and the Inspector shows a warning with a Fix Automatically button. It tries a gentle fix first — un-crossing the outline by repeatedly reversing the vertex run between a crossing edge pair (the same move used in 2-opt route optimization), keeping every vertex's exact position. If that can't resolve it, it falls back to a fix that's guaranteed to work: dropping near-duplicate points and reordering the rest by angle around their centroid — this can reshape the outline more noticeably, but never fails and never moves a surviving vertex. Either way it's a single Undo step, so Ctrl+Z reverts cleanly if the result isn't what you wanted. The mesh and collider simply keep showing their last valid state until the outline is simple again — triangulation never produces a broken mesh mid-edit.

Core Concepts

Scene View Editing

Selecting a ProtoShape2D turns on interactive editing directly in the Scene View — the same interaction model Unity's own PolygonCollider2D and SpriteShapeController editors use.

ActionResult
Drag a vertexMoves that single vertex.
Click a vertexKeeps it selected and opens a draggable Vertex Inspector in the Scene View for numeric local-position editing, previous/next navigation, and removal.
Change Tangent modeLinear is the default and has no handles. Continuous creates a smooth Bezier corner with aligned handles; Broken makes incoming and outgoing handles independent.
Drag an edgeMoves both its vertices together, preserving the edge.
Click an edge (no drag)Inserts a new vertex at the clicked point.
Double-click a vertex, select it + Delete, or use the Vertex InspectorRemoves that vertex (shapes never drop below 3 points).

Curves are tessellated into the same evaluated outline used by the generated mesh, collider, procedural material boundary, and PNG export. JSON format version 4 preserves the original control points, tangent modes, tangent offsets, outline settings, and inner-shadow settings.

Every operation is a full Undo step. Interactive Scene View dragging works on a single selected shape at a time — with multiple shapes selected, shared fields (color, collider toggle, etc.) still multi-edit normally in the Inspector, just not vertex dragging.

Swapping modes on the fly

Hold Alt while clicking a vertex or edge to temporarily use the other Scene View Edit Mode for that one click — extrude without leaving Edit Vertices, or edit a vertex without leaving Extrude Edge — mirroring how Ctrl temporarily bypasses snapping. If Alt is held over empty space (nothing to act on), the click falls through so Alt-drag still orbits the Scene View camera as usual.

Core Concepts

Extrude Edge Mode

Toggle Extrude Edge in the Inspector's Scene View Edit Mode selector to grow a shape from one of its edges — useful for pushing out a corridor or ledge without redrawing the whole outline.

  • Click-drag an edge outward; two new vertices are inserted and dragged along the edge's outward normal.
  • Hold Shift to drag freely instead of snapping to the normal direction.
  • Releasing without crossing the drag threshold cancels cleanly — no zero-area sliver gets left behind.
  • Hold Alt while clicking a vertex to edit it instead, without leaving Extrude Edge mode — see Scene View Editing.
Core Concepts

Snapping

Two independent snapping systems, both on by default and toggleable from the Inspector while a shape is selected:

  • Grid Snap — snaps dragged vertices and edges to the current Grid Size in Unity's Scene View Grid and Snap overlay.
  • Angle Snap — if an edge to a neighboring vertex is within a few degrees of horizontal/vertical, it's forced perfectly level, so you don't get accidental micro-slopes.

The two combine as: angle-snap first (straight edges win), then grid-snap the result. Hold Ctrl while dragging to temporarily disable both.

Core Concepts

Grid Ruler (Edit-Time)

While editing, a numbered grid overlay is drawn on Unity's current Scene View grid, using the same size, origin, and rotation as snapping. When zoomed out, it skips cells by whole-number multiples so it stays readable without ever drifting off-grid. This is purely an editing aid; it doesn't render at runtime. Toggle it from the same Inspector panel as the snapping options.

Core Concepts

Runtime Visual Materials

Flat, uniformly colored platforms make it hard to feel the camera or character moving. ProtoGridUnlit.shader solves that with a two-tier grid and ruler-style tick marks, rendered in Play Mode and in builds — not just in the Editor.

Major / minor grid

A coarse grid (your configured cell size) subdivided by a finer one, both computed from world-space position so adjacent shapes' grids line up seamlessly, like continuous graph paper.

Ruler ticks

Wherever a minor gridline meets one of a shape's own (near) horizontal or vertical edges, it's drawn bolder — like a tick mark on a ruler. Diagonal edges intentionally get none, to avoid visual clutter.

Works with both the standard Universal Renderer and URP's 2D Renderer — the shader ships two passes (UniversalForward and Universal2D) so it renders correctly either way. Per-shape fill color and the shape's own edge list (used for tick placement) are pushed per-instance via MaterialPropertyBlock; every shape otherwise shares one material instance.

Tuning the look

Select any ProtoShape2D, open its Mesh Renderer material in the Inspector, and adjust cell sizes, line thickness, colors, and tick length live — see the Material Properties reference below.

Solid

A simple texture-free fill driven only by each shape's Fill Color, ideal for clean blockouts and flat-color level art.

Cavern Stone

Texture-free layered rock with surface grain and irregular procedural cracks, useful for cave walls and natural platforms.

Mossy Ruins

Offset masonry blocks with chipped edges and moss patches, useful for temples, dungeons, and overgrown architecture.

Use Visual Style in the ProtoShape2D Inspector to switch among Proto Grid, Solid, Cavern Stone, and Mossy Ruins. Every bundled style supports the Universal2D and UniversalForward passes, uses each shape's Fill Color, and exposes shared Outline and Inner Shadow groups. Outline has an explicit checkbox, solid-black default color, and Thickness. Inner Shadow has Color, Blend Mode (Multiply by default), Choke, and Size. Both follow the real polygon boundary and are stored per shape. A Custom material manages its own effects and does not receive these bundled controls.

Core Concepts

Proto Label 2D

ProtoLabel2D is a lightweight text marker for naming areas ("Water Temple Entrance", "Boss Arena"). It has no runtime visual — it's an authoring/export-only concern, visible as Scene View text (whether or not its GameObject is selected) and included in PNG/JSON exports.

FieldTypeDescription
TextstringThe label's content.
ColorColorText color in the Scene View and in PNG exports.
World Font SizefloatWorld-unit size. In the Scene View this is converted to an actual screen pixel size from the current zoom (so it visibly grows/shrinks with the value and scales with zoom, like any world-space object); on export it's multiplied by the export's Pixels Per Unit.
AlignmentTextAnchorAnchors the text against the label's own transform position.

Position is just the GameObject's transform, so the standard Move tool (and its built-in Undo) repositions it — no custom Scene View dragging needed. Drawing uses Unity's [DrawGizmo] attribute rather than a custom Editor's OnSceneGUI, specifically so labels stay visible whether or not their GameObject is selected.

Core Concepts

Proto Player

A minimal, movement-only 2D character so you can actually walk your blockout and feel whether traversal works, not just look at it. GameObject > 2D Object > Proto Player creates one fully-configured GameObject — no prefab asset, no setup. It's a simplified port of a fuller character controller (combat, combos, health, dash, animation state machines) with everything except walking and jumping stripped out.

Walk

CharacterMovement — an acceleration/deceleration curve, snapping to a minimum starting speed, and an air-control penalty that PlayerJump applies while airborne.

Jump

PlayerJump — buffered jump input (a press just before landing still registers), coyote time (a press just after leaving a ledge still registers), and jump cutting (tap vs. hold Space gives a shorter vs. full jump).

Ground detection

CharacterGroundChecker — Physics2D contact-based, with dynamic friction enabled by default. Newly created Proto Players use the bundled PlayerAirborne.physicsMaterial2D and PlayerGrounded.physicsMaterial2D assets so the character doesn't "stick" to walls and ledges.

Input

CharacterInputController + a bundled ProtoPlayerInputActions asset (Move + Jump only, WASD/arrows/gamepad stick + Space/gamepad South) — self-contained, doesn't depend on your project's own Input Actions setup.

Facing direction

CharacterSpriteFlipper — flips the SpriteRenderer horizontally to face the current movement direction, driven by CharacterMovement.OnDirectionChanged rather than polling every frame.

No animation, no combat, no health — the sprite renderer just shows a fixed placeholder sprite, flipped to face left/right as you move. Ground detection defaults to the Default physics layer, matching where ProtoShape2D objects already live, so it works immediately against your blockout with no Layer/Tag setup.

Tuning it

Every tunable (move speed, acceleration, jump force, jump buffer window, air control, ground friction) is a normal serialized field on the respective component — select the Proto Player and adjust them in the Inspector like any other component.

Core Concepts

Proto Shape Group

ProtoShapeGroup is a purely organizational marker component (GameObject > 2D Object > Proto Shape Group) — parent a set of ProtoShape2D/ProtoLabel2D objects under it in the Hierarchy, and its Inspector (styled to match ProtoShape2D's, with the same banner header and collapsible sections) shows a Group Contents section reporting how many it found, plus an Export This Group section with its own Export PNG... / Export JSON... buttons.

These open the exact same export windows as Tools > Level Proto > Export PNG/JSON — same options, same code — just pre-scoped to that group's own hierarchy instead of the whole active scene. Useful for exporting one room/section of a larger level on its own, without touching everything else in the scene.

Scoping

"Under this group" means GetComponentsInChildren from the group's own GameObject — direct children, grandchildren, any depth, as long as they're parented somewhere underneath it in the Hierarchy. It does not do anything at runtime; it's authoring-only.

Exporting

PNG Export

Tools > Level Proto > Export PNG rasterizes every ProtoShape2D/ProtoLabel2D in the active scene straight from their data — vertex lists and text, not a camera screenshot — sized by a configurable Pixels Per Unit.

OptionDescription
Pixels Per UnitScale factor from world units to output pixels. Defaults from Project Settings.
Transparent BackgroundOff switches to a solid background color instead.
Include LabelsBakes every ProtoLabel2D's text into the export.
Include Grid PatternBakes each shape's major/minor grid and ruler ticks into the export, matching what the material shows in-Editor, instead of a flat fill.
Font (optional)Override font for label text; otherwise a built-in fallback is used automatically.

The output size is estimated live before you export, and very large images (beyond 8192px on an axis) prompt for confirmation before allocating memory.

How the fill works

Polygons are filled with a CPU scanline algorithm (even-odd rule) directly from world-space vertices — correct for concave shapes and free of the seams a per-triangle rasterization could show at shared mesh edges. Grid/tick shading, when enabled, is a hand-ported match of the runtime shader's math, sampled per output pixel.

Exporting

JSON Export

Tools > Level Proto > Export JSON dumps the prototype's raw data — local-space vertices plus each shape's full transform, so a consumer can reconstruct exact world-space geometry rather than working from a flattened approximation.

Schema

{
  "formatVersion": 4,
  "sceneName": "SampleScene",
  "exportedAtUtc": "2026-08-02T14:03:11.0000000Z",
  "shapes": [
    {
      "name": "Proto Shape",
      "position": { "x": 0, "y": 0, "z": 0 },
      "rotation": { "x": 0, "y": 0, "z": 0, "w": 1 },
      "scale":    { "x": 1, "y": 1, "z": 1 },
      "localVertices": [
        { "x": -1, "y": -1 },
        { "x":  1, "y": -1 },
        { "x":  1, "y":  1 },
        { "x": -1, "y":  1 }
      ],
      "fillColor": { "r": 1, "g": 1, "b": 1, "a": 1 },
      "outlineEnabled": false,
      "outlineColor": { "r": 0, "g": 0, "b": 0, "a": 1 },
      "outlineWidth": 0.06,
      "innerShadowEnabled": false,
      "innerShadowColor": { "r": 0, "g": 0, "b": 0, "a": 0.5 },
      "innerShadowBlendMode": "Multiply",
      "innerShadowChoke": 0.15,
      "innerShadowSize": 0.2,
      "generateCollider": true,
      "sortingOrder": 0,
      "tags": "ground,walkable"
    }
  ],
  "labels": [
    {
      "name": "Proto Label",
      "position": { "x": 4, "y": 1.5, "z": 0 },
      "text": "Boss Arena",
      "color": { "r": 1, "g": 1, "b": 1, "a": 1 },
      "worldFontSize": 1.0,
      "alignment": "MiddleCenter"
    }
  ]
}

Colors are linear 0–1 float components (not 0–255). alignment is the TextAnchor enum name as a string. tags is whatever free text you typed into the shape's Tags field - the package doesn't parse or use it, it's purely a hook for your own JSON-consuming tooling (e.g. a comma-separated list, a category name, a pipe-delimited key set - your call). The window shows a live count of shapes/labels found before you export, plus a Pretty Print toggle for human-readable vs. compact output.

Reference

Project Settings

Shared defaults live in a ProtoShapeSettings asset, lazily created the first time it's needed at Assets/Settings/ProtoLevelSettings.asset.

SettingDefaultUsed by
Default Export Pixels Per Unit32Initial value in the PNG export window.
Default Fill ColorWhiteReserved for future shape defaults.
Snap Angle Tolerance Degrees5°How close to horizontal/vertical an edge must be to angle-snap.
Grid Ruler ColorWhite, 35% alphaEdit-time Scene View ruler lines/labels.
Color palettes

A ProtoColorPalette ScriptableObject type is also available (Create > Level Proto > Proto Color Palette) for defining named swatches like Platform/Wall/Hazard/Water. It's not yet wired into the Inspector as a quick-pick UI in this version — assign colors via the normal Fill Color field for now.

Reference

Material Properties — Proto Grid Unlit

All exposed on the material Inspector for Level Proto/Proto Grid Unlit. Sizes/lengths are in world units.

PropertyDefaultDescription
_BaseColorWhiteSet per-shape from Fill Color; not usually edited on the material directly.
_MajorLineColorBlack, 35%Coarse grid line color.
_MajorCellSize1Spacing between major gridlines.
_MajorLineThickness0.025Half-width of major lines.
_MinorLineColorBlack, 12%Fine subdivision grid line color.
_MinorCellSize0.25Spacing between minor gridlines (4 per major cell by default).
_MinorLineThickness0.01Half-width of minor lines.
_TickColorBlack, 50%Ruler tick mark color.
_TickThickness0.018Half-width of tick marks.
_TickLength0.15How far from each qualifying edge tick marks extend.

Per-shape, non-Inspector properties set automatically via MaterialPropertyBlock: _EdgeA / _EdgeB (the shape's local-space edge list, capped at 64 edges) and _EdgeCount — these drive ruler-tick placement and aren't meant to be hand-edited.

Bundled visual styles

Level Proto/Proto Solid uses only _BaseColor. Level Proto/Proto Cavern Stone exposes stone palette, texture/strata scale, crack scale/width, and surface-detail controls. Level Proto/Proto Mossy Ruins exposes block and mortar sizes, stone/moss palettes, surface scale, moss scale, and moss coverage. Along with Proto Grid, all four receive per-shape Fill Color, Outline, Inner Shadow, and evaluated boundary data through a MaterialPropertyBlock.

Reference

Package Architecture

Namespace cloudedstudio.LevelProto2dMetroidvania (Runtime), with editor-only types nested under cloudedstudio.LevelProto2dMetroidvania.Editor. Split into two assemblies so nothing editor-only leaks into player builds.

Assets/CloudedStudio/LevelProto2dMetroidvania/
├── Runtime/            ProtoShape2D, ProtoLabel2D, geometry (triangulator,
│                        polygon utilities), the grid shader
│   └── Player/          Proto Player's components, bundled sprite and
│                        Input Actions asset
├── Editor/              Scene View editors/tools, snapping, grid ruler,
│                        PNG/JSON exporters, project settings
└── Tests/Editor/        EditMode unit tests (triangulator, rasterizer,
                          polygon utilities)
Reference

Known Limitations

  • Interactive Scene View vertex/edge dragging works on one selected shape at a time; multi-selection still supports shared-field edits (color, collider toggle, etc.).
  • The grid shader's edge list (used for ruler ticks) is capped at 64 edges per shape — beyond that, extra edges simply don't get tick marks; the grid pattern itself is unaffected.
  • Ruler ticks only appear on edges within roughly 2° of horizontal or vertical, by design — diagonal edges show the grid pattern but no ticks, to avoid visual clutter where vertical and horizontal ticks would otherwise overlap.
  • Text rendering (Scene View labels and PNG export) uses Unity's legacy Font glyph API, whose built-in resource name has changed across Unity versions. The package falls back automatically (LegacyRuntime.ttf → Arial.ttf → an OS font by name) — worth a quick visual check after exporting with labels on a new Unity version.
  • Self-intersecting polygons are detected and flagged, not auto-corrected; fix the outline to resume normal mesh/collider updates.
  • Proto Player has no animation - it's deliberately just a movement/jump rig for playtesting traversal, not a character template. It does flip to face its movement direction (CharacterSpriteFlipper); untick "Default Faces Right" on that component if your sprite's source artwork faces left instead. Ground detection defaults to the Default physics layer; if your blockout uses other layers for ground, update CharacterGroundChecker's Ground Layer field.