diff --git a/Assets/Resources/Prefabs/Facts/Circle.prefab b/Assets/Resources/Prefabs/Facts/Circle.prefab
index e9b352131d9a177cba1d7de192ae16fa71dfa22a..f32e8f44c0ce01f542f76b77a8f713da96011b2a 100644
--- a/Assets/Resources/Prefabs/Facts/Circle.prefab
+++ b/Assets/Resources/Prefabs/Facts/Circle.prefab
@@ -436,7 +436,7 @@ Transform:
   m_PrefabAsset: {fileID: 0}
   m_GameObject: {fileID: 6839596689016440457}
   m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
-  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalPosition: {x: -0.019, y: 0, z: 0}
   m_LocalScale: {x: 1, y: 1, z: 1}
   m_ConstrainProportionsScale: 0
   m_Children:
@@ -457,13 +457,14 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: 405087c38b8537e43bcc99727c5325ec, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
-  radius: 1
-  sideCount: 500
-  circleMesh:
+  Meshs:
   - {fileID: 7167210412035754299}
   - {fileID: 3164742056485930267}
   - {fileID: 1312883106029576503}
   - {fileID: 6626359674163989219}
+  NormalOffset: []
+  radius: 1
+  sideCount: 500
 --- !u!114 &6950663371922587874
 MonoBehaviour:
   m_ObjectHideFlags: 0
diff --git a/Assets/Resources/Prefabs/Facts/Cone.prefab b/Assets/Resources/Prefabs/Facts/Cone.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..035e2830d680e4a450612ec39bc6dbaea5dc53f7
--- /dev/null
+++ b/Assets/Resources/Prefabs/Facts/Cone.prefab
@@ -0,0 +1,662 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &2317807655120713368
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5818562496562931847}
+  - component: {fileID: 2028494018615604281}
+  - component: {fileID: 77904359947812862}
+  m_Layer: 17
+  m_Name: Cone
+  m_TagString: Selectable
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &5818562496562931847
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317807655120713368}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 2267903722640728620}
+  - {fileID: 1517323377706769618}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &2028494018615604281
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317807655120713368}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 626c435b76e0d334f959ede8b54b07ac, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  _URI: 
+  FactText:
+  - {fileID: 1723009895384754658}
+  StringLabelFormats:
+  - '{0}'
+  Default: {fileID: 0}
+  Selected: {fileID: 0}
+  Hint: {fileID: 0}
+  Solution: {fileID: 0}
+  renderer: []
+--- !u!114 &77904359947812862
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317807655120713368}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 171f36100fbf6384591cca35fc917317, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  Meshs:
+  - {fileID: 6398251481098695290}
+  - {fileID: 8620665629189134186}
+  - {fileID: 2701943617241909663}
+  NormalOffset:
+  - 0
+  - 0
+  - 0
+  AlternateNormals: 0
+  bottomRadius: 1
+  topRadius: 0.5
+  topPosition: {x: 0, y: 2, z: 0}
+  sideCount: 50
+--- !u!1 &4853696702160906218
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7972877566157790116}
+  - component: {fileID: 2096909858734684758}
+  - component: {fileID: 1723009895384754658}
+  - component: {fileID: 1586728893263614116}
+  m_Layer: 17
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &7972877566157790116
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 1517323377706769618}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 4, y: 0.5}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!23 &2096909858734684758
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_Enabled: 1
+  m_CastShadows: 0
+  m_ReceiveShadows: 0
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 1
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!114 &1723009895384754658
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_text: Test
+  m_isRightToLeft: 0
+  m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+  m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+  m_fontSharedMaterials: []
+  m_fontMaterial: {fileID: 0}
+  m_fontMaterials: []
+  m_fontColor32:
+    serializedVersion: 2
+    rgba: 4294967293
+  m_fontColor: {r: 0.993, g: 1, b: 1, a: 1}
+  m_enableVertexGradient: 0
+  m_colorMode: 3
+  m_fontColorGradient:
+    topLeft: {r: 1, g: 1, b: 1, a: 1}
+    topRight: {r: 1, g: 1, b: 1, a: 1}
+    bottomLeft: {r: 1, g: 1, b: 1, a: 1}
+    bottomRight: {r: 1, g: 1, b: 1, a: 1}
+  m_fontColorGradientPreset: {fileID: 0}
+  m_spriteAsset: {fileID: 0}
+  m_tintAllSprites: 0
+  m_StyleSheet: {fileID: 0}
+  m_TextStyleHashCode: -1183493901
+  m_overrideHtmlColors: 0
+  m_faceColor:
+    serializedVersion: 2
+    rgba: 4294967295
+  m_fontSize: 4
+  m_fontSizeBase: 4
+  m_fontWeight: 400
+  m_enableAutoSizing: 0
+  m_fontSizeMin: 18
+  m_fontSizeMax: 72
+  m_fontStyle: 0
+  m_HorizontalAlignment: 2
+  m_VerticalAlignment: 256
+  m_textAlignment: 65535
+  m_characterSpacing: 0
+  m_wordSpacing: 0
+  m_lineSpacing: 0
+  m_lineSpacingMax: 0
+  m_paragraphSpacing: 0
+  m_charWidthMaxAdj: 0
+  m_enableWordWrapping: 1
+  m_wordWrappingRatios: 0.4
+  m_overflowMode: 0
+  m_linkedTextComponent: {fileID: 0}
+  parentLinkedComponent: {fileID: 0}
+  m_enableKerning: 1
+  m_enableExtraPadding: 0
+  checkPaddingRequired: 0
+  m_isRichText: 1
+  m_parseCtrlCharacters: 1
+  m_isOrthographic: 0
+  m_isCullingEnabled: 0
+  m_horizontalMapping: 0
+  m_verticalMapping: 0
+  m_uvLineOffset: 0
+  m_geometrySortingOrder: 0
+  m_IsTextObjectScaleStatic: 0
+  m_VertexBufferAutoSizeReduction: 1
+  m_useMaxVisibleDescender: 1
+  m_pageToDisplay: 1
+  m_margin: {x: 0, y: 0, z: 0, w: 0}
+  m_isUsingLegacyAnimationComponent: 0
+  m_isVolumetricText: 0
+  _SortingLayer: 0
+  _SortingLayerID: 0
+  _SortingOrder: 0
+  m_hasFontAssetChanged: 0
+  m_renderer: {fileID: 2096909858734684758}
+  m_maskType: 0
+--- !u!114 &1586728893263614116
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 8cf5a358dacd3b54ab093ee289dd9ba2, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  Cam1: {fileID: 0}
+  Cam2: {fileID: 0}
+  BackUPCam: {fileID: 0}
+--- !u!1 &6028669276398914237
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2267903722640728620}
+  m_Layer: 17
+  m_Name: PolyMeshs
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &2267903722640728620
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6028669276398914237}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 3517099398133763913}
+  - {fileID: 2374130608748553515}
+  m_Father: {fileID: 5818562496562931847}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &6247621022589904505
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4678806186037624479}
+  - component: {fileID: 2701943617241909663}
+  - component: {fileID: 4008433908760336842}
+  m_Layer: 17
+  m_Name: PolyHighlight
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4678806186037624479
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6247621022589904505}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: -0.01, z: 0}
+  m_LocalScale: {x: 1.01, y: 1.01, z: 1.01}
+  m_ConstrainProportionsScale: 1
+  m_Children: []
+  m_Father: {fileID: 2374130608748553515}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &2701943617241909663
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6247621022589904505}
+  m_Mesh: {fileID: 0}
+--- !u!23 &4008433908760336842
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6247621022589904505}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 8ae9adf4dc782964387385c1e8c0eb72, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!1 &6378548342073962023
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 3517099398133763913}
+  - component: {fileID: 6398251481098695290}
+  - component: {fileID: 6015977261426572496}
+  - component: {fileID: 8352602335830303231}
+  - component: {fileID: 9072308735336053453}
+  - component: {fileID: 184519196497952346}
+  m_Layer: 17
+  m_Name: PolyOuter
+  m_TagString: SnapZone
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &3517099398133763913
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: -0.05, z: 0}
+  m_LocalScale: {x: 1.05, y: 1.05, z: 1.05}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 2267903722640728620}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &6398251481098695290
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Mesh: {fileID: 0}
+--- !u!23 &6015977261426572496
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 8ae9adf4dc782964387385c1e8c0eb72, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!64 &8352602335830303231
+MeshCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 4
+  m_Convex: 0
+  m_CookingOptions: 30
+  m_Mesh: {fileID: 0}
+--- !u!95 &9072308735336053453
+Animator:
+  serializedVersion: 4
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Enabled: 1
+  m_Avatar: {fileID: 0}
+  m_Controller: {fileID: 9100000, guid: 7f5a2c4324ecb83488857feb7887b5a7, type: 2}
+  m_CullingMode: 0
+  m_UpdateMode: 0
+  m_ApplyRootMotion: 0
+  m_LinearVelocityBlending: 0
+  m_StabilizeFeet: 0
+  m_WarningMessage: 
+  m_HasTransformHierarchy: 1
+  m_AllowConstantClipSamplingOptimization: 1
+  m_KeepAnimatorControllerStateOnDisable: 0
+--- !u!114 &184519196497952346
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 626c435b76e0d334f959ede8b54b07ac, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  _URI: 
+  FactText: []
+  StringLabelFormats: []
+  Default: {fileID: 2100000, guid: 8ae9adf4dc782964387385c1e8c0eb72, type: 2}
+  Selected: {fileID: 2100000, guid: 34a95baef388bb8458c97a626b732f9f, type: 2}
+  Hint: {fileID: 2100000, guid: 8621b710d7d1d5041bc6bfd0cc37cdff, type: 2}
+  Solution: {fileID: 2100000, guid: 2a003f0807acc1142965bb21bdc824f6, type: 2}
+  renderer:
+  - {fileID: 6015977261426572496}
+--- !u!1 &7289674876073244909
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1517323377706769618}
+  - component: {fileID: 4409226297024899106}
+  m_Layer: 17
+  m_Name: TextAnker
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &1517323377706769618
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7289674876073244909}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 7972877566157790116}
+  m_Father: {fileID: 5818562496562931847}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &4409226297024899106
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7289674876073244909}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0b53a9efe2eaabd4a9ae38ae148bed9e, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  x: 1
+  y: 1
+  z: 1
+  mesh: {fileID: 8620665629189134186}
+--- !u!1 &8536634090652517107
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2374130608748553515}
+  - component: {fileID: 8620665629189134186}
+  - component: {fileID: 2279887988868225897}
+  m_Layer: 17
+  m_Name: PolyInner
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &2374130608748553515
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8536634090652517107}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 4678806186037624479}
+  m_Father: {fileID: 2267903722640728620}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &8620665629189134186
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8536634090652517107}
+  m_Mesh: {fileID: 0}
+--- !u!23 &2279887988868225897
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8536634090652517107}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: a8a7bf60a30970f469a9c9d3ae2de6ef, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
diff --git a/Assets/Resources/Prefabs/Facts/Cone.prefab.meta b/Assets/Resources/Prefabs/Facts/Cone.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..8a1d149b4355711df912ddfbebe19df3145f8487
--- /dev/null
+++ b/Assets/Resources/Prefabs/Facts/Cone.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5ed47fa3432595f4398cb37a4f9bf30d
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Resources/Prefabs/Facts/Line.prefab b/Assets/Resources/Prefabs/Facts/Line.prefab
index 9da29198ba8341ff37f9d4928ef83f2cdf871860..552ad2a748d8501aa9181886d4bb21d8b0569556 100644
--- a/Assets/Resources/Prefabs/Facts/Line.prefab
+++ b/Assets/Resources/Prefabs/Facts/Line.prefab
@@ -46,15 +46,16 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: 626c435b76e0d334f959ede8b54b07ac, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
+  _URI: 
   FactText:
   - {fileID: 1723009895384754658}
   StringLabelFormats:
   - '{0}'
-  renderer: []
   Default: {fileID: 0}
   Selected: {fileID: 0}
   Hint: {fileID: 0}
   Solution: {fileID: 0}
+  renderer: []
 --- !u!1 &4853696702160906218
 GameObject:
   m_ObjectHideFlags: 0
@@ -490,14 +491,15 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: 626c435b76e0d334f959ede8b54b07ac, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
+  _URI: 
   FactText: []
   StringLabelFormats: []
-  renderer:
-  - {fileID: 6015977261426572496}
   Default: {fileID: 2100000, guid: 8ae9adf4dc782964387385c1e8c0eb72, type: 2}
   Selected: {fileID: 2100000, guid: 34a95baef388bb8458c97a626b732f9f, type: 2}
   Hint: {fileID: 2100000, guid: 8621b710d7d1d5041bc6bfd0cc37cdff, type: 2}
   Solution: {fileID: 2100000, guid: 2a003f0807acc1142965bb21bdc824f6, type: 2}
+  renderer:
+  - {fileID: 6015977261426572496}
 --- !u!1 &6754103560634016048
 GameObject:
   m_ObjectHideFlags: 0
diff --git a/Assets/Resources/Prefabs/Facts/Prism.prefab b/Assets/Resources/Prefabs/Facts/Prism.prefab
new file mode 100644
index 0000000000000000000000000000000000000000..9b60a73fb40b72dd858578fa569e899db0a581e5
--- /dev/null
+++ b/Assets/Resources/Prefabs/Facts/Prism.prefab
@@ -0,0 +1,664 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!1 &2317807655120713368
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 5818562496562931847}
+  - component: {fileID: 2028494018615604281}
+  - component: {fileID: 8334482767163788216}
+  m_Layer: 16
+  m_Name: Prism
+  m_TagString: Selectable
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &5818562496562931847
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317807655120713368}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 2267903722640728620}
+  - {fileID: 1517323377706769618}
+  m_Father: {fileID: 0}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &2028494018615604281
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317807655120713368}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 626c435b76e0d334f959ede8b54b07ac, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  _URI: 
+  FactText:
+  - {fileID: 1723009895384754658}
+  StringLabelFormats:
+  - '{0}'
+  Default: {fileID: 0}
+  Selected: {fileID: 0}
+  Hint: {fileID: 0}
+  Solution: {fileID: 0}
+  renderer: []
+--- !u!114 &8334482767163788216
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 2317807655120713368}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 2a639f1d1c3cdeb42bc5a7a66401dc02, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  Meshs:
+  - {fileID: 6398251481098695290}
+  - {fileID: 8620665629189134186}
+  - {fileID: 2701943617241909663}
+  NormalOffset:
+  - 0.05
+  - 0
+  - 0.01
+  AlternateNormals: 0
+  _vertices:
+  - {x: 1, y: 3, z: 1}
+  - {x: 1, y: 0, z: -3}
+  - {x: -4, y: 0, z: -3}
+  - {x: -1, y: 0, z: 1}
+  _offset: {x: 0, y: 0.05, z: 0}
+--- !u!1 &4853696702160906218
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 7972877566157790116}
+  - component: {fileID: 2096909858734684758}
+  - component: {fileID: 1723009895384754658}
+  - component: {fileID: 1586728893263614116}
+  m_Layer: 16
+  m_Name: Text
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!224 &7972877566157790116
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_LocalRotation: {x: -0, y: 0.7071068, z: -0, w: 0.7071068}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 1517323377706769618}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
+  m_AnchorMin: {x: 0.5, y: 0.5}
+  m_AnchorMax: {x: 0.5, y: 0.5}
+  m_AnchoredPosition: {x: 0, y: 0.5}
+  m_SizeDelta: {x: 4, y: 0.5}
+  m_Pivot: {x: 0.5, y: 0.5}
+--- !u!23 &2096909858734684758
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_Enabled: 1
+  m_CastShadows: 0
+  m_ReceiveShadows: 0
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 1
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!114 &1723009895384754658
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 9541d86e2fd84c1d9990edf0852d74ab, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_Material: {fileID: 0}
+  m_Color: {r: 1, g: 1, b: 1, a: 1}
+  m_RaycastTarget: 1
+  m_RaycastPadding: {x: 0, y: 0, z: 0, w: 0}
+  m_Maskable: 1
+  m_OnCullStateChanged:
+    m_PersistentCalls:
+      m_Calls: []
+  m_text: Test
+  m_isRightToLeft: 0
+  m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+  m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
+  m_fontSharedMaterials: []
+  m_fontMaterial: {fileID: 0}
+  m_fontMaterials: []
+  m_fontColor32:
+    serializedVersion: 2
+    rgba: 4294967293
+  m_fontColor: {r: 0.993, g: 1, b: 1, a: 1}
+  m_enableVertexGradient: 0
+  m_colorMode: 3
+  m_fontColorGradient:
+    topLeft: {r: 1, g: 1, b: 1, a: 1}
+    topRight: {r: 1, g: 1, b: 1, a: 1}
+    bottomLeft: {r: 1, g: 1, b: 1, a: 1}
+    bottomRight: {r: 1, g: 1, b: 1, a: 1}
+  m_fontColorGradientPreset: {fileID: 0}
+  m_spriteAsset: {fileID: 0}
+  m_tintAllSprites: 0
+  m_StyleSheet: {fileID: 0}
+  m_TextStyleHashCode: -1183493901
+  m_overrideHtmlColors: 0
+  m_faceColor:
+    serializedVersion: 2
+    rgba: 4294967295
+  m_fontSize: 4
+  m_fontSizeBase: 4
+  m_fontWeight: 400
+  m_enableAutoSizing: 0
+  m_fontSizeMin: 18
+  m_fontSizeMax: 72
+  m_fontStyle: 0
+  m_HorizontalAlignment: 2
+  m_VerticalAlignment: 256
+  m_textAlignment: 65535
+  m_characterSpacing: 0
+  m_wordSpacing: 0
+  m_lineSpacing: 0
+  m_lineSpacingMax: 0
+  m_paragraphSpacing: 0
+  m_charWidthMaxAdj: 0
+  m_enableWordWrapping: 1
+  m_wordWrappingRatios: 0.4
+  m_overflowMode: 0
+  m_linkedTextComponent: {fileID: 0}
+  parentLinkedComponent: {fileID: 0}
+  m_enableKerning: 1
+  m_enableExtraPadding: 0
+  checkPaddingRequired: 0
+  m_isRichText: 1
+  m_parseCtrlCharacters: 1
+  m_isOrthographic: 0
+  m_isCullingEnabled: 0
+  m_horizontalMapping: 0
+  m_verticalMapping: 0
+  m_uvLineOffset: 0
+  m_geometrySortingOrder: 0
+  m_IsTextObjectScaleStatic: 0
+  m_VertexBufferAutoSizeReduction: 1
+  m_useMaxVisibleDescender: 1
+  m_pageToDisplay: 1
+  m_margin: {x: 0, y: 0, z: 0, w: 0}
+  m_isUsingLegacyAnimationComponent: 0
+  m_isVolumetricText: 0
+  _SortingLayer: 0
+  _SortingLayerID: 0
+  _SortingOrder: 0
+  m_hasFontAssetChanged: 0
+  m_renderer: {fileID: 2096909858734684758}
+  m_maskType: 0
+--- !u!114 &1586728893263614116
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 4853696702160906218}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 8cf5a358dacd3b54ab093ee289dd9ba2, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  Cam1: {fileID: 0}
+  Cam2: {fileID: 0}
+  BackUPCam: {fileID: 0}
+--- !u!1 &6028669276398914237
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2267903722640728620}
+  m_Layer: 16
+  m_Name: PolyMeshs
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &2267903722640728620
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6028669276398914237}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 3517099398133763913}
+  - {fileID: 2374130608748553515}
+  m_Father: {fileID: 5818562496562931847}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &6247621022589904505
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 4678806186037624479}
+  - component: {fileID: 2701943617241909663}
+  - component: {fileID: 4008433908760336842}
+  m_Layer: 16
+  m_Name: PolyHighlight
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &4678806186037624479
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6247621022589904505}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 1
+  m_Children: []
+  m_Father: {fileID: 2374130608748553515}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &2701943617241909663
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6247621022589904505}
+  m_Mesh: {fileID: 0}
+--- !u!23 &4008433908760336842
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6247621022589904505}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 8ae9adf4dc782964387385c1e8c0eb72, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 1
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!1 &6378548342073962023
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 3517099398133763913}
+  - component: {fileID: 6398251481098695290}
+  - component: {fileID: 6015977261426572496}
+  - component: {fileID: 8352602335830303231}
+  - component: {fileID: 9072308735336053453}
+  - component: {fileID: 184519196497952346}
+  m_Layer: 16
+  m_Name: PolyOuter
+  m_TagString: SnapZone
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &3517099398133763913
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children: []
+  m_Father: {fileID: 2267903722640728620}
+  m_RootOrder: 0
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &6398251481098695290
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Mesh: {fileID: 0}
+--- !u!23 &6015977261426572496
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: 8ae9adf4dc782964387385c1e8c0eb72, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
+--- !u!64 &8352602335830303231
+MeshCollider:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Material: {fileID: 0}
+  m_IsTrigger: 0
+  m_Enabled: 1
+  serializedVersion: 4
+  m_Convex: 0
+  m_CookingOptions: 30
+  m_Mesh: {fileID: 0}
+--- !u!95 &9072308735336053453
+Animator:
+  serializedVersion: 4
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Enabled: 1
+  m_Avatar: {fileID: 0}
+  m_Controller: {fileID: 9100000, guid: 7f5a2c4324ecb83488857feb7887b5a7, type: 2}
+  m_CullingMode: 0
+  m_UpdateMode: 0
+  m_ApplyRootMotion: 0
+  m_LinearVelocityBlending: 0
+  m_StabilizeFeet: 0
+  m_WarningMessage: 
+  m_HasTransformHierarchy: 1
+  m_AllowConstantClipSamplingOptimization: 1
+  m_KeepAnimatorControllerStateOnDisable: 0
+--- !u!114 &184519196497952346
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 6378548342073962023}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 626c435b76e0d334f959ede8b54b07ac, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  _URI: 
+  FactText: []
+  StringLabelFormats: []
+  Default: {fileID: 2100000, guid: 8ae9adf4dc782964387385c1e8c0eb72, type: 2}
+  Selected: {fileID: 2100000, guid: 34a95baef388bb8458c97a626b732f9f, type: 2}
+  Hint: {fileID: 2100000, guid: 8621b710d7d1d5041bc6bfd0cc37cdff, type: 2}
+  Solution: {fileID: 2100000, guid: 2a003f0807acc1142965bb21bdc824f6, type: 2}
+  renderer:
+  - {fileID: 6015977261426572496}
+--- !u!1 &7289674876073244909
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1517323377706769618}
+  - component: {fileID: 4409226297024899106}
+  m_Layer: 16
+  m_Name: TextAnker
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &1517323377706769618
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7289674876073244909}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: -1.5, y: 1.525, z: -1}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 7972877566157790116}
+  m_Father: {fileID: 5818562496562931847}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &4409226297024899106
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 7289674876073244909}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0b53a9efe2eaabd4a9ae38ae148bed9e, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  x: 1
+  y: 1
+  z: 1
+  mesh: {fileID: 8620665629189134186}
+--- !u!1 &8536634090652517107
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 2374130608748553515}
+  - component: {fileID: 8620665629189134186}
+  - component: {fileID: 2279887988868225897}
+  m_Layer: 16
+  m_Name: PolyInner
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &2374130608748553515
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8536634090652517107}
+  m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_ConstrainProportionsScale: 0
+  m_Children:
+  - {fileID: 4678806186037624479}
+  m_Father: {fileID: 2267903722640728620}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!33 &8620665629189134186
+MeshFilter:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8536634090652517107}
+  m_Mesh: {fileID: 0}
+--- !u!23 &2279887988868225897
+MeshRenderer:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 8536634090652517107}
+  m_Enabled: 1
+  m_CastShadows: 1
+  m_ReceiveShadows: 1
+  m_DynamicOccludee: 1
+  m_StaticShadowCaster: 0
+  m_MotionVectors: 1
+  m_LightProbeUsage: 1
+  m_ReflectionProbeUsage: 1
+  m_RayTracingMode: 2
+  m_RayTraceProcedural: 0
+  m_RenderingLayerMask: 1
+  m_RendererPriority: 0
+  m_Materials:
+  - {fileID: 2100000, guid: a8a7bf60a30970f469a9c9d3ae2de6ef, type: 2}
+  m_StaticBatchInfo:
+    firstSubMesh: 0
+    subMeshCount: 0
+  m_StaticBatchRoot: {fileID: 0}
+  m_ProbeAnchor: {fileID: 0}
+  m_LightProbeVolumeOverride: {fileID: 0}
+  m_ScaleInLightmap: 1
+  m_ReceiveGI: 1
+  m_PreserveUVs: 0
+  m_IgnoreNormalsForChartDetection: 0
+  m_ImportantGI: 0
+  m_StitchLightmapSeams: 0
+  m_SelectedEditorRenderState: 3
+  m_MinimumChartSize: 4
+  m_AutoUVMaxDistance: 0.5
+  m_AutoUVMaxAngle: 89
+  m_LightmapParameters: {fileID: 0}
+  m_SortingLayerID: 0
+  m_SortingLayer: 0
+  m_SortingOrder: 0
+  m_AdditionalVertexStreams: {fileID: 0}
diff --git a/Assets/Resources/Prefabs/Facts/Prism.prefab.meta b/Assets/Resources/Prefabs/Facts/Prism.prefab.meta
new file mode 100644
index 0000000000000000000000000000000000000000..4b979f16cbddd5931deeb36dfa3256a7f09ecf1b
--- /dev/null
+++ b/Assets/Resources/Prefabs/Facts/Prism.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 5a1fad91749b4014a8eb28cd0b21d7a3
+PrefabImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Resources/Prefabs/Facts/Ring.prefab b/Assets/Resources/Prefabs/Facts/Ring.prefab
index 982ebf81f8608900d60cd5ce895a6adb74d56a51..eb4cbbc9950c0f716500bbfb998ac84e9ebf0e86 100644
--- a/Assets/Resources/Prefabs/Facts/Ring.prefab
+++ b/Assets/Resources/Prefabs/Facts/Ring.prefab
@@ -342,7 +342,6 @@ GameObject:
   - component: {fileID: 4775945639457863304}
   - component: {fileID: 2239887596765845809}
   - component: {fileID: 2358573561192576705}
-  - component: {fileID: 7100019936063167720}
   m_Layer: 14
   m_Name: LineHighlight
   m_TagString: Untagged
@@ -415,23 +414,6 @@ MeshRenderer:
   m_SortingLayer: 0
   m_SortingOrder: 0
   m_AdditionalVertexStreams: {fileID: 0}
---- !u!114 &7100019936063167720
-MonoBehaviour:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 7320042660989930446}
-  m_Enabled: 1
-  m_EditorHideFlags: 0
-  m_Script: {fileID: 11500000, guid: 35327f6b479454149a20587eb03337f8, type: 3}
-  m_Name: 
-  m_EditorClassIdentifier: 
-  torusRadius: 1
-  ringRadius: 0.026
-  ringSegmentCount: 50
-  segmentSideCount: 30
-  torusMesh: {fileID: 2239887596765845809}
 --- !u!1 &7644263571880024739
 GameObject:
   m_ObjectHideFlags: 0
@@ -479,11 +461,19 @@ MonoBehaviour:
   m_Script: {fileID: 11500000, guid: 35327f6b479454149a20587eb03337f8, type: 3}
   m_Name: 
   m_EditorClassIdentifier: 
+  Meshs:
+  - {fileID: 6307794999199274257}
+  - {fileID: 213008266423099231}
+  - {fileID: 2239887596765845809}
+  NormalOffset:
+  - 0
+  - 0.025
+  - 0.024
+  AlternateNormals: 0
   torusRadius: 1
-  ringRadius: 0.05
-  ringSegmentCount: 50
-  segmentSideCount: 30
-  torusMesh: {fileID: 6307794999199274257}
+  ringRadius: 0.0544
+  ringSegmentCount: 100
+  segmentSideCount: 20
 --- !u!114 &3963086670126537751
 MonoBehaviour:
   m_ObjectHideFlags: 0
@@ -517,7 +507,6 @@ GameObject:
   - component: {fileID: 5121703917865025706}
   - component: {fileID: 213008266423099231}
   - component: {fileID: 2162055944849665559}
-  - component: {fileID: 8620085494464208677}
   m_Layer: 14
   m_Name: LineInner
   m_TagString: Untagged
@@ -590,20 +579,3 @@ MeshRenderer:
   m_SortingLayer: 0
   m_SortingOrder: 0
   m_AdditionalVertexStreams: {fileID: 0}
---- !u!114 &8620085494464208677
-MonoBehaviour:
-  m_ObjectHideFlags: 0
-  m_CorrespondingSourceObject: {fileID: 0}
-  m_PrefabInstance: {fileID: 0}
-  m_PrefabAsset: {fileID: 0}
-  m_GameObject: {fileID: 8117705180640636930}
-  m_Enabled: 1
-  m_EditorHideFlags: 0
-  m_Script: {fileID: 11500000, guid: 35327f6b479454149a20587eb03337f8, type: 3}
-  m_Name: 
-  m_EditorClassIdentifier: 
-  torusRadius: 1
-  ringRadius: 0.025
-  ringSegmentCount: 50
-  segmentSideCount: 30
-  torusMesh: {fileID: 213008266423099231}
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/FactSpawner.cs b/Assets/Scripts/InteractionEngine/FactHandling/FactSpawner.cs
index 681d0712a89a4f93395dbb69f04365a9d4510344..a958a93c334c40f09e93282dcfd34c3e3009d6d4 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/FactSpawner.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/FactSpawner.cs
@@ -1,7 +1,9 @@
 using System;
 using System.Collections;
+using System.Linq;
 using TMPro;
 using UnityEngine;
+using UnityEngine.UIElements;
 using static CommunicationEvents;
 
 public class FactSpawner : MonoBehaviour
@@ -12,6 +14,8 @@ public GameObject
         Ray,
         Angle,
         Ring,
+        Prism,
+        Cone,
         Circle;
 
     void Start()
@@ -37,6 +41,12 @@ public void SpawnFactRepresentation(Fact fact)
                 SpawnRingAndCircle(CircleFact); break;
             case AttachedPositionFunction AttachedPositionFunction:
                 SpawnAttachedPositionFunction(AttachedPositionFunction); break;
+            case QuadFact QuadFact:
+                SpawnQuad(QuadFact); break;
+            case ConeVolumeFact ConeVolumeFact:
+                SpawnCone(ConeVolumeFact); break;
+            case TruncatedConeVolumeFact TruncatedConeVolumeFact:
+                SpawnTruncatedCone(TruncatedConeVolumeFact); break;
             default: break;
         };
     }
@@ -133,7 +143,7 @@ public void SpawnRing(CircleFact circleFact, Transform parent = null)
     {
         GameObject ring = GameObject.Instantiate(Ring, parent);
 
-        var tori = ring.GetComponentsInChildren<TorusGenerator>();
+        TorusGenerator[] tori = ring.GetComponentsInChildren<TorusGenerator>();
         foreach (var torus in tori)
             torus.torusRadius = circleFact.radius + (float)Math3d.vectorPrecission;
     }
@@ -145,6 +155,53 @@ public void SpawnCircle(CircleFact circleFact, Transform parent = null)
         circle.transform.localScale = Vector3.Scale(circle.transform.localScale, circleFact.LocalScale);
     }
 
+    public void SpawnQuad(QuadFact fact)
+    {
+        GameObject prism = GameObject.Instantiate(Prism);
+        fact.WorldRepresentation = prism.GetComponentInChildren<FactObject3D>();
+        fact.WorldRepresentation.Fact = fact;
+
+        prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation);
+
+        PrismGenerator[] prisms = prism.GetComponentsInChildren<PrismGenerator>();
+        foreach (var gen in prisms)
+            gen.Vertices = fact.Points.Select(p => p.Position).ToArray();
+    }
+
+    public void SpawnCone(ConeVolumeFact fact)
+    {
+        GameObject prism = GameObject.Instantiate(Cone);
+        fact.WorldRepresentation = prism.GetComponentInChildren<FactObject3D>();
+        fact.WorldRepresentation.Fact = fact;
+
+        prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation);
+
+        ConeGenerator[] prisms = prism.GetComponentsInChildren<ConeGenerator>();
+        foreach (var gen in prisms)
+        {
+            gen.topPosition = fact.Point.Position - fact.Circle.Position;
+            gen.topRadius = 0f;
+            gen.bottomRadius = fact.Circle.radius;
+        }
+    }
+
+    public void SpawnTruncatedCone(TruncatedConeVolumeFact fact)
+    {
+        GameObject prism = GameObject.Instantiate(Cone);
+        fact.WorldRepresentation = prism.GetComponentInChildren<FactObject3D>();
+        fact.WorldRepresentation.Fact = fact;
+
+        prism.transform.SetPositionAndRotation(fact.Position, fact.Rotation);
+
+        ConeGenerator[] prisms = prism.GetComponentsInChildren<ConeGenerator>();
+        foreach (var gen in prisms)
+        {
+            gen.topPosition = fact.CircleTop.Position - fact.CircleBase.Position;
+            gen.topRadius = fact.CircleTop.radius;
+            gen.bottomRadius = fact.CircleBase.radius;
+        }
+    }
+
     public void AnimateNonExistingFactTrigger(Fact fact)
     {
         StartCoroutine(_BlossomAndDie(fact));
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs
index 29f40959234283b74420fb120e5766049a2b823d..cab86c43fe4d6423d2e193c7051eea5a9613b68b 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractAngleFact.cs
@@ -64,7 +64,7 @@ protected AbstractAngleFact(string pid1, string pid2, string pid3, float angle,
     public override bool HasDependentFacts => true;
 
     /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new string[] { Pid1, Pid2, Pid3 };
 
     protected override void RecalculateTransform()
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs
index e8aca57e0428fb0c71966556fb045e9663956b16..6e9cdbc21250acff58c6b4011d3a252bb2e5e380 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/AbstractLineFact.cs
@@ -87,7 +87,7 @@ protected override void RecalculateTransform()
     public override bool HasDependentFacts => true;
 
     /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds() 
+    protected override string[] GetDependentFactIds() 
         => new string[] { Pid1, Pid2 };
 }
 
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/CircleFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/CircleFact.cs
new file mode 100644
index 0000000000000000000000000000000000000000..965ef2955f3c270b85feb918dd339f3beee6b507
--- /dev/null
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/CircleFact.cs
@@ -0,0 +1,1037 @@
+using System;
+using System.Collections.Generic;
+using UnityEngine;
+using Newtonsoft.Json;
+using REST_JSON_API;
+
+/// <summary>
+/// A Circle that is made out of a middle point, a plane and a radius
+/// </summary>
+public class CircleFact : FactWrappedCRTP<CircleFact>
+{
+    /// <summary> defining the middle point of the circle  </summary>
+    public string PidCenter;
+    /// <summary>  defining the base point of the circle plane </summary>
+    public string PidBase;
+
+    [JsonIgnore]
+    public PointFact PointCenter { get => (PointFact)FactRecorder.AllFacts[PidCenter]; }
+    [JsonIgnore]
+    public PointFact PointBase { get => (PointFact)FactRecorder.AllFacts[PidBase]; }
+
+    /// <summary>  radius of the circle </summary>
+    public float radius;
+    /// <summary> normal vector of the plane </summary>
+    public Vector3 normal;
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public CircleFact() : base()
+    {
+        this.normal = Vector3.zero;
+        this.PidCenter = null;
+        this.PidBase = null;
+        this.radius = 0;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates <see cref="PidCenter"/>, <see cref="PidBase"/>, <see cref="radius"/>,<see cref="dir1"/>,<see cref="dir2"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="pid1">sets <see cref="PidCenter"/></param>
+    /// <param name="pid2">sets <see cref="PidBase"/></param>
+    /// <param name="radius">sets <see cref="radius"/></param>
+    /// <param name="normal">sets <see cref="normal"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public CircleFact(string pid1, string pid2, float radius, Vector3 normal, FactRecorder organizer) : base(organizer)
+    {
+        this.PidCenter = pid1;
+        this.PidBase = pid2;
+
+        this.radius = radius;
+        this.normal = normal;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = PointCenter.Position;
+        { //Rotation
+            Vector3 arbitary_not_normal = normal == Vector3.forward ? Vector3.right : Vector3.forward;
+            Vector3 forwoard = Vector3.Cross(arbitary_not_normal, normal);
+
+            Rotation = Quaternion.LookRotation(forwoard, normal);
+        }
+        LocalScale = new Vector3(radius, 1, radius);
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Pid1">sets <see cref="PidCenter"/></param>
+    /// <param name="Pid2">sets <see cref="PidBase"/></param>
+    /// <param name="radius">sets <see cref="radius"/></param>
+    /// <param name="normal">sets <see cref="normal"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public CircleFact(string Pid1, string Pid2, float radius, Vector3 normal, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.PidCenter = Pid1;
+        this.PidBase = Pid2;
+
+        this.radius = radius;
+        this.normal = normal;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// <summary>
+    /// parses the Circlefact response of the MMT-Server
+    /// </summary>
+    /// \copydoc Fact.parseFact(ScrollFact) 
+    public new static CircleFact parseFact(MMTFact fact)
+    {
+        if (((MMTGeneralFact)fact).defines is not OMA df)
+            return null;
+
+        OMA planeOMA = (OMA)df.arguments[0];
+        string planeApplicant = ((OMS)planeOMA.applicant).uri;
+
+        Vector3 normal;
+        // Getting the plane
+        // IN case of a normale plane
+        if (planeApplicant.Equals(MMTConstants.pointNormalPlane))
+        {
+            //OMA pointAOMA = (OMA)planeOMA.arguments[0];
+            normal = SOMDoc.MakeVector3((OMA)planeOMA.arguments[1]);
+        }
+        // In case of parametrized plane
+        else if (planeApplicant.Equals(MMTConstants.ParametrizedPlane))
+        {
+            Vector3 v = SOMDoc.MakeVector3((OMA)planeOMA.arguments[1]);
+            Vector3 w = SOMDoc.MakeVector3((OMA)planeOMA.arguments[2]);
+
+            normal = Vector3.Cross(v, w).normalized;
+        }
+        // incase of smth else. Shouldn't hapepen unless there is an error
+        else throw new ArgumentException("Invalid planeApplicant: " + planeApplicant);
+
+        // get the mid point uri
+        string parse_id_M = df.arguments[1].ToString();
+        string M_uri = ParsingDictionary.parseTermsToId[parse_id_M];
+        string A_uri = ParsingDictionary.parseTermsToId[planeOMA.arguments[0].ToString()];
+        float radius = ((OMF)df.arguments[2]).@float;
+
+        if (!FactRecorder.AllFacts.ContainsKey(M_uri)
+         || !FactRecorder.AllFacts.ContainsKey(A_uri))
+            return null; //If dependent facts do not exist return null
+
+        return new CircleFact(M_uri, A_uri, radius, normal, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => "â—‹" + PointCenter.Label;
+
+    /// <summary>
+    /// Constructs struct for right-angled MMT %Fact <see cref="AddFactResponse"/>
+    /// </summary>
+    /// <param name="Pid1"> <see cref="PidCenter"/></param>
+    /// <param name="p2URI"> <see cref="PidBase"/></param>
+    /// <param name="radius"> <see cref="radius"/></param>
+    /// <returns>struct for <see cref="AddFactResponse"/></returns>
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc[] outerArguments = new SOMDoc[]
+        {
+           //CirclePlane,
+           new OMA(
+               //PointNormalPlane,
+               new OMS(MMTConstants.pointNormalPlane), 
+               //planeArgs,
+               new SOMDoc[] {
+                    //base point of the circle plane?,
+                    new OMS(PidBase),
+                    //NormalVector,
+                    new OMA(
+                        //"Vector"
+                        new OMS(MMTConstants.Tuple),
+                        //normalArgs,
+                        new[]  {
+                            new OMF(normal.x),
+                            new OMF(normal.y),
+                            new OMF(normal.z)
+                        }
+                    ),
+                }
+            ),
+           //middlePoint,
+           new OMS(PidCenter),
+           //Radius,
+           new OMF(radius),
+        };
+
+        // Do i need this here? doubt 
+        SOMDoc tp = new OMS(MMTConstants.CircleType3d);
+        SOMDoc df = new OMA(new OMS(MMTConstants.MkCircle3d), outerArguments);
+
+        return new MMTGeneralFact(Label, tp, df);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { PidCenter, PidBase };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(CircleFact f1, CircleFact f2)
+        => DependentFactsEquivalent(f1, f2)
+        && Math3d.IsApproximatelyEqual(f1.normal, f2.normal)
+        && Mathf.Approximately(f1.radius, f2.radius);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new CircleFact(old_to_new[this.PidCenter], old_to_new[this.PidBase], this.radius, this.normal, organizer);
+}
+
+/// <summary>
+/// A RadiusFact that corresponds to a <see cref="CircleFact">PointFacts</see> and has a float value (the actual radius).
+/// </summary>
+public class RadiusFact : FactWrappedCRTP<RadiusFact>
+{
+    /// <summary> The circle corresponding to the radius </summary>
+    public string Cid1;
+
+    [JsonIgnore]
+    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+
+    /// <summary> The radius as a float </summary>
+    public float rad;
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public RadiusFact() : base()
+    {
+        this.Cid1 = null;
+        this.rad = 0.0f;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates <see cref="Cid1"/> and <see cref="rad"/>
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public RadiusFact(string cid1, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+        this.rad = Circle.radius;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Circle.Position;
+        Rotation = Circle.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public RadiusFact(string Cid1, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static RadiusFact parseFact(MMTFact fact)
+    {
+        string CircleUri = ((OMS)((OMA)((MMTValueFact)fact).lhs).arguments[0]).uri;
+
+        if (!FactRecorder.AllFacts.ContainsKey(CircleUri))
+            return null;
+
+        return new RadiusFact(CircleUri, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => "r " + Circle.Label;
+
+    /// <summary>
+    /// Constructs struct for not-right-angled MMT %Fact <see cref="AddFactResponse"/>
+    /// </summary>
+    /// <param name="rad"> see <see cref="rad"/></param>
+    /// <param name="c1URI"> see <see cref="Cid1"/></param>
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc lhs =
+            new OMA(
+                new OMS(MMTConstants.RadiusCircleMetric),
+                new[] {
+                    new OMS(Cid1),
+                }
+            );
+
+        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
+        SOMDoc value = new OMF(rad);
+
+        return new MMTValueFact(this.Label, lhs, valueTp, value);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1 };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(RadiusFact f1, RadiusFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new RadiusFact(old_to_new[this.Cid1], organizer);
+}
+
+/// <summary>
+/// Area of a <see cref="CircleFact">CircleFact</see> 
+/// </summary>
+public class AreaCircleFact : FactWrappedCRTP<AreaCircleFact>
+{
+    /// <summary> the circle <see cref="CircleFact">CircleFact</see>  </summary>
+    public string Cid1;
+
+    [JsonIgnore]
+    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+
+    /// <summary> the area which is contained by the circle </summary>
+    public float A;
+
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public AreaCircleFact() : base()
+    {
+        this.Cid1 = null;
+        this.A = 0.0f;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates <see cref="Cid1"/> and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public AreaCircleFact(string cid1, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+
+        this.A = Circle.radius * Circle.radius * ((float)System.Math.PI);
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Circle.Position;
+        Rotation = Circle.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public AreaCircleFact(string Cid1, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static AreaCircleFact parseFact(MMTFact fact)
+    {
+        string CircleUri = ((OMS)((OMA)((MMTValueFact)fact).lhs).arguments[0]).uri;
+
+        if (!FactRecorder.AllFacts.ContainsKey(CircleUri))
+            return null;
+
+        return new AreaCircleFact(CircleUri, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => "A(" + Circle.Label + ")";
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc lhs =
+            new OMA(
+                new OMS(MMTConstants.AreaCircle),
+                new[] {
+                    new OMS(Cid1),
+                }
+            );
+
+        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
+        SOMDoc value = new OMF(A);
+
+        return new MMTValueFact(this.Label, lhs, valueTp, value);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1 };
+
+    /// \copydoc Fact.GetHashCode
+    public override int GetHashCode()
+        => base.GetHashCode() ^ A.GetHashCode();
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(AreaCircleFact f1, AreaCircleFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new AreaCircleFact(old_to_new[this.Cid1], organizer);
+}
+
+/// <summary>
+/// A <see cref="PointFact"/> on a <see cref="CircleFact"/>
+/// </summary>
+public class OnCircleFact : FactWrappedCRTP<OnCircleFact>
+{
+    /// <summary> the point on the circle  </summary>
+    public string Pid;
+    /// <summary> the circle, which the point is on  </summary>
+    public string Cid;
+
+    [JsonIgnore]
+    public PointFact Point { get => (PointFact)FactRecorder.AllFacts[Pid]; }
+    [JsonIgnore]
+    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid]; }
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public OnCircleFact() : base()
+    {
+        this.Pid = null;
+        this.Cid = null;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates <see cref="Pid"/>, <see cref="Rid"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="pid">sets <see cref="Pid"/></param>
+    /// <param name="cid">sets <see cref="Cid"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public OnCircleFact(string pid, string cid, FactRecorder organizer) : base(organizer)
+    {
+        this.Pid = pid;
+        this.Cid = cid; ;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Point.Position;
+        Rotation = Circle.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="pid">sets <see cref="Pid"/></param>
+    /// <param name="cid">sets <see cref="Cid"/></param>
+    /// <param name="uri">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public OnCircleFact(string pid, string cid, string uri, FactRecorder organizer) : base(organizer)
+    {
+        this.Pid = pid;
+        this.Cid = cid;
+        this._URI = uri;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static OnCircleFact parseFact(MMTFact fact)
+    {
+        if (((MMTGeneralFact)fact).type is not OMA type)
+            return null;
+
+        string circleUri = ((OMS)((OMA)type.arguments[0]).arguments[0]).uri;
+        string pointUri = ((OMS)((OMA)type.arguments[0]).arguments[1]).uri;
+
+        if (!FactRecorder.AllFacts.ContainsKey(pointUri)
+         || !FactRecorder.AllFacts.ContainsKey(circleUri))
+            return null;
+
+        return new OnCircleFact(pointUri, circleUri, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => Point.Label + "∈" + Circle.Label;
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Pid, Cid };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(OnCircleFact c1, OnCircleFact c2)
+        => DependentFactsEquivalent(c1, c2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new OnCircleFact(old_to_new[this.Pid], old_to_new[this.Cid], organizer);
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc tp =
+            new OMA(
+                new OMS(MMTConstants.Ded),
+                new[] {
+                    new OMA(
+                        new OMS(MMTConstants.OnCircle),
+                        new[] {
+                            new OMS(Cid),
+                            new OMS(Pid),
+        }),});
+
+        SOMDoc df = null;
+
+        return new MMTGeneralFact(Label, tp, df);
+    }
+}
+
+/// <summary>
+/// Angle comprised of a line and a circle 
+/// </summary>
+public class AngleCircleLineFact : FactWrappedCRTP<AngleCircleLineFact>
+{
+    /// @{ <summary>
+    /// One <see cref="Fact.Id">Id</see> of a <see cref="RayFact">RayFact</see> and a <see cref="CircleFact">CircleFact</see>  defining Angle [<see cref="Cid1"/>, <see cref="Rid2"/>].
+    /// </summary>
+    public string Cid1, Rid2;
+    /// @}
+
+    [JsonIgnore]
+    public AbstractLineFact Ray { get => (AbstractLineFact)FactRecorder.AllFacts[Rid2]; }
+    [JsonIgnore]
+    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+
+    //TODO? deg or rad?
+    [JsonIgnore]
+    public float angle;
+
+    [JsonIgnore]
+    public Vector3 intersection;
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public AngleCircleLineFact() : base()
+    {
+        this.Cid1 = null;
+        this.Rid2 = null;
+        this.angle = 0.0f;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates <see cref="Cid1"/>, <see cref="Rid2"/>, <see cref="angle"/> <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="rid2">sets <see cref="Rid2"/></param>
+    /// <param name="angle"> sets the angle </param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public AngleCircleLineFact(string cid1, string rid2, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+        this.Rid2 = rid2;
+        this.angle = Math3d.AngleVectorPlane(Ray.Dir, Circle.normal).ToDegrees();
+        Math3d.LinePlaneIntersection(out intersection, Ray.Point1.Position, Ray.Dir, Circle.normal, Circle.Position);
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = intersection;
+        { //Rotation
+            Vector3 from = (Circle.Position - Position).normalized;
+
+            Vector3 angle_to = Math3d.IsApproximatelyEqual(intersection, Ray.Point1.Position)
+                ? Ray.Point2.Position
+                : Ray.Point1.Position;
+            Vector3 to = (angle_to - Position).normalized;
+
+            Vector3 up = Vector3.Cross(to, from);
+            Vector3 forwoard = (from + to).normalized;
+
+            if (up.sqrMagnitude < Math3d.vectorPrecission)
+            { //Angle is 180° (or 0°)
+                Vector3 arbitary = up.normalized == Vector3.forward ? Vector3.right : Vector3.forward;
+                up = Vector3.Cross(arbitary, to);
+                forwoard = Vector3.Cross(up, to);
+            }
+
+            Rotation = Quaternion.LookRotation(forwoard, up);
+        }
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="´Rid2">sets <see cref="Rid2"/></param>
+    /// <param name="angle"> sets the angle </param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public AngleCircleLineFact(string Cid1, string Rid2, float angle, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+        this.Rid2 = Rid2;
+        this.angle = angle;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static AngleCircleLineFact parseFact(MMTFact fact)
+    {
+        if (((MMTValueFact)fact).lhs is not OMA lhs)
+            return null;
+
+        // init it with 0 degrees, so we don't accidentally generate orthogonalfacts 
+        // and the parsing works correctly if smb ever adds a scroll for this
+        float angle = 0.0f;
+
+        if (((MMTValueFact)fact).value is OMF oMFangle)
+            angle = oMFangle.@float;
+
+        string CircleUri = ((OMS)lhs.arguments[0]).uri;
+        string RayUri = ((OMS)lhs.arguments[1]).uri;
+
+        if (!FactRecorder.AllFacts.ContainsKey(CircleUri)
+         || !FactRecorder.AllFacts.ContainsKey(RayUri))
+            return null;
+
+        return new AngleCircleLineFact(CircleUri, RayUri, angle, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => "∠" + Circle.Label + Ray.Label;
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc lhs =
+            new OMA(
+                new OMS(MMTConstants.AnglePlaneLine),
+                new[] {
+                    new OMS(Cid1),
+                    new OMS(Rid2),
+                }
+            );
+
+        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
+        SOMDoc value = new OMF(angle);
+
+        return new MMTValueFact(this.Label, lhs, valueTp, value);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1, Rid2 };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(AngleCircleLineFact f1, AngleCircleLineFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new AngleCircleLineFact(old_to_new[this.Cid1], old_to_new[this.Rid2], organizer);
+}
+
+/// <summary>
+/// The fact that the plane of a <see cref="CircleFact">CircleFact</see> and the line <see cref="RayFact>RayFact</see> are orthogonal
+/// </summary>
+public class OrthogonalCircleLineFact : FactWrappedCRTP<OrthogonalCircleLineFact>
+{
+    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
+    public string Cid1;
+    [JsonIgnore]
+    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+
+    ///  <summary> a <see cref="RayFact">Rayfact</see> describing the line </summary>
+    public string Lid1;
+    [JsonIgnore]
+    public AbstractLineFact Ray { get => (AbstractLineFact)FactRecorder.AllFacts[Lid1]; }
+
+    //TODO? deg or rad?
+    [JsonIgnore]
+    public float angle = 90f;
+
+    [JsonIgnore]
+    public Vector3 intersection;
+
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public OrthogonalCircleLineFact() : base()
+    {
+        this.Cid1 = null;
+        this.Lid1 = null;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates members and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="lid1">sets <see cref="Lid1"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public OrthogonalCircleLineFact(string cid1, string lid1, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+        this.Lid1 = lid1;
+        Math3d.LinePlaneIntersection(out intersection, Ray.Point1.Position, Ray.Dir, Circle.normal, Circle.Position);
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = intersection;
+        { //Rotation
+            Vector3 from = (Circle.Position - Position).normalized;
+
+            Vector3 angle_to = Math3d.IsApproximatelyEqual(intersection, Ray.Point1.Position)
+                ? Ray.Point2.Position
+                : Ray.Point1.Position;
+            Vector3 to = (angle_to - Position).normalized;
+
+            Vector3 up = Vector3.Cross(to, from);
+            Vector3 forward = (from + to).normalized;
+            Rotation = Quaternion.LookRotation(forward, up);
+        }
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="Lid1">sets <see cref="Lid1"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public OrthogonalCircleLineFact(string Cid1, string Lid1, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+        this.Lid1 = Lid1;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static OrthogonalCircleLineFact parseFact(MMTFact fact)
+    {
+        if (((MMTGeneralFact)fact).type is not OMA type)
+            return null;
+
+        string CircleUri = ((OMS)((OMA)type.arguments[0]).arguments[0]).uri;
+        string LineUri = ((OMS)((OMA)type.arguments[0]).arguments[1]).uri;
+
+        if (!FactRecorder.AllFacts.ContainsKey(CircleUri)
+         || !FactRecorder.AllFacts.ContainsKey(LineUri))
+            return null;
+
+        return new OrthogonalCircleLineFact(CircleUri, LineUri, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => Circle.Label + "⊥" + Ray.Label;
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc tp = new OMA(
+            new OMS(MMTConstants.Ded),
+            new[]{
+                new OMA(
+                    new OMS(MMTConstants.OrthoCircleLine),
+                    new[] {
+                        new OMS(Cid1),
+                        new OMS(Lid1),
+                    }
+                ),
+            }
+        );
+
+        SOMDoc df = null;
+
+        return new MMTGeneralFact(this.Label, tp, df);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1, Lid1 };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(OrthogonalCircleLineFact f1, OrthogonalCircleLineFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new OrthogonalCircleLineFact(old_to_new[this.Cid1], old_to_new[this.Lid1], organizer);
+}
+
+/// <summary>
+/// A fact that describes, that two circles have the same size and is comprised of two <see cref="CircleFact">CircleFacts</see> 
+/// </summary>
+public class EqualCirclesFact : FactWrappedCRTP<EqualCirclesFact>
+{
+    /// @{ <summary>
+    /// two circles that are meant to be equal in area
+    /// </summary>
+    public string Cid1, Cid2;
+    /// @}
+
+    [JsonIgnore]
+    public CircleFact Circle1 { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+    [JsonIgnore]
+    public CircleFact Circle2 { get => (CircleFact)FactRecorder.AllFacts[Cid2]; }
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public EqualCirclesFact() : base()
+    {
+        this.Cid1 = null;
+        this.Cid2 = null;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates members and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="cid2">sets <see cref="Cid2"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public EqualCirclesFact(string cid1, string cid2, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+        this.Cid2 = cid2;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Circle1.Position;
+        Rotation = Circle1.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="Cid2">sets <see cref="Cid2"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public EqualCirclesFact(string Cid1, string Cid2, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+        this.Cid2 = Cid2;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static EqualCirclesFact parseFact(MMTFact fact)
+    {
+        if (((MMTGeneralFact)fact).type is not OMA proof_OMA) // proof DED
+            return null;
+
+        OMA parallel_circles_OMA = (OMA)proof_OMA.arguments[0]; // parallel
+
+        string circleAUri = ((OMS)parallel_circles_OMA.arguments[0]).uri;
+        string circleBUri = ((OMS)parallel_circles_OMA.arguments[1]).uri;
+
+        if (!FactRecorder.AllFacts.ContainsKey(circleAUri)
+         || !FactRecorder.AllFacts.ContainsKey(circleBUri))
+            return null;
+
+        return new EqualCirclesFact(circleAUri, circleBUri, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => Circle1.Label + " ≠ " + Circle2.Label;
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc tp = new OMA(
+            new OMS(MMTConstants.Ded),
+            new[] {
+                new OMA(
+                    new OMS(MMTConstants.EqualityCircles),
+                    new[]  {
+                        new OMS(Cid1),
+                        new OMS(Cid2),
+                    }
+                )
+            }
+        );
+
+        SOMDoc df = null;
+
+        return new MMTGeneralFact(this.Label, tp, df);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1, Cid2 };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(EqualCirclesFact f1, EqualCirclesFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new EqualCirclesFact(old_to_new[this.Cid1], old_to_new[this.Cid2], organizer);
+}
+
+/// <summary>
+/// A fact that describes, that two circles have not the same size and is comprised of two <see cref="CircleFact">CircleFacts</see> 
+/// </summary>
+public class UnEqualCirclesFact : FactWrappedCRTP<UnEqualCirclesFact>
+{
+    /// @{ <summary>
+    /// two circles that are meant to be unequal in area
+    /// </summary>
+    public string Cid1, Cid2;
+    /// @}
+
+    [JsonIgnore]
+    public CircleFact Circle1 { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+    [JsonIgnore]
+    public CircleFact Circle2 { get => (CircleFact)FactRecorder.AllFacts[Cid2]; }
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public UnEqualCirclesFact() : base()
+    {
+        this.Cid1 = null;
+        this.Cid2 = null;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates members and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="cid2">sets <see cref="Cid2"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public UnEqualCirclesFact(string cid1, string cid2, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+        this.Cid2 = cid2;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Circle2.Position;
+        Rotation = Circle2.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="Cid2">sets <see cref="Cid2"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public UnEqualCirclesFact(string Cid1, string Cid2, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+        this.Cid2 = Cid2;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static UnEqualCirclesFact parseFact(MMTFact fact)
+    {
+        if (((MMTGeneralFact)fact).type is not OMA proof_OMA) // proof DED
+            return null;
+
+        OMA unequal_circles_OMA = (OMA)proof_OMA.arguments[0]; // unequal
+
+        string circleAUri = ((OMS)unequal_circles_OMA.arguments[0]).uri;
+        string circleBUri = ((OMS)unequal_circles_OMA.arguments[1]).uri;
+
+        if (!FactRecorder.AllFacts.ContainsKey(circleAUri)
+         || !FactRecorder.AllFacts.ContainsKey(circleBUri))
+            return null;
+
+        return new UnEqualCirclesFact(circleAUri, circleBUri, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => Circle1.Label + " = " + Circle2.Label;
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc tp = new OMA(
+            new OMS(MMTConstants.Ded),
+            new[] {
+                new OMA(new OMS(MMTConstants.UnEqualityCircles),
+                new[]  {
+                    new OMS(Cid1),
+                    new OMS(Cid2),
+        }),});
+
+        SOMDoc df = null;
+
+        return new MMTGeneralFact(this.Label, tp, df);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1, Cid2 };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(UnEqualCirclesFact f1, UnEqualCirclesFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new UnEqualCirclesFact(old_to_new[this.Cid1], old_to_new[this.Cid2], organizer);
+}
diff --git a/Assets/Scripts/InventoryStuff/PointWrapper.cs.meta b/Assets/Scripts/InteractionEngine/FactHandling/Facts/CircleFact.cs.meta
similarity index 83%
rename from Assets/Scripts/InventoryStuff/PointWrapper.cs.meta
rename to Assets/Scripts/InteractionEngine/FactHandling/Facts/CircleFact.cs.meta
index 3af2b1ec95cab1d9da9b3d31c5e358085f051b88..6b925f98b5fa1d30727608f484bd1cf2297f4019 100644
--- a/Assets/Scripts/InventoryStuff/PointWrapper.cs.meta
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/CircleFact.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: d5e5e87a22cc1714dbacaa2632c40e98
+guid: 6862429fb0d51da458debc64eb68530c
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
index 2fa46e3e84c42154f8251dc28136934ebedcfe19..e34343bef8ba59a6e2c0643ec4c45d055e65314e 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/Fact.cs
@@ -6,6 +6,7 @@
 using JsonSubTypes;
 using System.Linq;
 using REST_JSON_API;
+using System.Drawing;
 
 public static class ParsingDictionary
 {
@@ -57,6 +58,8 @@ public static class ParsingDictionary
             UnEqualCirclesFact.parseFact },
         { MMTConstants.ListLiteral,
             ListFact.parseFact },
+        { MMTConstants.Wall,
+            QuadFact.parseFact },
     };
 
     // TODO: get rid of this
@@ -92,8 +95,7 @@ public static class ParsingDictionary
 [JsonSubtypes.KnownSubType(typeof(FunctionCallFact), nameof(FunctionCallFact))]
 [JsonSubtypes.KnownSubType(typeof(ListFact), nameof(ListFact))]
 [JsonSubtypes.KnownSubType(typeof(TupleFact), nameof(TupleFact))]
-//[JsonSubtypes.KnownSubType(typeof(FunctionFact<T0, TResult>), "FunctionFact<T0, TResult>")] //TODO: generics? => nameof does not work (generic agnostic)
-//[JsonSubtypes.KnownSubType(typeof(FunctionFactFloat<Vector3>), "FunctionFact<System.Single, UnityEngine.Vector3>")]
+[JsonSubtypes.KnownSubType(typeof(QuadFact), nameof(QuadFact))]
 public abstract class Fact
 {
     /// <summary>
@@ -124,12 +126,12 @@ public abstract class Fact
     /// <returns> array of Fact <see cref="Id"> Ids </see> on which this Fact depends.</returns>
     /// <example><see cref="AngleFact"/> needs 3 <see cref="PointFact"/>s to be defined.</example>
     [JsonIgnore]
-    public string[] DependentFactIds => _DependentFactIds ??= GetGetDependentFactIds();
+    public string[] DependentFactIds => _DependentFactIds ??= GetDependentFactIds();
     private string[] _DependentFactIds;
 
     /// <returns> array of Fact <see cref="Id"> Ids </see> on which this Fact depends.</returns>
     /// <example><see cref="AngleFact"/> needs 3 <see cref="PointFact"/>s to be defined.</example>
-    protected abstract string[] GetGetDependentFactIds();
+    protected abstract string[] GetDependentFactIds();
 
     /// <value>
     /// Unique Id. e.g.: MMT URI
@@ -601,7 +603,7 @@ public PointFact(Vector3 point, string uri, FactRecorder organizer) : base(organ
     public override bool HasDependentFacts => false;
 
     /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new string[] { };
 
     /// \copydoc Fact.GetHashCode
@@ -728,7 +730,7 @@ protected override string generateLabel()
     public override bool HasDependentFacts => true;
 
     /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new string[] { Pid, Rid };
 
     protected override bool EquivalentWrapped(OnLineFact f1, OnLineFact f2)
@@ -856,7 +858,7 @@ public override MMTFact MakeMMTDeclaration()
     public override bool HasDependentFacts => true;
 
     /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new string[] { Lid1, Lid2 };
 
     /// \copydoc Fact.Equivalent(Fact, Fact)
@@ -868,1433 +870,110 @@ protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, F
 }
 
 /// <summary>
-/// A Circle that is made out of a middle point, a plane and a radius
+/// Used for BouncingScroll
 /// </summary>
-public class CircleFact : FactWrappedCRTP<CircleFact>
+public class QuadFact : FactWrappedCRTP<QuadFact>
 {
-    /// <summary> defining the middle point of the circle  </summary>
-    public string Pid1;
-    /// <summary>  defining the base point of the circle plane </summary>
-    public string Pid2;
-
-    [JsonIgnore]
-    public PointFact Point1 { get => (PointFact)FactRecorder.AllFacts[Pid1]; }
-    [JsonIgnore]
-    public PointFact Point2 { get => (PointFact)FactRecorder.AllFacts[Pid2]; }
-
-    /// <summary>  radius of the circle </summary>
-    public float radius;
-    /// <summary> normal vector of the plane </summary>
-    public Vector3 normal;
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public CircleFact() : base()
-    {
-        this.normal = Vector3.zero;
-        this.Pid1 = null;
-        this.Pid2 = null;
-        this.radius = 0;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates <see cref="Pid1"/>, <see cref="Pid2"/>, <see cref="radius"/>,<see cref="dir1"/>,<see cref="dir2"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="pid1">sets <see cref="Pid1"/></param>
-    /// <param name="pid2">sets <see cref="Pid2"/></param>
-    /// <param name="radius">sets <see cref="radius"/></param>
-    /// <param name="normal">sets <see cref="normal"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public CircleFact(string pid1, string pid2, float radius, Vector3 normal, FactRecorder organizer) : base(organizer)
-    {
-        this.Pid1 = pid1;
-        this.Pid2 = pid2;
-
-        this.radius = radius;
-        this.normal = normal;
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Point1.Position;
-        { //Rotation
-            Vector3 arbitary_not_normal = normal == Vector3.forward ? Vector3.right : Vector3.forward;
-            Vector3 forwoard = Vector3.Cross(arbitary_not_normal, normal);
-
-            Rotation = Quaternion.LookRotation(forwoard, normal);
-        }
-        LocalScale = new Vector3(radius, 1, radius);
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Pid1">sets <see cref="Pid1"/></param>
-    /// <param name="Pid2">sets <see cref="Pid2"/></param>
-    /// <param name="radius">sets <see cref="radius"/></param>
-    /// <param name="normal">sets <see cref="normal"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public CircleFact(string Pid1, string Pid2, float radius, Vector3 normal, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Pid1 = Pid1;
-        this.Pid2 = Pid2;
-
-        this.radius = radius;
-        this.normal = normal;
-
-        this._URI = backendURI;
-        _ = this.Label;
-    }
-
-    /// <summary>
-    /// parses the Circlefact response of the MMT-Server
-    /// </summary>
-    /// \copydoc Fact.parseFact(ScrollFact) 
-    public new static CircleFact parseFact(MMTFact fact)
-    {
-        if (((MMTGeneralFact)fact).defines is not OMA df)
-            return null;
-
-        OMA planeOMA = (OMA)df.arguments[0];
-        string planeApplicant = ((OMS)planeOMA.applicant).uri;
-
-        Vector3 normal;
-        // Getting the plane
-        // IN case of a normale plane
-        if (planeApplicant.Equals(MMTConstants.pointNormalPlane))
-        {
-            //OMA pointAOMA = (OMA)planeOMA.arguments[0];
-            normal = SOMDoc.MakeVector3((OMA)planeOMA.arguments[1]);
-        }
-        // In case of parametrized plane
-        else if (planeApplicant.Equals(MMTConstants.ParametrizedPlane))
-        {
-            Vector3 v = SOMDoc.MakeVector3((OMA)planeOMA.arguments[1]);
-            Vector3 w = SOMDoc.MakeVector3((OMA)planeOMA.arguments[2]);
-
-            normal = Vector3.Cross(v, w).normalized;
-        }
-        // incase of smth else. Shouldn't hapepen unless there is an error
-        else throw new ArgumentException("Invalid planeApplicant: " + planeApplicant);
-
-        // get the mid point uri
-        string parse_id_M = df.arguments[1].ToString();
-        string M_uri = ParsingDictionary.parseTermsToId[parse_id_M];
-        string A_uri = ParsingDictionary.parseTermsToId[planeOMA.arguments[0].ToString()];
-        float radius = ((OMF)df.arguments[2]).@float;
-
-        if (!FactRecorder.AllFacts.ContainsKey(M_uri)
-         || !FactRecorder.AllFacts.ContainsKey(A_uri))
-            return null; //If dependent facts do not exist return null
-
-        return new CircleFact(M_uri, A_uri, radius, normal, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => "â—‹" + Point1.Label;
-
-    /// <summary>
-    /// Constructs struct for right-angled MMT %Fact <see cref="AddFactResponse"/>
-    /// </summary>
-    /// <param name="Pid1"> <see cref="Pid1"/></param>
-    /// <param name="p2URI"> <see cref="Pid2"/></param>
-    /// <param name="radius"> <see cref="radius"/></param>
-    /// <returns>struct for <see cref="AddFactResponse"/></returns>
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc[] outerArguments = new SOMDoc[]
-        {
-           //CirclePlane,
-           new OMA(
-               //PointNormalPlane,
-               new OMS(MMTConstants.pointNormalPlane), 
-               //planeArgs,
-               new SOMDoc[] {
-                    //base point of the circle plane?,
-                    new OMS(Pid2),
-                    //NormalVector,
-                    new OMA(
-                        //"Vector"
-                        new OMS(MMTConstants.Tuple),
-                        //normalArgs,
-                        new[]  {
-                            new OMF(normal.x),
-                            new OMF(normal.y),
-                            new OMF(normal.z)
-                        }
-                    ),
-                }
-            ),
-           //middlePoint,
-           new OMS(Pid1),
-           //Radius,
-           new OMF(radius),
-        };
-
-        // Do i need this here? doubt 
-        SOMDoc tp = new OMS(MMTConstants.CircleType3d);
-        SOMDoc df = new OMA(new OMS(MMTConstants.MkCircle3d), outerArguments);
-
-        return new MMTGeneralFact(Label, tp, df);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Pid1, Pid2 };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(CircleFact f1, CircleFact f2)
-        => DependentFactsEquivalent(f1, f2)
-        && Math3d.IsApproximatelyEqual(f1.normal, f2.normal)
-        && Mathf.Approximately(f1.radius, f2.radius);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new CircleFact(old_to_new[this.Pid1], old_to_new[this.Pid2], this.radius, this.normal, organizer);
-}
-
-/// <summary>
-/// A <see cref="PointFact"/> on a <see cref="CircleFact"/>
-/// </summary>
-public class OnCircleFact : FactWrappedCRTP<OnCircleFact>
-{
-    /// <summary> the point on the circle  </summary>
-    public string Pid;
-    /// <summary> the circle, which the point is on  </summary>
-    public string Cid;
-
-    [JsonIgnore]
-    public PointFact Point { get => (PointFact)FactRecorder.AllFacts[Pid]; }
-    [JsonIgnore]
-    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid]; }
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public OnCircleFact() : base()
-    {
-        this.Pid = null;
-        this.Cid = null;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates <see cref="Pid"/>, <see cref="Rid"/>, <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="pid">sets <see cref="Pid"/></param>
-    /// <param name="cid">sets <see cref="Cid"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public OnCircleFact(string pid, string cid, FactRecorder organizer) : base(organizer)
-    {
-        this.Pid = pid;
-        this.Cid = cid; ;
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Point.Position;
-        Rotation = Circle.Rotation;
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="pid">sets <see cref="Pid"/></param>
-    /// <param name="cid">sets <see cref="Cid"/></param>
-    /// <param name="uri">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public OnCircleFact(string pid, string cid, string uri, FactRecorder organizer) : base(organizer)
-    {
-        this.Pid = pid;
-        this.Cid = cid;
-        this._URI = uri;
-        _ = this.Label;
-    }
-
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static OnCircleFact parseFact(MMTFact fact)
-    {
-        if (((MMTGeneralFact)fact).type is not OMA type)
-            return null;
-
-        string circleUri = ((OMS)((OMA)type.arguments[0]).arguments[0]).uri;
-        string pointUri = ((OMS)((OMA)type.arguments[0]).arguments[1]).uri;
-
-        if (!FactRecorder.AllFacts.ContainsKey(pointUri)
-         || !FactRecorder.AllFacts.ContainsKey(circleUri))
-            return null;
-
-        return new OnCircleFact(pointUri, circleUri, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => Point.Label + "∈" + Circle.Label;
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Pid, Cid };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(OnCircleFact c1, OnCircleFact c2)
-        => DependentFactsEquivalent(c1, c2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new OnCircleFact(old_to_new[this.Pid], old_to_new[this.Cid], organizer);
-
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc tp =
-            new OMA(
-                new OMS(MMTConstants.Ded),
-                new[] {
-                    new OMA(
-                        new OMS(MMTConstants.OnCircle),
-                        new[] {
-                            new OMS(Cid),
-                            new OMS(Pid),
-        }),});
-
-        SOMDoc df = null;
-
-        return new MMTGeneralFact(Label, tp, df);
-    }
-}
-
-/// <summary>
-/// Angle comprised of a line and a circle 
-/// </summary>
-public class AngleCircleLineFact : FactWrappedCRTP<AngleCircleLineFact>
-{
-    /// @{ <summary>
-    /// One <see cref="Fact.Id">Id</see> of a <see cref="RayFact">RayFact</see> and a <see cref="CircleFact">CircleFact</see>  defining Angle [<see cref="Cid1"/>, <see cref="Rid2"/>].
-    /// </summary>
-    public string Cid1, Rid2;
-    /// @}
-
-    [JsonIgnore]
-    public AbstractLineFact Ray { get => (AbstractLineFact)FactRecorder.AllFacts[Rid2]; }
-    [JsonIgnore]
-    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-
-    //TODO? deg or rad?
-    [JsonIgnore]
-    public float angle;
-
-    [JsonIgnore]
-    public Vector3 intersection;
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public AngleCircleLineFact() : base()
-    {
-        this.Cid1 = null;
-        this.Rid2 = null;
-        this.angle = 0.0f;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates <see cref="Cid1"/>, <see cref="Rid2"/>, <see cref="angle"/> <see cref="Fact._URI"/> and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="rid2">sets <see cref="Rid2"/></param>
-    /// <param name="angle"> sets the angle </param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public AngleCircleLineFact(string cid1, string rid2, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-        this.Rid2 = rid2;
-        this.angle = Math3d.AngleVectorPlane(Ray.Dir, Circle.normal).ToDegrees();
-        Math3d.LinePlaneIntersection(out intersection, Ray.Point1.Position, Ray.Dir, Circle.normal, Circle.Position);
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = intersection;
-        { //Rotation
-            Vector3 from = (Circle.Position - Position).normalized;
-
-            Vector3 angle_to = Math3d.IsApproximatelyEqual(intersection, Ray.Point1.Position)
-                ? Ray.Point2.Position
-                : Ray.Point1.Position;
-            Vector3 to = (angle_to - Position).normalized;
-
-            Vector3 up = Vector3.Cross(to, from);
-            Vector3 forwoard = (from + to).normalized;
-
-            if (up.sqrMagnitude < Math3d.vectorPrecission)
-            { //Angle is 180° (or 0°)
-                Vector3 arbitary = up.normalized == Vector3.forward ? Vector3.right : Vector3.forward;
-                up = Vector3.Cross(arbitary, to);
-                forwoard = Vector3.Cross(up, to);
-            }
-
-            Rotation = Quaternion.LookRotation(forwoard, up);
-        }
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="´Rid2">sets <see cref="Rid2"/></param>
-    /// <param name="angle"> sets the angle </param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public AngleCircleLineFact(string Cid1, string Rid2, float angle, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-        this.Rid2 = Rid2;
-        this.angle = angle;
-
-        this._URI = backendURI;
-        _ = this.Label;
-    }
-
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static AngleCircleLineFact parseFact(MMTFact fact)
-    {
-        if (((MMTValueFact)fact).lhs is not OMA lhs)
-            return null;
-
-        // init it with 0 degrees, so we don't accidentally generate orthogonalfacts 
-        // and the parsing works correctly if smb ever adds a scroll for this
-        float angle = 0.0f;
-
-        if (((MMTValueFact)fact).value is OMF oMFangle)
-            angle = oMFangle.@float;
-
-        string CircleUri = ((OMS)lhs.arguments[0]).uri;
-        string RayUri = ((OMS)lhs.arguments[1]).uri;
-
-        if (!FactRecorder.AllFacts.ContainsKey(CircleUri)
-         || !FactRecorder.AllFacts.ContainsKey(RayUri))
-            return null;
-
-        return new AngleCircleLineFact(CircleUri, RayUri, angle, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => "∠" + Circle.Label + Ray.Label;
-
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc lhs =
-            new OMA(
-                new OMS(MMTConstants.AnglePlaneLine),
-                new[] {
-                    new OMS(Cid1),
-                    new OMS(Rid2),
-                }
-            );
-
-        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
-        SOMDoc value = new OMF(angle);
-
-        return new MMTValueFact(this.Label, lhs, valueTp, value);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1, Rid2 };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(AngleCircleLineFact f1, AngleCircleLineFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new AngleCircleLineFact(old_to_new[this.Cid1], old_to_new[this.Rid2], organizer);
-}
-
-/// <summary>
-/// A RadiusFact that corresponds to a <see cref="CircleFact">PointFacts</see> and has a float value (the actual radius).
-/// </summary>
-public class RadiusFact : FactWrappedCRTP<RadiusFact>
-{
-    /// <summary> The circle corresponding to the radius </summary>
-    public string Cid1;
-
-    [JsonIgnore]
-    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-
-    /// <summary> The radius as a float </summary>
-    public float rad;
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public RadiusFact() : base()
-    {
-        this.Cid1 = null;
-        this.rad = 0.0f;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates <see cref="Cid1"/> and <see cref="rad"/>
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public RadiusFact(string cid1, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-        this.rad = Circle.radius;
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Circle.Position;
-        Rotation = Circle.Rotation;
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public RadiusFact(string Cid1, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-
-        this._URI = backendURI;
-        _ = this.Label;
-    }
-
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static RadiusFact parseFact(MMTFact fact)
-    {
-        string CircleUri = ((OMS)((OMA)((MMTValueFact)fact).lhs).arguments[0]).uri;
-
-        if (!FactRecorder.AllFacts.ContainsKey(CircleUri))
-            return null;
-
-        return new RadiusFact(CircleUri, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => "r " + Circle.Label;
-
-    /// <summary>
-    /// Constructs struct for not-right-angled MMT %Fact <see cref="AddFactResponse"/>
-    /// </summary>
-    /// <param name="rad"> see <see cref="rad"/></param>
-    /// <param name="c1URI"> see <see cref="Cid1"/></param>
-
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc lhs =
-            new OMA(
-                new OMS(MMTConstants.RadiusCircleMetric),
-                new[] {
-                    new OMS(Cid1),
-                }
-            );
-
-        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
-        SOMDoc value = new OMF(rad);
-
-        return new MMTValueFact(this.Label, lhs, valueTp, value);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1 };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(RadiusFact f1, RadiusFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new RadiusFact(old_to_new[this.Cid1], organizer);
-}
-
-/// <summary>
-/// Area of a <see cref="CircleFact">CircleFact</see> 
-/// </summary>
-public class AreaCircleFact : FactWrappedCRTP<AreaCircleFact>
-{
-    /// <summary> the circle <see cref="CircleFact">CircleFact</see>  </summary>
-    public string Cid1;
-
-    [JsonIgnore]
-    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-
-    /// <summary> the area which is contained by the circle </summary>
-    public float A;
-
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public AreaCircleFact() : base()
-    {
-        this.Cid1 = null;
-        this.A = 0.0f;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates <see cref="Cid1"/> and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public AreaCircleFact(string cid1, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-
-        this.A = Circle.radius * Circle.radius * ((float)System.Math.PI);
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Circle.Position;
-        Rotation = Circle.Rotation;
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public AreaCircleFact(string Cid1, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-
-        this._URI = backendURI;
-        _ = this.Label;
-    }
-
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static AreaCircleFact parseFact(MMTFact fact)
-    {
-        string CircleUri = ((OMS)((OMA)((MMTValueFact)fact).lhs).arguments[0]).uri;
-
-        if (!FactRecorder.AllFacts.ContainsKey(CircleUri))
-            return null;
-
-        return new AreaCircleFact(CircleUri, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => "A(" + Circle.Label + ")";
-
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc lhs =
-            new OMA(
-                new OMS(MMTConstants.AreaCircle),
-                new[] {
-                    new OMS(Cid1),
-                }
-            );
-
-        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
-        SOMDoc value = new OMF(A);
-
-        return new MMTValueFact(this.Label, lhs, valueTp, value);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1 };
-
-    /// \copydoc Fact.GetHashCode
-    public override int GetHashCode()
-        => base.GetHashCode() ^ A.GetHashCode();
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(AreaCircleFact f1, AreaCircleFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new AreaCircleFact(old_to_new[this.Cid1], organizer);
-}
-
-/// <summary>
-/// The volume of a cone A  defined by a base area  <see cref="CircleFact">CircleFact</see>, an apex <see cref="PointFact">PointFact</see> and the volume as float
-/// </summary>
-public class ConeVolumeFact : FactWrappedCRTP<ConeVolumeFact>
-{
-    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
-    public string Cid1;
-    [JsonIgnore]
-    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-
-    ///  <summary> a <see cref="PointFact">PointFact</see> describing the apex point  </summary>
-    public string Pid1;
-    [JsonIgnore]
-    public PointFact Point { get => (PointFact)FactRecorder.AllFacts[Pid1]; }
-
-    ///  <summary> the volume of the cone as a float </summary>
-    public float vol;
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public ConeVolumeFact() : base()
-    {
-        this.Cid1 = null;
-        this.Pid1 = null;
-        this.vol = 0.0f;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates members and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="pid1">sets <see cref="Pid1"/></param>
-    /// <param name="vol">sets <see cref="vol"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public ConeVolumeFact(string cid1, string pid1, float vol, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-        this.Pid1 = pid1;
-        this.vol = vol;
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Point.Position;
-        Rotation = Circle.Rotation;
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="Pid1">sets <see cref="Pid1"/></param>
-    /// <param name="volume">sets <see cref="vol"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public ConeVolumeFact(string Cid1, string Pid1, float volume, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-        this.Pid1 = Pid1;
-        this.vol = volume;
-
-        this._URI = backendURI;
-        _ = this.Label;
-    }
-
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static ConeVolumeFact parseFact(MMTFact fact)
-    {
-        if (((MMTValueFact)fact).lhs is not OMA lhs)
-            return null;
-
-        string CircleUri = ((OMS)((OMA)lhs.arguments[0]).arguments[0]).uri;
-        string PointUri = ((OMS)((OMA)lhs.arguments[0]).arguments[1]).uri;
-
-        float volume = 0.0f;
-        if (((MMTValueFact)fact).value is OMF oMFvolume)
-            volume = oMFvolume.@float;
-
-        if (!FactRecorder.AllFacts.ContainsKey(CircleUri)
-         || !FactRecorder.AllFacts.ContainsKey(PointUri))
-            return null;
-
-        return new ConeVolumeFact(CircleUri, PointUri, volume, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => "V(" + Circle.Label + "," + Point.Label + ")";
-
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc lhs =
-            new OMA(
-                new OMS(MMTConstants.VolumeCone),
-
-                new[] {
-                    new OMA(new OMS(MMTConstants.ConeOfCircleApex),
-                        new[]  {
-                            new OMS(Cid1),
-                            new OMS(Pid1),
-                         }
-                    ),
-                }
-            );
-
-        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
-        SOMDoc value = new OMF(vol);
-
-        return new MMTValueFact(this.Label, lhs, valueTp, value);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1, Pid1 };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(ConeVolumeFact f1, ConeVolumeFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new ConeVolumeFact(old_to_new[this.Cid1], old_to_new[this.Pid1], this.vol, organizer);
-}
-
-/// <summary>
-/// The fact that the plane of a <see cref="CircleFact">CircleFact</see> and the line <see cref="RayFact>RayFact</see> are orthogonal
-/// </summary>
-public class OrthogonalCircleLineFact : FactWrappedCRTP<OrthogonalCircleLineFact>
-{
-    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
-    public string Cid1;
-    [JsonIgnore]
-    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-
-    ///  <summary> a <see cref="RayFact">Rayfact</see> describing the line </summary>
-    public string Lid1;
-    [JsonIgnore]
-    public AbstractLineFact Ray { get => (AbstractLineFact)FactRecorder.AllFacts[Lid1]; }
-
-    //TODO? deg or rad?
-    [JsonIgnore]
-    public float angle = 90f;
-
-    [JsonIgnore]
-    public Vector3 intersection;
-
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public OrthogonalCircleLineFact() : base()
-    {
-        this.Cid1 = null;
-        this.Lid1 = null;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates members and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="lid1">sets <see cref="Lid1"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public OrthogonalCircleLineFact(string cid1, string lid1, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-        this.Lid1 = lid1;
-        Math3d.LinePlaneIntersection(out intersection, Ray.Point1.Position, Ray.Dir, Circle.normal, Circle.Position);
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = intersection;
-        { //Rotation
-            Vector3 from = (Circle.Position - Position).normalized;
-
-            Vector3 angle_to = Math3d.IsApproximatelyEqual(intersection, Ray.Point1.Position)
-                ? Ray.Point2.Position
-                : Ray.Point1.Position;
-            Vector3 to = (angle_to - Position).normalized;
-
-            Vector3 up = Vector3.Cross(to, from);
-            Vector3 forward = (from + to).normalized;
-            Rotation = Quaternion.LookRotation(forward, up);
-        }
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="Lid1">sets <see cref="Lid1"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public OrthogonalCircleLineFact(string Cid1, string Lid1, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-        this.Lid1 = Lid1;
-
-        this._URI = backendURI;
-        _ = this.Label;
-    }
-
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static OrthogonalCircleLineFact parseFact(MMTFact fact)
-    {
-        if (((MMTGeneralFact)fact).type is not OMA type)
-            return null;
-
-        string CircleUri = ((OMS)((OMA)type.arguments[0]).arguments[0]).uri;
-        string LineUri = ((OMS)((OMA)type.arguments[0]).arguments[1]).uri;
-
-        if (!FactRecorder.AllFacts.ContainsKey(CircleUri)
-         || !FactRecorder.AllFacts.ContainsKey(LineUri))
-            return null;
-
-        return new OrthogonalCircleLineFact(CircleUri, LineUri, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => Circle.Label + "⊥" + Ray.Label;
-
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc tp = new OMA(
-            new OMS(MMTConstants.Ded),
-            new[]{
-                new OMA(
-                    new OMS(MMTConstants.OrthoCircleLine),
-                    new[] {
-                        new OMS(Cid1),
-                        new OMS(Lid1),
-                    }
-                ),
-            }
-        );
-
-        SOMDoc df = null;
-
-        return new MMTGeneralFact(this.Label, tp, df);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1, Lid1 };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(OrthogonalCircleLineFact f1, OrthogonalCircleLineFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new OrthogonalCircleLineFact(old_to_new[this.Cid1], old_to_new[this.Lid1], organizer);
-}
-
-/// <summary>
-/// The volume of a cone A  defined by a base area  <see cref="CircleFact">CircleFact</see>, a top area <see cref="CircleFact">CircleFact</see> and the volume as float
-/// </summary>
-public class TruncatedConeVolumeFact : FactWrappedCRTP<TruncatedConeVolumeFact>
-{
-    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
-    public string Cid1;
-    [JsonIgnore]
-    public CircleFact Circle1 { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-
-    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the top area  </summary>
-    public string Cid2;
+    /// <summary> Defining Corners; Order is Cyclic;
+    /// <see cref="PointFact"/>.<see cref="Fact.Id">Id</see> </summary>
+    public string[] Pids;
     [JsonIgnore]
-    public CircleFact Circle2 { get => (CircleFact)FactRecorder.AllFacts[Cid2]; }
-
-    ///  <summary> the volume of Truncated the cone as a float </summary>
-    public float vol;
-    /// <summary> a proof that both circles have not the same size </summary>
-    public string unequalCirclesProof;
-    ///  <summary> OMA proof that the two circles are parallel  </summary>
-    public OMA proof;
-
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public TruncatedConeVolumeFact() : base()
-    {
-        this.Cid1 = null;
-        this.Cid2 = null;
-        this.vol = 0.0f;
-        this.unequalCirclesProof = null;
-        this.proof = null;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates members and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="cid2">sets <see cref="Cid2"/></param>
-    /// <param name="vol">sets <see cref="vol"/></param>
-    /// <param name="proof">sets <see cref="proof"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public TruncatedConeVolumeFact(string cid1, string cid2, float vol, string unequalproof, OMA proof, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-        this.Cid2 = cid2;
-        this.proof = proof;
-        this.unequalCirclesProof = unequalproof;
-        this.vol = vol;
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Circle2.Position;
-        Rotation = Circle2.Rotation;
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="Cid2">sets <see cref="Cid2"/></param>
-    /// <param name="volume">sets <see cref="vol"/></param>
-    /// <param name="proof">sets <see cref="proof"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public TruncatedConeVolumeFact(string Cid1, string Cid2, float volume, string unequalproof, OMA proof, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-        this.Cid2 = Cid2;
-        this.vol = volume;
-        this.proof = proof;
-        this.unequalCirclesProof = unequalproof;
-
-        this._URI = backendURI;
-        _ = this.Label;
-    }
-
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static TruncatedConeVolumeFact parseFact(MMTFact fact)
-    {
-        string Circle1Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[0]).uri;
-        string Circle2Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[1]).uri;
-        float volume = ((OMF)((MMTValueFact)fact).value).@float;
-
-        string UnEqualCirclesProof = ((OMS)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[2])).uri;
-        OMA proof = (OMA)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[3]);
-
-        if (!FactRecorder.AllFacts.ContainsKey(Circle1Uri)
-         || !FactRecorder.AllFacts.ContainsKey(Circle2Uri))
-            return null;
-
-        return new TruncatedConeVolumeFact(Circle1Uri, Circle2Uri, volume, UnEqualCirclesProof, proof, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => "V(" + Circle1.Label + "," + Circle2.Label + ")";
-
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc lhs =
-            new OMA(
-                new OMS(MMTConstants.TruncatedVolumeCone),
-                new SOMDoc[] {
-                    new OMS(Cid1),
-                    new OMS(Cid2),
-                    new OMS(unequalCirclesProof),
-                    proof,
-                }
-            );
-
-        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
-        SOMDoc value = new OMF(vol);
-
-        return new MMTValueFact(this.Label, lhs, valueTp, value);
+    public PointFact[] Points { 
+        get => _Points ??= Pids.Select(pid => (PointFact)FactRecorder.AllFacts[pid]).ToArray();
     }
+    private PointFact[] _Points;
 
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1, Cid2 };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(TruncatedConeVolumeFact f1, TruncatedConeVolumeFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new TruncatedConeVolumeFact(old_to_new[this.Cid1], old_to_new[this.Cid2], this.vol, old_to_new[this.unequalCirclesProof], this.proof, organizer);
-}
-
-/// <summary>
-/// The volume of a cylinder defined by a base area  <see cref="CircleFact">CircleFact</see>, a top area <see cref="CircleFact">CircleFact</see> and the volume as float
-/// </summary>
-public class CylinderVolumeFact : FactWrappedCRTP<CylinderVolumeFact>
-{
-    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
-    public string Cid1;
-    [JsonIgnore]
-    public CircleFact Circle1 { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-
-    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the top area  </summary>
-    public string Cid2;
     [JsonIgnore]
-    public CircleFact Circle2 { get => (CircleFact)FactRecorder.AllFacts[Cid2]; }
-
-    ///  <summary> the volume of the cylinder as a float </summary>
-    public float vol;
-    /// <summary> a proof that both circles have the same size </summary>
-    public string equalCirclesProof;
-    ///  <summary> OMA proof that the two circles are parallel  </summary>
-    public OMA proof;
+    public Vector3 Normal;
 
     /// <summary> \copydoc Fact.Fact </summary>
-    public CylinderVolumeFact() : base()
-    {
-        this.Cid1 = null;
-        this.Cid2 = null;
-        this.vol = 0.0f;
-        this.proof = null;
-        this.equalCirclesProof = null;
-    }
+    public QuadFact() : base() { }
 
     /// <summary>
     /// Standard Constructor:
-    /// Initiates members and creates MMT %Fact Server-Side
+    /// Initiates <see cref="Pids"/> and creates MMT %Fact Server-Side
     /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="cid2">sets <see cref="Cid2"/></param>
-    /// <param name="vol">sets <see cref="vol"/></param>
-    /// <param name="proof">sets <see cref="proof"/></param>
+    /// <param name="pid_corners">sets <see cref="Pids"/></param>
     /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public CylinderVolumeFact(string cid1, string cid2, float vol, string eqProof, OMA proof, FactRecorder organizer) : base(organizer)
+    public QuadFact(string[] pid_corners, FactRecorder organizer) : base(organizer)
     {
-        this.Cid1 = cid1;
-        this.Cid2 = cid2;
-        this.proof = proof;
-        this.equalCirclesProof = eqProof;
-        this.vol = vol;
-
+        Init(pid_corners);
         SendToMMT();
     }
 
-    protected override void RecalculateTransform()
-    {
-        Position = Circle2.Position;
-        Rotation = Circle2.Rotation;
-    }
-
     /// <summary>
     /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
     /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="Cid2">sets <see cref="Cid2"/></param>
-    /// <param name="volume">sets <see cref="vol"/></param>
-    /// <param name="proof">sets <see cref="proof"/></param>
-    /// <param name="backendURI">MMT URI</param>
+    /// <param name="pid_corners">sets <see cref="Pids"/></param>
+    /// <param name="uri">MMT URI</param>
     /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public CylinderVolumeFact(string Cid1, string Cid2, float volume, string eqProof, OMA proof, string backendURI, FactRecorder organizer) : base(organizer)
+    public QuadFact(string[] pid_corners, string uri, FactRecorder organizer) : base(organizer)
     {
-        this.Cid1 = Cid1;
-        this.Cid2 = Cid2;
-        this.vol = volume;
-        this.proof = proof;
-        this.equalCirclesProof = eqProof;
+        Init(pid_corners);
 
-        this._URI = backendURI;
+        this._URI = uri;
         _ = this.Label;
     }
 
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static CylinderVolumeFact parseFact(MMTFact fact)
+    private void Init(string[] pid_corners)
     {
-        string Circle1Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[0]).uri;
-        string Circle2Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[1]).uri;
-        float volume = ((OMF)((MMTValueFact)fact).value).@float;
-        string EqualCirclesProof = ((OMS)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[2])).uri;
-
-        OMA proof = (OMA)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[3]);
-
-        if (!FactRecorder.AllFacts.ContainsKey(Circle1Uri)
-         || !FactRecorder.AllFacts.ContainsKey(Circle2Uri))
-            return null;
-
-        return new CylinderVolumeFact(Circle1Uri, Circle2Uri, volume, EqualCirclesProof, proof, fact.@ref.uri, StageStatic.stage.factState);
-    }
-
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => "V(" + Circle1.Label + "," + Circle2.Label + ")";
+        Pids = pid_corners;
 
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc lhs =
-            new OMA(
-                new OMS(MMTConstants.CylinderVolume),
-
-                new SOMDoc[] {
-                    new OMS(Cid1),
-                    new OMS(Cid2),
-                    new OMS(equalCirclesProof),
-                    proof,
-                }
+        Normal = Vector3.Cross(
+                Points[0].Point - Points[1].Point,
+                Points[0].Point - Points[2].Point
             );
 
-        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
-        SOMDoc value = new OMF(vol);
-
-        return new MMTValueFact(this.Label, lhs, valueTp, value);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1, Cid2, equalCirclesProof };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(CylinderVolumeFact f1, CylinderVolumeFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new CylinderVolumeFact(old_to_new[this.Cid1], old_to_new[this.Cid2], this.vol, old_to_new[this.equalCirclesProof], this.proof, organizer);
-}
-
-/// <summary>
-/// A fact that describes, that two circles have the same size and is comprised of two <see cref="CircleFact">CircleFacts</see> 
-/// </summary>
-public class EqualCirclesFact : FactWrappedCRTP<EqualCirclesFact>
-{
-    /// @{ <summary>
-    /// two circles that are meant to be equal in area
-    /// </summary>
-    public string Cid1, Cid2;
-    /// @}
-
-    [JsonIgnore]
-    public CircleFact Circle1 { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-    [JsonIgnore]
-    public CircleFact Circle2 { get => (CircleFact)FactRecorder.AllFacts[Cid2]; }
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public EqualCirclesFact() : base()
-    {
-        this.Cid1 = null;
-        this.Cid2 = null;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates members and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="cid2">sets <see cref="Cid2"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public EqualCirclesFact(string cid1, string cid2, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-        this.Cid2 = cid2;
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Circle1.Position;
-        Rotation = Circle1.Rotation;
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="Cid2">sets <see cref="Cid2"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public EqualCirclesFact(string Cid1, string Cid2, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-        this.Cid2 = Cid2;
-
-        this._URI = backendURI;
-        _ = this.Label;
+        if (Mathf.Approximately(0, Vector3.Dot(Normal, Points[0].Point - Points[3].Point)))
+            throw new ArgumentException("All Points must lie on the same Plane!");
     }
 
     /// \copydoc Fact.parseFact(ScrollFact)
-    public new static EqualCirclesFact parseFact(MMTFact fact)
+    public new static QuadFact parseFact(MMTFact fact)
     {
-        if (((MMTGeneralFact)fact).type is not OMA proof_OMA) // proof DED
-            return null;
-
-        OMA parallel_circles_OMA = (OMA)proof_OMA.arguments[0]; // parallel
-
-        string circleAUri = ((OMS)parallel_circles_OMA.arguments[0]).uri;
-        string circleBUri = ((OMS)parallel_circles_OMA.arguments[1]).uri;
-
-        if (!FactRecorder.AllFacts.ContainsKey(circleAUri)
-         || !FactRecorder.AllFacts.ContainsKey(circleBUri))
-            return null;
-
-        return new EqualCirclesFact(circleAUri, circleBUri, fact.@ref.uri, StageStatic.stage.factState);
+        throw new NotImplementedException();
     }
 
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => Circle1.Label + " ≠ " + Circle2.Label;
-
     public override MMTFact MakeMMTDeclaration()
     {
         SOMDoc tp = new OMA(
-            new OMS(MMTConstants.Ded),
-            new[] {
-                new OMA(
-                    new OMS(MMTConstants.EqualityCircles),
-                    new[]  {
-                        new OMS(Cid1),
-                        new OMS(Cid2),
-                    }
-                )
-            }
-        );
-
+                new OMS(MMTConstants.Wall),
+                Pids.Select(pid => new OMS(pid)).ToArray()
+            );
         SOMDoc df = null;
 
-        return new MMTGeneralFact(this.Label, tp, df);
-    }
-
-    /// \copydoc Fact.hasDependentFacts
-    public override bool HasDependentFacts => true;
-
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1, Cid2 };
-
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(EqualCirclesFact f1, EqualCirclesFact f2)
-        => DependentFactsEquivalent(f1, f2);
-
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new EqualCirclesFact(old_to_new[this.Cid1], old_to_new[this.Cid2], organizer);
-}
-
-/// <summary>
-/// A fact that describes, that two circles have not the same size and is comprised of two <see cref="CircleFact">CircleFacts</see> 
-/// </summary>
-public class UnEqualCirclesFact : FactWrappedCRTP<UnEqualCirclesFact>
-{
-    /// @{ <summary>
-    /// two circles that are meant to be unequal in area
-    /// </summary>
-    public string Cid1, Cid2;
-    /// @}
-
-    [JsonIgnore]
-    public CircleFact Circle1 { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
-    [JsonIgnore]
-    public CircleFact Circle2 { get => (CircleFact)FactRecorder.AllFacts[Cid2]; }
-
-    /// <summary> \copydoc Fact.Fact </summary>
-    public UnEqualCirclesFact() : base()
-    {
-        this.Cid1 = null;
-        this.Cid2 = null;
-    }
-
-    /// <summary>
-    /// Standard Constructor:
-    /// Initiates members and creates MMT %Fact Server-Side
-    /// </summary>
-    /// <param name="cid1">sets <see cref="Cid1"/></param>
-    /// <param name="cid2">sets <see cref="Cid2"/></param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public UnEqualCirclesFact(string cid1, string cid2, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = cid1;
-        this.Cid2 = cid2;
-
-        SendToMMT();
-    }
-
-    protected override void RecalculateTransform()
-    {
-        Position = Circle2.Position;
-        Rotation = Circle2.Rotation;
-    }
-
-    /// <summary>
-    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
-    /// </summary>
-    /// <param name="Cid1">sets <see cref="Cid1"/></param>
-    /// <param name="Cid2">sets <see cref="Cid2"/></param>
-    /// <param name="backendURI">MMT URI</param>
-    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
-    public UnEqualCirclesFact(string Cid1, string Cid2, string backendURI, FactRecorder organizer) : base(organizer)
-    {
-        this.Cid1 = Cid1;
-        this.Cid2 = Cid2;
-
-        this._URI = backendURI;
-        _ = this.Label;
+        return new MMTGeneralFact(Label, tp, df);
     }
 
-    /// \copydoc Fact.parseFact(ScrollFact)
-    public new static UnEqualCirclesFact parseFact(MMTFact fact)
+    protected override bool EquivalentWrapped(QuadFact f1, QuadFact f2)
     {
-        if (((MMTGeneralFact)fact).type is not OMA proof_OMA) // proof DED
-            return null;
-
-        OMA unequal_circles_OMA = (OMA)proof_OMA.arguments[0]; // unequal
-
-        string circleAUri = ((OMS)unequal_circles_OMA.arguments[0]).uri;
-        string circleBUri = ((OMS)unequal_circles_OMA.arguments[1]).uri;
-
-        if (!FactRecorder.AllFacts.ContainsKey(circleAUri)
-         || !FactRecorder.AllFacts.ContainsKey(circleBUri))
-            return null;
-
-        return new UnEqualCirclesFact(circleAUri, circleBUri, fact.@ref.uri, StageStatic.stage.factState);
-    }
+        if(f1.Points.Length != f2.Points.Length)
+            return false;
 
-    /// \copydoc Fact.generateLabel
-    protected override string generateLabel()
-        => Circle1.Label + " = " + Circle2.Label;
+        int i = 0;
+        for (; i < f2.Points.Length; i++) // 1st incedence
+            if (f2.Points[i].Equivalent(f1.Points[0]))
+                break;
 
-    public override MMTFact MakeMMTDeclaration()
-    {
-        SOMDoc tp = new OMA(
-            new OMS(MMTConstants.Ded),
-            new[] {
-                new OMA(new OMS(MMTConstants.UnEqualityCircles),
-                new[]  {
-                    new OMS(Cid1),
-                    new OMS(Cid2),
-        }),});
+        if (i == f2.Points.Length) // no match
+            return false;
 
-        SOMDoc df = null;
+        for (int j = 1; j < f2.Points.Length; j++) // cyclic match
+            if (!f2.Points[(i + j) % f2.Points.Length].Equivalent(f1.Points[j]))
+                return false;
 
-        return new MMTGeneralFact(this.Label, tp, df);
+        return true;
     }
 
-    /// \copydoc Fact.hasDependentFacts
     public override bool HasDependentFacts => true;
 
-    /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
-        => new string[] { Cid1, Cid2 };
+    protected override string[] GetDependentFactIds()
+        => Pids;
 
-    /// \copydoc Fact.Equivalent(Fact, Fact)
-    protected override bool EquivalentWrapped(UnEqualCirclesFact f1, UnEqualCirclesFact f2)
-        => DependentFactsEquivalent(f1, f2);
+    protected override void RecalculateTransform() { }
 
-    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
-        => new UnEqualCirclesFact(old_to_new[this.Cid1], old_to_new[this.Cid2], organizer);
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer) 
+        => new QuadFact(Pids.Select(pid => old_to_new[pid]).ToArray(), organizer);
 }
 
 #pragma warning disable // Testing...
@@ -2364,7 +1043,7 @@ protected override string generateLabel()
     public override bool HasDependentFacts => false;
 
     /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new string[] { };
 
     /// \copydoc Fact.GetHashCode
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
index cdda3745718dc8ece334841a82422f3b5326fe01..92e2c5d57e6cfb43edebe8710f77a582e5475040 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/FunctionFact.cs
@@ -2,7 +2,6 @@
 using System.Collections.Generic;
 using UnityEngine;
 using Newtonsoft.Json;
-using System.Linq.Expressions;
 using System.Linq;
 using REST_JSON_API;
 
@@ -46,7 +45,7 @@ public object Call(float t)
     public override bool HasDependentFacts
         => true;
 
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new[] { func_id, arg_func_id };
 
     protected override bool EquivalentWrapped(FunctionCallFact f1, FunctionCallFact f2)
@@ -147,7 +146,7 @@ public override bool HasDependentFacts
         => false;
 
     /// \copydoc Fact.getDependentFactIds
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new string[] { };
 
     /// \copydoc Fact.GetHashCode
@@ -261,7 +260,7 @@ public override MMTFact MakeMMTDeclaration()
     public override bool HasDependentFacts
         => true;
 
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => new string[] { fid }.ShallowCloneAppend(func_calls_ids);
     //=> new string[] { fid, func_calls_list_id };
 
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs
index adc880b49b6207ea94ee838f6dc305028c5cd29b..204229589803bf0b092bdb09f9867b9c37540c75 100644
--- a/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/MMTTypes.cs
@@ -169,7 +169,7 @@ public override MMTFact MakeMMTDeclaration()
         return new MMTGeneralFact(Label, ListType, List);
     }
 
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => lids.Where(lid => lid != null).ToArray();
 
     protected override void RecalculateTransform() { }
@@ -259,7 +259,7 @@ public override MMTFact MakeMMTDeclaration()
         return new MMTGeneralFact(Label, Tupel.SOMDocType(), Tupel);
     }
 
-    protected override string[] GetGetDependentFactIds()
+    protected override string[] GetDependentFactIds()
         => lids.Where(lid => lid != null).ToArray();
 
     protected override void RecalculateTransform() { }
diff --git a/Assets/Scripts/InteractionEngine/FactHandling/Facts/VolumeFacts.cs b/Assets/Scripts/InteractionEngine/FactHandling/Facts/VolumeFacts.cs
new file mode 100644
index 0000000000000000000000000000000000000000..347dffe9098e27613b63ca36bb0fcbaa6169e44c
--- /dev/null
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/VolumeFacts.cs
@@ -0,0 +1,402 @@
+using System.Collections.Generic;
+using Newtonsoft.Json;
+using REST_JSON_API;
+
+/// <summary>
+/// The volume of a cone A  defined by a base area  <see cref="CircleFact">CircleFact</see>, an apex <see cref="PointFact">PointFact</see> and the volume as float
+/// </summary>
+public class ConeVolumeFact : FactWrappedCRTP<ConeVolumeFact>
+{
+    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
+    public string Cid1;
+    [JsonIgnore]
+    public CircleFact Circle { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+
+    ///  <summary> a <see cref="PointFact">PointFact</see> describing the apex point  </summary>
+    public string Pid1;
+    [JsonIgnore]
+    public PointFact Point { get => (PointFact)FactRecorder.AllFacts[Pid1]; }
+
+    ///  <summary> the volume of the cone as a float </summary>
+    public float vol;
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public ConeVolumeFact() : base()
+    {
+        this.Cid1 = null;
+        this.Pid1 = null;
+        this.vol = 0.0f;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates members and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="pid1">sets <see cref="Pid1"/></param>
+    /// <param name="vol">sets <see cref="vol"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public ConeVolumeFact(string cid1, string pid1, float vol, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+        this.Pid1 = pid1;
+        this.vol = vol;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Point.Position;
+        Rotation = Circle.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="Pid1">sets <see cref="Pid1"/></param>
+    /// <param name="volume">sets <see cref="vol"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public ConeVolumeFact(string Cid1, string Pid1, float volume, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+        this.Pid1 = Pid1;
+        this.vol = volume;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static ConeVolumeFact parseFact(MMTFact fact)
+    {
+        if (((MMTValueFact)fact).lhs is not OMA lhs)
+            return null;
+
+        string CircleUri = ((OMS)((OMA)lhs.arguments[0]).arguments[0]).uri;
+        string PointUri = ((OMS)((OMA)lhs.arguments[0]).arguments[1]).uri;
+
+        float volume = 0.0f;
+        if (((MMTValueFact)fact).value is OMF oMFvolume)
+            volume = oMFvolume.@float;
+
+        if (!FactRecorder.AllFacts.ContainsKey(CircleUri)
+         || !FactRecorder.AllFacts.ContainsKey(PointUri))
+            return null;
+
+        return new ConeVolumeFact(CircleUri, PointUri, volume, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => "V(" + Circle.Label + "," + Point.Label + ")";
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc lhs =
+            new OMA(
+                new OMS(MMTConstants.VolumeCone),
+
+                new[] {
+                    new OMA(new OMS(MMTConstants.ConeOfCircleApex),
+                        new[]  {
+                            new OMS(Cid1),
+                            new OMS(Pid1),
+                         }
+                    ),
+                }
+            );
+
+        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
+        SOMDoc value = new OMF(vol);
+
+        return new MMTValueFact(this.Label, lhs, valueTp, value);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1, Pid1 };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(ConeVolumeFact f1, ConeVolumeFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new ConeVolumeFact(old_to_new[this.Cid1], old_to_new[this.Pid1], this.vol, organizer);
+}
+
+/// <summary>
+/// The volume of a cone A  defined by a base area  <see cref="CircleFact">CircleFact</see>, a top area <see cref="CircleFact">CircleFact</see> and the volume as float
+/// </summary>
+public class TruncatedConeVolumeFact : FactWrappedCRTP<TruncatedConeVolumeFact>
+{
+    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
+    public string CidBase;
+    [JsonIgnore]
+    public CircleFact CircleBase { get => (CircleFact)FactRecorder.AllFacts[CidBase]; }
+
+    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the top area  </summary>
+    public string CidTop;
+    [JsonIgnore]
+    public CircleFact CircleTop { get => (CircleFact)FactRecorder.AllFacts[CidTop]; }
+
+    ///  <summary> the volume of Truncated the cone as a float </summary>
+    [JsonIgnore]
+    public float vol;
+    /// <summary> a proof that both circles have not the same size </summary>
+    public string unequalCirclesProof;
+    ///  <summary> OMA proof that the two circles are parallel  </summary>
+    public OMA proof;
+
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public TruncatedConeVolumeFact() : base()
+    {
+        this.CidBase = null;
+        this.CidTop = null;
+        this.vol = 0.0f;
+        this.unequalCirclesProof = null;
+        this.proof = null;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates members and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="CidBase"/></param>
+    /// <param name="cid2">sets <see cref="CidTop"/></param>
+    /// <param name="vol">sets <see cref="vol"/></param>
+    /// <param name="proof">sets <see cref="proof"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public TruncatedConeVolumeFact(string cid1, string cid2, float vol, string unequalproof, OMA proof, FactRecorder organizer) : base(organizer)
+    {
+        this.CidBase = cid1;
+        this.CidTop = cid2;
+        this.proof = proof;
+        this.unequalCirclesProof = unequalproof;
+        this.vol = vol;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = CircleTop.Position;
+        Rotation = CircleTop.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="CidBase"/></param>
+    /// <param name="Cid2">sets <see cref="CidTop"/></param>
+    /// <param name="volume">sets <see cref="vol"/></param>
+    /// <param name="proof">sets <see cref="proof"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public TruncatedConeVolumeFact(string Cid1, string Cid2, float volume, string unequalproof, OMA proof, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.CidBase = Cid1;
+        this.CidTop = Cid2;
+        this.vol = volume;
+        this.proof = proof;
+        this.unequalCirclesProof = unequalproof;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static TruncatedConeVolumeFact parseFact(MMTFact fact)
+    {
+        string Circle1Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[0]).uri;
+        string Circle2Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[1]).uri;
+        float volume = ((OMF)((MMTValueFact)fact).value).@float;
+
+        string UnEqualCirclesProof = ((OMS)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[2])).uri;
+        OMA proof = (OMA)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[3]);
+
+        if (!FactRecorder.AllFacts.ContainsKey(Circle1Uri)
+         || !FactRecorder.AllFacts.ContainsKey(Circle2Uri))
+            return null;
+
+        return new TruncatedConeVolumeFact(Circle1Uri, Circle2Uri, volume, UnEqualCirclesProof, proof, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => "V(" + CircleBase.Label + "," + CircleTop.Label + ")";
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc lhs =
+            new OMA(
+                new OMS(MMTConstants.TruncatedVolumeCone),
+                new SOMDoc[] {
+                    new OMS(CidBase),
+                    new OMS(CidTop),
+                    new OMS(unequalCirclesProof),
+                    proof,
+                }
+            );
+
+        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
+        SOMDoc value = new OMF(vol);
+
+        return new MMTValueFact(this.Label, lhs, valueTp, value);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { CidBase, CidTop };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(TruncatedConeVolumeFact f1, TruncatedConeVolumeFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new TruncatedConeVolumeFact(old_to_new[this.CidBase], old_to_new[this.CidTop], this.vol, old_to_new[this.unequalCirclesProof], this.proof, organizer);
+}
+
+/// <summary>
+/// The volume of a cylinder defined by a base area  <see cref="CircleFact">CircleFact</see>, a top area <see cref="CircleFact">CircleFact</see> and the volume as float
+/// </summary>
+public class CylinderVolumeFact : FactWrappedCRTP<CylinderVolumeFact>
+{
+    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the base area </summary>
+    public string Cid1;
+    [JsonIgnore]
+    public CircleFact Circle1 { get => (CircleFact)FactRecorder.AllFacts[Cid1]; }
+
+    ///  <summary> a <see cref="CircleFact">CircleFact</see> describing the top area  </summary>
+    public string Cid2;
+    [JsonIgnore]
+    public CircleFact Circle2 { get => (CircleFact)FactRecorder.AllFacts[Cid2]; }
+
+    ///  <summary> the volume of the cylinder as a float </summary>
+    public float vol;
+    /// <summary> a proof that both circles have the same size </summary>
+    public string equalCirclesProof;
+    ///  <summary> OMA proof that the two circles are parallel  </summary>
+    public OMA proof;
+
+    /// <summary> \copydoc Fact.Fact </summary>
+    public CylinderVolumeFact() : base()
+    {
+        this.Cid1 = null;
+        this.Cid2 = null;
+        this.vol = 0.0f;
+        this.proof = null;
+        this.equalCirclesProof = null;
+    }
+
+    /// <summary>
+    /// Standard Constructor:
+    /// Initiates members and creates MMT %Fact Server-Side
+    /// </summary>
+    /// <param name="cid1">sets <see cref="Cid1"/></param>
+    /// <param name="cid2">sets <see cref="Cid2"/></param>
+    /// <param name="vol">sets <see cref="vol"/></param>
+    /// <param name="proof">sets <see cref="proof"/></param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public CylinderVolumeFact(string cid1, string cid2, float vol, string eqProof, OMA proof, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = cid1;
+        this.Cid2 = cid2;
+        this.proof = proof;
+        this.equalCirclesProof = eqProof;
+        this.vol = vol;
+
+        SendToMMT();
+    }
+
+    protected override void RecalculateTransform()
+    {
+        Position = Circle2.Position;
+        Rotation = Circle2.Rotation;
+    }
+
+    /// <summary>
+    /// Bypasses initialization of new MMT %Fact by using existend URI, _which is not checked for existence_.
+    /// </summary>
+    /// <param name="Cid1">sets <see cref="Cid1"/></param>
+    /// <param name="Cid2">sets <see cref="Cid2"/></param>
+    /// <param name="volume">sets <see cref="vol"/></param>
+    /// <param name="proof">sets <see cref="proof"/></param>
+    /// <param name="backendURI">MMT URI</param>
+    /// <param name="organizer">sets <see cref="Fact._Facts"/></param>
+    public CylinderVolumeFact(string Cid1, string Cid2, float volume, string eqProof, OMA proof, string backendURI, FactRecorder organizer) : base(organizer)
+    {
+        this.Cid1 = Cid1;
+        this.Cid2 = Cid2;
+        this.vol = volume;
+        this.proof = proof;
+        this.equalCirclesProof = eqProof;
+
+        this._URI = backendURI;
+        _ = this.Label;
+    }
+
+    /// \copydoc Fact.parseFact(ScrollFact)
+    public new static CylinderVolumeFact parseFact(MMTFact fact)
+    {
+        string Circle1Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[0]).uri;
+        string Circle2Uri = ((OMS)((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[1]).uri;
+        float volume = ((OMF)((MMTValueFact)fact).value).@float;
+        string EqualCirclesProof = ((OMS)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[2])).uri;
+
+        OMA proof = (OMA)(((OMA)((OMA)((MMTValueFact)fact).lhs).arguments[0]).arguments[3]);
+
+        if (!FactRecorder.AllFacts.ContainsKey(Circle1Uri)
+         || !FactRecorder.AllFacts.ContainsKey(Circle2Uri))
+            return null;
+
+        return new CylinderVolumeFact(Circle1Uri, Circle2Uri, volume, EqualCirclesProof, proof, fact.@ref.uri, StageStatic.stage.factState);
+    }
+
+    /// \copydoc Fact.generateLabel
+    protected override string generateLabel()
+        => "V(" + Circle1.Label + "," + Circle2.Label + ")";
+
+    public override MMTFact MakeMMTDeclaration()
+    {
+        SOMDoc lhs =
+            new OMA(
+                new OMS(MMTConstants.CylinderVolume),
+
+                new SOMDoc[] {
+                    new OMS(Cid1),
+                    new OMS(Cid2),
+                    new OMS(equalCirclesProof),
+                    proof,
+                }
+            );
+
+        SOMDoc valueTp = new OMS(MMTConstants.RealLit);
+        SOMDoc value = new OMF(vol);
+
+        return new MMTValueFact(this.Label, lhs, valueTp, value);
+    }
+
+    /// \copydoc Fact.hasDependentFacts
+    public override bool HasDependentFacts => true;
+
+    /// \copydoc Fact.getDependentFactIds
+    protected override string[] GetDependentFactIds()
+        => new string[] { Cid1, Cid2, equalCirclesProof };
+
+    /// \copydoc Fact.Equivalent(Fact, Fact)
+    protected override bool EquivalentWrapped(CylinderVolumeFact f1, CylinderVolumeFact f2)
+        => DependentFactsEquivalent(f1, f2);
+
+    protected override Fact _ReInitializeMe(Dictionary<string, string> old_to_new, FactRecorder organizer)
+        => new CylinderVolumeFact(old_to_new[this.Cid1], old_to_new[this.Cid2], this.vol, old_to_new[this.equalCirclesProof], this.proof, organizer);
+}
\ No newline at end of file
diff --git a/Assets/Scripts/InventoryStuff/PythagorasScript.cs.meta b/Assets/Scripts/InteractionEngine/FactHandling/Facts/VolumeFacts.cs.meta
similarity index 83%
rename from Assets/Scripts/InventoryStuff/PythagorasScript.cs.meta
rename to Assets/Scripts/InteractionEngine/FactHandling/Facts/VolumeFacts.cs.meta
index d103391a54d7b560a25e62dcf0a525e66a54ef9c..7a4644ed38caf8df47e00b59cc98b55525301476 100644
--- a/Assets/Scripts/InventoryStuff/PythagorasScript.cs.meta
+++ b/Assets/Scripts/InteractionEngine/FactHandling/Facts/VolumeFacts.cs.meta
@@ -1,5 +1,5 @@
 fileFormatVersion: 2
-guid: 413dcae9856bd794ab03d29210561c57
+guid: 4ffde2f4d1b634a4e9e8e98b8b01ca64
 MonoImporter:
   externalObjects: {}
   serializedVersion: 2
diff --git a/Assets/Scripts/InteractionEngine/WorldCursor.cs b/Assets/Scripts/InteractionEngine/WorldCursor.cs
index b5689c10c562b974ddfea34bd2259b0d500f29b9..746c97c592598b3f30f4a410a91b271b961b769c 100644
--- a/Assets/Scripts/InteractionEngine/WorldCursor.cs
+++ b/Assets/Scripts/InteractionEngine/WorldCursor.cs
@@ -92,12 +92,12 @@ void Update()
             else if (fact is CircleFact circleFact)
             {
                 var projPlane =
-                    Math3d.ProjectPointOnPlane(circleFact.normal, circleFact.Point1.Point, Hits[i].point);
+                    Math3d.ProjectPointOnPlane(circleFact.normal, circleFact.PointCenter.Point, Hits[i].point);
 
-                var circleDistance = projPlane - circleFact.Point1.Point;
+                var circleDistance = projPlane - circleFact.PointCenter.Point;
                 if (circleDistance.magnitude >= circleFact.radius)
                 {
-                    projPlane = circleFact.Point1.Point + circleDistance.normalized * circleFact.radius;
+                    projPlane = circleFact.PointCenter.Point + circleDistance.normalized * circleFact.radius;
                     Hits[i].normal = circleDistance.normalized;
                 }
 
diff --git a/Assets/Scripts/InventoryStuff/PointWrapper.cs b/Assets/Scripts/InventoryStuff/PointWrapper.cs
deleted file mode 100644
index a8da0acd5943d0d223f7cd13b2eaa03b34e2e9b5..0000000000000000000000000000000000000000
--- a/Assets/Scripts/InventoryStuff/PointWrapper.cs
+++ /dev/null
@@ -1,6 +0,0 @@
-using UnityEngine;
-
-public class PointWrapper : MonoBehaviour
-{
-    public Fact point;
-}
diff --git a/Assets/Scripts/InventoryStuff/PythagorasScript.cs b/Assets/Scripts/InventoryStuff/PythagorasScript.cs
deleted file mode 100644
index 0b7537d1d9fce9776263e1d6b0c02cfaffbd0775..0000000000000000000000000000000000000000
--- a/Assets/Scripts/InventoryStuff/PythagorasScript.cs
+++ /dev/null
@@ -1,25 +0,0 @@
-using System.Collections.Generic;
-using UnityEngine;
-
-public class PythagorasScript : MonoBehaviour
-{
-    private Dictionary<string, Fact> items = new Dictionary<string, Fact>();
-
-    public void putFact(string name, Fact obj)
-    {
-        if (this.items.ContainsKey(name))
-        {
-            this.items.Remove(name);
-        }
-        this.items.Add(name, obj);
-    }
-
-    public void doMagic()
-    {
-        Dictionary<string, Fact>.Enumerator enumerator = this.items.GetEnumerator();
-        while (enumerator.MoveNext())
-        {
-            Debug.Log(enumerator.Current.Key + " is mapped to " + enumerator.Current.Value);
-        }
-    }
-}
diff --git a/Assets/Scripts/InventoryStuff/ToggleRotateImage.cs b/Assets/Scripts/InventoryStuff/ToggleRotateImage.cs
index 84a91bdd19ec5b2bb3ca82f63cbef986d78c1c88..3c893c1023de43904f33fa1d0946615534550a36 100644
--- a/Assets/Scripts/InventoryStuff/ToggleRotateImage.cs
+++ b/Assets/Scripts/InventoryStuff/ToggleRotateImage.cs
@@ -6,10 +6,7 @@ public class ToggleRotateImage : MonoBehaviour {
     [SerializeField] Transform targetGraphic; 
 
     Toggle _toggle;
-    Toggle toggle
-    {
-        get { return _toggle ?? (_toggle = GetComponent<Toggle>()); }
-    }
+    Toggle toggle => _toggle ??= GetComponent<Toggle>();
 
     void Awake()
     {
diff --git a/Assets/Scripts/MMTServer/CommunicationProtocoll/MMTConstants.cs b/Assets/Scripts/MMTServer/CommunicationProtocoll/MMTConstants.cs
index 61695802a6f93b2cde7a0971b153ba80d011a451..d2c3fe51bbff7b0fccd38bd28a2497847c48a287 100644
--- a/Assets/Scripts/MMTServer/CommunicationProtocoll/MMTConstants.cs
+++ b/Assets/Scripts/MMTServer/CommunicationProtocoll/MMTConstants.cs
@@ -7,6 +7,7 @@ namespace REST_JSON_API
     public static class MMTConstants
     {
         public static readonly string Point = "http://mathhub.info/MitM/core/geometry?3DGeometry?point";
+        public static readonly string Wall = "?wall";
         public static readonly string LineType = "http://mathhub.info/MitM/core/geometry?Geometry/Common?line_type";
         public static readonly string LineOf = "http://mathhub.info/MitM/core/geometry?Geometry/Common?lineOf";
 
diff --git a/Assets/Scripts/MeshGenerator/BoundingPositioning.cs b/Assets/Scripts/MeshGenerator/BoundingPositioning.cs
new file mode 100644
index 0000000000000000000000000000000000000000..0805001d41f19ae75e4af3887603c2ef160a1f66
--- /dev/null
+++ b/Assets/Scripts/MeshGenerator/BoundingPositioning.cs
@@ -0,0 +1,37 @@
+using UnityEngine;
+
+public class BoundingPositioning : MonoBehaviour
+{
+    public Anker x = Anker.center;
+    public Anker y = Anker.center;
+    public Anker z = Anker.center;
+
+    public MeshFilter mesh = null;
+
+    public enum Anker
+    {
+        min = 0, center = 1, max = 2
+    }
+
+    private void OnValidate() => UpdatePosition();
+    private void Awake() => UpdatePosition();
+
+    private void UpdatePosition()
+    {
+        if (mesh == null
+         || mesh.sharedMesh == null)
+            return;
+
+        Vector3[] bounds = {
+            mesh.sharedMesh.bounds.min,
+            mesh.sharedMesh.bounds.center,
+            mesh.sharedMesh.bounds.max,
+        };
+
+        transform.position = new Vector3(
+            bounds[(int)x][0], 
+            bounds[(int)y][1], 
+            bounds[(int)z][2]
+        );
+    }
+}
diff --git a/Assets/Scripts/MeshGenerator/BoundingPositioning.cs.meta b/Assets/Scripts/MeshGenerator/BoundingPositioning.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..0ceb274da7a6c9adc7ee7ba396e684aa2f46c357
--- /dev/null
+++ b/Assets/Scripts/MeshGenerator/BoundingPositioning.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0b53a9efe2eaabd4a9ae38ae148bed9e
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/MeshGenerator/CircleGenerator.cs b/Assets/Scripts/MeshGenerator/CircleGenerator.cs
index c07a99c8b781fc2cecc3b98dd291178457b68bcd..5f8e3b70e2598908e1ea01991ee59914240c0a32 100644
--- a/Assets/Scripts/MeshGenerator/CircleGenerator.cs
+++ b/Assets/Scripts/MeshGenerator/CircleGenerator.cs
@@ -1,7 +1,6 @@
 using System;
-using System.Collections.Generic;
-using UnityEngine;
 using System.Linq;
+using UnityEngine;
 
 public class CircleGenerator : ShapeGenerator
 {
@@ -11,28 +10,11 @@ public class CircleGenerator : ShapeGenerator
 
     [Header("Technical")]
     [Range(3,1000)] public int sideCount = 500;
-
-    [Header("Parts")]
-    public List<MeshFilter> circleMesh;
     #endregion InspectorVariables
 
     #region Implementation
-    protected override void GenerateShape()
-    {
-        foreach (MeshFilter filter in circleMesh)
-        {
-            if (filter == null) continue;
-
-            var circle = CreateCircle(radius, sideCount);
-
-            if (filter.sharedMesh != null)
-                filter.sharedMesh.Clear();
-            filter.mesh = CreateMesh(circle);
-
-            if (filter.transform.TryGetComponent(out MeshCollider meshCol))
-                meshCol.sharedMesh = filter.sharedMesh;
-        }
-    }
+    protected override (Vector3[] vertices, int[] triangles) GenerateTopology()
+        => CreateCircle(radius, sideCount);
 
     /// <summary>
     /// Creates circle vertecies and triangles around the midPoint at (0,0,0)
@@ -40,18 +22,19 @@ protected override void GenerateShape()
     /// <param name="points"></param>
     /// <param name="invert"></param>
     /// <returns></returns>
-    static (Vector3[], int[]) CreateCircle(float radius, int sideCount, bool invert = false)
+    public static (Vector3[], int[]) CreateCircle(float radius, int sideCount, Vector3 offset, bool invert = false)
     {
-        Vector3[] vertices = GetCirclePoints(radius, sideCount).Union(new Vector3[] { Vector3.zero }).ToArray();
-        int[] triangles = new int[(vertices.Length - 1) * 3];
-        int vertLen = vertices.Length;
-        for (int i = 0; i < vertLen-1; i++)
-        {
-            triangles[i * 3 + 0] = vertLen-1; // midPoint
-            triangles[i * 3 + 1] = i;
-            triangles[i * 3 + 2] = (i + 1) % (vertLen-1);
-        }
-        return (vertices, invert ? triangles.Reverse().ToArray() : triangles);
+        Vector3[] edge = GetCirclePoints(radius, sideCount);
+        Vector3[] vertices =
+            new Vector3[] { offset }
+            .AppendRange(edge)
+            .Append(edge[0])
+            .ToArray();
+
+        return CreatePlane(vertices, invert);
     }
+
+    public static (Vector3[], int[]) CreateCircle(float radius, int sideCount, bool invert = false)
+        => CreateCircle(radius, sideCount, Vector3.zero, invert);
     #endregion Implementation
 }
diff --git a/Assets/Scripts/MeshGenerator/ConeGenerator.cs b/Assets/Scripts/MeshGenerator/ConeGenerator.cs
index 73cc683360f1c588a9765645aa395ea5824a5fc0..ebc95111e39c11e369f3eb94069e60a4908da894 100644
--- a/Assets/Scripts/MeshGenerator/ConeGenerator.cs
+++ b/Assets/Scripts/MeshGenerator/ConeGenerator.cs
@@ -1,82 +1,56 @@
 using System;
-using System.Collections;
-using System.Collections.Generic;
-using UnityEngine;
 using System.Linq;
+using UnityEngine;
 
 public class ConeGenerator : ShapeGenerator
 {
     #region InspectorVariables
     [Header("Cone values")]
-    [Range(0,100)] public float bottomRadius = 1f;
-    [Range(0,100)] public float topRadius = 0f;
+    [Range(0, 100)] public float bottomRadius = 1f;
+    [Range(0, 100)] public float topRadius = 0f;
     public Vector3 topPosition = new Vector3(0, 1f, 0);
 
     [Header("Technical")]
-    [Range(3,1000)] public int sideCount = 500;
-    public bool generateTop = true;
-    public bool generateBottom = false;
-
-    [Header("Parts")]
-    public MeshFilter topMesh;
-    public MeshFilter sideMesh;
-    public MeshFilter bottomMesh;
+    [Range(3,1000)] 
+    public int sideCount = 500;
     #endregion InspectorVariables
 
     #region Implementation
-    protected override void GenerateShape()
+    protected override (Vector3[] vertices, int[] triangles) GenerateTopology()
     {
-        Vector3[] bottomCircle = GetCirclePoints(bottomRadius, sideCount);
-        Vector3[] topCircle = GetCirclePoints(topRadius, sideCount, topPosition);
+        Vector3[] top_circle = new[] { topPosition };
+        Vector3[] bottom_circle = new[] { Vector3.zero };
 
-        if (sideMesh == null || topMesh == null || bottomMesh == null)
-            return;
+        int[] top_boundary = new int[] { 0 };
+        int[] bottom_boundary = new int[] { 0 };
 
-        //side
-        if (sideMesh.sharedMesh != null)
-            sideMesh.sharedMesh.Clear();
-        sideMesh.mesh = CreateMesh(CreateConeSide(sideCount, bottomCircle, topCircle));
-
-        //top
-        if (topMesh.sharedMesh != null)
-            topMesh.sharedMesh.Clear();
-        if (generateTop)
-            topMesh.mesh = CreateMesh(CreatePlane(topCircle, false));
-
-        //bottom
-        if (bottomMesh.sharedMesh != null)
-            bottomMesh.sharedMesh.Clear();
-        if (generateBottom)
-            bottomMesh.mesh = CreateMesh(CreatePlane(bottomCircle, true));
-    }
-
-    private static (Vector3[], int[]) CreateConeSide(int sideCount, Vector3[] bottomCircle, Vector3[] topCircle)
-    {
-        Vector3[] vertices = new Vector3[sideCount * 4];
-        int[] triangles = new int[sideCount * 6];
-
-        //generate vertices
-        for (int i = 0; i < sideCount; i++)
+        if (topRadius > 0f)
         {
-            vertices[i * 4] = bottomCircle[i];
-            vertices[i * 4 + 1] = bottomCircle[(i + 1) % sideCount];
-            vertices[i * 4 + 2] = topCircle[i];
-            vertices[i * 4 + 3] = topCircle[(i + 1) % sideCount];
-        }
+            Vector3[] edge = GetCirclePoints(topRadius, sideCount, topPosition);
+            top_circle = top_circle
+                .AppendRange(edge)
+                .Append(edge[0])
+                .ToArray();
 
-        //generate triangles
-        for (int t = 0, i = 0; t < triangles.Length; t += 6, i += 4)
+            top_boundary = Enumerable.Range(1, edge.Length).ToArray();
+        }
+        if (bottomRadius > 0f)
         {
-            triangles[t]     = i;
-            triangles[t + 1] = i + 1;
-            triangles[t + 2] = i + 2;
+            Vector3[] edge = GetCirclePoints(bottomRadius, sideCount);
+            bottom_circle = bottom_circle
+                .AppendRange(edge)
+                .Append(edge[0])
+                .ToArray();
 
-            triangles[t + 3] = i + 1;
-            triangles[t + 4] = i + 3;
-            triangles[t + 5] = i + 2;
+            bottom_boundary = Enumerable.Range(1, edge.Length).ToArray();
         }
 
-        return (vertices, triangles);
+        return CreatePrism(
+                    CreatePlane(top_circle),
+                    CreatePlane(bottom_circle, true),
+                    top_boundary,
+                    bottom_boundary
+                );
     }
     #endregion Implementation
 }
diff --git a/Assets/Scripts/MeshGenerator/PlaneGenerator.cs b/Assets/Scripts/MeshGenerator/PlaneGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..6d89d16dd78b27932a71dd35d018c0095e6ef09e
--- /dev/null
+++ b/Assets/Scripts/MeshGenerator/PlaneGenerator.cs
@@ -0,0 +1,24 @@
+using UnityEngine;
+
+public class PlaneGenerator : ShapeGenerator
+{
+    #region InspectorVariables
+    [Header("Plane values")]
+    [SerializeField]
+    protected Vector3[] _vertices;
+    public Vector3[] Vertices
+    {
+        get => _vertices.Clone() as Vector3[];
+        set
+        {
+            _vertices = value;
+            GenerateShapeForAll();
+        }
+    }
+    #endregion InspectorVariables
+
+    #region Implementation
+    protected override (Vector3[] vertices, int[] triangles) GenerateTopology()
+        => CreatePlane(_vertices);
+    #endregion Implementation
+}
\ No newline at end of file
diff --git a/Assets/Scripts/MeshGenerator/PlaneGenerator.cs.meta b/Assets/Scripts/MeshGenerator/PlaneGenerator.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..603ca4b52a69c7c647fe3f3a0d4787b9a21bfb82
--- /dev/null
+++ b/Assets/Scripts/MeshGenerator/PlaneGenerator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f599175127741c14f97241d989002207
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/MeshGenerator/PrismGenerator.cs b/Assets/Scripts/MeshGenerator/PrismGenerator.cs
new file mode 100644
index 0000000000000000000000000000000000000000..9a0c646baa672da1851003a0c13ebd50e8360cce
--- /dev/null
+++ b/Assets/Scripts/MeshGenerator/PrismGenerator.cs
@@ -0,0 +1,36 @@
+using System.Linq;
+using UnityEngine;
+
+public class PrismGenerator : PlaneGenerator
+{
+    #region InspectorVariables
+    [Header("Plane values")]
+    [SerializeField]
+    private Vector3 _offset;
+    public Vector3 Offset
+    {
+        get => _offset;
+        set
+        {
+            _offset = value;
+            GenerateShapeForAll();
+        }
+    }
+    #endregion InspectorVariables
+
+    #region Implementation
+    protected override (Vector3[] vertices, int[] triangles) GenerateTopology()
+    {
+        (Vector3[] vertices, int[] triangles) plane = CreatePlane(_vertices);
+        Vector3 center = CreateMesh(plane).bounds.center;
+
+        return CreatePrism(
+                (plane.vertices.Select(v => v + _offset).ToArray()
+                    , plane.triangles),
+                (plane.vertices.Select(v => v).ToArray()
+                    , plane.triangles.Reverse().ToArray()),
+                null, null
+            );
+    }
+    #endregion Implementation
+}
\ No newline at end of file
diff --git a/Assets/Scripts/MeshGenerator/PrismGenerator.cs.meta b/Assets/Scripts/MeshGenerator/PrismGenerator.cs.meta
new file mode 100644
index 0000000000000000000000000000000000000000..5265c9a4b186d26d14a9c7ace1ea72c834536119
--- /dev/null
+++ b/Assets/Scripts/MeshGenerator/PrismGenerator.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2a639f1d1c3cdeb42bc5a7a66401dc02
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Assets/Scripts/MeshGenerator/ShapeGenerator.cs b/Assets/Scripts/MeshGenerator/ShapeGenerator.cs
index b7309740d44bdaadf2fc29a945825c48cea7ce39..2ce160f9cc95cdff58e72f43f023a1d4c9e8b821 100644
--- a/Assets/Scripts/MeshGenerator/ShapeGenerator.cs
+++ b/Assets/Scripts/MeshGenerator/ShapeGenerator.cs
@@ -1,32 +1,79 @@
+using System;
+using System.Collections.Generic;
 using System.Linq;
+using Unity.Mathematics;
 using UnityEngine;
 
 public abstract class ShapeGenerator : MonoBehaviour
 {
+    #region InspectorVariables
+    [Header("Parts")]
+    public List<MeshFilter> Meshs;
+    public List<float> NormalOffset;
+    public bool AlternateNormals = false;
+    #endregion InspectorVariables
+
     #region UnityMethods
-    void Start() => GenerateShape();
+    void Start() => GenerateShapeForAll();
 
-    #if UNITY_EDITOR
+#if UNITY_EDITOR
     void OnValidate()
     {
         // prevent 'SendMessage cannot be called during Awake, CheckConsistency, or OnValidate' warning
-        UnityEditor.EditorApplication.delayCall += GenerateShape;
+        UnityEditor.EditorApplication.delayCall += GenerateShapeForAll;
     }
-    #endif
+#endif
     #endregion UnityMethods
 
-    protected abstract void GenerateShape();
+    protected void GenerateShapeForAll()
+    {
+        float[] _NormalOffset = new float[Meshs.Count];
+        NormalOffset?.CopyTo(0, _NormalOffset, 0
+            , math.min(NormalOffset.Count, Meshs.Count));
+
+        for (int i = 0; i < Meshs.Count; i++)
+        {
+            MeshFilter filter = Meshs[i];
+            if (filter == null)
+                continue;
+
+            Mesh mesh = CreateMesh(GenerateTopology());
+            var normals = AlternateNormals 
+                ? GetUnweightedNormals(mesh)
+                : mesh.normals;
+
+            mesh.SetVertices(
+                mesh.vertices
+                .Zip(normals, (v, n) 
+                    => v + n * _NormalOffset[i])
+                .ToList()
+            );
+
+            if (filter.sharedMesh != null)
+                filter.sharedMesh.Clear();
+            filter.sharedMesh = mesh;
+
+            if (filter.transform.TryGetComponent(out MeshCollider meshCol))
+                meshCol.sharedMesh = filter.sharedMesh;
+        }
+    }
+
+    protected abstract (Vector3[] vertices, int[] triangles) GenerateTopology();
 
     #region Helper
     protected static Mesh CreateMesh((Vector3[] vertices, int[] triangles) meshValues)
     {
-        Mesh mesh = new Mesh();
-        (mesh.vertices, mesh.triangles) = (meshValues.vertices, meshValues.triangles);
+        Mesh mesh = new()
+        {
+            vertices = meshValues.vertices,
+            triangles = meshValues.triangles
+        };
+        mesh.Optimize();
         mesh.RecalculateNormals(); //fix lighting
         return mesh;
     }
 
-    protected static Vector3[] GetCirclePoints(float circleRadius, int pointCount) 
+    protected static Vector3[] GetCirclePoints(float circleRadius, int pointCount)
         => GetCirclePoints(circleRadius, pointCount, Vector3.zero);
 
     protected static Vector3[] GetCirclePoints(float circleRadius, int pointCount, Vector3 offset)
@@ -35,8 +82,13 @@ protected static Vector3[] GetCirclePoints(float circleRadius, int pointCount, V
         float slice = (2f * Mathf.PI) / pointCount;
         for (int i = 0; i < pointCount; i++)
         {
-            float angle = i * slice;
-            circle[i] = new Vector3(circleRadius * Mathf.Sin(angle), 0, circleRadius * Mathf.Cos(angle)) + offset;
+            float rad_angle = i * slice;
+            circle[i] =
+                new Vector3(
+                    circleRadius * Mathf.Sin(rad_angle),
+                    0,
+                    circleRadius * Mathf.Cos(rad_angle)
+                ) + offset;
         }
         return circle;
     }
@@ -47,9 +99,11 @@ protected static Vector3[] GetCirclePoints(float circleRadius, int pointCount, V
     /// <param name="points"></param>
     /// <param name="invert"></param>
     /// <returns></returns>
-    protected static (Vector3[], int[]) CreatePlane(Vector3[] points, bool invert = false)
+    protected static (Vector3[] vertices, int[] triangles) CreatePlane(Vector3[] vertices, bool invert = false)
     {
-        Vector3[] vertices = points;
+        if (vertices.Length < 3)
+            return (vertices, new int[0]);
+
         int[] triangles = new int[(vertices.Length - 2) * 3];
         for (int i = 1; i < vertices.Length - 1; i++)
         {
@@ -57,7 +111,98 @@ protected static (Vector3[], int[]) CreatePlane(Vector3[] points, bool invert =
             triangles[(i - 1) * 3 + 1] = i;
             triangles[(i - 1) * 3 + 2] = (i + 1);
         }
+
         return (vertices, invert ? triangles.Reverse().ToArray() : triangles);
     }
+
+    protected static (Vector3[] vertices, int[] triangles) CreatePrism(
+        (Vector3[] vertices, int[] triangles) top,
+        (Vector3[] vertices, int[] triangles) bottom,
+        int[] boundary_top,
+        int[] boundary_bottom
+    )
+    {
+        boundary_top ??= Enumerable.Range(0, top.vertices.Length).ToArray();
+        boundary_bottom ??= Enumerable.Range(0, bottom.vertices.Length).ToArray();
+
+        if (boundary_top.Length != boundary_bottom.Length)
+            Debug.LogWarning("Arguments of different Size; Resulting mesh may be weird!");
+        int max = math.max(boundary_top.Length, boundary_bottom.Length);
+        int tri_sum = top.triangles.Length + bottom.triangles.Length;
+
+        Vector3[] new_vertices = top.vertices.ShallowCloneAppend(bottom.vertices);
+
+        int[] new_triangles = new int[tri_sum + 2 * max * 3];
+        top.triangles.CopyTo(new_triangles, 0);
+        bottom.triangles
+            .Select(i => i + top.vertices.Length)
+            .ToArray()
+            .CopyTo(new_triangles, top.triangles.Length);
+
+        for (int i = 0; i < max; i++)
+        {
+            if (boundary_top.Length > 1)
+            {
+                new_triangles[tri_sum + i * 6 + 0] = boundary_top[(i + 1) % boundary_top.Length];
+                new_triangles[tri_sum + i * 6 + 1] = boundary_top[i % boundary_top.Length];
+                new_triangles[tri_sum + i * 6 + 2] =
+                    top.vertices.Length + boundary_bottom[i % boundary_bottom.Length];
+            }
+            if (boundary_bottom.Length > 1)
+            {
+                new_triangles[tri_sum + i * 6 + 3] =
+                    top.vertices.Length + boundary_bottom[i % boundary_bottom.Length];
+                new_triangles[tri_sum + i * 6 + 4] =
+                    top.vertices.Length + boundary_bottom[(i + 1) % boundary_bottom.Length];
+                new_triangles[tri_sum + i * 6 + 5] = boundary_top[(i + 1) % boundary_top.Length];
+            }
+        }
+
+        return (new_vertices, new_triangles);
+    }
+
+    // Artefacts appear when mesh is unbalanced (e.g. many edges at one vert)
+    public static Vector3[] GetUnweightedNormals(Mesh mesh)
+    {
+        int[] triangles = mesh.triangles;
+        Vector3[] verts = mesh.vertices;
+
+        Vector3[] normals = new Vector3[mesh.vertexCount];
+        int[] weightsum = new int[mesh.vertexCount];
+
+        HashSet<int>[] deltas = new HashSet<int>[mesh.vertexCount];
+        for (int i = 0; i < deltas.Length; i++)
+            deltas[i] = new();
+
+        for (int i = 0; i < triangles.Length; i += 3)
+        {
+            AddEdge(triangles[i + 0], triangles[i + 1]);
+            AddEdge(triangles[i + 0], triangles[i + 2]);
+
+            AddEdge(triangles[i + 1], triangles[i + 0]);
+            AddEdge(triangles[i + 1], triangles[i + 2]);
+
+            AddEdge(triangles[i + 2], triangles[i + 0]);
+            AddEdge(triangles[i + 2], triangles[i + 1]);
+        }
+
+        for (int i = 0; i < normals.Length; i++)
+            normals[i] = (normals[i] / weightsum[i]).normalized;
+
+        return normals;
+
+        void AddEdge(int this_id, int other_id)
+        {
+            if (deltas[this_id].Add(other_id))
+            {
+                Vector3 delta = (verts[this_id] - verts[other_id]).normalized;
+                if (Math3d.IsApproximatelyEqual(delta, Vector3.zero))
+                    return;
+
+                normals[this_id] += delta;
+                weightsum[this_id]++;
+            }
+        }
+    }
     #endregion Helper
 }
diff --git a/Assets/Scripts/MeshGenerator/TorusGenerator.cs b/Assets/Scripts/MeshGenerator/TorusGenerator.cs
index 4ea8e96e3a6abaee0b69ef7b9d2c9fa456fd6c31..8601672bbccac243bbac8896339e76d561c07eb3 100644
--- a/Assets/Scripts/MeshGenerator/TorusGenerator.cs
+++ b/Assets/Scripts/MeshGenerator/TorusGenerator.cs
@@ -6,61 +6,53 @@ public class TorusGenerator : ShapeGenerator
     #region InspectorVariables
     [Header("Torus values")]
     [Range(0, 100)] public float torusRadius = 1f;
-    [Range(0, 10)]  public float ringRadius = 0.1f;
+    [Range(0, 10)] public float ringRadius = 0.1f;
 
     [Header("Technical")]
     [Range(8, 150)] public int ringSegmentCount = 50;
     [Range(3, 100)] public int segmentSideCount = 30;
-
-    [Header("Parts")]
-    public MeshFilter torusMesh;
     #endregion InspectorVariables
 
     #region Implementation
-    protected override void GenerateShape()
-    {
-        if (torusMesh == null)
-            return;
-
-        if (torusMesh.sharedMesh != null)
-            torusMesh.sharedMesh.Clear();
-
-        torusMesh.mesh = CreateMesh(CreateTorus(torusRadius, ringRadius, ringSegmentCount, segmentSideCount));
-
-        if (torusMesh.transform.TryGetComponent(out MeshCollider meshCol))
-            meshCol.sharedMesh = torusMesh.sharedMesh;
-    }
+    protected override (Vector3[] vertices, int[] triangles) GenerateTopology()
+        => CreateTorus(torusRadius, ringRadius, ringSegmentCount, segmentSideCount);
 
     private static (Vector3[] vertices, int[] triangles) CreateTorus(float torusRadius, float ringRadius, int ringSegmentCount, int segmentSideCount)
     {
-        Vector3[] vertices = new Vector3[ringSegmentCount * segmentSideCount * 4];
+        Vector3[] vertices = new Vector3[ringSegmentCount * segmentSideCount];
         int[] triangles = new int[ringSegmentCount * segmentSideCount * 6];
 
-        //generate vertices
         float iStep = (2f * Mathf.PI) / ringSegmentCount;
         float jStep = (2f * Mathf.PI) / segmentSideCount;
+
+        int t = 0;
         for (int i = 0; i < ringSegmentCount; i++)
-        {
             for (int j = 0; j < segmentSideCount; j++)
             {
-                vertices[(i * segmentSideCount + j) * 4]     = GetPointOnTorus(torusRadius, ringRadius, i * iStep, j * jStep);
-                vertices[(i * segmentSideCount + j) * 4 + 1] = GetPointOnTorus(torusRadius, ringRadius, i * iStep, (j + 1) * jStep);
-                vertices[(i * segmentSideCount + j) * 4 + 2] = GetPointOnTorus(torusRadius, ringRadius, (i + 1) * iStep, j * jStep);
-                vertices[(i * segmentSideCount + j) * 4 + 3] = GetPointOnTorus(torusRadius, ringRadius, (i + 1) * iStep, (j + 1) * jStep);
-            }
-        }
+                //generate vertices
+                vertices[i * segmentSideCount + j] = GetPointOnTorus(torusRadius, ringRadius, i * iStep, j * jStep);
 
-        //generate triangles
-        for (int t = 0, i = 0; t < triangles.Length; t += 6, i += 4)
-        {
-            triangles[t]   = i;
-            triangles[t+1] = i + 1;
-            triangles[t+2] = i + 2;
+                //generate triangles
+                triangles[t++] =
+                    (i + 0) % ringSegmentCount * segmentSideCount
+                    + (j + 0) % segmentSideCount;
+                triangles[t++] =
+                    (i + 1) % ringSegmentCount * segmentSideCount
+                    + (j + 0) % segmentSideCount;
+                triangles[t++] =
+                    (i + 1) % ringSegmentCount * segmentSideCount
+                    + (j + 1) % segmentSideCount;
 
-            triangles[t+3] = i + 1;
-            triangles[t+4] = i + 3;
-            triangles[t+5] = i + 2;
-        }
+                triangles[t++] =
+                    (i + 1) % ringSegmentCount * segmentSideCount
+                    + (j + 1) % segmentSideCount;
+                triangles[t++] =
+                    (i + 0) % ringSegmentCount * segmentSideCount
+                    + (j + 1) % segmentSideCount;
+                triangles[t++] =
+                    (i + 0) % ringSegmentCount * segmentSideCount
+                    + (j + 0) % segmentSideCount;
+            }
 
         return (vertices, triangles);
     }
diff --git a/ProjectSettings/TagManager.asset b/ProjectSettings/TagManager.asset
index 408e5aa981a3d2e4738e6a4b162f9d15d919ff8d..200e61f66ac65754e32d641bcca9475ac1f220d3 100644
--- a/ProjectSettings/TagManager.asset
+++ b/ProjectSettings/TagManager.asset
@@ -28,8 +28,8 @@ TagManager:
   - Ray
   - Ring
   - Circle
-  - 
-  - 
+  - Plane
+  - Cone
   - TalkingZone
   - Tree
   - SnapZone