v1.0.1 · Unity 2021.3+

HyperCasual
Essentials

Drop-in Unity toolkit for hyper-casual games. Audio, economy, IAP, ads, haptics, daily rewards, reward wheel, skin shop, toon shaders, and more — all wired up and ready to ship.

Unity 2021.3+ 20 Modules 148+ Runtime Scripts BiRP / URP / HDRP

🏠 Overview

Everything you need for a hyper-casual game, nothing you don't.

ⓘ
Modular by design. Every system is independent. Use only what you need — no monolithic dependencies.

⚡ Quick Start

Get up and running in under 2 minutes.

Import the package
Import HyperCasual Essentials into your Unity project via the Asset Store or by copying the HyperCasualEssentials/ folder into Assets/.
Run the Setup Wizard
Open Tools → HCE → Setup Wizard. Toggle both options (create default configs + enable cheats) and click Run.
Open the Toolset
Open Tools → HCE → Toolset to see the status of all modules. Green = ready, yellow = warning, red = action needed.
Import the Demo (optional)
Import the sample from Samples~/Demo/ and open DemoScene.unity. Press Play to see every module in action.
Configure for production
Open Resources/HCE/HCESettings.asset and fill in your ad unit IDs, IAP product IDs, and notification settings. Switch modes from Dummy to Production when ready.
💡
No auto-modifications. HyperCasual Essentials never edits your Packages/manifest.json, opens URLs, or downloads anything without your explicit consent.

Automatic Bootstrap

At runtime, two bootstrappers fire automatically — no scene setup required:

BeforeSceneLoad → ServiceBootstrap → Register MonoHost → AfterSceneLoad → GameBootstrapper → Apply Settings

GameBootstrapper applies your HCESettings: target frame rate (default 60), screen sleep prevention, time scale restoration, and multi-touch.

Sample Prefabs

PrefabPurpose
HCE_BootstrapInitializes services, loads save data
HCE_ToastCanvasFIFO toast notification queue
HCE_PopupCanvasModal popup stack with backdrop
HCE_FadeCanvasBlack overlay for scene transitions
HCE_WheelPrefabSpinning prize wheel UI
HCE_ShopItemPrefabSingle shop item row template
HCE_CoinBurstPrefabCoin gather particle animation
HCE_BannerAnchorBanner ad positioning container
HCE_HudPrefabLive currency balance display

🛠 Architecture

How everything connects under the hood.

Service Locator Pattern

All modules register and resolve dependencies through the static HCE.Core.Services class. This keeps systems decoupled — Audio doesn't know about Economy, Economy doesn't know about Shop.

Factory Pattern

Platform-specific backends (Ads, Haptics, IAP, Notifications, Rate Us) are created by factory classes that read HCESettings and select the right implementation. Missing SDKs gracefully fall back to dummy/mock backends.

ScriptableObject Configuration

Every system is configured through Inspector-editable ScriptableObject assets. No hardcoded values, no code changes needed for designers to tune behavior.

Event-Driven Updates

Services emit C# events (BalanceChanged, Purchased, SpinCompleted, etc.) so UI automatically reacts to state changes without polling.

Folder Structure

HyperCasualEssentials/
  Config/            // Default ScriptableObject configs
  Demo/              // Feature dashboard
  Documentation~/    // This documentation
  Editor/            // Editor windows, inspectors, importers
  Plugins/           // Native iOS/Android code
  Resources/HCE/     // HCESettings singleton + icons
  Runtime/           // All game systems (148 C# files)
    Ads/  Analytics/  Audio/  Cheats/  Core/
    DailyReward/  Economy/  Flow/  Gating/
    Haptics/  IAP/  Minigames/  Notifications/
    RateUs/  Save/  Shaders/  Shop/  UI/  Wheel/
  Samples~/          // Optional importable demo

🔌 Service Locator

Minimal static registry for dependency injection.

// Register a service (once, during bootstrap)
Services.Register<AudioService>(new AudioService());

// Resolve anywhere
var audio = Services.Resolve<IAudioService>();
audio.Play(new SoundId("click"));

// Safe resolve (no exception if missing)
if (Services.TryResolve<IWalletService>(out var wallet))
    wallet.Credit(CurrencyId.Coins, 100, "bonus");C#
MethodDescription
Register<T>(T instance)Bind a singleton by type. Throws if already registered.
Resolve<T>()Get a registered service. Throws if missing.
TryResolve<T>(out T)Non-throwing resolve. Returns false if missing.
IsRegistered<T>()Check existence without throwing.
Unregister<T>()Remove a binding. No-op if absent.

⚙ HCE Settings

Single ScriptableObject configuring every module.

Located at Resources/HCE/HCESettings.asset. Access at runtime via HCESettings.Instance. Falls back to safe defaults if the asset is missing.

General Settings
FieldDefaultDescription
TargetFrameRate60Application.targetFrameRate (set if currently ≤ 0)
NeverSleeptruePrevent screen sleep on mobile
VerboseLoggingfalseEnable detailed HCE log output
All Sub-Settings

HCESettings contains nested settings objects for each module:

PropertyTypeSection
AdsAdMobSettingsAds
AnalyticsAnalyticsSettingsAnalytics
IAPIAPSettingsIAP
AudioAudioSettingsAudio
HapticsHapticsSettingsHaptics
NotificationsNotificationsSettingsNotifications
RateUsRateUsSettingsRate Us
WelcomeGiftsWelcomeGiftsSettingsDaily Rewards
MinigamesMinigamesSettingsMinigames
GeneralGeneralSettingsAbove

💾 Save System

Versioned JSON blobs with schema migration and debounced writes.

How It Works

All game state is serialized into a SaveBlobV1 and stored in a single PlayerPrefs key (HCE_SAVE_V1). Writes are debounced to at most once per second to avoid I/O spam.

// Save
var blob = new SaveBlobV1();
walletService.SaveToBlob(blob);
shopService.SaveToBlob(blob);
backend.WriteBlob(blob);

// Load
var loaded = backend.ReadBlob();
if (loaded != null) {
    loaded = SaveMigrator.Upgrade(loaded, loaded.SchemaVersion, SaveMigrator.CurrentVersion);
    walletService.LoadFromBlob(loaded);
    shopService.LoadFromBlob(loaded);
}C#

SaveBlobV1 Structure

FieldTypePurpose
SchemaVersionintCurrent schema version (1)
BalancesList<BalanceRecord>Currency ID + amount pairs
StringsList<StringKvp>Generic key-value pairs
OwnedList<OwnedEntry>Shop item ownership + equipped flag
LastDailyStampstringLast daily reward claim timestamp
StreakCountintCurrent daily reward streak

Schema Migration

When adding new fields, create a new schema version and register an upgrader in SaveMigrator.Upgrade(). The migrator chains upgrades: V0 → V1 → V2 → etc.

ⓘ
All HCE PlayerPrefs keys are prefixed with HCE_ to avoid collisions with your project's data.

🎬 Scene Flow

Async scene loading with fade transitions and cooldown timers.

SceneFadeService

Load scenes with a smooth fade-out / load / fade-in sequence. Uses unscaled delta time so it works even when the game is paused.

var fadeService = new SceneFadeService(fadeConfig, overlayImage);
await fadeService.LoadAsync(sceneRef);C#
Fade Out → Load Scene (async) → Activate Scene → Fade In

CooldownTimer

Invariant-culture cooldown gate. Serializes to tick strings that are safe across locales and devices.

var timer = new CooldownTimer(timeSource, TimeSpan.FromHours(24), "daily_reward", savedStamp);
if (timer.IsReady) {
    // Grant reward
    timer.Stamp();
    PlayerPrefs.SetString("stamp", timer.ToSave());
} else {
    Debug.Log($"Ready in {timer.Remaining.TotalHours:F1}h");
}C#

Time Sources

SourceUse CaseAnti-Cheat
LocalTimeSourceDefault wall-clock timeNo — user can change device clock
ServerTimeSourceHTTP HEAD probe for UTC timeYes — reads server Date header

Tweening

Lightweight static tween driver via TweenRunner. Supports Move, Rotate, Scale, and Fade with easing and cancellation.

TweenRunner.Scale(transform, Vector3.zero, Vector3.one, 0.4f, Easing.OutBack);
TweenRunner.Fade(canvasGroup, 0f, 1f, 0.3f, Easing.InOutSine);C#

Available easing functions: Linear, InOutQuart, InOutSine, OutCubic, OutBack.

🔊 Audio

Pooled SFX playback, crossfading music, and a per-category mixer.

Setup

Create a SoundBank
Right-click in Project → Create → HCE → Audio → Sound Bank. Add entries with ID, AudioClip, volume, pitch, and category.
Assign to Settings
Drag your SoundBank into HCESettings → Audio → DefaultSoundBank.
Play sounds
Resolve the service and call Play() with a SoundId.
// Play SFX
var audio = Services.Resolve<IAudioService>();
audio.Play(new SoundId("click"));
audio.Play(new SoundId("explosion"), 0.5f);  // 50% volume

// Play music with crossfade
audio.PlayMusic(new SoundId("menu_loop"), 2f);

// Mixer control
audio.SetVolume(AudioCategory.Sfx, 0.8f);
audio.SetMute(AudioCategory.Music, true);C#

SoundBank Entry Fields

FieldRangeDescription
Id—Unique string identifier
Clip—AudioClip reference
Volume0–1Entry volume (multiplied by master × category)
Pitch0.1–3Playback pitch
PitchJitter0–0.5Random pitch variance (±jitter)
Category—Sfx, Music, UI, Voice, or Ambient
Loop—Continuous playback for music/ambient

CSV Import

Bulk-populate a SoundBank: select it in the Project window, then Tools → HCE → Import SoundBank CSV.

# id, clipName, volume, pitch, pitchJitter
click, UI_Click, 0.8, 1.0, 0.05
footstep, Footstep_Concrete, 1.0, 1.2, 0.1
ambient_wind, , 1.0, 1.0, 0CSV
💡
Auto-routing: If you call Play() on an entry tagged as AudioCategory.Music, it automatically routes to PlayMusic() with crossfade.

Audio Mix Formula

Final Volume = Entry.Volume × Master × Category
               (0 if MasterMuted OR CategoryMuted)
Final Pitch  = Entry.Pitch ± Random(PitchJitter)text

📳 Haptics

Pattern-based vibration with platform-specific backends.

Setup

var haptics = new HapticService();
haptics.Initialize();

var pattern = Resources.Load<HapticPattern>("Light");
haptics.Play(pattern);
haptics.Cancel();  // Stop vibrationC#

HapticPattern Fields

FieldTypeDescription
DurationsMslong[]Duration of each pulse in ms
Amplitudesint[]Intensity per pulse (0–255)
PredefinedIdintPlatform effect ID (-1 = use custom waveform)

Platform Backends

PlatformBackendFeatures
Android 26+AndroidHapticsBackendVibrationEffect waveforms, predefined effects (29+)
Android <26AndroidHapticsBackendLegacy vibrate (no amplitudes)
iOSIOSHapticsBackendCoreHaptics via native plugin
EditorEditorHapticsBackendLog-only (no vibration)

Mode Configuration

In HCESettings → Haptics:

ⓘ
HCE doesn't ship a Plugins folder. To enable Android haptics, open Tools → HCE → Toolset → Haptics and click "Add VIBRATE permission to project" — the Toolset writes a single <uses-permission> entry into your Assets/Plugins/Android/AndroidManifest.xml (creating the file if it doesn't exist).

💰 Economy

Multi-currency wallet with overflow protection and transaction logging.

Wallet Service

// Credit
wallet.Credit(CurrencyId.Coins, 500, "level_complete");

// Debit (returns false if insufficient)
if (wallet.TryDebit(CurrencyId.Gems, 10, "shop_purchase")) {
    // Purchase succeeded
}

// Read balance
long coins = wallet.Get(CurrencyId.Coins);

// Listen for changes
wallet.BalanceChanged += (id, newBalance) => UpdateHud(id, newBalance);C#

Built-in Currencies

CurrencyId.Coins and CurrencyId.Gems are predefined. Create custom currencies with new CurrencyId("keys").

Overflow Protection

Balances are capped at long.MaxValue / 2 instead of crashing on overflow. Safe for long-term play sessions.

Transaction Log

Every credit/debit is recorded in a ring buffer (default 50 entries) with timestamp, currency, delta, and reason string. Use transactionLog.GetRecent(10) for analytics or debugging.

Coin Burst Animation

Spawn a stream of coins flying from a world position to your HUD:

var request = new CoinBurstRequest {
    CoinCount = 15,
    TotalReward = 100,
    OriginWorld = transform.position,
    HudPositionProvider = () => hudCoinIcon.position,
    StaggerSeconds = 0.02f
};
coinBurstRunner.PlayAsync(request, onCompleted: () => Debug.Log("done"));C#

🛒 Shop & Skins

Item catalog with material and mesh skin payloads.

Setup

Create a ShopCatalog
Create → HCE → Shop → Catalog
Create ShopItems
Create → HCE → Shop → Item. Set ID, price, currency, icon, and skin payload.
Create Skin Payloads
Create → HCE → Shop → Material Skin Payload or Mesh Skin Payload.
Wire the SkinApplier
Add SkinApplier to the target GameObject. It auto-applies skins when items are equipped.
// Purchase
if (shopService.TryPurchase(item)) {
    Debug.Log("Bought!");
}

// Equip
shopService.Equip(item);  // Fires Equipped event → SkinApplier applies it

// Events
shopService.Purchased += (item) => ShowToast("Purchased!");
shopService.Equipped += (item) => RefreshUI();C#

CSV Import

Select a ShopCatalog, then Tools → HCE → Import Shop CSV:

# id, price, currency, englishName
blue_skin, 100, coins, Blue Skin
fire_sword, 50, gems, Fire SwordCSV

Skin Payload Types

TypeWhat It Does
MaterialSkinPayloadSwaps the first Renderer's sharedMaterial
MeshSkinPayloadSwaps the first MeshFilter's sharedMesh

💳 In-App Purchases

Unified purchase flow with real and dummy store backends.

Product Setup

Create an IAPCatalog
Create → HCE → IAP → Catalog
Create IAPProducts
Create → HCE → IAP → Product. Set store ID (lowercase a-z0-9_), kind, and reward hook.
Create Reward Hooks
Use CoinsPurchaseReward for consumables or FlagPurchaseReward for non-consumables.
Configure HCESettings
Set IAP mode: Dummy (testing), Test (real SDK, test environment), or Production.

Purchase Flow

var result = await iapBridge.PurchaseAsync("com.game.1000coins");
if (result.Success) {
    // Reward already granted via RewardHook
    ShowToast("Thank you!");
}C#
User taps Buy → IAPBridge.PurchaseAsync → Store Backend → PurchaseResult → RewardHook.Grant()

Reward Hook Types

TypeUse CaseAction
CoinsPurchaseRewardConsumable (coins, gems)Credits wallet
FlagPurchaseRewardNon-consumable (no-ads, skin pack)Sets PlayerPrefs flag

Failure Reasons (PurchaseResult.Reason)

The Unity IAP backend pre-validates every purchase request before calling the store, so failures surface as a clean PurchaseResult { Success = false, Reason = "..." } instead of throwing. Show Reason in toasts/logs to diagnose live issues.

ReasonMeaningCommon cause
not_initializedBackend hasn't finished InitializeAsync.Buy tapped before init resolved — gate the button on IsInitialized.
invalid_product_idEmpty or null product id passed in.Caller bug, e.g. missing IapProductId on a shop entry.
product_not_in_catalogThe id isn't in the controller's product list.Product not registered in Play Console / App Store Connect for this package, or the id was misspelled.
product_not_availableStore fetched the product but flagged it unavailable.Product inactive on the store, region not supported, or test track config issue.
purchase_threw: <message>Synchronous exception from controller.InitiatePurchase.Last-line guard against any future Unity Purchasing change. Inspect the wrapped message.
UserCancelled · NetworkError · PaymentDeclined …Forwarded from Unity Purchasing's PurchaseFailureReason.Standard live-purchase failure modes — show a generic error toast.
ⓘ
The product_not_in_catalog guard prevents the deep InvalidCartItemException that Unity Purchasing v5 throws when an unregistered id reaches InitiatePurchase. Surface it as "Product unavailable" to the user and check Play Console / App Store Connect first.

Dummy Backend

The dummy backend simulates purchases with configurable behavior:

Latency is configurable (default 250ms) to test loading spinners.

📺 Ads

AdMob integration with rewarded, interstitial, and banner support.

Showing Ads

var adService = Services.Resolve<AdService>();

// Rewarded video
var result = await adService.ShowRewardedAsync(rewardedPlacement);
if (result.Completed) GrantReward();

// Interstitial
bool shown = await adService.ShowInterstitialAsync(interstitialPlacement);

// Banner
adService.LoadBanner(bannerPlacement);
adService.HideBanner(bannerPlacement);C#

RewardedResult

FieldMeaning
CompletedUser watched the full video
SkippedUser dismissed before completion
FailedLoad or show error (check Reason)

Mode Configuration

ModeBackendUse When
DummyMockAdBackendDevelopment — no SDK needed
TestAdMobBackendTesting — uses Google's test ad unit IDs
ProductionAdMobBackendRelease — uses your production ad unit IDs

Production Setup

Install Google Mobile Ads SDK
The HCE_ADMOB define is auto-set when the SDK is detected.
Fill production IDs
In HCESettings → Ads, fill in all Android and iOS production ad unit IDs.
Switch to Production mode
The Toolset window will show green status when all IDs are configured.
⚠
GDPR: RequestNonPersonalizedAdsOnly is true by default, adding "npa"="1" to all ad requests for EU consent compliance.

🎁 Daily Rewards

Streak-based welcome gifts with ad-boosted claiming.

How It Works

Player opens app → DailyStreakTracker.RegisterLogin() → Streak advances (or resets) → WelcomeGiftSchedule.TryGetForDay() → Grant reward

Streak Logic

Default Schedule

DayRewardAmount
1Coins50
2Coins100
3Gems5
4Coins250
5Coins500
6Gems20
7Coins (Jackpot)1000

Ad-Boosted Claiming

// 2x reward via rewarded ad
if (service.TryClaimWithMultiplier(2, out var gift)) {
    ShowCelebration(gift);
}C#

The WelcomeGiftPanel UI has built-in "x2 via Ad" button support. Wire an AdPlacement in settings and the panel handles the ad flow automatically.

Welcome Gift Configuration

SettingDefaultDescription
Schedule—WelcomeGiftSchedule ScriptableObject
LoopAfterLastDayfalseRe-grant last day's gift on day 8+
GraceDays0Missed days that don't break the streak
UseServerTimefalseAnti-cheat: use server UTC time
DoubleAdPlacement—AdPlacement for 2x via Ad button

Tile States

The WelcomeGiftPanel renders each day as a tile with one of four states:

🎱 Reward Wheel

Weighted prize spinner with visual building and tick audio cues.

Setup

Create a WheelSliceDatabase
Create → HCE → Wheel → Slice Database. Define slices with icon, label, amount, and weight.
Assign the WheelSpinner
Add WheelSpinner to your wheel UI. Assign the database and the RectTransform to rotate.
Spin!
Call Spin() and listen for SpinCompleted.
wheelSpinner.Spin();
wheelSpinner.SpinCompleted += (result) => {
    Debug.Log($"Won {result.Slice.Amount} coins!");
    wallet.Credit(CurrencyId.Coins, result.Slice.Amount, "wheel_reward");
};C#

WheelSlice Fields

FieldDescription
IconSprite displayed on the wheel
LabelLocalizedText name
AmountReward amount
WeightProbability weight (higher = more likely)
RewardIdIdentifier for the reward type

Spin Animation

The spinner performs _extraSpins full rotations (default 5) before landing on the selected slice, using InOutQuart easing over _spinDuration seconds (default 4s).

The WheelTickEmitter fires a Tick event for every slice boundary crossed — perfect for driving a click sound.

Weighted Selection

Uses prefix-sum binary search for O(log N) selection. Zero-weight slices are never selected. The inspector warns if total weight is 0 or slice count is outside 2–12.

🎲 Minigames

Chest loot drops and slot machine.

Chests

var result = chestService.TryOpen("rare_chest");
if (result.Success)
    Debug.Log($"Got {result.Drop.Amount} {result.Drop.CurrencyId}!");C#

Each ChestTier has a key cost (debited from wallet), an icon, a tint color, and a weighted loot table of ChestRewardDrop entries. Drops can grant currency or set item flags.

Slot Machine

if (slotMachine.TrySpin(out var result)) {
    if (result.HitJackpot)
        Debug.Log($"JACKPOT! Won {result.RewardAmount}!");
}C#

Configure reels, symbols (with weights), and payout rules. The default setup: 3 reels, symbols Cherry/Lemon/Bell/Bar/Seven with payouts from 30 to 2500.

Config FieldDefaultDescription
ReelCount3Number of spinning reels
SpinDurationSeconds2.5Animation duration
StopStaggerSeconds0.3Delay between reel stops
SpinCost10Currency cost per spin

🔒 Feature Gating

Lock features behind level, currency, cooldown, or flag conditions.

UnlockGate Component

Add an UnlockGate to any Button. Assign an UnlockCondition asset. The gate automatically disables the button, shows a lock reason, and toggles a lock overlay.

Condition Types

TypeUnlocks WhenLock Message Example
LevelUnlockConditionPlayer level ≥ required"Unlocks at level 4"
CurrencyUnlockConditionCurrency balance ≥ required"Need 100 coins (have 42)"
CooldownUnlockConditionTime elapsed since last use"Ready in 14:32"
FlagUnlockConditionPlayerPrefs flag is set (or NOT set)"Locked" (customizable)
CompositeUnlockConditionAll children (AND) or Any child (OR)First locked child's message

Usage

// Listen for gate status changes
unlockGate.StatusChanged += (status) => {
    if (status.Unlocked)
        Debug.Log("Feature unlocked!");
    else
        Debug.Log(status.LockReason);
};C#
💡
Composable: Use CompositeUnlockCondition to combine conditions. Example: "Level 5 AND 100 coins AND 24h cooldown" using All mode.

🗨 Popups & Toasts

Modal popup stack and FIFO toast notifications.

Popups

// Show a popup
popupService.Open(new PopupRequest(myPopupPrefab, dimBackdrop: true, payload: someData));

// Close from inside the popup
public class MyPopup : PopupView {
    public override void OnOpened(object payload) { /* setup UI */ }
    public void OnCloseClicked() => Close();
}C#

Popups stack. The backdrop uses reference counting — it stays visible until all popups are closed. Set IgnoreTimeScale = true for pause-proof animations.

Toasts

toastService.Show(new ToastRequest("Level complete!", ToastKind.Success, 2f));
toastService.Show(new ToastRequest("Not enough coins", ToastKind.Warning));C#

Toast Kinds

KindVisual
InfoDefault neutral style
SuccessGreen accent
WarningYellow accent
ErrorRed accent

Toasts queue in FIFO order with 0.1s pause between each. Duration defaults to 2 seconds.

🎨 UI Helpers

Ready-made components for common UI patterns.

ComponentWhat It Does
NumberTickerAnimates a TMP label from one number to another with OutCubic easing (0.6s default)
PressFeedbackScales a button down to 94% on press, bounces back with OutBack on release (0.06s)
SafeAreaFitterAdjusts RectTransform anchors to match Screen.safeArea, handling notches and rounded corners
ModalBlockerFull-screen transparent raycast target that swallows all pointer events
RewardButtonPlays an Animator dismiss animation then self-destructs
SceneFadeTriggerInspector-wired button that loads a scene via SceneFadeService
WalletHudAuto-updates a TMP label when the bound currency balance changes
// NumberTicker usage
numberTicker.SetImmediate(0);
numberTicker.TweenTo(1500);  // Animates 0 → 1500 over 0.6sC#

🌈 Toon Shaders

Cel-shaded rendering for BiRP, URP, and HDRP.

Shader Variants

ShaderPipelineFeature
HCE/Toon/BiRP-LitBuilt-in RPBanded toon lighting + rim highlight
HCE/Toon/BiRP-OutlineBuilt-in RPInverted hull outline pass
HCE/Toon/BiRP-TransparentBuilt-in RPAlpha blended toon (no rim)
HCE/Toon/URP-LitUniversal RPSelf-contained toon + rim
HCE/Toon/URP-OutlineUniversal RPClip-space outline pass
HCE/Toon/URP-TransparentUniversal RPAlpha blended toon
HCE/Toon/HDRP-LitHD RPMinimal toon (linear blend)

Material Properties

PropertyRangeDefaultDescription
_BaseMap—whiteAlbedo texture
_BaseColor—whiteTint color
_ShadowTint—(0.4, 0.4, 0.55)Shadow color (blue-ish)
_RimColor—whiteRim highlight color
_RimPower0.1–164Rim falloff exponent
_BandCount1–83Number of discrete light bands
_BandSmoothness0–10.15Edge softness between bands
_ToonFloor0–10.25Minimum brightness
_ToonCeiling0–11.0Maximum brightness
_OutlineColor—blackOutline color (outline shader only)
_OutlineWidthPixels0–162.0Screen-space outline width in pixels

Pipeline Detection

// Auto-select the right shader for the active pipeline
string shaderName = RenderPipelineUtil.GetPreferredToonShader();
var shader = Shader.Find(shaderName);C#

📊 Analytics

Pluggable event bus with multiple sink backends.

var bus = Services.Resolve<AnalyticsBus>();
bus.Emit("level_complete", new Dictionary<string, object> {
    { "level", 5 },
    { "score", 1200 },
    { "time_seconds", 42.5 }
});C#

Available Sinks

SinkRequiresOutput
DebugLogSinkNothingUnity Console: [HCE.Analytics] event_name { key=value }
UnityAnalyticsSinkcom.unity.services.analyticsUnity Services dashboard
FirebaseAnalyticsSinkFirebase SDKFirebase console

Sinks are isolated — if one throws, others still receive the event. Configure in HCESettings → Analytics.

🔔 Notifications

Schedule local push notifications on mobile.

var svc = NotificationService.CreateFromSettings();
await svc.InitializeAsync();
await svc.RequestPermissionAsync();

// Schedule a notification 4 hours from now
string id = svc.Schedule("Come back!", "Your energy is full.", TimeSpan.FromHours(4));

// Cancel it
svc.Cancel(id);
svc.CancelAll();C#

Platform Behavior

PlatformBackendPermission
Android 13+UnityMobileNotificationBackendPOST_NOTIFICATIONS runtime permission
Android <13UnityMobileNotificationBackendNo permission needed
iOSUnityMobileNotificationBackendUNUserNotificationCenter authorization
EditorDummyNotificationBackendLogs to console
ⓘ
Requires com.unity.mobile.notifications package. The HCE_MOBILE_NOTIFICATIONS define is auto-set when detected.

⭐ Rate Us

Gated review prompts with platform-native dialogs.

// Register each app launch
rateUsService.RegisterSession();

// Gated prompt (checks all conditions first)
var result = await rateUsService.MaybeRequestReviewAsync();

// Force prompt (for explicit "Rate Us" button in settings)
var result = await rateUsService.ForceRequestReviewAsync();C#

Gate Conditions

GateDefaultDescription
Min sessions3Minimum app launches before first prompt
Min seconds since first launch600 (10 min)Minimum time since first app launch
Min days between asks30Cooldown between prompts
Max lifetime asks3Apple caps at 3 per 365 days
Skip if ratedtrueDon't prompt again after user rated

Soft Prompt

Enable UseSoftPrompt to show a custom dialog ("Enjoying the game?") before the native review UI. If the user declines, the attempt is counted but the native dialog is skipped.

Production Setup — Native Popup Wiring

HCE ships a fully self-contained wiring for the Android native popup — no project-level Gradle edits required. iOS needs nothing at all.

Android — one-click Gradle wiring
HCE itself ships zero third-party content. To enable the native popup, open Tools → HCE → Toolset → Rate Us and click "Add Play Review dep to mainTemplate.gradle". The Toolset writes the line implementation 'com.google.android.play:review:2.0.1' into your project's Assets/Plugins/Android/mainTemplate.gradle (creating the file if it doesn't exist). At YOUR build time, Gradle resolves the artifact from Google's Maven repository and links it into your APK. Without this dep, the backend silently opens the Play Store listing instead.
iOS — nothing to install
SKStoreReviewController ships with iOS StoreKit. The included Plugins/iOS/HCERateUs.mm calls requestReviewInScene: on iOS 14+ and requestReview on 10.3+. Set RateUs → IOSAppId for the deep-link fallback when the soft cap kicks in.
Test on a Play-Store install
Sideloaded debug APKs and direct downloads will not display the Android native popup — Google requires the app to be installed via the Play Store (Internal/Closed/Open testing tracks all qualify). On iOS, the native popup is rate-limited to 3 prompts per 365 days per app and can no-op silently.
ⓘ
Run the Pre-flight checks button on the Rate Us tab to confirm wiring. A green "Play Review gradle dep is in mainTemplate.gradle" banner means you're ready — the HCE_PLAY_REVIEW scripting define is optional (build-time hint only; the runtime backend uses reflection).
⚠
Both platforms silently rate-limit. Apple caps at 3 prompts per 365 days; Google enforces a per-user quota that's not exposed to your app. Either may complete MaybeRequestReviewAsync with no visible UI — that's normal, not a bug. Don't show "thanks for rating!" toasts pre-emptively.

🔧 Editor Tools

Setup wizard, toolset window, custom inspectors, and CSV importers.

Tools Menu

Menu PathPurpose
Tools → HCE → ToolsetMain editor window with 11 tabs for all modules
Tools → HCE → Setup WizardFirst-run project setup
Tools → HCE → Create Default Config AssetsGenerate all default configs
Tools → HCE → Import SoundBank CSVBulk import audio entries
Tools → HCE → Import Shop CSVBulk import shop items

Toolset Window

The main HCE editor window (11 tabs) shows the health status of every module:

Tabs: Overview, Ads, Analytics, IAP, Audio, Haptics, Notifications, Rate Us, Welcome Gifts, Minigames, General.

Custom Inspectors

InspectorAsset TypeExtra Feature
SoundBankInspectorSoundBankReorderable drag list
WheelSliceDatabaseInspectorWheelSliceDatabaseTotal weight display + warnings
ShopCatalogInspectorShopCatalogDuplicate ID detection + auto-fix
IAPCatalogInspectorIAPCatalogProduct ID format validation
HapticPatternInspectorHapticPatternVisual waveform preview

Property Drawers

Smart dropdown pickers are provided for SoundId, CurrencyId, ShopItemId, and SceneReference fields. They auto-scan all relevant assets in the project.

Build Validator

Runs automatically before every build (IPreprocessBuildWithReport). Warns if a SoundBank or ShopCatalog is missing — never blocks the build.

🎮 Cheat Console

Debug console with hotkeys and 3-finger mobile gesture.

⚠
The entire cheat system is compiled only when HCE_CHEATS is defined. It compiles to empty stubs in release builds.

Activation

Built-in Cheats

CheatHotkeyAction
Grant CoinsF1Credit 1000 coins (configurable)
Wipe SaveF2Delete all persisted data
Reload SceneF3Reload the active scene

CheatBindings Config

Create via Create → HCE → Cheats → Bindings. Customize hotkeys and grant amounts in the Inspector.

📚 Scripting Defines

Feature flags for optional SDK integrations.

DefineRequired PackageWhat It EnablesAuto-Set
HCE_ADMOBGoogle Mobile Ads SDKAdMob backendYes (asmdef)
HCE_UNITY_ANALYTICScom.unity.services.analyticsUnity Analytics sinkYes (asmdef)
HCE_FIREBASEFirebase SDKFirebase Analytics sinkNo (manual)
HCE_MOBILE_NOTIFICATIONScom.unity.mobile.notificationsOS push notificationsYes (asmdef)
HCE_CHEATSNoneDebug cheat consoleSetup Wizard
HCE_LOG_VERBOSENoneDetailed HCE log outputNo (manual)
💡
Most defines are auto-set via asmdef version defines when you install the corresponding package. No manual setup needed.

💡 Troubleshooting

Common issues and their solutions.

"HCESettings asset not found" warning at runtime

The singleton asset must exist at Assets/HyperCasualEssentials/Resources/HCE/HCESettings.asset. Run Tools → HCE → Setup Wizard to create it, or verify the path hasn't been moved.

Ads always show as mock/dummy

Check three things: (1) Google Mobile Ads SDK is installed, (2) HCE_ADMOB define is present in Player Settings, (3) HCESettings → Ads → Mode is set to Test or Production.

IAP purchases fail with "not_initialized"

Ensure await iapBridge.InitializeAsync(catalog) is called and awaited before any purchase. Check Unity Console for initialization errors.

Haptics don't work on device

Verify: (1) HCESettings → Haptics → Mode is Production, (2) Platform toggles (EnableOnAndroid/EnableOnIOS) are on, (3) you've clicked Tools → HCE → Toolset → Haptics → "Add VIBRATE permission to project" so your Android manifest declares the permission.

Daily reward resets unexpectedly

The streak tracker uses UTC dates. If you're testing across midnight UTC, the streak will advance. For forgiving behavior, increase GraceDays in WelcomeGiftsSettings. Enable UseServerTime to prevent clock manipulation.

Toon shaders are pink / not rendering

Make sure you're using the shader that matches your render pipeline. Use RenderPipelineUtil.GetPreferredToonShader() to auto-detect, or manually assign: BiRP-Lit for Built-in, URP-Lit for Universal, HDRP-Lit for HD.

Build validator warns about missing SoundBank

Run Tools → HCE → Create Default Config Assets to generate all default configs. Then assign your SoundBank in HCESettings → Audio → DefaultSoundBank.

Notifications don't appear on device

Ensure com.unity.mobile.notifications is installed, HCE_MOBILE_NOTIFICATIONS define is set, Mode is Production, and RequestPermissionAsync() was called and returned true.

Threading Rules

⚠
Main thread only: All UnityEngine.* calls, PlayerPrefs, MonoBehaviour callbacks, Mathf.
Background safe: System.Math, CultureInfo.InvariantCulture, pure C# collections.
Use MonoHost.Post(action) to marshal work back to the main thread from native callbacks.

📬 Support

Need help? We're here for you.

📧

Get in Touch

If you run into any issues, have feature requests, or need help integrating HyperCasual Essentials into your project, don't hesitate to reach out.

✉ ragendom@gmail.com

We typically respond within 24–48 hours.

💬 Before Contacting
  • Check the Troubleshooting section
  • Verify your Scripting Defines are set
  • Open Tools → HCE → Toolset to check module status
  • Include your Unity version and target platform
📋 Helpful Info to Include
  • Unity version & render pipeline (BiRP/URP/HDRP)
  • HCE version (currently 1.0.1)
  • Target platform (Android/iOS/both)
  • Console error logs or screenshots

HyperCasual Essentials v1.0.1 · Built for Unity 2021.3+

Support: ragendom@gmail.com