public void StartGeneration()
        {
            if (running)
            {
                return;
            }

            if (started)
            {
                StopGeneration();
            }

            tileOutput?.ClearTiles();

            var generator = GetComponent <TesseraGenerator>();

            helper = generator.CreateTesseraGeneratorHelper();
            helper.Setup();
            // TODO: Should be *all tiles* to start with
            lastTiles    = helper.Propagator.ToValueSets <ModelTile>();
            lastStepTime = GetTime();
            tileOutput   = generator.GetComponent <ITesseraTileOutput>() ?? new UpdatableInstantiateOutput(transform);
            if (!tileOutput.SupportsIncremental)
            {
                throw new Exception($"Output {tileOutput} does not support animations");
            }
            supportsCubes = generator.GetComponent <ITesseraTileOutput>() == null;
            hasObject     = new bool[helper.Propagator.Topology.IndexCount];
            cubesByIndex  = new GameObject[helper.Propagator.Topology.IndexCount];
            started       = true;

            ResumeGeneration();
        }
        void Step()
        {
            if (!running)
            {
                return;
            }

            if (gameObject == null)
            {
                StopGeneration();
            }

            if (GetTime() < lastStepTime + secondsPerStep)
            {
                return;
            }

            var generator = GetComponent <TesseraGenerator>();

            var propagator = helper.Propagator;
            var topology   = propagator.Topology;

            propagator.Step();
            lastStepTime = GetTime();
            if (propagator.Status != DeBroglie.Resolution.Undecided)
            {
                started = false;
                PauseGeneration();
            }

            var tiles = propagator.ToValueSets <ModelTile>();

            var mask            = topology.Mask;
            var maskOrProcessed = mask.ToArray();

            var updateInstances = new List <TesseraTileInstance>();

            var tileCount = helper.Propagator.TileModel.Tiles.Count();
            var minScale  = 0.1f;
            var maxScale  = 1.0f;

            foreach (var i in topology.GetIndices())
            {
                // Skip indices that are masked out or already processed
                if (!maskOrProcessed[i])
                {
                    continue;
                }

                var before = lastTiles.Get(i);
                var after  = tiles.Get(i);

                // Skip if nothing has changed
                if (before.SetEquals(after))
                {
                    continue;
                }


                if (after.Count == 1)
                {
                    topology.GetCoord(i, out var x, out var y, out var z);
                    var p = new Vector3Int(x, y, z);

                    var modelTile = after.Single();
                    var ti        = generator.GetTesseraTileInstance(x, y, z, modelTile);

                    foreach (var p2 in ti.Cells)
                    {
                        if (GeometryUtils.InBounds(p2, generator.size))
                        {
                            var i2 = topology.GetIndex(p2.x, p2.y, p2.z);
                            ClearCube(i2);
                            maskOrProcessed[i2] = true;
                            hasObject[i2]       = true;
                        }
                    }

                    updateInstances.Add(ti);
                }
                else
                {
                    topology.GetCoord(i, out var x, out var y, out var z);

                    maskOrProcessed[i] = true;

                    // Draw cube
                    ClearCube(i);
                    if (uncertaintyTile != null && supportsCubes)
                    {
                        var p = new Vector3Int(x, y, z);

                        var c     = cubesByIndex[i] = Instantiate(uncertaintyTile, generator.transform.TransformPoint(generator.GetLocalPosition(p)), Quaternion.identity, generator.transform);
                        var scale = (maxScale - minScale) * after.Count / tileCount + minScale;
                        c.transform.localScale = Vector3.one * scale;
                    }

                    // Remove object
                    if (hasObject[i])
                    {
                        updateInstances.Add(new TesseraTileInstance
                        {
                            Cells = new[] { new Vector3Int(x, y, z) }
                        });
                        hasObject[i] = false;
                    }
                }
            }

            tileOutput.UpdateTiles(updateInstances);
            lastTiles = tiles;
        }