public IStoryLayoutInstance ArrangeAndDecorate(IStoryGraph sg)
        {
            var springModel = new NestedCirclesStorySpringModel(coroutineService, x => ArrangeAndDecorateInternal(sg.Root, 0, x, sg), sg);

            springModel.Apply();
            return(new BasicStoryLayoutInstance(sg));
        }
        private void ArrangeAndDecorateInternal(int nodeIndex, int level, NestedCirclesStorySpringModel springModel, IStoryGraph sg)
        {
            var node   = sg.NodeObjects[nodeIndex];
            var aspect = sg.Aspects[nodeIndex];
            var index  = node.Id;

            var dynamicParts = new StoryNodeDynamicParts();
            var scale        = springModel.GetVisualRadius(index);
            var visualElems  = new List <IVisualElement>
            {
                new ModelVisualElement <object>(null)
                .SetModel(circleModel)
                .SetMaterial(circleMaterials[level % circleMaterials.Length])
                .SetRenderState(circleRenderState)
                .SetTransform(Transform.Scaling(scale))
                .SetTransformSpace(TransformSpace.ScreenAlighned)
            };

            var transform = Transform.Translation(new Vector3(springModel.GetPosition(index), 0));

            node.Transform = transform;

            if (level == 0)
            {
                var edgeVisuals = sg.Edges.Select(edge => CreateEdgeVisualElement(node, sg.NodeObjects[edge.First], sg.NodeObjects[edge.Second]));
                visualElems.AddRange(edgeVisuals);
            }

            if (sg.Children[index].Any())
            {
                foreach (var childIndex in sg.Children[index])
                {
                    ArrangeAndDecorateInternal(childIndex, level + 1, springModel, sg);
                }
            }

            dynamicParts.VisualElements            = visualElems;
            dynamicParts.Hittable                  = new CircleHittable <ISceneNode>(node, Transform.Identity, x => new Circle2(Vector2.Zero, scale), x => - 0.01f * level);
            dynamicParts.DefaultViewpointMechanism = new OrthoDefaultViewpointMechanism(node, new PlaneOrthoBoundControlledCamera.Props
            {
                Target   = Vector2.Zero,
                Distance = 1.5f * scale,
                ZNear    = 0.1f,
                ZFar     = 1000f
            });
            aspect.SetDynamicParts(dynamicParts);
        }