Skip to content

Repository files navigation

PurrUI

A Unity UI framework by the PurrNet team featuring procedural UI rendering, view management, and UI pooling.

imageimage

Features

  • Procedural UI - SDF-based rendering with RectangleGraphic and GlowGraphic (for glow/shadows)
  • Material Icons - Simple to use material icon support for textmeshpro
  • View Management - ViewStack and ViewCollection for managing UI views with transition support
  • Color Palette - Theme your UI from a single asset; ColoredGraphic applies slots to any graphic with smooth transitions
  • Sounds2D - Lightweight 2D audio system with a fluent API for fire-and-forget sound effects

Installation

Unity Package Manager (Git URL)

Latest release:

https://github.com/PurrNet/PurrUI.git?path=Assets/PurrUI#release

Latest development:

https://github.com/PurrNet/PurrUI.git?path=Assets/PurrUI#dev

Procedural UI

imageimage

Material Icons

image
Hello world
<icon=reddit><icon=gamepad_circle><icon=gamepad_variant>
<icon=gamepad_square><icon=keyboard_f1><icon=keyboard_return>

To use Material Icons you simply need to follow the example above <icon=your_icon_name> and you also need to add the MaterialIconProcessor component to your text.

image

This MaterialIconProcessor allows the icons to work but it also gives you a handy little search bar to search for icons so you never get lost.

image

The Copy button will give you something like this directly: <icon=account_alert>.

View System Documentation

PurrUI provides a stack-based view navigation system for Unity. Views are managed through a ViewStack that handles pushing, popping, ordering, visibility, and animated transitions.

All classes live in the PurrNet.UI namespace.

Core Concepts

ClassTypePurpose
ViewStackMonoBehaviourNavigation controller that manages a stack of views
MonoViewMonoBehaviourBase class for all views
ViewCollectionScriptableObjectAsset that holds references to view prefabs
ViewTransitionsStatic classBuilt-in transition animations (fade, slide, etc.)

Setup

1. Create a ViewCollection

Right-click in your Project window and select Create > PurrNet > View Collection.

A ViewCollection is a ScriptableObject that stores references to your view prefabs. It has two modes:

  • Auto Generate (default): Assign folders to watch and the collection automatically discovers all MonoView prefabs inside them. It refreshes whenever assets change.
  • Manual: Disable autoGenerate and drag prefabs into the views array yourself.
image

2. Create View Prefabs

Each view is a prefab with a MonoView (or subclass) component on its root GameObject. MonoView automatically requires a Canvas and CanvasGroup, so those are added for you.

image

3. Add a ViewStack to Your Scene

Add a ViewStack component to a GameObject. In the inspector, configure:

  • Parent: The transform where instantiated views will be parented (defaults to the ViewStack's own transform).
  • Prefabs: Your ViewCollection asset.
  • Push On Start (optional): A view to automatically push when the scene starts.
  • Order Offset: An offset applied to canvas sorting order values.
image

Creating Custom Views

Subclass MonoView to create your own views:

usingPurrNet.UI;usingUnityEngine;publicclassProfileView:MonoView{[SerializeField]privateTMPro.TMP_Text_username;[SerializeField]privateTMPro.TMP_Text_bio;publicvoidSetup(stringusername,stringbio){_username.text=username;_bio.text=bio;}}

The Setup Convention

We follow a convention of adding a Setup method to views that need initialization data. This is not enforced by the base class, it's simply a pattern. The idea is that Setup is called immediately after pushing:

_stack.Push<ProfileView>().Setup("Jane","Hello world!");

All built-in views provided by PurrUI follow this pattern. You are encouraged to do the same for consistency, but it is not required.

Pushing and Popping Views

Pushing

There are two ways to push a view onto the stack:

// Generic push: looks up the prefab by type from the ViewCollectionvarview=_stack.Push<DialogView>();// Direct prefab pushvarview=_stack.Push(someViewPrefab);

When a view is pushed:

  1. The current top view (if any) is moved to the background (raycasts disabled).
  2. The prefab is instantiated under the configured parent transform.
  3. The view is initialized and assigned a sorting order.
  4. If the view defines an enter transition, it plays (raycasts are blocked until it completes).

Popping

// Pop the top view_stack.Pop();// Pop a specific view instance (regardless of position in the stack)_stack.Pop(viewInstance);// From inside a view, call CloseMe() (can be wired to a button in the inspector)CloseMe();

When a view is popped:

  1. If the view defines an exit transition, it plays before the view is destroyed.
  2. The new top view is moved to the foreground (raycasts re-enabled, OnBecomeForeground called).

Other Stack Operations

// Remove all views from the stack (exit transitions play for each)_stack.Clear();// Move an existing view to the top of the stack_stack.MoveToTop(viewInstance);_stack.MoveToTop<DialogView>();

Transitions

Override OnEnterTransition and OnExitTransition in your MonoView subclass to define animated transitions. They return IEnumerator coroutines.

publicclassMyView:MonoView{[SerializeField]privateRectTransform_content;protectedoverrideIEnumeratorOnEnterTransition(){returnViewTransitions.FadeIn(this);}protectedoverrideIEnumeratorOnExitTransition(){returnViewTransitions.FadeOut(this);}}

Built-in Transitions

ViewTransitions provides ready-to-use animations. All use smoothstep easing and unscaled time (unaffected by Time.timeScale). Default duration is 0.2s.

Fade:

ViewTransitions.FadeIn(view,duration)
ViewTransitions.FadeOut(view,duration)ViewTransitions.Fade(canvasGroup,fromAlpha,toAlpha,duration)

Slide:

ViewTransitions.SlideFromLeft(content,duration)
ViewTransitions.SlideToLeft(content,duration)
ViewTransitions.SlideFromRight(content,duration)
ViewTransitions.SlideToRight(content,duration)
ViewTransitions.SlideFromTop(content,duration)
ViewTransitions.SlideToTop(content,duration)
ViewTransitions.SlideFromBottom(content,duration)
ViewTransitions.SlideToBottom(content,duration)

Slide methods operate on a RectTransform (typically a child content container, not the root view), using anchoredPosition and the rect's own width/height to calculate offsets.

Combining Transitions

Use ViewTransitions.Parallel to run multiple transitions at the same time:

protectedoverrideIEnumeratorOnEnterTransition(){varfade=ViewTransitions.FadeIn(this);varslide=ViewTransitions.SlideFromLeft(_content);returnViewTransitions.Parallel(fade,slide);}protectedoverrideIEnumeratorOnExitTransition(){varfade=ViewTransitions.FadeOut(this);varslide=ViewTransitions.SlideToRight(_content);returnViewTransitions.Parallel(fade,slide);}

View Lifecycle & Visibility

  • Sorting Order: Each view in the stack is assigned an incrementing sorting order (plus _orderOffset), so views higher in the stack render on top.
  • Raycasts: Only the top view receives raycasts. Views below the top have raycasts disabled.
  • Cull Windows Behind: If a view has cullWindowsBehind enabled, all views below it in the stack have their Canvas disabled entirely. Useful for fullscreen views where nothing behind them is visible.
  • OnBecomeForeground: Override this virtual method in your MonoView subclass to react when the view returns to the top of the stack (e.g., after the view above it is popped).

Color Palette

A theming system for UI. Define a ColorPalette once, drive any Graphic from it with ColoredGraphic, and cascade the palette down the hierarchy through IPaletteProvider. Changes propagate live, with optional smooth transitions between colors.

ColorPalette

Right-click in your Project window and select Create > PurrNet > PurrUI > Color Palette. The asset exposes nine slots grouped into Base (Black, White, Muted), Backgrounds (Background, Surface), Primary (Accent), and Status (Success, Warning, Danger). Each slot (except Base) also has a dedicated contrast color - the foreground used for text or content rendered on top of it.

Color Palette Scriptable Object: image

The inspector includes a live mock-UI preview built from rectangles so you can see how the slots land together as you tweak them - useful for catching low-contrast pairings at a glance.

ColoredGraphic

Add a ColoredGraphic next to any UI.Graphic (Image, RawImage, TMP_Text, etc.) to drive its color from the active palette.

Colored Graphic Component: image

Pick a slot via the dropdown. Toggle Contrast to use that slot's paired foreground instead (e.g. Accent with contrast on = the accent foreground color).

For multi-colored targets - components implementing IColored - the inspector lists one row per named key with its index ([0] Background, [1] Text, etc.). Each row has an enable checkbox so you opt in only to the slots you want to override; untouched slots keep whatever color the target already had.

Transitions

ColoredGraphic has a Transition Duration field. Any palette change - either editing the asset or calling the runtime API - smoothly lerps from the current color to the new target. Set to 0 to snap. Edit-mode changes always snap (for a stable editor preview without needing continuous repaints).

Runtime API

// Single-graphic targetcoloredGraphic.SetColor(newColorInfo{enabled=true,color=ColorType.Accent});// Specific slot on an IColored targetcoloredGraphic.SetColor(1,newColorInfo{enabled=true,color=ColorType.Background,contrast=true});// Tweak the blend duration at runtimecoloredGraphic.transitionDuration=0.25f;

Your own state machine (hover/pressed/etc.) can push new ColorInfos and the transition system handles the visual blend.

Providers

ColoredGraphic walks up the hierarchy via GetComponentInParent<IPaletteProvider>() to find the active palette:

  • ViewStack already implements IPaletteProvider - the palette you configure on it cascades into every view pushed onto the stack.
  • Drop a PaletteProvider component on any child GameObject to override the palette for that subtree (e.g., a "dark card" inside an otherwise-light scene).

The closest provider wins, so nested providers work naturally for scoped theme overrides.

Sounds2D

A lightweight, fire-and-forget 2D audio system. It manages a small pool of AudioSource components (up to 5) on a DontDestroyOnLoad GameObject, so you never have to wire up audio sources yourself.

Quick Start

usingPurrNet.UI;usingUnityEngine;publicclassButtonSFX:MonoBehaviour{[SerializeField]privateAudioClip_clickSound;publicvoidOnClick(){Sounds2D.Play(newAudioSession(_clickSound));}}

AudioSession

AudioSession is a struct that describes what to play and how. It uses a fluent builder API:

// Simple: play a clip at default volume and pitchSounds2D.Play(newAudioSession(clip));// With volume and pitchSounds2D.Play(newAudioSession(clip).WithVolume(0.8f).WithPitch(1.2f));// Random variation: adds ± randomRange to the base value each timeSounds2D.Play(newAudioSession(clip).WithVolume(0.7f,0.1f).WithPitch(1f,0.15f));// Random clip from an array (great for footsteps, impacts, etc.)AudioClip[]hitSounds={hit1,hit2,hit3};Sounds2D.Play(newAudioSession(hitSounds).WithVolume(0.9f));

Master Volume

// Set a global master volume (0-1) that scales all soundsSounds2D.masterVolume=0.5f;

About

A stack based screen manager for Unity's UI.

Resources

Stars

76 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages