No-Code Setup

Both scenes in this sample (NoCode_MenuScene.unity and NoCode_LevelScene.unity) come pre-wired — every button, event, and cross-scene handoff is already connected. Everything below this point documents what’s already there and how to adapt it. All connections use Unity’s Inspector (drag & drop, UnityEvent wiring) — no C# needed anywhere in this sample.

This sample ships with no custom art. Both scenes use Unity’s default UI Button/Text styling, flat colors, and unstyled panels — there are no custom sprites, fonts, icons, or layout polish. “Pre-wired” means the wiring and logic are done, not that the screens are finished. Before shipping, restyle the Canvas, buttons, panels, and board backdrop with your own art — see Bundled assets and Before you ship below for what’s safe to restyle without breaking the wiring.

Two things are still required before pressing Play, even though nothing else needs wiring:

  1. Add both scenes to Build Settings (File ▸ Build Settings ▸ Scenes In Build) — the
    menu-to-level and level-to-menu transitions call SceneManager.LoadScene by name, which
    throws if the scene isn’t registered there, even in the Editor.
  2. Assign (or create) an AquariumGameConfig — without one, NoCode_MenuScene spawns no
    size buttons at all (see below), and any other config-dependent field falls back to whatever
    the project has at the canonical Resources path, which is nothing until you run
    Tools ▸ Aquarium ▸ Project Setup ▸ Create Project Configuration at least once. Every
    empty Game Config/Registry field in this sample’s Inspectors has an Assign button
    that does this for you in one click — finds an existing project asset of that type, or
    creates one via Project Setup, and drops it into the field.

What’s already wired

NoCode_LevelScene — has no board-size buttons of its own. The board size always comes from whatever the menu scene sent over (a specific level, or a category via the size buttons there) — that’s what AquariumSceneHandoff is for. Press Play directly in this scene (without going through the menu first) and it falls back to PuzzleController‘s Default Board Width/Height (6×6). What’s wired:

  • A board (AquariumPuzzleBoardView) wired to a PuzzleController, which reads the pending
    SceneHandoff selection on Start automatically.
  • Check and Reset buttons, a status text, and an optional ProgressTracker that
    marks the current level complete on solve.
  • Next Level → AquariumPuzzleController.LoadNextLevel — advances within the level’s
    collection if one is active, otherwise generates another random puzzle at the same size.
  • Back to Menu → a small AquariumSceneLoader component (Scene Name = NoCode_MenuScene).
    UnityEvents in the Inspector can’t call static methods like SceneManager.LoadScene
    directly, so this component exists purely to give Button.onClick something to call.
  • The board sits inside a PlayArea panel that leaves room for the buttons around it.
    AquariumBoardAutoFit (wired to OnPuzzleLoaded) scales the board down to fit PlayArea
    only when a puzzle is big enough to need it — a 6×6 or 10×10 board renders at its normal
    cell size; a 15×15 board shrinks just enough to stay clear of the buttons.

NoCode_MenuScene — press Play to see one size button per category in your assigned AquariumGameConfig (three, for the default 6×6/10×10/15×15 categories), plus an (empty) authored-level panel:

  • LevelMenuController reads its Game Config field on Start and auto-spawns one
    AquariumRandomButton into the RandomButtonsPanel for every category it finds there — add
    or remove a category in the config and the buttons follow automatically, nothing to re-wire.
    If no config is assigned or found (see Two things are still required above), no buttons
    spawn at all and a warning is logged instead.
  • Levels (assign your collections) panel is empty until you assign your own
    AquariumLevelCollection assets — see below. This is the one part of the sample that
    can’t ship pre-filled, since it’s exactly the content you’re meant to author yourself.
  • Picking a size or a level writes into the SceneHandoff asset and immediately loads
    NoCode_LevelScene via the same AquariumSceneLoader component used for “Back to Menu” —
    both scenes are already connected end to end, press Play and click through.

Everything past this point is either (a) how to connect your own levels into the parts that ship empty, or (b) a from-scratch reference if you want to rebuild the layout differently than the bundled one.


Connecting and changing your levels

The authored-level list ships empty on purpose, since your levels are the one thing the sample can’t guess. The recommended way to fill it in is the registry — one project-wide list that every scene can read automatically, so you only maintain your levels in one place:

  1. Author some levels: Assets ▸ Create ▸ Aquarium ▸ Puzzle Asset, or use
    Tools > Aquarium > Puzzle Workbench to draw/generate them.
  2. Group them: Assets ▸ Create ▸ Aquarium ▸ Level Collection, drag your levels into it
    (or use the AquariumLevelCollectionMode presets — ByTheme / ByDifficulty / BySize
    — and the “Add all matching levels” button in the collection’s Inspector).
  3. Run Tools ▸ Aquarium ▸ Project Setup ▸ Sync Project Level Collection Registry (this also
    creates the project’s AquariumLevelCollectionRegistry asset the first time, if one doesn’t
    exist yet). This scans the project for every AquariumLevelCollection and lists them in the
    registry — run it again any time you add, remove, or rename a collection.
  4. Leave LevelMenuController‘s Collections field empty. Press Play — the level list fills
    in from the registry immediately, nothing else to wire. (If the field isn’t already empty,
    clear it — see Collections vs. the registry below for why a non-empty one wins instead.)

If you’d rather link a specific registry asset instead of relying on it being auto-discovered from the project’s canonical Resources path, drag it onto LevelMenuController‘s own Registry field. This is optional — most projects never need it, since the auto-discovered project registry already does the same job.

Collections vs. the registry

LevelMenuController‘s Collections field is for a curated, hand-picked set that bypasses the registry entirely: a different menu per game mode, a “featured levels” screen, or hiding a work-in-progress collection even though it’s already in the project registry. It’s exclusive, not additive — the moment Collections has one or more entries, the registry (and the Registry field) is ignored completely, and only what’s in Collections shows up. Leave Collections empty to show everything from the registry instead, as described above.

To change which levels show up later (swap a collection, add more levels, remove one): edit the collection asset itself (drag levels in/out, or use the “Add all matching levels” button again after adding new level assets) — LevelMenuController reads it fresh every time the scene starts, nothing to re-wire. If you’re using Collections directly, also add or remove the collection asset itself from that array as needed.

To change the board sizes offered (the 6×6/10×10/15×15 buttons): this sample has no bundled config of its own — click Assign next to the empty Game Config field (on LevelMenuController or PuzzleController), or run Tools > Aquarium > Project Setup > Create Project Configuration directly, then edit its categories there. The buttons in this sample reference categories by id (size_6x6, size_10x10, size_15x15), so renaming a category’s id means updating the matching AquariumRandomButton‘s Category Id field too (or switch that button over to AquariumCategoryDropdownPopulator, which reads whatever categories exist automatically — see Filters (optional) below).

Scene transitions already work in both directions via AquariumSceneLoader (a tiny helper that just calls SceneManager.LoadScene — UnityEvents in the Inspector can’t target static methods directly, so this component exists to give a Button something to call):

  • Menu → Level: wired onto LevelMenuController‘s OnLevelSelected/OnRandomCategoryRequested,
    alongside the SceneHandoff calls.
  • Level → Menu: the Back to Menu button in the level scene.

Both scenes must be added to File ▸ Build Settings ▸ Scenes In Build for SceneManager.LoadScene to find them by name — Unity throws otherwise. If you rename either scene file, update the matching AquariumSceneLoader‘s Scene Name field to match.


Building it yourself from scratch (reference)

Everything below documents how the bundled scenes were put together, in case you want a different layout, a ScrollView instead of the plain stacked panel, or Dropdown-based filters instead of the three fixed size buttons. None of it is required just to use the sample.


NoCode_MenuScene — Level Select Menu

Goal

A menu with two sections:

  • Random puzzle buttons — one per board-size category defined in your config asset.
  • Authored level buttons — scrollable list from your collections, filterable by difficulty and size.

Clicking anything fires an event you route to your gameplay scene or controller.


Step 1 — Canvas & EventSystem

GameObject → UI → Canvas (Screen Space – Overlay recommended). Unity creates an EventSystem automatically.


Step 2 — Random Puzzle Buttons

This is the recommended approach: place buttons manually, pick the category in the Inspector.

For each board size you want to offer:

  1. GameObject → UI → Button — style it as you like.
  2. Add Component → Aquarium Puzzle No Code → Aquarium Random Button.
  3. In the component Inspector:
    • Config — assign your AquariumGameConfig asset (or leave empty to use the project config from Resources).
    • Category — a dropdown appears with all categories from the config (e.g. 6×6, 10×10, 15×15). Pick the one for this button.
    • Category Name Text — optionally assign a child Text to auto-fill the label.
  4. Wire the Button’s onClick → AquariumRandomButton.Click.
  5. Wire OnClicked → AquariumPuzzleController.GenerateRandomByCategoryId
    (works across scenes via a persistent manager, or directly if both are in the same scene).

Tip: duplicate the button for each category — change only the Category dropdown.


Step 3 — Authored Level Buttons

3a. Create a Level Button Prefab

  • GameObject → UI → Button — style it as you like.
  • Add Component → Aquarium Puzzle No Code → Aquarium Level Button.
  • Optionally add child Text objects and assign them to Level Name Text / Level Size Text / Level Difficulty Text — they are filled automatically.
  • Wire the Button’s onClick → AquariumLevelButton.Click.
  • Save as a Prefab.

3b. Create a ScrollView

  • GameObject → UI → Scroll View.
  • Add a Vertical Layout Group on the Content child (recommended for auto-stacking).

3c. Create the LevelMenuController

  • Create an empty GameObject, name it LevelMenuController.
  • Add Component → Aquarium Puzzle No Code → Aquarium Level Menu Controller.
  • Collections — assign your AquariumLevelCollection asset(s).
  • Level Button Container — assign the ScrollView’s Content.
  • Level Button Prefab — assign the prefab from step 3a.
  • Wire On Level Selected → AquariumPuzzleController.LoadLevel.

Step 4 — Filters (optional)

Filter by difficulty:

  • GameObject → UI → Dropdown, options: All / Easy / Medium / Hard.
  • Dropdown.onValueChanged → AquariumLevelMenuController.FilterByDifficulty.

Filter by size (recommended way):

  • GameObject → UI → Dropdown.
  • Add Component → Aquarium Puzzle No Code → Aquarium Category Dropdown Populator.
  • Assign the same Dropdown, tick Include All Option, optionally assign Config
    (leave empty to use the project config from Resources).
  • Wire On Category Selected → AquariumLevelMenuController.FilterBySizeByCategoryId.
  • The populator builds the dropdown’s options from the config itself, so there’s nothing to
    keep in sync by hand, and “All” always means the empty-string id it reports.

Filter by size (manual alternative):

  • GameObject → UI → Dropdown, options: All + one entry per category in the config
    (e.g. All / 6×6 / 10×10 / 15×15). Order must match the category order in the config asset —
    if you add or reorder categories later, update the Dropdown’s options too, or switch to the
    populator above.
  • Dropdown.onValueChanged → AquariumLevelMenuController.FilterBySizeByIndex.

Clear all filters button:

  • Button.onClick → AquariumLevelMenuController.ClearFilters.

NoCode_LevelScene — Gameplay

Goal

A board view with buttons for Generate, Check, Reset, and optional Next/Previous navigation.


Step 1 — Canvas & EventSystem

Same as the menu scene.


Step 2 — Add AquariumPuzzleBoardView

Copy the BoardView GameObject (with its cell and clue prefabs) from the Demo sample’s UGUIDemoScene.unity — it is fully reusable. Restyle it without touching any scripts.


Step 3 — Create the PuzzleController

  • Create an empty GameObject, name it PuzzleController.
  • Add Component → Aquarium Puzzle No Code → Aquarium Puzzle Controller.

Inspector fields to assign:

FieldWhat to assign
Board ViewYour AquariumPuzzleBoardView
Random ConfigYour AquariumGameConfig asset (optional — falls back to project config)
Status TextA Text component (optional)
Default Board Width/HeightStarting size when no category is selected

Step 4 — Wire buttons

Button labelMethod to wire
GenerateAquariumPuzzleController.GenerateRandom
CheckAquariumPuzzleController.CheckMistakes
ResetAquariumPuzzleController.ResetPuzzle
NextAquariumPuzzleController.LoadNextLevel
PreviousAquariumPuzzleController.LoadPreviousLevel

Step 5 — Wire board size selection

Option A — Random buttons in the same scene (recommended)

  • Place AquariumRandomButton components on buttons (see Menu Scene Step 2).
  • Wire OnClicked → AquariumPuzzleController.GenerateRandomByCategoryId.
  • This sets the size from the config and immediately generates a puzzle in one step.

Option B — Dropdown (recommended way)

  • GameObject → UI → Dropdown.
  • Add Component → Aquarium Puzzle No Code → Aquarium Category Dropdown Populator.
  • Assign the same Dropdown and, optionally, Config. Leave Include All Option unticked —
    a board-size selector always needs a concrete category.
  • Wire On Category Selected → AquariumPuzzleController.SetBoardSizeByCategoryId.
  • A separate Generate button → AquariumPuzzleController.GenerateRandom.
  • (Or skip the separate button and wire straight to GenerateRandomByCategoryId instead of
    SetBoardSizeByCategoryId — see Option A above; it sets the size and generates in one call.)

Option B′ — Dropdown (manual alternative)

  • GameObject → UI → Dropdown.
  • Add one option per category in the config asset (order must match — if the config changes
    later, update the Dropdown’s options too, or switch to the populator above).
  • Dropdown.onValueChanged → AquariumPuzzleController.SetBoardSizeByIndex.
  • A separate Generate button → AquariumPuzzleController.GenerateRandom.

Option C — Inspector default

  • Set Default Board Width / Height directly in the controller Inspector.
  • Press Generate — done. No runtime size switching needed.

Step 6 — Wire events (optional)

In the Events section of AquariumPuzzleController:

EventExample use
OnPuzzleSolvedPlay a win sound, show a “Congratulations” panel
OnMistakesFound (int)Flash the board, play an error sound
OnNoMistakesShow a checkmark animation
OnPuzzleLoadedHide a loading spinner
OnStatusChanged (string)Drive a TMP or additional Text component

Passing a selection from the menu scene to the level scene

If NoCode_MenuScene and NoCode_LevelScene are two separate scenes, a plain click event can’t reach across the scene load by itself — you need somewhere to park “what was picked” until the level scene’s Start runs. AquariumSceneHandoff is a small ScriptableObject asset built for exactly this, and needs no C#:

  1. Assets ▸ Create ▸ Aquarium ▸ No-Code ▸ Scene Handoff — make one asset, e.g. SceneHandoff.
  2. Menu scene: wire it into the same events you already wired to AquariumPuzzleController, in
    addition to them:
    • AquariumLevelMenuController.OnLevelSelected → SceneHandoff.SetLevel
    • AquariumLevelMenuController.OnRandomCategoryRequested → SceneHandoff.SetCategory
    • (if you spawn AquariumRandomButtons directly without the menu controller, wire their
      OnClicked → SceneHandoff.SetCategory instead)
  3. Level scene: drag the same asset onto the Scene Handoff field on AquariumPuzzleController.
  4. Trigger your own scene load however you normally do it (a Button wired to SceneManager.LoadScene,
    or any scene-loading asset/router you already use) — the handoff only remembers the selection, it
    does not load scenes itself.

AquariumPuzzleController checks the handoff on Start and, if it holds a pending level or category, loads that instead of its own Default Board Width/Height, then clears the handoff. The asset stays loaded across the scene switch as long as both controllers reference it, exactly like any other asset reference — no singleton, DontDestroyOnLoad, or static field required. (The bundled scenes already have this wired via Config/SceneHandoff.asset — this section is for rebuilding it from scratch.)


Tracking level completion (optional)

AquariumLevelProgressTracker remembers which authored levels a player has finished, using PlayerPrefs. It’s a completion flag only, not a save system — it doesn’t store board state, hints/checks used, currency, or anything else.

Gameplay scene:

  1. Add an empty GameObject, name it ProgressTracker.
  2. Add Component → Aquarium Puzzle No Code → Aquarium Level Progress Tracker.
  3. Puzzle Controller — assign your AquariumPuzzleController.
  4. Wire AquariumPuzzleController.OnPuzzleSolved → AquariumLevelProgressTracker.MarkCurrentLevelComplete.
    Random puzzles have no level id and are silently skipped — nothing to mark complete.

Menu scene — showing a completed badge on level buttons:

  1. On the level button prefab (Step 3a), add a child object for the badge (a checkmark Image
    works well) and assign it to AquariumLevelButton‘s Completed Badge field. It’s hidden
    unless the level is complete.
  2. Add an AquariumLevelProgressTracker to the menu scene too (same steps as above, just without
    the OnPuzzleSolved wiring — the menu only reads completion, it doesn’t write it).
  3. On LevelMenuController (Step 3c), assign that tracker to its Progress Tracker field.

The gameplay scene’s tracker and the menu scene’s tracker can be two separate component instances in two separate scenes — they still share the same completion data, since it’s stored in PlayerPrefs, not on the component. Just keep the Player Prefs Key Prefix field identical on both (it defaults to Aquarium.Completed. and there’s no reason to change it unless this project’s PlayerPrefs namespace already has a collision).

To feed AquariumThematicCollectionsOrder‘s progression queries (TryGetNextUncompletedByDifficulty/BySize), pass the tracker’s IsCompletedCallback method as the isCompleted argument. Those two methods aren’t events, so calling them takes a line of C# — everything above this paragraph needs none.


Currency / reward hookup (optional)

Each board-size category in your AquariumGameConfig can define a RewardCurrencyId/WinReward (and an optional LaunchCostCurrencyId/LaunchCost), set in the config asset’s Inspector. This works for authored levels (with the level’s own CustomCompletionReward as an override) and for random puzzles alike, matched by board size.

No-code path — AquariumCurrencyRewarder:

  1. Add an empty GameObject in the gameplay scene, name it CurrencyRewarder.
  2. Add Component → Aquarium Puzzle No Code → Aquarium Currency Rewarder.
  3. Puzzle Controller — assign your AquariumPuzzleController.
  4. Wire AquariumPuzzleController.OnPuzzleSolved → AquariumCurrencyRewarder.AwardCurrentLevelReward.
  5. Tick Award Currency On Solve to turn payouts on. Leave it ticked; untick it later to pause
    payouts without touching the wiring — useful while you’re still tuning the economy.

That’s it — no C# required. The balance is stored per currency id via PlayerPrefs (same minimal approach as AquariumLevelProgressTracker: one integer per currency, no transaction history, no spending API — launch cost is defined on the config but not deducted by this component). Read a balance for a HUD Text with GetBalance(currencyId), or subscribe to the CurrencyAwarded event from your own script to update it live.

Code path, if you’d rather resolve the reward yourself (e.g. to hand it to an existing wallet system instead of the built-in PlayerPrefs one): call AquariumGameConfig.TryResolveWinReward(level, out currencyId, out amount) for an authored level, or TryGetCategoryForSize(width, height, out category) for a random puzzle (no level asset to pass), from a script wired to OnPuzzleSolved the same way.


Bundled assets

This sample ships these prefabs and one data asset you can reuse or restyle directly, under Samples~/NoCodeIntegration/Prefabs/ and .../Config/:

  • AquariumLevelButton.prefab — the level list button used by LevelMenuController.
  • AquariumRandomButton.prefab — the size-category button used in both scenes.
  • Cell.prefab, ClueText.prefab, Border.prefab — assigned to AquariumPuzzleBoardView‘s
    Cell Prefab, Clue Prefab, and Line Overlay Prefab fields in NoCode_LevelScene: the
    board’s per-cell visual, the row/column clue text, and the line image drawn for region borders
    and (if enabled) cell grid lines. This sample ships its own copies so it works without the
    Demo sample also being imported.
  • Config/SceneHandoff.asset — the shared handoff asset both scenes already reference.

The same no-custom-art warning from the top of this document applies to all of these — none of them carry final visuals. Restyle them (colors, fonts, adding a background image) and the scenes’ own UI before shipping. The components and their wiring stay intact as long as you don’t remove the Text/Image/Button references each script’s Inspector fields point at.


Before you ship

This sample is a wiring reference, not finished UI. At minimum, before release:

  • Replace the default Unity Button/Text styling on every button and panel in both scenes with
    your own art.
  • Add a background/theme to BoardPanel and the menu Canvas (currently a flat placeholder
    backdrop).
  • Add real category art/labels instead of the plain 6×6 / 10×10 / 15×15 button text.
  • Decide what happens when a random puzzle is solved — it has no level id, so it never gets a
    completion badge (that’s level-id based), but it can still pay out currency by size category
    if you’ve wired Currency / reward hookup above.
  • Fill the empty Levels (assign your collections) panel with your own authored content (see
    Connecting and changing your levels).

Component Reference

ComponentScenePurpose
AquariumRandomButtonMenu or LevelOne button per board-size category. Pick category via Inspector dropdown.
AquariumLevelButtonMenuOne button per authored level. Auto-fills name/size/difficulty labels and a completed badge.
AquariumLevelMenuControllerMenuSpawns level buttons from collections, manages difficulty/size filters.
AquariumPuzzleControllerLevelGameplay: generate, load, check, reset. Reads sizes from config.
AquariumSceneHandoffMenu + Level (shared asset)Carries a level/category selection from the menu scene to the level scene across a scene load. Optional — only needed when they’re separate scenes.
AquariumCategoryDropdownPopulatorMenu or LevelFills a Dropdown from the config and reports the selection by category id instead of a raw index. Recommended over SetBoardSizeByIndex/FilterBySizeByIndex.
AquariumLevelProgressTrackerMenu and/or LevelMarks authored levels complete in PlayerPrefs and reports completion back. Optional.
AquariumCurrencyRewarderLevelPays out the solved puzzle’s configured currency reward (authored or random) into a PlayerPrefs balance. Optional.
AquariumSceneLoaderMenu and LevelCalls SceneManager.LoadScene(sceneName) — exists so a Button.onClick (or another UnityEvent) has something to call, since events can’t target static methods directly.
AquariumBoardAutoFitLevelScales the board down to fit an available-space rectangle, only when it would otherwise be too big for it. Wired to OnPuzzleLoaded.

Tips

  • AquariumRandomButton category is selected via dropdown in the Inspector — no string IDs to type.
  • GenerateRandomByCategoryId sets the size and generates in a single call — one wiring in the Inspector covers both actions.
  • For any other Dropdown that should pick a category, use AquariumCategoryDropdownPopulator and wire
    its On Category Selected to a ...ByCategoryId method (SetBoardSizeByCategoryId,
    GenerateRandomByCategoryId, FilterBySizeByCategoryId). It builds the options from the config itself,
    so there’s no “Dropdown order must match config order” bookkeeping and no risk of an off-by-one.
  • The older SetBoardSizeByIndex / FilterBySizeByIndex methods still work and are still wired above as
    manual alternatives, but they take a raw int and disagree with each other on what index 0 means
    (first category vs. “All”) — prefer the populator + ...ByCategoryId pairing for new setups.