Block Loop Shooter — Buyer Guide

Unity 6000.0.62f1 · Universal Render Pipeline 17.0.4 · version 3

Overview

Block Loop Shooter is a portrait puzzle game. A train of coloured blocks runs around a closed loop. The player sends shooters from a pit to four pads in front of the loop; each shooter fires at the blocks of its own colour as they pass. Clear every block to win; let every pad fill with shooters that can no longer hit anything and the attempt is lost.

The package contains the playable game with 500 levels, three boosters (Swap, Pad +, Burst), a visual level editor and a seeded level generator, and the HyperCasualLiveOpsKit shell (menu, results, coins, shop, booster bar and refill offer). The first level and level 200 are the two authored levels of the campaign, written directly as level files; the other 498 levels were made by the generator that ships in this package.

Getting Started

Requirements

Import into a new project

  1. Create a new Universal 3D project in Unity 6000.0.62f1 and install the three packages above at those versions (Window → Package Manager).
  2. Import TMP Essential Resources and keep their default location Assets/TextMesh Pro.
  3. Import Block-Loop-Shooter-v3.unitypackage (Assets → Import Package → Custom Package, import everything). It creates exactly two folders: Assets/Game and Assets/HyperCasualLiveOpsKit. Wait for compilation to finish.
  4. Edit → Project Settings → Player → Other Settings → Active Input Handling: Input System Package (New) or Both.
  5. Edit → Project Settings → Graphics: set the Default Render Pipeline to Assets/Game/ProjectRenderSettings/PC_RPAsset.asset. In Quality, set the same asset as the Render Pipeline Asset of every quality level you use. Keep the Color Space on Linear (Player → Other Settings).
  6. File → Build Profiles (Build Settings): add Assets/HyperCasualLiveOpsKit/StarterMenu/Scenes/HLK_MainMenu.unity first and Assets/Game/Scenes/Game.unity second. The menu scene opens the gameplay scene by its name Game.
  7. Open HLK_MainMenu.unity and press Play. Close the welcome card, press PLAY: level 1 opens with a short lesson.

A unitypackage carries assets only, never Project Settings: steps 4 to 6 are yours to make in every new project. The clean-import test of this package made the same settings in a new empty project (only the three packages and Unity's built-in modules, TMP Essentials, then this package), built a Windows development player from the two scenes and played it from the menu.

Editor menu

MenuWhat it does
Tools → Block Loop Shooter → DocumentationOpens this file (Assets/Game/Documentation/Documentation.html) in your browser.
Tools → Block Loop Shooter → Level EditorOpens the level window on the saved campaign (Level Editor).
Tools → Block Loop Shooter → Auto Level GeneratorOpens the same window; the generator is its lower half (Auto Level Generator).

Folder Structure

Assets/Game/
  AI-DISCLOSURE.txt              list of AI-generated and AI-assisted files
  Documentation/Documentation.html   this guide
  Campaign/Resources/Levels/     the campaign: Level_1.json ... Level_500.json + CampaignAuthoring.json   (written by the level tools)
  Resources/Levels/              level-1.json, level-200.json: the two authored levels (the generator reads them)
  Resources/Art/                 HUD and effect sprites of the game
  Resources/Materials/           game materials (shaders in Assets/Game/Shaders)
  Resources/Models/registry.json the model registry (procedural default set and two generated alternate sets)
  Resources/NativeModels/        the two generated alternate model sets as Unity prefabs, meshes, materials, textures
  Scenes/Game.unity              the gameplay scene
  Scripts/Core/                  rules: level data, simulation (pure C#)
  Scripts/Game/, Scripts/UI/, Scripts/Models/   presentation: board, camera fit, HUD, effects, models
  Integration/                   the connection to HyperCasualLiveOpsKit (bridge, booster adapter, campaign catalogue, lesson caption)
  Integration/PowerUps/          the three booster definitions (blockloop_swap, blockloop_pad, blockloop_burst)
  Integration/Resources/HLK/BoosterProgression.json   unlock levels, free charges and refill prices
  UI/Boosters/Icons/, UI/Boosters/Tutorials/          booster icons and first-use pictures
  LevelTools/Editor/             the game's level editor adapter and generator (editor only)
  ProductionLevelTools/Editor/   the shared level window, campaign store and validation (editor only)
  ProjectRenderSettings/         URP pipeline assets, renderers and volume profiles
Assets/HyperCasualLiveOpsKit/    the shell: menu, results, coins, shop, ads and purchase interfaces, booster bar (own guide inside)

Editable by you: everything under Assets/Game. Written by tools: Campaign/Resources/Levels is owned by the level tools; edit levels through the level window so that every file is validated and CampaignAuthoring.json stays in step (a level file changed by hand is refused at the next save until you reload). Do not move Assets/Game/Resources/Levels, Assets/Game/Scenes/Game.unity or the Resources folders: the generator and the game find them by these paths and keys.

Gameplay

Campaign

500 levels in seven chapters starting at levels 1, 21, 61, 121, 201, 301 and 401. Each level combines a loop silhouette (square, stadium, arch, oval, heart, horseshoe, bell and others), zero to two feeder lanes and a pit outline, and introduces its mechanics in order: the first feeder lane on level 3, two feeder lanes on level 8, hidden shooters on level 10, the first dispenser box on level 16. Later chapters raise the number of cells, colours, hidden shooters and boxes; recovery levels in between are easier. The first level and level 200 are authored levels.

Every level file stores a winning tap list (its witness; the two authored levels keep theirs in CampaignAuthoring.json). The editor and the generator refuse to save a level whose witness does not win on the game's own simulation, both as the game runs it and as the kit shell builds it.

Boosters

BoosterUnlocksEffect (the first-use card's text)Refused free when
SWAP
blockloop_swap
level 2"Upright shooters in the pit trade cells, so a different one sits above each buried shooter. Use it before pads fill." A dispenser box can also show a different shooter at its front.the swap would leave the pit looking the same
PAD +
blockloop_pad
level 7"Opens one more pad for this attempt, so one more shooter can fire. It closes again when the level restarts."the extra pad is already open in this attempt
BURST
blockloop_burst
level 12"The parked shooter with the most shots left fires them all at once. Its pad is free again." It hits its blocks anywhere on the loop, nearest the firing stretch first, then whole rows of its colour still waiting in the feeder lanes.no parked shooter has a block to take

Coins and Saves

A win credits 50 coins (WinCoinReward in Assets/HyperCasualLiveOpsKit/StarterMenu/Resources/HLK/StarterMenuConfig.asset). Progress (completed levels), coins and booster charges are saved locally by the kit (Unity PlayerPrefs, under your Player Settings company and product name) and survive a restart; the menu's PLAY opens the next unfinished level. Opening a level by number (the DEV level picker of development builds) does not change saved progress. The shop, wheel, chests, quests and other kit screens are described in the kit's own guide (Assets/HyperCasualLiveOpsKit/Documentation/Documentation.html).

Scripts Reference

Type (assembly)Responsibility
BlockLoop.Core.LevelData, Sim (BlockLoop.Runtime)Reads a level JSON; the deterministic simulation in 10 ms steps: train, feeders, presses, shooters, boxes, boosters, win and loss.
BlockLoop.Game.GameControllerThe gameplay scene's driver: loads the level, steps the simulation, forwards input, applies boosters.
WorldView, Viewport, FxView, TrackMesh, MeshFactory, GameAssetsThe board's 3D presentation, the portrait camera fit above the booster shelf, effects and generated meshes and masks.
HudViewThe game's own HUD; hidden while the kit shell runs the level.
ModelLibrary, ProceduralModelsThe model registry: the procedural set (default) and the two generated alternate sets.
BlockLoop.Integration.BlockLoopHlkBridge (BlockLoop.HLK)Connects a level to the kit shell: level number, win and loss, coins, results, settings and pointer blocking.
BlockLoopPowerUpAdapter, BlockLoopBoosterPolicyThe three boosters on the kit's booster bar and the unlock and refill policy.
BlockLoopCampaignThe runtime level catalogue: Resources.Load("Levels/Level_" + n).
BlockLoopLessonCaptionThe level 1 lesson sentence.
BlockLoop.LevelTools.GameAdapter (editor)The game's adapter for the shared level window: canvas, validation, witness replay, generation, Play saved level.
BlockLoopMenu, BlockLoopWitness (editor)The three menu entries; Rebuild + find witness.
BlockLoop.LevelTools.Gen.Schedule, LevelBuilder, LevelFile, Solver, Rules (editor)The 500-level plan, drafting a level from its plan row, layout ↔ level JSON, the simulated players, the level rules.
Production.LevelTools.LevelToolsWindow, Campaign, CampaignStore (editor)The window, campaign-wide validation and the transactional save of the level folder.

Level Editor

Tools → Block Loop Shooter → Level Editor opens the window BlockLoop Levels on the saved campaign (found by its CampaignAuthoring.json).

Saving: Validate + save checks the whole campaign (count equal to the saved request, contiguous numbering, every level's rules and witness on both simulations, no duplicate puzzle, no more than two equal formations in a row, at least the minimum number of formations, the chapter plan) and only then replaces Assets/Game/Campaign/Resources/Levels in one step. A failed check changes no file and shows the reason. The previous folder is kept as a backup in LevelToolBackups of your project (outside Assets) and the request in ProjectSettings/LevelTools/BlockLoop.json. Checking all 500 levels takes about two minutes on a desktop CPU.

Worked Example: edit, validate, save, play

Make the loop of level 3 lower by one row of the world grid. This exact edit was made in a new project with this package and checked as described.

  1. Open Tools → Block Loop Shooter → Level Editor and select Level 3 (a stadium loop of 64 rows, one diagonal feeder lane, five shooters).
  2. In Exact game data, find the layout's control polygon:
    "control": [[-11.925, 0, 6.615], [11.925, 0, 6.615], [11.925, 13.5, 6.615], [-11.925, 13.5, 6.615]],
    and change the two top points from 13.5 to 12.5:
    "control": [[-11.925, 0, 6.615], [11.925, 0, 6.615], [11.925, 12.5, 6.615], [-11.925, 12.5, 6.615]],
  3. Press Apply data edit (invalidates witness). The canvas says the level has no witness and cannot be saved.
  4. Press Rebuild + find witness. The level is rebuilt from its layout: the loop now has 62 rows instead of 64, the extra rows of blocks move to the feeder lane, and a new witness is found: 60:1.1 90:1.2 120:1.3 150:2.2 1101:2.3 (five taps; each tap is step:row.column, a step being 10 ms).
  5. Press Validate selected: "Selected level model + witness passed."
  6. Press Validate + save: Level_3.json and CampaignAuthoring.json are written after the whole campaign passed.
  7. Press Play saved level (or start from HLK_MainMenu): level 3 runs on the shorter loop. In the clean-import test the saved file was what the game loaded, and the new witness won it on the simulation the kit shell plays.
  8. To undo the example: Undo before saving, or set the values back to 13.5, rebuild, find witness and save again (that test then restored the shipped campaign byte for byte).

Edits that fail are explained in the status line, for example a loop that leaves the board (rule G15), two stretches closer than one track width (G1), or blocks and shots of a colour that do not match (G8).

Auto Level Generator

Tools → Block Loop Shooter → Auto Level Generator opens the same window; the generator is the Saved generation request part below the level view.

FieldShipped valueMeaning
Final campaign count500The total after generation, in both modes.
Seed20261013With the count it fixes the plan: which silhouette, pit, colours, feeders, hidden shooters and boxes each level gets. The same seed and count always give the same levels.
Attempts per level40Candidates tried per level before the generator gives up and reports the level as unproven (nothing is replaced).
Minimum structural formations80Distinct loop / feeder / pit combinations the campaign must contain.
Maximum repeat streak2No more than this many levels in a row with the same formation.
Append to saved campaignoffOn: keep every saved level and add levels up to the count. Off: replace the campaign.
Game rules JSONnames the two authored levelsStored with the campaign; the generator always reads the authored levels from Assets/Game/Resources/Levels.

Save request stores these values; Generate into editor (review, then save) generates, checks every new level (rules, a winning witness, its difficulty band against seeded random plays) and validates the campaign in memory. Nothing is written until you press Validate + save. Cancel on the progress bar stops generation and leaves both the editor's levels and the files unchanged.

Example: append two levels

  1. Set Final campaign count to 502, keep Seed 20261013, tick Append to saved campaign.
  2. Press Generate into editor. This takes under a minute on a desktop CPU (plus about two minutes the first time the window checks all 500 saved levels). Levels 1 to 500 stay exactly as they were. Level 501 is a mushroom loop with two diagonal feeder lanes; level 502 a bell loop with a diagonal and a rail feeder lane; each comes with its own witness.
  3. Review them on the canvas, then press Validate + save: Level_501.json and Level_502.json are written and the game counts 502 levels. Set VisibleLevelCount in StarterMenuConfig.asset to the new count if the menu should show them.

The clean-import test generated, validated and saved exactly this append, then saved the shipped 500 levels back. Replace mode drafts every level one after another in the window (tens of seconds per level), so regenerating all 500 takes hours; it was not part of the test. The two authored levels (the first level and level 200) are never generated: replace mode keeps their files and finds their witness again.

Level Format

A level is one JSON file, Assets/Game/Campaign/Resources/Levels/Level_<n>.json, loaded at runtime as Levels/Level_<n>. This is the complete shipped Level_3.json (the long point lists are shortened here with …; the real file has every point):

{
  "id": "level-3",
  "title": "Level 3",
  "number": 3,
  "aspect": 0.56296,
  "coinsText": "0",
  "reward": 40,
  "rewardX2": 80,
  "newFeature": false,
  "tutorialText": "",
  "colours": [{"name": "red", "hex": "#EC1238"}, {"name": "yellow", "hex": "#FFDE28"}, {"name": "green", "hex": "#22C52A"}, {"name": "blue", "hex": "#2464EC"}, {"name": "orange", "hex": "#ED782E"}],
  "track": {
    "shape": "stadium",
    "rows": 64,
    "lanes": 5,
    "rowsPerSecond": 3.85852,
    "stretchEntryU": 56,
    "stretchRows": 17.0,
    "fireRate": 40.73333,
    "fireRampSeconds": 2.42667,
    "fireRampStart": 0.7,
    "fireDelay": 0.09833,
    "cubeRemoveDelay": 0.35,
    "halfWidth": 0.06822,
    "centreline": [[0.49725, 0.50658, 0], [0.52332, 0.50658, 1.008], … , [0.48422, 0.50658, 63.496]],
    "loop": [{"colour": "yellow", "rows": 9}, {"colour": "blue", "rows": 4}, {"colour": "green", "rows": 20}, {"colour": "orange", "rows": 20}, {"colour": "yellow", "rows": 11}],
    "feeders": [{"id": "TR", "u": 24.69291, "curved": true, "runs": [{"colour": "blue", "rows": 16}, {"colour": "red", "rows": 20}], "path": [[0.68204, 0.35502], [0.68864, 0.3446], … , [0.95529, -0.07638]]}]
  },
  "pads": [[0.23, 0.63889], [0.41, 0.63889], [0.59, 0.63889], [0.77, 0.63889]],
  "padRadius": 0.04934,
  "pit": {
    "cols": 3,
    "rows": 2,
    "x0": 0.33553,
    "y0": 0.74537,
    "dx": 0.16447,
    "dy": 0.11574,
    "cells": [{"row": 1, "col": 1, "kind": "shooter", "colour": "yellow"}, {"row": 1, "col": 2, "kind": "shooter", "colour": "green"}, {"row": 1, "col": 3, "kind": "shooter", "colour": "orange"}, {"row": 2, "col": 2, "kind": "shooter", "colour": "blue"}, {"row": 2, "col": 3, "kind": "shooter", "colour": "red"}]
  },
  "timing": {"inputFrom": 0.6, "pitSlideStart": 0.1, "pitSlideEnd": 0.35, "padsStart": 0.35, "padsEnd": 0.6, "exitSeconds": 0.45, "jumpMin": 0.07, "jumpMax": 0.2, "padReleaseDelay": 0.1, "boxReleaseDelay": 0.0, "resultDelay": 0.83},
  "tutorial": {"enabled": false, "at": 0, "row": 0, "col": 0},
  "endgame": {"speedMultiplier": 1.0, "rampSeconds": 0.15, "praise": false},
  "nextRect": {"x": 0.3, "y": 0.905, "w": 0.4, "h": 0.07},
  "layout": {"version": 1, "seed": 14828430738318, "chapter": 1, "role": "normal", "class": "shallow", "silhouette": "stadium", "loopFamily": "ring", "loopSignature": "jjihgffghijjjjihgffghijj", "pitFamily": "small", "pitOutline": "###/.##", "formation": "stadium|diagonal|###/##.",
    "control": [[-11.925, 0, 6.615], [11.925, 0, 6.615], [11.925, 13.5, 6.615], [-11.925, 13.5, 6.615]],
    "feeders": [{"side": 1, "kind": "diagonal"}],
    "stream": "1x20 4x20 2x20 3x20 0x20"},
  "witness": "60:1.1 90:1.2 120:1.3 150:2.2 963:2.3",
  "note": "Generated by the Block Loop Shooter level generator (seed 14828430738318); every runtime field is derived from the layout block."
}

Fields

FieldMeaning
id, title, numberIdentity; number is the level number shown by the shell.
aspectWidth / height of the board the normalised coordinates refer to; the camera fit keeps it visible in any portrait window.
coinsText, reward, rewardX2, newFeature, tutorialText, nextRectUsed only by the game's built-in result screen and HUD. Under the kit shell (the shipped flow) the win reward is WinCoinReward and the kit's cards are shown.
coloursThe level's palette: name (referenced everywhere below) and hex colour.
track.shapeSilhouette name (informative).
track.rows, lanesRows on the loop and blocks per row (5). loop must add up to rows.
track.rowsPerSecondTrain speed.
track.stretchEntryU, stretchRowsWhere the firing stretch starts on the loop (in rows) and how long it is.
track.fireRate, fireRampSeconds, fireRampStart, fireDelay, cubeRemoveDelayShots per second, the ramp from fireRampStart × rate to full rate, the delay before a parked shooter's first shot, and how long a hit block stays visible.
track.halfWidth, centrelineTrack half width and the loop's centre line: points [x, y, u] in normalised screen coordinates with u the distance along the loop in rows.
track.loopThe blocks on the loop at the start, as runs {"colour", "rows"} from row 0; colour "empty" leaves rows empty.
track.feedersFeeder lanes: id (TL top left, TR top right), junction u on the loop, runs of rows waiting in the lane (front first), the lane's drawn path.
pads, padRadius, extraPad (optional)The four pad centres and their radius. Pad + opens a fifth pad next in the row (or at extraPad when given).
pit.cols, rows, x0, y0, dx, dyThe pit grid: size, centre of cell (row 1, column 1) and the cell pitch. Row 1 is the top (mouth) row.
pit.cellsOccupied cells: kind shooter or hidden with a colour (optional ammo, default 100), or box with dir (−1 releases to the left, 1 to the right) and a queue of colours. Missing cells are empty.
timingBoard entry animation and when input starts (inputFrom seconds), shooter jump and exit times, pad and box release delays, the delay before the result.
tutorialThe built-in tutorial hand (on for the first level only).
endgameTrain speed multiplier, ramp and fire multiplier once the pit is empty; praise shows praise words.
layoutThe generator's description the runtime fields are derived from: seed, chapter, role, board class, silhouette, the loop family and signature computed from its shape, pit family and outline, formation key, the loop's control polygon ([x, z, corner radius] in world rows), the feeders (side −1 left / 1 right and kind), and the stream of runs as colourIndex x rows. The game ignores it; the editor rebuilds the level from it.
witnessA winning tap list step:row.column (10 ms steps). The game ignores it; the tools require it.
noteA free note: on generated levels the generator's note with the seed, on the two authored levels a short description. Nothing reads it.

CampaignAuthoring.json in the same folder lists every level (index, formation, payload = the file's exact text, witness) with the saved request; the tools compare it with the files before every save. The two authored levels are the generator's anchor levels: it plans the campaign around them and never regenerates them, and their formation keys start with anchor-oval (level 1) and anchor-heart (level 200).

Customization

Limitations

AI Disclosure

Assets/Game/AI-DISCLOSURE.txt lists every AI-generated or AI-assisted file of this folder by path: the three booster icons and three first-use pictures (generated in 2026-10 with an OpenAI image model; they carry content credentials), the two generated alternate 3D model sets in Resources/NativeModels (text-to-3D and image-to-3D; service not recorded), and the AI assistance with code, levels and documentation, including that the two authored levels were built by version 1's AI agent. Facts that were not recorded are marked "not recorded".

Support

Contact satisvizion@gmail.com. Please include your Unity version, the package version (Block Loop Shooter version 3) and the steps that reproduce the problem. Never send account credentials or signing keys.