diff --git a/README.md b/README.md
index 7c3d21d242c76ba7d91b7e58eb4501241557a18d..0ce61b85b8a8307ebfd7b674d1ea7e449fe80bef 100644
--- a/README.md
+++ b/README.md
@@ -1,101 +1,61 @@
-# IVMI
+# IVMI-builder
 
 (work in progress)
 
-Godot 3.X and PureData > 0.51
+IVMI-builder is a free-software framework that facilitates the design of 
+Immersive Virtual Musical Instruments. It relies on the Godot game engine
+and the PureData audio programming language.
 
-Facilitates creating immersive instruments
 
-Connects to or integrates PureData patches 
+## Prerequisites
 
-Share scenes 
-
-## Install
-
-To run the Pd patches, install gdpd, otherwise you can run PureData 
-on a computer on the same network, which enables live-editing of the sound
-synthesis while the instrument is running.
-
-To render with an OpenXR compatible device (HMD, mobile) install godot-openxr
-
-To render on a stereoscopic (anaglyph, passive in splitscreen, or quadbuffer) 
-display install GdScreenVr
-
----
-
-## Example instruments
-
-todo
-
----
-
-## Connecting to PureData
-
-todo
-
-### OpenSoundControl and live editing
-
-todo
-
-### Release with LibPd
-
-todo
+* PureData from [https://puredata.info](https://puredata.info)
+* Godot 4.x from [https://godotengine.org/](https://godotengine.org/), with [OpenXR activated](https://docs.godotengine.org/en/stable/tutorials/xr/setting_up_xr.html)
+* If you want to be able to integrate the audio when releasing your instrument
+    (e.g. in a binary or as an app), install the [Gdpd addon](https://gitlab.univ-lille.fr/ivmi/gdpd)
 
 ---
 
-## Rendering
-
-### Mono
-
-### SteamVR headsets
+## A first example
 
-1. Install the OpenXR addon from the AssetLib (godot-openxr)
+### Scene creation
 
-### Android based headset
 
-1. Install the OpenXR addon from the AssetLib (godot-openxr)
-2. Add an Android export (Project->Export) and choose OpenXR for the XR Mode 
-   in XR Features
-3. Install an Android compiling model (Project)
-4. In the IvmiScene node, select **Open XR Hmd** in XR Mode
-5. Plug-in the headset and authorize access to the headset
-6. Start the application on the headset by clicking on the android logo 
-	at the top right of the Godot window
+### Patch creation
 
-If you are using the **Osc** Pd Mode, make sure the headset is on the same 
-network as your computer.
 
+### Design process
 
-### Stereoscopic displays
 
-### AR on Mobile devices
-
-### WebXR
-
----
-
-## Networking
+### Release
 
 ---
 
 ## Creating your instrument
 
 
-### IVMI-scene
+### Godot IvmiScene
 
 The root of your scene must extend from the IvmiScene class/script.
 Attach a script to it and start it with :
 
 ``` python
 extends IvmiScene
+
+func _ready() :
+	super._ready()
+
+
+func _process(delta) :
+	super._process(delta)
 ```
 
 Then your scene tree can look like :
 
 * Main (with attached script extending IvmiScene)
-	* ARVROrigin
-		* ARVRCamera
-		* ARVRController
+	* XROrigin
+		* XRCamera
+		* XRController
 		* MeshInstance
 
 You can also directly attach the script extending IvmiScene to the ARVROrigin
@@ -109,7 +69,8 @@ IvmiScene provides a number of settings to help you design immersive instruments
 * XR Mode
 * ...
 
-### IVMI-node
+
+### Godot IvmiNode
 
 IVMI-node are the main components of any IVMI instruments. IVMI-node contains IVMI-properties. By inheriting IVMI-node.gd you are able to define a specific behavior/feedback for each IVMI-property change that occur within the node. You can for example write a code that change the size of the node's mesh when the node is selected.
 
@@ -117,45 +78,91 @@ IVMI-node are the main components of any IVMI instruments. IVMI-node contains IV
 extends IvmiNode
 
 func _ready():
-	#Optionally define a node type
+    # Call default IvmiNode constructor
+    super._ready()
+
+	# Optionally define a node type
 	_set_ivmi_type("my_node")
 	
-	#Add custom properties with array of values
+	# Add custom properties with array of values
 	_add_property("selected", [0])
+    
+    # Properties are sent by default, optionnally deactivate sending
+    _properties["selected"].set_listen(false)
 	
+    
+func process(delta) : 
+    # Call default IvmiNode processing, required for updates
+    super._process(delta)
+    
 
 func _set_property(prop, vals) :
-	#call default properties handling
-	._set_property(prop, vals)
+	# Call default properties handling
+	super._set_property(prop, vals)
 	
-	#handle custom properties
-	if prop == "selected":
-		if vals[0]:
-			get_node("MeshInstance").scale.x = 3
+	# Handle custom properties
+	match prop:
+        "selected":
+            get_node("MeshInstance").scale.x = 2.0*vals[0]+1.0
 ```
 
 
-### IVMI-property
+### IvmiProperty
 
-IVMI-property are the messages sent to Pure Data.
-The properties are composed of :
-- A name : a simple string
-- Values : An array of values
+IvmiProperties are composed of :
+- A name : A string
+- Values : An array of values (floats, ints, bools, strings, ...)
 
-Each property change is send to Pure Data along with the name from which the property originate.
+Each property change is sent to Pure Data, 
+when their _listen variable is set to true,
+which is the case by default.
 
 ``` python
 # Add a new property
 _add_property("radius", [1])
 # Retrieve property values
-radius = get_property("radius")[0]
+radius = _get_property("radius")[0]
 # Set a property
 set_property("radius",[0.5])
 ```
 
+### PureData ivmi_scene
+
+
+### PureData ivmi_node
+
+
+### PureData ivmi_property
+
+---
+
+## Rendering
+
+### Mono
+
+### SteamVR headsets
+
+TODO
+
+### Android based headset
+
+TODO
+
+### Stereoscopic displays
+
+
+---
+
+## Multi-user Instruments
+
+---
+
+
+## Using 3D Interaction Techniques
+
 
-### Using 3D Interaction Techniques
+--- 
 
-todo
+## Using PureData abstractions
 
 
diff --git a/core/IvmiNode.gd b/core/IvmiNode.gd
index 83eda32842c4983938043456257e8a48676bcd1e..9a67aa06523ca8c09aa07fe86f47cde90a6b8624 100644
--- a/core/IvmiNode.gd
+++ b/core/IvmiNode.gd
@@ -1,9 +1,8 @@
-extends Spatial
-
+extends Node3D
 class_name IvmiNode
 
 var _properties = {}
-var _ivmi 
+@onready var _ivmi  = get_tree().root.get_viewport().get_child(0)
 
 var _full_name = ""
 var _send_data = true
@@ -14,27 +13,22 @@ var _can_be_selected = true
 var _can_be_rotated = true
 var _can_be_moved = true
 
-
 func _ready():
-
 	add_to_group("ivmi_nodes")
 	
 	#add default properties
-	_add_property("position", [translation.x, translation.y, translation.z])
-	_add_property("global_position", [global_translation.x, global_translation.y, global_translation.z])
-	_add_property("scale", [scale.x, scale.y, scale.z])
-	_add_property("selected", [0])
-	_add_property("triggered", [0])
-	_add_property("transparency", [0])
-	_add_property("color_hsv", [0,0,0])
-	_add_property("rotation", [rotation_degrees.x,rotation_degrees.y,rotation_degrees.z])
-	var quat = transform.basis.get_rotation_quat()
-	_add_property("quaternion",[quat.w,quat.x,quat.y,quat.z])
-	_add_property("distance_to_camera", [0])
+	_add_property("position", [position.x, position.y, position.z], false)
+	_add_property("global_position", [position.x, position.y, position.z], false)
+	_add_property("scale", [scale.x, scale.y, scale.z], false)
+	_add_property("selected", [0], false)
+	_add_property("triggered", [0], false)
+	_add_property("transparency", [0], false)
+	_add_property("color_hsv", [0,0,0], false)
+	_add_property("rotation", [rotation_degrees.x,rotation_degrees.y,rotation_degrees.z], false)
+	var quat = transform.basis.get_rotation_quaternion()
+	_add_property("quaternion",[quat.w,quat.x,quat.y,quat.z], false)
+	_add_property("distance_to_camera", [0], false)
 	
-	#retrieve current scene
-	_ivmi = get_viewport().get_child(0)
-
 	#retrieve full name within scene
 	_full_name = String(get_path()).lstrip("/root/")
 	_full_name = _full_name.right(_full_name.find("/")+1)
@@ -51,20 +45,12 @@ func declare() :
 func _allow_send_data(value : bool):
 	_send_data = value
 	
-func _add_property(prop, values) :
-	_properties[prop] = load("res://addons/ivmi-builder/core/IvmiProperty.gd").new()
-	_properties[prop].set_values(values)
-	_properties[prop].set_name(prop)
-	var tags = ""
-	for v in values :
-		if v is float :
-			tags+="f"
-		elif v is int :
-			tags+="f"
-		elif v is String :
-			tags+="s"
-	_properties[prop].set_tags(tags)
+func _add_property(prop, values, listen=true) -> void :
+	_properties[prop] = IvmiProperty.new()
+	_properties[prop].init_values(values)
+	_properties[prop].set_listen(listen)
 	_properties[prop].set_ivmi_node(self)
+	_properties[prop].set_name(prop)
 
 func parse(prop, args) :
 	if _properties.has(prop) :
@@ -80,13 +66,12 @@ func parse(prop, args) :
 				set_property(prop, args)
 
 func set_property(prop, vals):
-	if _ivmi._is_connected:
+	if(_ivmi._network_mode!=IvmiScene.NetMode.None and _ivmi._is_connected):
 		rpc("_set_property", prop, vals);
 	else:
 		_set_property(prop, vals)
 
-remotesync func _set_property(prop, vals):
-	#print("set prop in ",name, " ", prop, " ", vals)
+@rpc("any_peer", "call_local") func _set_property(prop, vals):
 	if _properties.has(prop):
 		_properties[prop].set_values(vals)
 		match prop :
@@ -94,20 +79,22 @@ remotesync func _set_property(prop, vals):
 				scale = Vector3(vals[0],vals[1],vals[2])
 			"position":
 				if _can_be_moved:
-					translation = Vector3(vals[0],vals[1],vals[2])
+					position = Vector3(vals[0],vals[1],vals[2])
 			"global_position":
 				if _can_be_moved:
-					global_translation = Vector3(vals[0],vals[1],vals[2])
+					global_position = Vector3(vals[0],vals[1],vals[2])
 			"rotation":
 				if _can_be_rotated:
 					rotation_degrees = Vector3(vals[0],vals[1],vals[2])
-					var quat = transform.basis.get_rotation_quat()
+					var quat = transform.basis.get_rotation_quaternion()
 					_properties["quaternion"]._values = [quat.x,quat.x,quat.y,quat.w]
+					_properties["quaternion"]._changed = true
 			"quaternion":
 				if _can_be_rotated:
 					var _scale = scale
-					self.transform.basis = Basis(Quat(vals[0],vals[1],vals[2],vals[3]))
+					self.transform.basis = Basis(Quaternion(vals[0],vals[1],vals[2],vals[3]))
 					_properties["rotation"]._values = [rotation_degrees.x,rotation_degrees.y,rotation_degrees.z]
+					_properties["rotation"]._changed = true
 					scale = _scale
 					
 func get_extent():
@@ -118,7 +105,7 @@ func get_extent():
 	else:
 		var _children = get_children()
 		for _child in _children:
-			if _child is MeshInstance:
+			if _child is MeshInstance3D:
 				var _scale = _child.global_transform.basis.get_scale()
 				_extent = _child.get_aabb().size*_scale
 				break
@@ -142,24 +129,24 @@ func _set_ivmi_type(type):
 func _get_ivmi_type():
 	return _ivmi_type
 
-func _process(delta):
-	if !Engine.editor_hint: 
-		#get cam dist if needed
+func _process(delta):	
+	#get cam dist if needed
+	if _properties.has("distance_to_camera") :
 		if _properties["distance_to_camera"]._listen:
-			var cam_pos = get_viewport().get_camera().to_global(Vector3(0,0,0))
+			var cam_pos = get_viewport().get_camera_3d().to_global(Vector3(0,0,0))
 			var obj_pos = to_global(Vector3(0,0,0))
 			_properties["distance_to_camera"].set_values([(cam_pos-obj_pos).length()])
-		
-		#output all values listened to which have changed
-		if _send_data:
-			for k in _properties.keys():
-				if _properties[k]._changed :
-					if _properties[k]._listen :
-						send_prop(k)
-					if _ivmi.is_recording():
-						_ivmi.record_property(name+"/"+k, _properties[k]._tags, get_property(k))
-					_properties[k]._changed=false
+	
+	#output all values listened to which have changed
+	if _send_data:
+		for k in _properties.keys():
+			if _properties[k]._changed :
+				if _properties[k]._listen :
+					_ivmi.send(name+"/"+k, _properties[k]._tags, get_property(k))
+				if _properties[k]._record and _ivmi.is_recording():
+					_ivmi.record_property(name+"/"+k, _properties[k]._tags, get_property(k))
+				_properties[k]._changed=false
+
 
 func send_prop(prop) :
 	_ivmi.send(name+"/"+prop, _properties[prop]._tags, get_property(prop))
-				
diff --git a/core/IvmiProperty.gd b/core/IvmiProperty.gd
index 3a39026886eebbb2a851b5b70dd53fc96f4bf325..19d26bd972241e9dff662556426c21e2eb50a746 100644
--- a/core/IvmiProperty.gd
+++ b/core/IvmiProperty.gd
@@ -6,39 +6,60 @@ var _name
 var _values = []
 var _type = ""
 var _changed = false
-var _listen = false
+var _listen = true
 var _tags = ""
 var _immediate = false
 var _ivmi_node = null
+var _record = false
 
-func _ready():
-	pass
-
-func set_values(vals) :
-	for v in range(0, min(_values.size(), vals.size())) :
-		if vals[v] != _values[v] :
-			_changed=true
-	_values = vals
+func set_values(vals : Array) :
+	if vals.size() ==  _values.size() :
+		for v in range(0, min(_values.size(), vals.size())) :
+			if vals[v] != _values[v] :
+				_changed=true
+		_values.assign(vals)
+	else :
+		init_values(vals)
 	
 	if _immediate and _listen :
 		_changed = false
 		_ivmi_node.send_prop(_name)
 	
+func init_values(vals : Array) :
+	var tags = ""
+	for v in vals :
+		if v is float :
+			tags+="f"
+		elif v is int :
+			tags+="f"
+		elif v is String :
+			tags+="s"
+	set_tags(tags)
+	_values.assign(vals)
+	_changed=true
+
 func set_tags(t):
 	_tags=t
-	
+
 func set_name(n):
 	_name=n
 	
 func set_listen(l) :
 	_listen=l
 	
+func set_record(r) :
+	_record=r
+	
 func set_immediate(i) :
 	_immediate=i
 	
 func set_ivmi_node(n) :
 	_ivmi_node=n
 	
+func copy(prop : IvmiProperty) -> void:
+	_values.assign(prop._values)
+
+	
 func duplicate(flags: int = 15):
 	var new_IvmiProperty = get_script().new()
 	
diff --git a/core/IvmiScene.gd b/core/IvmiScene.gd
index cadbc8d72cade5dd155f08d9f6fea349519d6f85..05d54518949789f27d5c9795b5728aceb1d26821 100644
--- a/core/IvmiScene.gd
+++ b/core/IvmiScene.gd
@@ -1,20 +1,20 @@
-extends Spatial
-
+extends Node3D
 class_name IvmiScene
 
+@export_group("PureData")
 enum PdMode {OSC, LIBPD, NONE}
-export (PdMode) var _pd_mode=PdMode.OSC
+@export var _pd_mode : PdMode = PdMode.OSC
 
 #OSC variables
-var _input_port = 8215 
+var _input_port = 8215
 var _discov_input_port = 8216
-export var _osc_output_address = "" 
-var _osc_output_port = 8217 
-var _osc_to_pd
-var _osc_discov
+var _osc_output_address = "127.0.0.1"
+var _osc_output_port = 8217
+var _osc_to_pd : GodOSC
+var _osc_discov : GodOSC
 
 #PD variables
-export (String, FILE, "*.pd") var _pd_patch
+@export_file("*.pd") var _pd_patch
 var _gdpd
 var _audio_stream
 var _audio_player
@@ -24,29 +24,33 @@ var _buffer_size = 64
 var phase = 0
 
 #XR variables
-enum XRMode {Mono, OpenXrMobile, OpenXrHmd, ScreenVr}
-export(XRMode) var _xr_mode = XRMode.Mono
-export(bool) var _open_xr_passthrough=false
+@export_group("XR")
+enum XRMode {Mono, OpenXR}
+@export var _xr_mode: XRMode = XRMode.OpenXR
+@export var _open_xr_passthrough: bool=false
+
+@export_group("ScreenVR")
 enum VRMode {SplitHorizontal, SplitVertical, Anaglyph, QuadBuffer}
-export(VRMode) var _screen_vr_mode=VRMode.SplitHorizontal
-export var _screen_vr_iod=0.06 setget set_screen_vr_iod
-export var _screen_vr_head_position=Vector3(0,0,3) setget set_screen_vr_head_position
-export var _screen_vr_screen_size=Vector2(3,2) setget set_screen_vr_screen_size
-export var _screen_vr_window_size=Vector2(1024,600) setget set_screen_vr_window_size
-export var _screen_vr_window_position=Vector2(640,480) setget set_screen_vr_window_position
-var _arvr_interface
+@export var _screen_vr_mode: VRMode=VRMode.SplitHorizontal
+@export var _screen_vr_iod=0.06 : set = set_screen_vr_iod
+@export var _screen_vr_head_position=Vector3(0,0,3) : set = set_screen_vr_head_position
+@export var _screen_vr_screen_size=Vector2(3,2) : set = set_screen_vr_screen_size
+@export var _screen_vr_window_size=Vector2(1024,600) : set = set_screen_vr_window_size
+@export var _screen_vr_window_position=Vector2(640,480) : set = set_screen_vr_window_position
+var _xr_interface : XRInterface = null
 var _config
 
 # Network variables
+@export_group("Network")
 enum NetMode {None, Peer, Client, Server}
-export(NetMode) var _network_mode = NetMode.None
+@export var _network_mode: NetMode = NetMode.None
 enum NetProto {Enet, WebRTC}
-export(NetProto) var _network_protocol = NetProto.Enet 
+@export var _network_protocol: NetProto = NetProto.Enet
 var _client_name = ""
 var _is_connected = false
-export var _server_ip = "127.0.0.1" setget set_server_ip
-export var _server_port = 7596 setget set_server_port
-#export var _max_player = 10 setget set_max_player
+@export var _server_ip = "127.0.0.1" : set = set_server_ip
+@export var _server_port = 7596 : set = set_server_port
+#export var _max_player = 10 : set = set_max_player
 var player_info = {} # all players infos ( { id: { name } } )
 var my_info = {} # current player info ( { name } )
 var _player_count = 0
@@ -54,13 +58,7 @@ var _network_discov
 var _network_client
 var _network_server
 
-
-# Internal
-var _is_2D = false
-export(bool) var _debug = false
-var _ivmi_node = load("res://addons/ivmi-builder/core/IvmiNode.gd")
-var _ivmi_nodes = []
-
+# Recording
 enum RecordingState {STOPPED, RECORDING, PLAYING}
 var _recording_state = RecordingState.STOPPED
 var _recorded_props = []
@@ -68,69 +66,78 @@ var _recording_time = 0
 var _recording_index = 0
 
 
+@export var _debug_osc: bool = false
+
+var _is_2D : bool = true
+var _ivmi_node = load("res://addons/ivmi-builder/core/IvmiNode.gd")
+
 func _ready():
-	_is_2D = true
+	
+	print("IVMI : Creating IvmiScene")
+	
+	_is_2D=true
 	match _xr_mode :
-		XRMode.OpenXrHmd, XRMode.OpenXrMobile:
-			_is_2D = false
-			_arvr_interface = ARVRServer.find_interface("OpenXR")
-			if _arvr_interface and _arvr_interface.initialize():
-				_config = load("res://addons/godot-openxr/config/OpenXRConfig.gdns").new()
-				#set format
-				if _xr_mode==XRMode.OpenXrHmd:
-					_config.form_factor = "HMD"
-				else :
-					_config.form_factor = "Hand Held"
-				#Set refresh rate
-				var refresh_rate = _config.get_refresh_rate()
-				if refresh_rate == 0:
-					Engine.iterations_per_second = 144
-				else:
-					Engine.iterations_per_second = refresh_rate
-				get_viewport().arvr = true
-				get_viewport().keep_3d_linear = _config.keep_3d_linear() 
-				Engine.iterations_per_second = _config.get_refresh_rate()
-				if _open_xr_passthrough : 
-					get_viewport().transparent_bg = true
-					get_tree().get_root().set_transparent_background(true)
-					_config.start_passthrough()
-				else:
-					print("Error : Could not activate OpenXR Passthrough")
+		XRMode.OpenXR :
+			_xr_interface = XRServer.find_interface("OpenXR")
+			if _xr_interface and _xr_interface.initialize():
+				#remove v-sync
+				DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_DISABLED)
+				get_viewport().use_xr = true
+				#_xr_interface.play_area_changed.connect(_on_play_area_changed)
+				_is_2D = false
 				print("IVMI : Initialised OpenXR Interface")
+				if _open_xr_passthrough :
+					get_viewport().transparent_bg=true
+					var pt : bool = true
+					if _xr_interface.is_passthrough_supported():
+						if !_xr_interface.start_passthrough():
+							pt=false
+						else:
+							var modes = _xr_interface.get_supported_environment_blend_modes()
+							if _xr_interface.XR_ENV_BLEND_MODE_ALPHA_BLEND in modes:
+								_xr_interface.set_environment_blend_mode(_xr_interface.XR_ENV_BLEND_MODE_ALPHA_BLEND)
+							else:
+								pt=false
+					if pt :
+						print("IVMI : Activated OpenXR Passthrough")
+					else:
+						print("Error : Could not activate OpenXR Passthrough")
 			else:
-				print("Error : Could not initialize OpenXR interface")
-				_is_2D=true	
-		XRMode.ScreenVr:
-			_arvr_interface = ARVRServer.find_interface("ScreenVR")
-			if _arvr_interface and _arvr_interface.initialize():
-				get_viewport().arvr = true
-				_config = load("res://addons/gdscreenvr/ScreenVRConfig.gdns").new()
-				_config.set_iod(_screen_vr_iod)
-				_config.set_stereo_mode(_screen_vr_mode+1)
-				_config.set_head_pos(_screen_vr_head_position)
-				_config.set_screen_size(_screen_vr_screen_size)
-				_config.set_window_size(_screen_vr_window_size)
-				_config.set_window_position(_screen_vr_window_position)
-				print("IVMI : Initialised ScreenVR Interface")
-			else:
-				print("Error : Could not activate ScreenVR")
-				_is_2D=true
-
+					print("Error : Could not initialize OpenXR interface")
+#		XRMode.ScreenVr:
+#			XRServer.add_interface(Gd4ScreenVR.new())
+#			_config = XRServer.find_interface("Gd4ScreenVR")
+#			if _config and _config.initialize():
+#				#get_viewport().arvr = true
+#				#get_viewport().use_xr = true
+#				#_config = load("res://addons/gdscreenvr/ScreenVRConfig.gdns").new()
+#				_config.set_intraocular_dist(_screen_vr_iod)
+#				_config.set_stereo_mode(_screen_vr_mode+1)
+#				_config.set_head_pos(_screen_vr_head_position)
+#				_config.set_screen_size(_screen_vr_screen_size)
+#				_config.set_window_size(_screen_vr_window_size)
+#				_config.set_window_position(_screen_vr_window_position)
+#				print("IVMI : Initialised ScreenVR Interface")
+#			else:
+#				print("Error : Could not activate ScreenVR")
+#			pass
+
+	# PureData mode
 	if _pd_mode==PdMode.LIBPD :
-		var gdpd_dir = Directory.new();
+		var gdpd_dir = FileAccess
 		var exists = gdpd_dir.dir_exists("res://addons/gdpd")
 		if exists :
 			_gdpd = load("res://addons/gdpd/bin/gdpd.gdns").new()
 			add_child(_gdpd)
-			_input_buffer = PoolVector2Array()
+			_input_buffer = PackedVector2Array()
 			_input_buffer.resize(_buffer_size)
-			_output_buffer = PoolVector2Array()
+			_output_buffer = PackedVector2Array()
 			_output_buffer.resize(_buffer_size)
 			if _pd_patch!="" :
-				#initialize pd 
+				#initialize pd
 				_gdpd.init(2, 2, 44100)
 				#open patch
-				var patch_name = _pd_patch.right(_pd_patch.find_last("/")+1)
+				var patch_name = _pd_patch.right(_pd_patch.rfind("/")+1)
 				var patch_dir = (_pd_patch.rstrip(patch_name)).right(6)
 				_gdpd.openfile(patch_name, patch_dir)
 		else :
@@ -138,108 +145,106 @@ func _ready():
 			_pd_mode=PdMode.OSC
 
 	if _pd_mode==PdMode.OSC :
-		# multicast discovery
-		_osc_discov = GodOSC.new()
-		_osc_discov.set_input_port(_discov_input_port)
-		#discover only if address was not provided
-		if _osc_output_address=="" :
-			_osc_discov.set_multicast("239.215.216.217")
-			_osc_output_address="127.0.0.1"
-		
-		# unicast 
+		# unicast
 		_osc_to_pd = GodOSC.new()
 		_osc_to_pd.set_input_port(_input_port)
 		_osc_to_pd.set_output(_osc_output_address, _osc_output_port)
-		var local_addr = _get_local_address()
-		if local_addr!="":
-			_osc_to_pd.send_msg("/ivmi/hello_from_gd","sf",[local_addr, _input_port])
-		
+
+		# multicast discovery
+		_osc_discov = GodOSC.new()
+		_osc_discov.set_input_port(_discov_input_port)
+		_osc_discov.set_multicast("239.215.216.217")
 
 	#initialize either libpd or osc patch
 	send("init", "f", [1])
 
-	for argument in OS.get_cmdline_args():
-		if argument == "--serve":
-			_network_mode = NetMode.Server
-		#elif argument.find("=") > -1:
-		#	var key_value = argument.split("=")
-		#	if key_value[0] == "--name":
-		#		_client_name = key_value[1]
-		#		my_info.name = _client_name
-		#	elif key_value[0] == "--ip":
-		#		_server_ip = key_value[1]
-		#	elif key_value[0] == "--port":
-		#		_server_port = key_value[1]
-	
-	
 	if _network_mode!=NetMode.None :
-		
-		
-		if _network_protocol==NetProto.WebRTC :
-			
-			if OS.get_name()=="HTML5" :
-				#create client
-				_network_client = IvmiClient.new()
-				_network_client.connect("on_peers_ready", self, "_on_network_ready")
-				add_child(_network_client)
-				#connect to server
-				_on_found_server(_server_ip, _server_port)
-			else :
-				
-				#create client
-				_network_client = IvmiClient.new()
-				_network_client.connect("on_peers_ready", self, "_on_network_ready")
-				add_child(_network_client)
-				
-				#if server, create server, promote it and connect to it 
-				if _network_mode==NetMode.Server :
-					print("IVMI : Starting server")
-					_network_server = IvmiServer.new()
-					_network_server._port = _server_port
-					add_child(_network_server)
-					#connect locally
-					_on_found_server("127.0.0.1", _server_port)
-					
-		elif _network_protocol==NetProto.Enet :	
-				match _network_mode :
-					NetMode.Server :
-						# init server
-						var peer = NetworkedMultiplayerENet.new()
-						peer.create_server(_server_port)
-						get_tree().network_peer = peer
-						_is_connected = true
-					NetMode.Client :
-						if _server_ip!="" :
-							_on_found_server(_server_ip, _server_port)
-
-			
+		if _network_protocol==NetProto.Enet :
+			match _network_mode :
+				NetMode.Server :
+					# init server
+					var peer = ENetMultiplayerPeer.new()
+					peer.create_server(_server_port)
+					multiplayer.multiplayer_peer = peer
+					_on_network_ready()
+					print("IVMI : Starting Server")
+				NetMode.Client :
+					if _server_ip!="" :
+						_on_found_server(_server_ip, _server_port)
+
+
 		#start discov
 		_network_discov = IvmiDiscov.new()
 		if _network_mode==NetMode.Server :
 			_network_discov.set_server(_server_port)
 		add_child(_network_discov)
-		_network_discov.connect("found_server", self, "_on_found_server")
-		_network_discov.connect("timeout", self, "_on_timeout")
+		_network_discov.connect("found_server",Callable(self,"_on_found_server"))
+		_network_discov.connect("timeout",Callable(self,"_on_timeout"))
 		_network_discov.start()
-	
+
+# TODO trying to fix resume error on quest, not working yet ...
+func _on_play_area_changed() :
+	get_viewport().use_xr = true
+
+func _process(delta) :
+	if is_inside_tree() :
+		match _pd_mode :
+			PdMode.OSC :
+				#process osc messages
+				while _osc_to_pd.has_msg() :
+					var msg = _osc_to_pd.get_msg()
+					_parse_message(msg)
+
+				while _osc_discov.has_msg() :
+					var msg = _osc_discov.get_msg()
+					#print("from discov ", msg, _osc_discov.get_last_peer())
+					match msg["address"] :
+						"/ivmi/hello_from_pd" :
+							var peer = _osc_discov.get_last_peer()
+							#print(_output_address, _output_port)
+							if _osc_output_address!=peer["address"] or _osc_output_port!=peer["port"] :
+								_osc_output_address = peer["address"]
+								_osc_output_port = peer["port"]
+								_osc_to_pd.set_output(_osc_output_address, _osc_output_port)
+								var local_addr = _osc_to_pd.get_local_address()
+								_osc_to_pd.send_msg("/ivmi/hello_from_gd","sf",[local_addr, _input_port])
+
+			PdMode.LIBPD : #libpd mode
+				while _gdpd.has_message() :
+					var list = _gdpd.get_next()
+					var msg = {}
+					msg["address"]=list[0]
+					list.pop_front()
+					msg["args"]=list
+					_parse_message(msg)
+
+		if _recording_state == RecordingState.PLAYING :
+			var t = Time.get_ticks_msec() - _recording_time
+			while _recording_index<_recorded_props.size() and _recorded_props[_recording_index]["time"] < t :
+				_parse_message(_recorded_props[_recording_index])
+				_recording_index+=1
+			if _recording_index>=_recorded_props.size():
+				_recording_state=RecordingState.STOPPED
+				_recording_playing_done()
+
 
 
 # --------Network-----------------
 
 func _on_found_server(server_ip, port) :
-	if not _is_connected :
-		match _network_protocol :
-				NetProto.WebRTC :
-					_network_client.connect_to_server(server_ip, port)
-				NetProto.Enet :
-					var peer = NetworkedMultiplayerENet.new()
+	match _network_protocol :
+			NetProto.WebRTC :
+				#_network_client.connect_to_server(server_ip, port)
+				pass
+			NetProto.Enet :
+				if !_is_connected or _server_ip!=server_ip :
+					print("IVMI : Connecting to server ", server_ip, " ", port)
+					var peer = ENetMultiplayerPeer.new()
+					_server_ip=server_ip
 					peer.create_client(server_ip, port)
-					get_tree().network_peer = peer
-					get_tree().connect("network_peer_disconnected", self, "_player_disconnected")
-					get_tree().connect("connected_to_server", self, "_connected_ok")
-					get_tree().connect("connection_failed", self, "_connected_fail")
-					get_tree().connect("server_disconnected", self, "_server_disconnected")
-					
+					multiplayer.multiplayer_peer = peer
+					multiplayer.connected_to_server.connect(_on_network_ready)
+
 
 func _on_timeout() :
 	#we haven't found an existing server
@@ -254,90 +259,25 @@ func _on_timeout() :
 				add_child(_network_server)
 				_on_found_server("127.0.0.1", _server_port)
 			NetProto.Enet :
-				var peer = NetworkedMultiplayerENet.new()
+				var peer = ENetMultiplayerPeer.new()
 				peer.create_server(_server_port)
-				get_tree().network_peer = peer
-				_is_connected=true
+				multiplayer.multiplayer_peer = peer
+				_on_network_ready()
 		print("IVMI : Starting server")
 
 func _on_network_ready() :
 	print("IVMI : Network ready")
-	get_tree().set_network_peer(_network_client.get_network_peer())
 	_is_connected=true
 
-func _connected_ok():
-	print("IVMI : Connected to server")
-	rpc_id(1, "register_player", my_info)
-	_is_connected = true
-
-func _server_disconnected():
-	print("IVMI : Disconnected from server")
-	_is_connected = false
-
-func _connected_fail():
-	print("IVMI : Could not connect to server")
-
-remote func register_player(info):
-	var id = get_tree().get_rpc_sender_id()
-	if (not info.has("name")):
-		info.name = str("Client ", id)
-	print("IVMI : ", info.name," connected to server")
-	player_info[id] = info
-	
-func _player_disconnected(id):
-	print("IVMI : ", player_info[id].name, "disconnected from server")
-	player_info.erase(id)
-
-# -------------------------
-
-func get_interface() -> ARVRInterface:
-	return _arvr_interface
+func set_server_ip(ip):
+	_server_ip = ip
 
-func _process(delta) :
-	match _pd_mode :
-		PdMode.OSC :
-			#process osc messages
-			while _osc_to_pd.has_msg() :
-				var msg = _osc_to_pd.get_msg()
-				_parse_message(msg)
-				
-			while _osc_discov.has_msg() :
-				var msg = _osc_discov.get_msg()
-				#print("from discov ", msg, _osc_discov.get_last_peer())	
-				match msg["address"] : 
-					"/ivmi/hello_from_pd" :
-						var peer = _osc_discov.get_last_peer()
-						if _osc_output_address!=peer["address"] or _osc_output_port!=peer["port"] :
-							
-							print("IVMI : Got hello from pd ", peer)
-							_osc_output_address = peer["address"]
-							_osc_output_port = peer["port"]
-							_osc_to_pd.set_output(_osc_output_address, _osc_output_port)
-							var local_addr = _get_local_address()
-							if local_addr!="" :
-								_osc_to_pd.send_msg("/ivmi/hello_from_gd","sf",[local_addr, _input_port])
-		
-		PdMode.LIBPD : #libpd mode
-			while _gdpd.has_message() :
-				var list = _gdpd.get_next()
-				var msg = {}
-				msg["address"]=list[0]
-				list.pop_front()
-				msg["args"]=list
-				_parse_message(msg)
-	
-	if _recording_state == RecordingState.PLAYING :
-		var t = Time.get_ticks_msec() - _recording_time
-		while _recording_index<_recorded_props.size() and _recorded_props[_recording_index]["time"] < t :
-			_parse_message(_recorded_props[_recording_index])
-			_recording_index+=1
-		if _recording_index>=_recorded_props.size():
-			_recording_state=RecordingState.STOPPED
+func set_server_port(port):
+	_server_port = port
 
 
 func _parse_message(msg) :
-	if _debug :
-		print("received ", msg["address"], " ", msg["args"])
+	#print("received ", msg["address"], " ", msg["args"])
 	var split = msg["address"].split("/")
 	if split[1] == "ivmi" && split.size()>2 :
 		if split[2] == "scene" :
@@ -351,12 +291,53 @@ func _parse_message(msg) :
 				"listen" :
 					print("IVMI : listen to scene is not implemented yet")
 		else :
-			var node = find_node(split[2], true, false)
-			if node is  _ivmi_node :
+			var node = find_child(split[2], true, false)
+			if node is  IvmiNode :
 				node.parse(split[3], msg["args"])
-			elif _debug :
+			elif _debug_osc :
 				print("IVMI : Node ", split[2], " not found in scene")
 
+
+func send(address, tags, args) :
+	#print("sending ", address, " ", args)
+	var addr = "/ivmi/"+address
+	match _pd_mode :
+		PdMode.OSC :
+			_osc_to_pd.send_msg(addr, tags, args)
+		PdMode.LIBPD :
+			var split = address.split("/")
+			_gdpd.start_message(args.size()+split.size())
+			split.remove(0)
+			for s in split :
+				_gdpd.add_symbol(s)
+			for a in args :
+				if a is float :
+					_gdpd.add_float(a)
+				elif a is String :
+					_gdpd.add_symbol(a)
+			_gdpd.finish_list("from_gdpd")
+
+#func _player_disconnected(id):
+#	print("\n", player_info[id].name, " just disconnected from server", "\n")
+#	player_info.erase(id)
+
+#func _server_disconnected():
+#	printerr("\n", "Disconnected from server", "\n")
+
+#func _connected_fail():
+#	printerr("\n", "Could not connect to server", "\n")
+
+#remote func register_player(info):
+#	var id = get_tree().get_remote_sender_id()
+#	if (not info.has("name")):
+#		info.name = str("Client ", id)
+#	print("\n", info.name, " just connected to server", "\n")
+#	player_info[id] = info
+
+
+#func _signaling_inited(lobby):
+#	print("got signal")
+
 ################LOGGING#########################
 
 func recording_start() :
@@ -373,11 +354,11 @@ func recording_play() :
 	_recording_time = Time.get_ticks_msec()
 
 func recording_save(f) :
-	var saved_file = File.new()
-	if saved_file.open(f, File.WRITE) == OK :
+	var saved_file = FileAccess.open(f,FileAccess.WRITE)
+	if saved_file != null :
 	
 		for rp in _recorded_props :
-			var json_string = to_json(rp)
+			var json_string = JSON.stringify(rp)
 			saved_file.store_line(json_string)
 		
 		saved_file.close()
@@ -385,17 +366,15 @@ func recording_save(f) :
 		print("IVMI : Could not save recording to file ", f)	
 
 func recording_load(f) :
-	var loaded_file = File.new()
-	if loaded_file.file_exists(f) :
-		loaded_file.open(f, File.READ)
+	if FileAccess.file_exists(f) :
+		var loaded_file = FileAccess.open(f,FileAccess.READ)
 		_recorded_props.clear()
-		while loaded_file.get_position() < loaded_file.get_len():
-			var prop_msg = parse_json(loaded_file.get_line())
+		while loaded_file.get_position() < loaded_file.get_length():
+			var prop_msg = JSON.parse_string(loaded_file.get_line())
 			_recorded_props.append(prop_msg)
 		loaded_file.close()
 	else :
 		print("IVMI : Could not load recording from file ", f)	
-		
 
 func is_recording() :
 	return _recording_state==RecordingState.RECORDING
@@ -406,63 +385,47 @@ func record_property(address, tags, values) :
 	args.append_array(values)
 	var t = Time.get_ticks_msec()-_recording_time
 	_recorded_props.append({"time":t, "address":addr, "tags":tags, "args":args})
-				
-### Nodes
-
-func _create_node(node_name) :
+	
+func _recording_playing_done() :
 	pass
 
+# --------------------------
 
-#### Network
+func get_interface() -> XRInterface:
+	return _xr_interface
 
-func send(address, tags, args) :
-	#print("sending ", address, " ", args)
-	var addr = "/ivmi/"+address
-	match _pd_mode :
-		PdMode.OSC :
-			_osc_to_pd.send_msg(addr, tags, args)
-		PdMode.LIBPD :
-			var split = address.split("/")
-			_gdpd.start_message(args.size()+split.size())
-			split.remove(0)
-			for s in split :
-				_gdpd.add_symbol(s)
-			for a in args :
-				if a is float :
-					_gdpd.add_float(a)
-				elif a is String :
-					_gdpd.add_symbol(a)
-			_gdpd.finish_list("from_gdpd")
+func _create_node(node_name) :
+	pass
 
 func _exit_tree ( ):
 	pass
 
 func get_xr_mode():
 	return _xr_mode
-	
+
 func is_2D() :
 	return _is_2D
-	
+
 func set_screen_vr_iod(iod) :
 	_screen_vr_iod=iod
 	if is_inside_tree():
-		_config.set_iod(_screen_vr_iod)
+		_config.set_intraocular_dist(_screen_vr_iod)
 
 func set_screen_vr_head_position(pos) :
 	_screen_vr_head_position=pos
 	if is_inside_tree():
 		_config.set_head_pos(_screen_vr_head_position)
-	
+
 func set_screen_vr_screen_size(size) :
 	_screen_vr_screen_size=size
 	if is_inside_tree():
 		_config.set_screen_size(_screen_vr_screen_size)
-	
+
 func set_screen_vr_window_size(size) :
 	_screen_vr_window_size=size
 	if is_inside_tree():
 		_config.set_window_size(_screen_vr_window_size)
-	
+
 func set_screen_vr_window_position(pos) :
 	_screen_vr_window_position=pos
 	if is_inside_tree():
@@ -477,7 +440,7 @@ func set_screen_vr_stereo_images(imgL, imgR) :
 
 func vector3_to_array(vec):
 	return [vec.x,vec.y,vec.z]
-	
+
 func array_to_vector3(arr):
 	if arr.size() == 3:
 		return Vector3(arr[0],arr[1],arr[2])
@@ -487,21 +450,3 @@ func array_to_vector3(arr):
 		return Vector3(arr[0],0,0)
 	return Vector3.ZERO
 
-func set_server_ip(ip):
-	_server_ip = ip
-
-func set_server_port(port):
-	_server_port = port
-	
-func _get_local_address() :
-	var local_addr = ""
-							
-#	if OS.has_feature("Windows"):
-#		if OS.has_environment("COMPUTERNAME"):
-#			local_addr =  IP.resolve_hostname(str(OS.get_environment("COMPUTERNAME")),1)
-#	elif OS.has_feature("X11") or OS.has_feature("OSX") or OS.has_feature("Android"):
-#		if OS.has_environment("HOSTNAME"):
-#			local_addr =  IP.resolve_hostname(str(OS.get_environment("HOSTNAME")),1)
-	local_addr = IP.get_local_addresses()[0]
-			
-	return local_addr
diff --git a/core/ivmi_scene.pd b/core/ivmi_scene.pd
index 0033abce37a102e6f9adfeeefeeaeaecb56c7c13..4baa00c9f5157fc6cb5889f14880d4ea693903a1 100644
Binary files a/core/ivmi_scene.pd and b/core/ivmi_scene.pd differ
diff --git a/core/net/GodOSC.gd b/core/net/GodOSC.gd
index 77c6db0620fec4ddd6b00385b3f50f7fe6fa7b6b..08cd94a306699c865368291bb82b61a42be12b54 100644
--- a/core/net/GodOSC.gd
+++ b/core/net/GodOSC.gd
@@ -7,6 +7,10 @@ var _socket = PacketPeerUDP.new()
 var _output_address = "127.0.0.1"
 var _output_port = 7770
 var _input_port = 7771
+var _verbose = false
+
+func set_verbose(v : bool) -> void:
+	_verbose=v
 
 func set_output(address, port) :
 	_output_address=address
@@ -14,14 +18,16 @@ func set_output(address, port) :
 	if _socket.set_dest_address(_output_address, _output_port)!=OK :
 		print("GodOSC : Error setting output ", address, ":",port)
 	else :
-		print("GodOSC : Setting output to ", address, ":", port)
+		if _verbose :
+			print("GodOSC : Setting output to ", address, ":", port)
 
 func set_input_port(port) :
 	_input_port=port
-	if _socket.listen(_input_port)!= OK : 
+	if _socket.bind(_input_port)!= OK : 
 		print("GodOSC : Error setting input ", port)
 	else :
-		print("GodOSC : Listening to port ", port)
+		if _verbose :
+			print("GodOSC : Listening to port ", port)
 	
 		
 func set_multicast(addr) :
@@ -30,7 +36,8 @@ func set_multicast(addr) :
 			if _socket.join_multicast_group(addr, interf.name)!=OK :
 				print("GodOSC : Error joining multicast on ", interf.name)
 			else :
-				print("GodOSC : Joining multicast on ", interf.name)
+				if _verbose :
+					print("GodOSC : Joining multicast on ", interf.name)
 
 
 func send_msg(address, tags, args) :
@@ -43,13 +50,22 @@ func has_msg() :
 	return _socket.get_available_packet_count()>0
 
 func get_msg() :
-	 return _unpack_osc(_socket.get_packet())
-	
+	return _unpack_osc(_socket.get_packet())
+
 func get_last_peer() :
 	return {"address":_socket.get_packet_ip(), "port":_socket.get_packet_port()}
 	
+func get_local_address() -> String :
+	var address : String = "127.0.0.1"
+	
+	var addrs = IP.get_local_addresses()
+	for a in addrs :
+		if a!="127.0.0.1" and not a.contains(":") and not a.begins_with("169.") :
+			address=a
+	return address
+	
 func _make_osc_string(s,buff) :
-	buff.put_data(s.to_ascii())
+	buff.put_data(s.to_ascii_buffer())
 	buff.put_u8(0)
 	if (s.length()+1)%4>0 :
 		var diff = 4-(s.length()+1)%4
@@ -83,7 +99,7 @@ func _unpack_osc(packet) :
 	
 	var offset = address.length()
 	offset+=(4-(address.length())%4)
-	tags = packet.subarray(offset,packet.size()-1).get_string_from_ascii()
+	tags = packet.slice(offset,packet.size()-1).get_string_from_ascii()
 	offset+=tags.length()
 	offset+=(4-(tags.length())%4)
 	tags = tags.substr(1, tags.length()-1)
@@ -93,12 +109,12 @@ func _unpack_osc(packet) :
 	for t in range(tags.length()):
 		match tags[t] :
 			'f' :
-				_buf.data_array = packet.subarray(offset, min(offset+fsize, packet.size()-1))
+				_buf.data_array = packet.slice(offset, min(offset+fsize, packet.size()-1))
 				var val = _buf.get_float()
 				args.push_back(val)
 				offset+=(fsize)
 			'i' :
-				_buf.data_array = packet.subarray(offset, min(offset+fsize, packet.size()-1))
+				_buf.data_array = packet.slice(offset, min(offset+fsize, packet.size()-1))
 				var val = _buf.get_32()
 				args.push_back(val)
 				offset+=(fsize)
@@ -109,7 +125,7 @@ func _unpack_osc(packet) :
 				#offset+=(fsize)
 				offset+=1
 			's' :
-				var val = packet.subarray(offset, packet.size()-1).get_string_from_ascii()
+				var val = packet.slice(offset, packet.size()-1).get_string_from_ascii()
 				args.push_back(val)
 				offset+=val.length()
 				offset+=(4-(val.length())%4)
diff --git a/core/net/IvmiClient.gd b/core/net/IvmiClient.gd
index e00632fda10d3d464fb0b339429ed99b605168b9..5d5d5ccf5184e0fe01e5244fb63b5d6b7d76b677 100644
--- a/core/net/IvmiClient.gd
+++ b/core/net/IvmiClient.gd
@@ -7,7 +7,7 @@ var _match = []
 var _rtc_peers = {}
 var _id = 0
 var _player_number = 0
-var _client : WebSocketClient
+var _client : WebSocketPeer
 var _initialised = false
 var peers_ready : bool = false
 
@@ -36,24 +36,24 @@ func connect_to_server(websocket_url, port):
 	_rtc_peers = {}
 	_id = 0
 	_player_number = 0
-	_client = WebSocketClient.new()
+	_client = WebSocketPeer.new()
 	_initialised = false
 
-	_client.connect("connection_closed", self, "_closed")
-	_client.connect("connection_error", self, "_closed")
-	_client.connect("connection_established", self, "_connected")
-	_client.connect("data_received", self, "_on_data")
+	_client.connect("connection_closed",Callable(self,"_closed"))
+	_client.connect("connection_error",Callable(self,"_closed"))
+	_client.connect("connection_established",Callable(self,"_connected"))
+	_client.connect("data_received",Callable(self,"_on_data"))
 	
 	add_child(_rtc)
-	_rtc.connect("on_message", self, "rtc_on_message")
-	_rtc.connect("on_send_message", self, "rtc_on_send_message")
-	_rtc.connect("peer_connected", self, "rtc_on_peer_connected")
+	_rtc.connect("on_message",Callable(self,"rtc_on_message"))
+	_rtc.connect("on_send_message",Callable(self,"rtc_on_send_message"))
+	_rtc.connect("peer_connected",Callable(self,"rtc_on_peer_connected"))
 
 	var err = _client.connect_to_url(uri)
 	if err != OK:
 		set_process(false)
 		
-func get_network_peer() :
+func get_multiplayer_peer() :
 	return _rtc.rtc_mp
 
 func rtc_on_peer_connected(id):
diff --git a/core/net/IvmiDiscov.gd b/core/net/IvmiDiscov.gd
index b128faa55049af5fa554d683f8bd6e11ad7308cb..7663ece30e3fa4b6bc30ea164c221d9425998e53 100644
--- a/core/net/IvmiDiscov.gd
+++ b/core/net/IvmiDiscov.gd
@@ -25,32 +25,26 @@ func start() :
 	print("IVMI : Starting Network Discovery")
 	var mcadd = "239.215.216.217"
 	var mcprt = 8173
-	if not _is_server :
-		_osc_discov.set_input_port(mcprt)
-	else :
+	if _is_server :
 		_osc_discov.set_output(mcadd, mcprt)
+	else :
+		_osc_discov.set_input_port(mcprt)
 	_osc_discov.set_multicast(mcadd)
 	
-	
-	
 	#retrieve local address
-	_local_addr = "127.0.0.1"
-	for addr in IP.get_local_addresses() :
-		if addr!="127.0.0.1" and not ":" in addr :
-			_local_addr = addr
+	_local_addr = _osc_discov.get_local_address()
 
 func _process(delta) :
 	#when server send ping to multicast
 	if _is_server :
 		_ping_time+=delta
 		if _ping_time>5.0 :
-			_osc_discov.send_msg("/ivmi/hello_from_server","si",[_local_addr, _port])
+			_osc_discov.send_msg("/ivmi/hello_from_server","sf",[_local_addr, _port])
 			_ping_time=0
 		while _osc_discov.has_msg() :
 			var msg = _osc_discov.get_msg()
 	else :
 		_ping_time+=delta
-		
 		#if not test multicast messages for hello from server
 		while _osc_discov.has_msg() :
 			var msg = _osc_discov.get_msg()
diff --git a/core/net/IvmiServer.gd b/core/net/IvmiServer.gd
index 89b4497449c12cfa3bfd766108fa9558a7ef4216..ee648cbdf29139f081dc00f11b1641c70c61042c 100644
--- a/core/net/IvmiServer.gd
+++ b/core/net/IvmiServer.gd
@@ -5,14 +5,14 @@ extends Node
 class_name IvmiServer
 
 var _port 
-var _server = WebSocketServer.new()
+var _server = WebSocketPeer.new()
 
 var _peers = {}
 var _peer_id = 0
 
 func _logger_coroutine():
 	while(true):
-		yield(get_tree().create_timer(3), "timeout")
+		await get_tree().create_timer(3).timeout
 
 		var p = ""
 		for peer in _peers.keys():
@@ -26,10 +26,10 @@ func _logger_coroutine():
 		#printt("Match queue: " + m + "\n")
 
 func _ready():
-	_server.connect("client_connected", self, "_connected")
-	_server.connect("client_disconnected", self, "_disconnected")
-	_server.connect("client_close_request", self, "_close_request")
-	_server.connect("data_received", self, "_on_data")
+	_server.connect("client_connected",Callable(self,"_connected"))
+	_server.connect("client_disconnected",Callable(self,"_disconnected"))
+	_server.connect("client_close_request",Callable(self,"_close_request"))
+	_server.connect("data_received",Callable(self,"_on_data"))
 
 	var err = _server.listen(_port)
 	if err != OK:
diff --git a/core/net/WebRTCClient.gd b/core/net/WebRTCClient.gd
index d911159fdc607ef39fc96af59d9abf9b910d178f..bc85f56a117419de793d3df9cde428092a2f453a 100644
--- a/core/net/WebRTCClient.gd
+++ b/core/net/WebRTCClient.gd
@@ -8,14 +8,14 @@ signal peer_connected(id)
 
 var _my_id
 
-onready var rtc_mp : WebRTCMultiplayer = WebRTCMultiplayer.new()
+@onready var rtc_mp : WebRTCMultiplayerPeer = WebRTCMultiplayerPeer.new()
 
 func _ready():
-	rtc_mp.connect("connection_failed", self, "_on_connection_failed")
-	rtc_mp.connect("connection_succeeded", self, "_on_connection_succeeded")
-	rtc_mp.connect("peer_connected", self, "_on_peer_connected")
-	rtc_mp.connect("peer_disconnected", self, "_on_peer_disconnected")
-	rtc_mp.connect("server_disconnected", self, "_on_server_disconnected")
+	rtc_mp.connect("connection_failed",Callable(self,"_on_connection_failed"))
+	rtc_mp.connect("connection_succeeded",Callable(self,"_on_connection_succeeded"))
+	rtc_mp.connect("peer_connected",Callable(self,"_on_peer_connected"))
+	rtc_mp.connect("peer_disconnected",Callable(self,"_on_peer_disconnected"))
+	rtc_mp.connect("server_disconnected",Callable(self,"_on_server_disconnected"))
 
 func initialize(id):
 	_my_id = id
@@ -53,8 +53,8 @@ func create_peer(id):
 	})
 	if err!=OK :
 		print(err)
-	peer.connect("session_description_created", self, "_offer_created", [id])
-	peer.connect("ice_candidate_created", self, "_new_ice_candidate", [id])
+	peer.connect("session_description_created",Callable(self,"_offer_created").bind(id))
+	peer.connect("ice_candidate_created",Callable(self,"_new_ice_candidate").bind(id))
 	err = rtc_mp.add_peer(peer, id)
 	if err!=OK:
 		print(err)
diff --git a/core/net/WsMessage.gd b/core/net/WsMessage.gd
index acc50e63f733daec213040276395c8bc437d6a88..a5a968ed3c33cc726d98bf20e71ac2b8c6f02266 100644
--- a/core/net/WsMessage.gd
+++ b/core/net/WsMessage.gd
@@ -14,8 +14,8 @@ var is_echo : bool
 
 var content
 
-func get_raw() -> PoolByteArray:
-	var message = PoolByteArray()
+func get_raw() -> PackedByteArray:
+	var message = PackedByteArray()
 	
 	var byte = 0
 	byte = set_bit(byte, SERVER_LOGIN, server_login)
@@ -23,11 +23,11 @@ func get_raw() -> PoolByteArray:
 	byte = set_bit(byte, UPDATE_PEERS, update_peers)
 	
 	message.append(byte)
-	message.append_array(var2bytes(content))
+	message.append_array(var_to_bytes(content))
 	
 	return message
 
-func from_raw(var arr : PoolByteArray):
+func from_raw(arr : PackedByteArray):
 	var flags = arr[0]
 	
 	server_login = get_bit(flags, SERVER_LOGIN)
@@ -36,12 +36,12 @@ func from_raw(var arr : PoolByteArray):
 	
 	content = null
 	if (arr.size() > 1):
-		content = bytes2var(arr.subarray(1, -1))
+		content = bytes_to_var(arr.slice(1, -1))
 
-static func get_bit(var byte : int, var flag : int) -> bool:
+static func get_bit(byte : int, flag : int) -> bool:
 	return byte & flag == flag
 
-static func set_bit(var byte : int, var flag : int, var is_set : bool = true) -> int:
+static func set_bit(byte : int, flag : int, is_set : bool = true) -> int:
 	if is_set:
 		return byte | flag
 	else:
diff --git a/examples/controls/Controls.tscn b/examples/controls/Controls.tscn
index 2a6b41a6997923eaeffdfbb11ee96949179b7fbe..39bcce22462a079fc280f95db95a521043a1fe54 100644
--- a/examples/controls/Controls.tscn
+++ b/examples/controls/Controls.tscn
@@ -1,32 +1,33 @@
-[gd_scene load_steps=9 format=2]
+[gd_scene load_steps=9 format=3 uid="uid://dgcabodnr6ngu"]
 
-[ext_resource path="res://addons/ivmi-builder/examples/EmptyScene.tscn" type="PackedScene" id=1]
-[ext_resource path="res://addons/ivmi-builder/techniques/packed_techniques/FlyingGazeHOMER.tscn" type="PackedScene" id=2]
-[ext_resource path="res://addons/ivmi-builder/techniques/control/1DSlider/1DSlider.tscn" type="PackedScene" id=3]
-[ext_resource path="res://addons/ivmi-builder/techniques/control/Knob/Knob.tscn" type="PackedScene" id=4]
-[ext_resource path="res://addons/ivmi-builder/techniques/control/2DSlider/2DSlider.tscn" type="PackedScene" id=5]
-[ext_resource path="res://addons/ivmi-builder/techniques/control/3DSlider/3DSlider.tscn" type="PackedScene" id=6]
-[ext_resource path="res://addons/ivmi-builder/techniques/control/Tunnel/Tunnel.tscn" type="PackedScene" id=7]
-[ext_resource path="res://addons/ivmi-builder/examples/manipulation/Worm.tscn" type="PackedScene" id=8]
+[ext_resource type="Script" path="res://addons/ivmi-builder/core/IvmiScene.gd" id="1_q0qfo"]
+[ext_resource type="PackedScene" path="res://addons/ivmi-builder/techniques/packed_techniques/FlyingGazeHOMER.tscn" id="2"]
+[ext_resource type="PackedScene" path="res://addons/ivmi-builder/techniques/control/1DSlider/1DSlider.tscn" id="3"]
+[ext_resource type="PackedScene" path="res://addons/ivmi-builder/techniques/control/Knob/Knob.tscn" id="4"]
+[ext_resource type="PackedScene" path="res://addons/ivmi-builder/techniques/control/2DSlider/2DSlider.tscn" id="5"]
+[ext_resource type="PackedScene" path="res://addons/ivmi-builder/techniques/control/3DSlider/3DSlider.tscn" id="6"]
+[ext_resource type="PackedScene" uid="uid://bngkenwtwh5fg" path="res://addons/ivmi-builder/techniques/control/Tunnel/Tunnel.tscn" id="7"]
+[ext_resource type="PackedScene" uid="uid://b8jefoccnhqkp" path="res://addons/ivmi-builder/examples/manipulation/Worm.tscn" id="8"]
 
-[node name="IvmiScene2" instance=ExtResource( 1 )]
+[node name="Controls" type="Node3D"]
+script = ExtResource("1_q0qfo")
 
-[node name="FlyingGazeHOMER" parent="." index="0" instance=ExtResource( 2 )]
+[node name="FlyingGazeHOMER" parent="." instance=ExtResource("2")]
 
-[node name="Slider" parent="." index="1" instance=ExtResource( 3 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.08952, -3.40316 )
+[node name="Slider" parent="." instance=ExtResource("3")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1.08952, -3.40316)
 
-[node name="Knob" parent="." index="2" instance=ExtResource( 4 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00739098, 0, -6.39298 )
+[node name="Knob" parent="." instance=ExtResource("4")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.00739098, 0, -6.39298)
 
-[node name="3DSlider" parent="." index="3" instance=ExtResource( 6 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -2.61473, 0, -3.17461 )
+[node name="3DSlider" parent="." instance=ExtResource("6")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -2.61473, 0, -3.17461)
 
-[node name="2DSlider" parent="." index="4" instance=ExtResource( 5 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 2.77847, 0, -3.53746 )
+[node name="2DSlider" parent="." instance=ExtResource("5")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 2.77847, 0, -3.53746)
 
-[node name="Tunnel" parent="." index="5" instance=ExtResource( 7 )]
-transform = Transform( 0.472071, 0.835558, -0.281054, -0.71795, 0.549402, 0.427441, 0.511563, 0, 0.859246, 0, 0, -1.8966 )
+[node name="Tunnel" parent="." instance=ExtResource("7")]
+transform = Transform3D(0.472071, 0.835558, -0.281054, -0.71795, 0.549402, 0.427441, 0.511563, 0, 0.859246, 0, 0, -1.8966)
 
-[node name="Worm" parent="." index="6" instance=ExtResource( 8 )]
-transform = Transform( 0.5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -3.2962 )
+[node name="Worm" parent="." instance=ExtResource("8")]
+transform = Transform3D(0.5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -3.2962)
diff --git a/examples/manipulation/HOMER_Looping.gd b/examples/manipulation/HOMER_Looping.gd
index d453402c5a9d874374bd48af77fc69421a85b0de..3902da5fc54dfa2621c56b3ce83d48d1ee79ec29 100644
--- a/examples/manipulation/HOMER_Looping.gd
+++ b/examples/manipulation/HOMER_Looping.gd
@@ -2,29 +2,26 @@ extends "res://addons/ivmi-builder/techniques/manipulation/HOMER.gd"
 
 var _looping =false
 
-func _physics_process(delta):
-	pass
-
 func _input(event):
 	if event is InputEventMouseButton :
-		if event.button_index==BUTTON_RIGHT:
+		if event.button_index==MOUSE_BUTTON_RIGHT:
 			if _selected:
 				if event.is_pressed():
 					_selected.set_property("looped", [1])
 				else:
 					_selected.set_property("looped", [0])
-		elif event.button_index==BUTTON_LEFT:
+		elif event.button_index==MOUSE_BUTTON_LEFT:
 			if _selected:
 				_selected.set_property("looped", [-1])
 
 func _on_HOMER_button_pressed(button):
-	._on_HOMER_button_pressed(button)
-	if button == JOY_OCULUS_AX :
+	super._on_HOMER_button_pressed(button)
+	if button == JOY_BUTTON_A :
 		if _selected:
 			_selected.set_property("looped", [1])
 
 func _on_HOMER_button_release(button):
-	._on_HOMER_button_release(button)
-	if button == JOY_OCULUS_AX :
+	super._on_HOMER_button_release(button)
+	if button == JOY_BUTTON_A :
 		if _selected:
 			_selected.set_property("looped", [0])
diff --git a/examples/manipulation/Manipulation.tscn b/examples/manipulation/Manipulation.tscn
index 6dcf2b399ba19c8a30d3398034a0acc1fa38981e..8f87e3ce24f1a5776f9dabcd6f6a0dd1f71e1d76 100644
--- a/examples/manipulation/Manipulation.tscn
+++ b/examples/manipulation/Manipulation.tscn
@@ -1,18 +1,20 @@
-[gd_scene load_steps=11 format=2]
+[gd_scene load_steps=11 format=3 uid="uid://bauqqd2ugf74u"]
 
-[ext_resource path="res://addons/ivmi-builder/techniques/manipulation/HOMER.tscn" type="PackedScene" id=1]
-[ext_resource path="res://addons/ivmi-builder/examples/manipulation/Worm.tscn" type="PackedScene" id=2]
-[ext_resource path="res://addons/ivmi-builder/techniques/control/Tunnel/Tunnel_v2.tscn" type="PackedScene" id=3]
-[ext_resource path="res://addons/ivmi-builder/core/IvmiScene.gd" type="Script" id=5]
-[ext_resource path="res://addons/ivmi-builder/examples/manipulation/HOMER_Looping.gd" type="Script" id=6]
+[ext_resource type="PackedScene" uid="uid://cp6bltsdhj3aw" path="res://addons/ivmi-builder/techniques/manipulation/HOMER.tscn" id="1"]
+[ext_resource type="PackedScene" uid="uid://b8jefoccnhqkp" path="res://addons/ivmi-builder/examples/manipulation/Worm.tscn" id="2"]
+[ext_resource type="PackedScene" uid="uid://bngkenwtwh5fg" path="res://addons/ivmi-builder/techniques/control/Tunnel/Tunnel_v2.tscn" id="3"]
+[ext_resource type="Script" path="res://addons/ivmi-builder/core/IvmiScene.gd" id="5"]
+[ext_resource type="Script" path="res://addons/ivmi-builder/examples/manipulation/HOMER_Looping.gd" id="6"]
 
-[sub_resource type="Curve" id=4]
-_data = [ Vector2( 0.000567034, 0.00308013 ), 0.0, 1.13193, 0, 0, Vector2( 1, 0.968172 ), 0.953202, 0.0, 0, 0 ]
+[sub_resource type="Curve" id="4"]
+_data = [Vector2(0.000567034, 0.00308013), 0.0, 1.13193, 0, 0, Vector2(1, 0.968172), 0.953202, 0.0, 0, 0]
+point_count = 2
 
-[sub_resource type="Curve" id=5]
-_data = [ Vector2( 0, 0 ), 0.0, 1.09533, 0, 0, Vector2( 1, 1 ), 1.38712, 0.0, 0, 0 ]
+[sub_resource type="Curve" id="5"]
+_data = [Vector2(0, 0), 0.0, 1.09533, 0, 0, Vector2(1, 1), 1.38712, 0.0, 0, 0]
+point_count = 2
 
-[sub_resource type="Shader" id=1]
+[sub_resource type="Shader" id="1"]
 code = "shader_type spatial;
 
 varying float height;
@@ -31,69 +33,70 @@ void fragment() {
 }
 "
 
-[sub_resource type="ShaderMaterial" id=2]
-shader = SubResource( 1 )
+[sub_resource type="ShaderMaterial" id="2"]
+render_priority = 0
+shader = SubResource("1")
 
-[sub_resource type="PlaneMesh" id=3]
-material = SubResource( 2 )
-size = Vector2( 1, 1 )
+[sub_resource type="PlaneMesh" id="3"]
+material = SubResource("2")
+size = Vector2(1, 1)
 subdivide_width = 500
 subdivide_depth = 500
 
-[node name="Manipulation" type="Spatial"]
-script = ExtResource( 5 )
+[node name="Manipulation" type="Node3D"]
+script = ExtResource("5")
 _network_mode = 1
 
-[node name="ARVROrigin" type="ARVROrigin" parent="."]
+[node name="XROrigin3D" type="XROrigin3D" parent="."]
 
-[node name="ARVRController" type="ARVRController" parent="ARVROrigin"]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0 )
+[node name="XRController3D" type="XRController3D" parent="XROrigin3D"]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0)
+tracker = &"right_hand"
 
-[node name="ARVRCamera" type="ARVRCamera" parent="ARVROrigin"]
+[node name="XRCamera3D" type="XRCamera3D" parent="XROrigin3D"]
 
-[node name="OmniLight" type="DirectionalLight" parent="ARVROrigin/ARVRCamera"]
-transform = Transform( 1, 0, 0, 0, 0.301738, 0.953391, 0, -0.953391, 0.301738, 0, 1.97807, -0.453438 )
+[node name="OmniLight3D" type="DirectionalLight3D" parent="XROrigin3D/XRCamera3D"]
+transform = Transform3D(1, 0, 0, 0, 0.301738, 0.953391, 0, -0.953391, 0.301738, 0, 1.97807, -0.453438)
 light_energy = 0.38
 light_indirect_energy = 1.154
-light_specular = 1.26
 shadow_enabled = true
 shadow_bias = 0.7
 
-[node name="HOMER" parent="ARVROrigin" instance=ExtResource( 1 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.030427, -0.352326, 0 )
-script = ExtResource( 6 )
-_controller_node_path = NodePath("../ARVRController")
-_camera_node_path = NodePath("../ARVRCamera")
+[node name="HOMER" parent="XROrigin3D" instance=ExtResource("1")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.030427, -0.352326, 0)
+script = ExtResource("6")
+_controller_node_path = NodePath("../XRController3D")
+_camera_node_path = NodePath("../XRCamera3D")
 _arvr_origin_node_path = NodePath("..")
 
-[node name="Worms" type="Spatial" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1.5 )
+[node name="Worms" type="Node3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1.5)
 
-[node name="worm1" parent="Worms" instance=ExtResource( 2 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
+[node name="worm1" parent="Worms" instance=ExtResource("2")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
 
-[node name="worm2" parent="Worms" instance=ExtResource( 2 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.749196, 0, 0 )
+[node name="worm2" parent="Worms" instance=ExtResource("2")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0.749196, 0, 0)
 
-[node name="worm3" parent="Worms" instance=ExtResource( 2 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1.22147, 0, 0 )
+[node name="worm3" parent="Worms" instance=ExtResource("2")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -1.22147, 0, 0)
 
-[node name="Tunnels" type="Spatial" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1.5 )
+[node name="Tunnels" type="Node3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1.5)
 
-[node name="tunnel1" parent="Tunnels" instance=ExtResource( 3 )]
-transform = Transform( 0.920505, -0.390731, 0, 0.390731, 0.920505, 0, 0, 0, 1, 0, 1, 0 )
+[node name="tunnel1" parent="Tunnels" instance=ExtResource("3")]
+transform = Transform3D(0.920505, -0.390731, 0, 0.390731, 0.920505, 0, 0, 0, 1, 0, 1, 0)
 _color_active = true
 _color_data_type = 0
-_color_curve = SubResource( 4 )
+_color_curve = SubResource("4")
 
-[node name="tunnel2" parent="Tunnels" instance=ExtResource( 3 )]
+[node name="tunnel2" parent="Tunnels" instance=ExtResource("3")]
 _height_active = true
 _height_data_type = 0
-_height_curve = SubResource( 5 )
+_height_curve = SubResource("5")
 
-[node name="env" type="Spatial" parent="."]
+[node name="env" type="Node3D" parent="."]
 
-[node name="MeshInstance" type="MeshInstance" parent="env"]
-transform = Transform( 100, 0, 0, 0, 1, 0, 0, 0, 100, 0, -0.729825, -2.20273 )
-mesh = SubResource( 3 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="env"]
+transform = Transform3D(100, 0, 0, 0, 1, 0, 0, 0, 100, 0, -0.729825, -2.20273)
+mesh = SubResource("3")
diff --git a/examples/manipulation/Worm.tscn b/examples/manipulation/Worm.tscn
index 2807e88e659c0e136ce3cf45b4f2559a6b483ee2..4646832728942e2be54ab133a043df6094239004 100644
--- a/examples/manipulation/Worm.tscn
+++ b/examples/manipulation/Worm.tscn
@@ -1,13 +1,13 @@
-[gd_scene load_steps=5 format=2]
+[gd_scene load_steps=5 format=3 uid="uid://b8jefoccnhqkp"]
 
-[sub_resource type="GDScript" id=1]
-script/source = "extends \"res://addons/ivmi-builder/core/IvmiNode.gd\"
+[sub_resource type="GDScript" id="1"]
+script/source = "extends IvmiNode
 
 enum State {STOPPED, RECORDING, PLAYING}
 var _loop_state = State.STOPPED
 var _loop_time=0
 
-export(String) var height = \"test\"
+@onready var mesh : MeshInstance3D = $MeshInstance3D
 
 var _positions = []
 var _cur_pos = 0
@@ -24,7 +24,7 @@ func _ready():
 	_add_property(\"grabbed\",[0])
 
 func move(pos) :
-	self.translation = pos
+	self.position = pos
 
 
 func _process(delta): 
@@ -35,7 +35,7 @@ func _process(delta):
 			_loop_time+=delta
 			if _positions.size()>0 :
 				while _positions[_cur_pos][0] < _loop_time :
-					self.translation = _ivmi.array_to_vector3(_positions[_cur_pos][1])
+					self.position = _ivmi.array_to_vector3(_positions[_cur_pos][1])
 					_cur_pos= _cur_pos + 1
 					if _cur_pos >= _positions.size() :
 						_cur_pos=0
@@ -59,19 +59,20 @@ func set_looped(lo) :
 		_cur_pos=0
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		\"tunnel_height\" :
-			get_node(\"MeshInstance\").scale.y = 0.1+0.9*vals[0]
+			mesh.scale.y = 0.1+0.9*vals[0]
 		\"tunnel_color_scale\" :
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.h=fmod(vals[0]*5.0,1.0)
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.s=1.0-abs(vals[0]*2.0-1.0)
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.v=vals[0]
+			var matr : StandardMaterial3D = mesh.mesh.surface_get_material(0)
+			matr.albedo_color.h=fmod(vals[0]*5.0,1.0)
+			matr.albedo_color.s=1.0-abs(vals[0]*2.0-1.0)
+			matr.albedo_color.v=vals[0]
 		\"tunnel_rotation\" :
-			get_node(\"MeshInstance\").rotation_degrees.y = vals[0]*90
+			mesh.rotation_degrees.y = vals[0]*90
 		\"radius\" :
-			get_node(\"MeshInstance\").scale.x = vals[0]
-			get_node(\"MeshInstance\").scale.z = vals[0]
+			mesh.scale.x = vals[0]
+			mesh.scale.z = vals[0]
 		\"selected\":
 			set_selected(vals[0])
 		\"position\":
@@ -81,43 +82,36 @@ func _set_property(prop, vals) :
 			set_looped(vals[0])
 		\"grabbed\":
 			if _loop_state == State.PLAYING and vals[0]==1:
-				print(\"blup\")
 				set_looped(-1)
 
 
 "
 
-[sub_resource type="CylinderMesh" id=2]
+[sub_resource type="StandardMaterial3D" id="StandardMaterial3D_f2vtc"]
+resource_local_to_scene = true
+
+[sub_resource type="CylinderMesh" id="2"]
+resource_local_to_scene = true
+material = SubResource("StandardMaterial3D_f2vtc")
 top_radius = 0.1
 bottom_radius = 0.1
 height = 0.3
 radial_segments = 5
 rings = 1
 
-[sub_resource type="SpatialMaterial" id=3]
-resource_local_to_scene = true
-albedo_color = Color( 0.25, 0.5, 0.5, 1 )
-metallic = 0.33
-metallic_specular = 1.0
-
-[sub_resource type="CylinderShape" id=4]
+[sub_resource type="CylinderShape3D" id="4"]
 height = 0.3
-radius = 0.2
+radius = 0.105646
 
-[node name="Worm" type="Spatial"]
-transform = Transform( 0.5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
-script = SubResource( 1 )
-__meta__ = {
-"IVMI": true,
-"IVMI_Node_Type": "Worm"
-}
+[node name="Worm" type="Node3D"]
+transform = Transform3D(0.5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
+script = SubResource("1")
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( 0.5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0 )
-mesh = SubResource( 2 )
-material/0 = SubResource( 3 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D(0.5, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0)
+mesh = SubResource("2")
 
-[node name="StaticBody" type="StaticBody" parent="."]
+[node name="StaticBody3D" type="StaticBody3D" parent="."]
 
-[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
-shape = SubResource( 4 )
+[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
+shape = SubResource("4")
diff --git a/examples/manipulation/manipulation.pd b/examples/manipulation/manipulation.pd
index bde0ee39bebbfa90d8d8fe6f7f442124adf81776..a741ec706a1c7b11d97d73509f4d6fd683f80a1c 100644
Binary files a/examples/manipulation/manipulation.pd and b/examples/manipulation/manipulation.pd differ
diff --git a/examples/navigation/BeatSphere.tscn b/examples/navigation/BeatSphere.tscn
index 313ff8045c3a381b2146ab300ad97cf5c11c843a..e14182a5736a106851558f7d9c9a56389e72abe8 100644
--- a/examples/navigation/BeatSphere.tscn
+++ b/examples/navigation/BeatSphere.tscn
@@ -4,9 +4,9 @@
 script/source = "tool 
 extends \"res://addons/ivmi-builder/core/IvmiNode.gd\"
 
-export(float, 60, 400) var _tempo setget set_tempo
-export(float, 0, 1) var _filter setget set_filter
-export(float, 0, 1) var _noisiness setget set_noisiness
+@export var _tempo setget set_tempo # (float, 60, 400)
+@export var _filter setget set_filter # (float, 0, 1)
+@export var _noisiness setget set_noisiness # (float, 0, 1)
 
 var hsv = [0, 1, 1]
 
@@ -41,24 +41,24 @@ func set_noisiness(n) :
 		set_property(\"color_hsv\", hsv)
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		\"transparency\" :
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.a=vals[0]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.a=vals[0]
 		\"color_hsv\" :
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.h=vals[0]
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.s=vals[1]
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.v=vals[2]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.h=vals[0]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.s=vals[1]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.v=vals[2]
 			
 func get_property(prop) :
 	match prop :
 		\"transparency\" :
-			return get_node(\"MeshInstance\").get_surface_material(0).albedo_color.a
+			return get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.a
 		\"color_hsv\" :
-			return [get_node(\"MeshInstance\").get_surface_material(0).albedo_color.h,
-					get_node(\"MeshInstance\").get_surface_material(0).albedo_color.s,
-					get_node(\"MeshInstance\").get_surface_material(0).albedo_color.v]
-	return .get_property(prop)
+			return [get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.h,
+					get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.s,
+					get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.v]
+	return super.get_property(prop)
 "
 
 [sub_resource type="SphereMesh" id=2]
@@ -76,7 +76,7 @@ noise = SubResource( 3 )
 seamless = true
 noise = SubResource( 5 )
 
-[sub_resource type="SpatialMaterial" id=7]
+[sub_resource type="StandardMaterial3D" id=7]
 resource_local_to_scene = true
 flags_transparent = true
 albedo_color = Color( 0.130739, 0.6845, 0.598475, 1 )
@@ -93,7 +93,7 @@ depth_flip_tangent = false
 depth_flip_binormal = false
 depth_texture = SubResource( 4 )
 
-[node name="BeatSphere" type="Spatial"]
+[node name="BeatSphere" type="Node3D"]
 script = SubResource( 1 )
 __meta__ = {
 "IVMI": true,
@@ -104,6 +104,6 @@ _tempo = 221.197
 _filter = 0.369
 _noisiness = 0.191
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
 mesh = SubResource( 2 )
 material/0 = SubResource( 7 )
diff --git a/examples/navigation/Navigation.tscn b/examples/navigation/Navigation.tscn
index d232ba0e85230b32ed3cf4aa01f6a9705c5ebf0e..b08a1d726c95d88f76b4f2c64ce82df9e0b1d64b 100644
--- a/examples/navigation/Navigation.tscn
+++ b/examples/navigation/Navigation.tscn
@@ -28,7 +28,7 @@ width = 1000
 height = 1000
 noise = SubResource( 2 )
 
-[sub_resource type="PanoramaSky" id=4]
+[sub_resource type="Sky" id=4]
 radiance_size = 0
 panorama = SubResource( 3 )
 
@@ -63,65 +63,65 @@ adjustment_brightness = 1.27
 adjustment_contrast = 2.19
 adjustment_saturation = 0.63
 
-[node name="Navigation" type="Spatial"]
+[node name="Navigation" type="Node3D"]
 script = SubResource( 1 )
 _pd_patch = "res://examples/navigation/navigation.pd"
 _screen_vr_mode = 1
 
-[node name="ARVRorigin" type="ARVROrigin" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.379932 )
+[node name="ARVRorigin" type="XROrigin3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.379932 )
 
-[node name="Camera" type="ARVRCamera" parent="ARVRorigin"]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.28588, 1.16185 )
+[node name="Camera3D" type="XRCamera3D" parent="ARVRorigin"]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.28588, 1.16185 )
 environment = SubResource( 5 )
 current = true
 
-[node name="OmniLight" type="OmniLight" parent="ARVRorigin/Camera"]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0 )
+[node name="OmniLight3D" type="OmniLight3D" parent="ARVRorigin/Camera3D"]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 3, 0 )
 light_energy = 11.51
 light_indirect_energy = 5.17
 light_specular = 1.0
 omni_range = 12.0
 omni_attenuation = 0.732043
 
-[node name="ARVRController" type="ARVRController" parent="ARVRorigin"]
+[node name="XRController3D" type="XRController3D" parent="ARVRorigin"]
 
 [node name="flying" parent="ARVRorigin" instance=ExtResource( 1 )]
-_camera_node_path = NodePath("../Camera")
-_controller_node_path = NodePath("../ARVRController")
+_camera_node_path = NodePath("../Camera3D")
+_controller_node_path = NodePath("../XRController3D")
 _arvrorigin_node_path = NodePath("..")
 _speed = 6
 
 [node name="sphere1" parent="." instance=ExtResource( 2 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.45, 0, -2.735 )
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.45, 0, -2.735 )
 _tempo = 136.387
 _filter = 0.0
 _noisiness = 0.218
 
 [node name="sphere2" parent="." instance=ExtResource( 2 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -3.74067, -11.2131 )
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -3.74067, -11.2131 )
 _tempo = 213.258
 _filter = 0.545
 _noisiness = 0.412
 
 [node name="line1" parent="." instance=ExtResource( 3 )]
-transform = Transform( 0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 0, 1.1, -8.93681 )
+transform = Transform3D( 0.707107, -0.707107, 0, 0.707107, 0.707107, 0, 0, 0, 1, 0, 1.1, -8.93681 )
 _modulation = 1.0
 _filter = 0.308
 _noisiness = 0.249
 _pitch = 52.0
 
 [node name="line2" parent="." instance=ExtResource( 3 )]
-transform = Transform( 0.764977, -0.644057, 0, 0.644057, 0.764977, 0, 0, 0, 1, 26.4684, -17.7985, -70.6241 )
+transform = Transform3D( 0.764977, -0.644057, 0, 0.644057, 0.764977, 0, 0, 0, 1, 26.4684, -17.7985, -70.6241 )
 _modulation = 0.891
 _filter = 0.7
 _noisiness = 1.0
 _pitch = 47.0
 
 [node name="sphere3" parent="." instance=ExtResource( 2 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 10.5408, 3.06207, -32.1897 )
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 10.5408, 3.06207, -32.1897 )
 _filter = 0.247
 _noisiness = 0.423
 
 [node name="SynthLine" parent="." instance=ExtResource( 3 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.46475, -9.24963 )
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1.46475, -9.24963 )
diff --git a/examples/navigation/SynthLine.tscn b/examples/navigation/SynthLine.tscn
index 0f28fd989abaf9aba1f5a8306ba533e7435cfa75..408002e010b73a63dcb6df9df20339f786882ba5 100644
--- a/examples/navigation/SynthLine.tscn
+++ b/examples/navigation/SynthLine.tscn
@@ -4,10 +4,10 @@
 script/source = "tool 
 extends \"res://addons/ivmi-builder/core/IvmiNode.gd\"
 
-export(float, 0, 1) var _modulation setget set_modulation
-export(float, 0, 1) var _filter setget set_filter
-export(float, 0, 1) var _noisiness setget set_noisiness
-export(float, 30, 60) var _pitch setget set_pitch
+@export var _modulation setget set_modulation # (float, 0, 1)
+@export var _filter setget set_filter # (float, 0, 1)
+@export var _noisiness setget set_noisiness # (float, 0, 1)
+@export var _pitch setget set_pitch # (float, 30, 60)
 
 var _hsv = [0, 1, 1]
 
@@ -48,25 +48,25 @@ func set_pitch(p) :
 		set_property(\"color_hsv\", _hsv)
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		\"transparency\" :
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.a=vals[0]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.a=vals[0]
 		\"color_hsv\" :
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.h=vals[0]
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.s=vals[1]
-			get_node(\"MeshInstance\").get_surface_material(0).albedo_color.v=vals[2]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.h=vals[0]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.s=vals[1]
+			get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.v=vals[2]
 			
 func get_property(prop) :
 	match prop :
 		\"transparency\" :
-			return get_node(\"MeshInstance\").get_surface_material(0).albedo_color.a
+			return get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.a
 		\"color_hsv\" :
-			return [get_node(\"MeshInstance\").get_surface_material(0).albedo_color.h,
-					get_node(\"MeshInstance\").get_surface_material(0).albedo_color.s,
-					get_node(\"MeshInstance\").get_surface_material(0).albedo_color.v]
+			return [get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.h,
+					get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.s,
+					get_node(\"MeshInstance3D\").get_surface_override_material(0).albedo_color.v]
 		
-	return .get_property(prop)
+	return super.get_property(prop)
 "
 
 [sub_resource type="CylinderMesh" id=2]
@@ -74,12 +74,12 @@ top_radius = 0.1
 bottom_radius = 0.1
 height = 500.0
 
-[sub_resource type="SpatialMaterial" id=3]
+[sub_resource type="StandardMaterial3D" id=3]
 resource_local_to_scene = true
 flags_transparent = true
 albedo_color = Color( 1, 0.023622, 0, 1 )
 
-[node name="SynthLine" type="Spatial"]
+[node name="SynthLine" type="Node3D"]
 script = SubResource( 1 )
 __meta__ = {
 "IVMI": true,
@@ -87,7 +87,7 @@ __meta__ = {
 }
 _pitch = 0.5
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D( -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0, 1, 0, 0, 0 )
 mesh = SubResource( 2 )
 material/0 = SubResource( 3 )
diff --git a/examples/selection/Grain.tscn b/examples/selection/Grain.tscn
index 2c0778c80425237ad5b5a210ef4938159e3ca0fa..1b51505a91e95c07544cf175528ab25477d122bb 100644
--- a/examples/selection/Grain.tscn
+++ b/examples/selection/Grain.tscn
@@ -11,39 +11,39 @@ func _ready():
 
 
 func _set_property(property, vals):
-	._set_property(property, vals)
+	super._set_property(property, vals)
 	match property :
 		\"position\" :
-			var mat = get_node(\"MeshInstance\").get_surface_material(0)
+			var mat = get_node(\"MeshInstance3D\").get_surface_override_material(0)
 			for i in range(0,2) : 
 				_col[i] = (vals[i]/5.0+0.5)*2.0
 				mat.albedo_color[i] = _col[i]
 			
 		\"selected\" :
-			var mat = get_node(\"MeshInstance\").get_surface_material(0)
+			var mat = get_node(\"MeshInstance3D\").get_surface_override_material(0)
 			for i in range(0,2) : 
 				mat.albedo_color[i] = _col[i]+0.4*vals[0]
 "
 
-[sub_resource type="CubeMesh" id=2]
+[sub_resource type="BoxMesh" id=2]
 size = Vector3( 0.2, 0.2, 0.2 )
 
-[sub_resource type="SpatialMaterial" id=3]
+[sub_resource type="StandardMaterial3D" id=3]
 resource_local_to_scene = true
 flags_transparent = true
 albedo_color = Color( 1, 1, 1, 0.835294 )
 
-[sub_resource type="BoxShape" id=4]
-extents = Vector3( 0.1, 0.1, 0.1 )
+[sub_resource type="BoxShape3D" id=4]
+size = Vector3( 0.1, 0.1, 0.1 )
 
-[node name="Spatial" type="Spatial"]
+[node name="Node3D" type="Node3D"]
 script = SubResource( 1 )
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
 mesh = SubResource( 2 )
 material/0 = SubResource( 3 )
 
-[node name="StaticBody" type="StaticBody" parent="."]
+[node name="StaticBody3D" type="StaticBody3D" parent="."]
 
-[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
 shape = SubResource( 4 )
diff --git a/examples/selection/Selection.tscn b/examples/selection/Selection.tscn
index 251f5a34f06dffa1f30ccbb2481eca57e67c23bc..241452337e0475fc5696d3208548e8af3c8e2ebc 100644
--- a/examples/selection/Selection.tscn
+++ b/examples/selection/Selection.tscn
@@ -1,9 +1,9 @@
-[gd_scene load_steps=4 format=2]
+[gd_scene load_steps=4 format=3 uid="uid://b45pg7vpjrpsk"]
 
-[ext_resource path="res://addons/ivmi-builder/techniques/manipulation/Cursor.tscn" type="PackedScene" id=1]
-[ext_resource path="res://addons/ivmi-builder/examples/selection/Grain.tscn" type="PackedScene" id=2]
+[ext_resource type="PackedScene" path="res://addons/ivmi-builder/techniques/manipulation/Cursor.tscn" id="1"]
+[ext_resource type="PackedScene" path="res://addons/ivmi-builder/examples/selection/Grain.tscn" id="2"]
 
-[sub_resource type="GDScript" id=1]
+[sub_resource type="GDScript" id="1"]
 script/source = "extends \"res://addons/ivmi-builder/core/IvmiScene.gd\"
 
 func _ready():
@@ -15,31 +15,31 @@ var _grains = []
 func _create_node(name) :
 	print(\"Create grain \", name)
 	var Grain = load(\"res://addons/ivmi-builder/examples/selection/Grain.tscn\")
-	var new_grain = Grain.instance()
+	var new_grain = Grain.instantiate()
 	new_grain.set_name(name)
 	_grains.push_back(new_grain)
 	get_node(\"Grains\").add_child(new_grain)
 "
 
-[node name="Selection" type="Spatial"]
-script = SubResource( 1 )
+[node name="Selection" type="Node3D"]
+script = SubResource("1")
 _pd_patch = "res://examples/selection/selection.pd"
 
-[node name="ARVROrigin" type="ARVROrigin" parent="."]
+[node name="XROrigin3D" type="XROrigin3D" parent="."]
 
-[node name="ARVRCamera" type="ARVRCamera" parent="ARVROrigin"]
+[node name="XRCamera3D" type="XRCamera3D" parent="XROrigin3D"]
 
-[node name="OmniLight" type="OmniLight" parent="ARVROrigin/ARVRCamera"]
+[node name="OmniLight3D" type="OmniLight3D" parent="XROrigin3D/XRCamera3D"]
 
-[node name="ARVRController" type="ARVRController" parent="ARVROrigin"]
+[node name="XRController3D" type="XRController3D" parent="XROrigin3D"]
 
-[node name="Cursor" parent="." instance=ExtResource( 1 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -4 )
-_controller_node_path = NodePath("../ARVROrigin/ARVRController")
-_camera_node_path = NodePath("../ARVROrigin/ARVRCamera")
+[node name="Cursor" parent="." instance=ExtResource("1")]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -4)
+_controller_node_path = NodePath("../XROrigin3D/XRController3D")
+_camera_node_path = NodePath("../XROrigin3D/XRCamera3D")
 
-[node name="Grains" type="Spatial" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, -4 )
+[node name="Grains" type="Node3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, -4)
 
-[node name="Spatial" parent="Grains" instance=ExtResource( 2 )]
+[node name="Node3D" parent="Grains" instance=ExtResource("2")]
 visible = false
diff --git a/patches/ivm-fx-autogate.pd b/patches/ivm-fx-autogate.pd
index 060a6603e8f846bea5daf384c541fa86cd5be1bb..5ba82e98751ee2fe7f7d92a65761b0c1d8df21e7 100644
Binary files a/patches/ivm-fx-autogate.pd and b/patches/ivm-fx-autogate.pd differ
diff --git a/patches/ivm-syn-granular.pd b/patches/ivm-syn-granular.pd
index 572ca4f482e4609a9372414d3ef9a9717c624500..fb3aebf84cac978796ec3427554cfc40713b35e2 100644
Binary files a/patches/ivm-syn-granular.pd and b/patches/ivm-syn-granular.pd differ
diff --git a/techniques/control/1DSlider/1DSlider.gd b/techniques/control/1DSlider/1DSlider.gd
index 6eb31b4db2d17383cc43884a5ec0099226074ceb..47e253bbc33e4cce43c627ab5a80033d063e9a6a 100644
--- a/techniques/control/1DSlider/1DSlider.gd
+++ b/techniques/control/1DSlider/1DSlider.gd
@@ -1,8 +1,8 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-onready var _surface_mat = get_node("MeshInstance").get_surface_material(0)
-onready var _parent = get_parent()
-onready var _parent_scale = get_parent().scale
+@onready var _surface_mat = get_node("MeshInstance3D").get_surface_override_material(0)
+@onready var _parent = get_parent()
+@onready var _parent_scale = get_parent().scale
 
 
 
@@ -11,13 +11,13 @@ func _ready():
 	_add_property("value", [0])
 
 func set_property(prop, vals):
-	.set_property(prop, vals)
+	super.set_property(prop, vals)
 	match prop:
 		"position":
-			translation.x = clamp(translation.x,-_parent_scale.x,_parent_scale.x)
-			translation.y = 0
-			translation.z = 0
-			_parent.set_property("value",[pos_to_val(translation.x,_parent_scale.x)])
+			position.x = clamp(position.x,-_parent_scale.x,_parent_scale.x)
+			position.y = 0
+			position.z = 0
+			_parent.set_property("value",[pos_to_val(position.x,_parent_scale.x)])
 			update_color()
 		"value":
 			set_property("position",[val_to_pos(vals[0],_parent_scale.x),0,0])
@@ -30,4 +30,4 @@ func val_to_pos(val,upper_lower_bound):
 	return (val*upper_lower_bound*2)-upper_lower_bound
 
 func update_color():
-	_surface_mat.albedo_color.h= ((translation.x + _parent_scale.x)/(_parent_scale.x*2))
+	_surface_mat.albedo_color.h= ((position.x + _parent_scale.x)/(_parent_scale.x*2))
diff --git a/techniques/control/1DSlider/1DSlider.tscn b/techniques/control/1DSlider/1DSlider.tscn
index 9b8ddba23123bdadd1853c77ae9cb78aec0f28e8..8d269e4ab5c01076ea99736f7206cca1b83b5a4a 100644
--- a/techniques/control/1DSlider/1DSlider.tscn
+++ b/techniques/control/1DSlider/1DSlider.tscn
@@ -1,47 +1,42 @@
-[gd_scene load_steps=8 format=2]
+[gd_scene load_steps=7 format=3 uid="uid://f6hwoypk1cff"]
 
-[ext_resource path="res://addons/ivmi-builder/techniques/control/1DSlider/1DSlider.gd" type="Script" id=1]
-[ext_resource path="res://addons/ivmi-builder/techniques/control/1DSlider/1DSliderParent.gd" type="Script" id=2]
-[ext_resource path="res://addons/ivmi-builder/visualization/SimpleLine.tscn" type="PackedScene" id=3]
+[ext_resource type="Script" path="res://addons/ivmi-builder/techniques/control/1DSlider/1DSlider.gd" id="1"]
+[ext_resource type="Script" path="res://addons/ivmi-builder/techniques/control/1DSlider/1DSliderParent.gd" id="2"]
+[ext_resource type="PackedScene" uid="uid://cbede1qesppcg" path="res://addons/ivmi-builder/visualization/SimpleLine.tscn" id="3"]
 
-[sub_resource type="QuadMesh" id=1]
+[sub_resource type="QuadMesh" id="1"]
 
-[sub_resource type="CubeMesh" id=2]
+[sub_resource type="BoxMesh" id="2"]
 
-[sub_resource type="SpatialMaterial" id=3]
-albedo_color = Color( 0, 0.833333, 1, 1 )
+[sub_resource type="BoxShape3D" id="4"]
+size = Vector3(0.100379, 0.0983211, 0.100575)
 
-[sub_resource type="BoxShape" id=4]
-extents = Vector3( 0.100379, 0.0983211, 0.100575 )
+[node name="Slider" type="Node3D"]
+script = ExtResource("2")
 
-[node name="Slider" type="Spatial"]
-script = ExtResource( 2 )
-
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( 2, 0, 0, 0, 0.5, 0, 0, 0, 1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D(2, 0, 0, 0, 0.5, 0, 0, 0, 1, 0, 0, 0)
 visible = false
-mesh = SubResource( 1 )
-material/0 = null
+mesh = SubResource("1")
 
-[node name="Cursor" type="Spatial" parent="."]
-script = ExtResource( 1 )
+[node name="Cursor" type="Node3D" parent="."]
+script = ExtResource("1")
 
-[node name="MeshInstance" type="MeshInstance" parent="Cursor"]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
-mesh = SubResource( 2 )
-material/0 = SubResource( 3 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Cursor"]
+transform = Transform3D(0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0)
+mesh = SubResource("2")
 
-[node name="StaticBody" type="StaticBody" parent="Cursor"]
+[node name="StaticBody3D" type="StaticBody3D" parent="Cursor"]
 
-[node name="CollisionShape" type="CollisionShape" parent="Cursor/StaticBody"]
-shape = SubResource( 4 )
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Cursor/StaticBody3D"]
+shape = SubResource("4")
 
-[node name="SimpleLine" parent="." instance=ExtResource( 3 )]
-_pointA_path = NodePath("../Position3D")
+[node name="SimpleLine" parent="." instance=ExtResource("3")]
+_pointA_path = NodePath("../Marker3D")
 _pointB_path = NodePath("../Position3D2")
 
-[node name="Position3D" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, -1, 8.74228e-08, 0, -8.74228e-08, -1, -1, 0, 0 )
+[node name="Marker3D" type="Marker3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, -1, 8.74228e-08, 0, -8.74228e-08, -1, -1, 0, 0)
 
-[node name="Position3D2" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 )
+[node name="Position3D2" type="Marker3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0)
diff --git a/techniques/control/1DSlider/1DSliderParent.gd b/techniques/control/1DSlider/1DSliderParent.gd
index ba6dad701e41bd17e551d36b9a6387ec30891886..879b16db243e775579db109cc86f30c33a88c21b 100644
--- a/techniques/control/1DSlider/1DSliderParent.gd
+++ b/techniques/control/1DSlider/1DSliderParent.gd
@@ -1,12 +1,12 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-onready var _cursor = get_node("Cursor")
+@onready var _cursor = get_node("Cursor")
 
 func _ready():
 	_add_property("value",[0])
 	
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		"value":
 			var _value = _cursor.get_property("value")
diff --git a/techniques/control/2DSlider/2DSlider.gd b/techniques/control/2DSlider/2DSlider.gd
index 3b820c388875945679ed8e706fdb7200bb69447a..6fc27e60a108c9dca2c89cee2bee1b2f7d1cd376 100644
--- a/techniques/control/2DSlider/2DSlider.gd
+++ b/techniques/control/2DSlider/2DSlider.gd
@@ -1,22 +1,22 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-onready var _surface_mat = get_node("MeshInstance").get_surface_material(0)
-onready var _parent = get_parent()
-onready var _parent_scale = get_parent().scale
+@onready var _surface_mat = get_node("MeshInstance3D").get_surface_override_material(0)
+@onready var _parent = get_parent()
+@onready var _parent_scale = get_parent().scale
 
 func _ready():
 	_can_be_rotated = false
 	_add_property("value", [0,0])
 
 func set_property(prop, vals) :
-	.set_property(prop, vals)
+	super.set_property(prop, vals)
 	match prop:
 		"position":
-			translation.x = clamp(translation.x,-_parent_scale.x,_parent_scale.x)
-			translation.y = clamp(translation.y,-_parent_scale.y,_parent_scale.y)
-			translation.z = 0
-			var value = [pos_to_val(translation.x,_parent_scale.x),
-						 pos_to_val(translation.y,_parent_scale.y)]
+			position.x = clamp(position.x,-_parent_scale.x,_parent_scale.x)
+			position.y = clamp(position.y,-_parent_scale.y,_parent_scale.y)
+			position.z = 0
+			var value = [pos_to_val(position.x,_parent_scale.x),
+						 pos_to_val(position.y,_parent_scale.y)]
 			_parent.set_property("value",value)
 			update_color()
 		"value":
@@ -34,5 +34,5 @@ func val_to_pos(val,upper_lower_bound):
 
 
 func update_color():
-	_surface_mat.albedo_color.h= ((translation.x + _parent_scale.x)/(_parent_scale.x*2))
-	_surface_mat.albedo_color.s= ((translation.y + _parent_scale.y)/(_parent_scale.y*2))
+	_surface_mat.albedo_color.h= ((position.x + _parent_scale.x)/(_parent_scale.x*2))
+	_surface_mat.albedo_color.s= ((position.y + _parent_scale.y)/(_parent_scale.y*2))
diff --git a/techniques/control/2DSlider/2DSlider.tscn b/techniques/control/2DSlider/2DSlider.tscn
index dc18ac2f5b4b7bfefa1a75780410ef4cede70a35..82d379ac88a6353274afc10753e02225ff0c32ab 100644
--- a/techniques/control/2DSlider/2DSlider.tscn
+++ b/techniques/control/2DSlider/2DSlider.tscn
@@ -3,9 +3,9 @@
 [ext_resource path="res://addons/ivmi-builder/techniques/control/2DSlider/2DSlider.gd" type="Script" id=1]
 [ext_resource path="res://addons/ivmi-builder/techniques/control/2DSlider/2DSliderParent.gd" type="Script" id=2]
 [ext_resource path="res://addons/ivmi-builder/visualization/SimpleLine.tscn" type="PackedScene" id=3]
-[ext_resource path="res://addons/ivmi-builder/visualization/box_slider.shader" type="Shader" id=4]
+[ext_resource path="res://addons/ivmi-builder/visualization/box_slider.gdshader" type="Shader" id=4]
 
-[sub_resource type="CubeMesh" id=1]
+[sub_resource type="BoxMesh" id=1]
 size = Vector3( 1, 1, 1 )
 subdivide_width = 10
 subdivide_height = 10
@@ -14,33 +14,33 @@ subdivide_depth = 10
 [sub_resource type="ShaderMaterial" id=2]
 shader = ExtResource( 4 )
 
-[sub_resource type="CubeMesh" id=3]
+[sub_resource type="BoxMesh" id=3]
 
-[sub_resource type="SpatialMaterial" id=4]
+[sub_resource type="StandardMaterial3D" id=4]
 albedo_color = Color( 0.5, 0.916667, 1, 1 )
 
-[sub_resource type="BoxShape" id=5]
-extents = Vector3( 0.100379, 0.0983211, 0.100575 )
+[sub_resource type="BoxShape3D" id=5]
+size = Vector3( 0.100379, 0.0983211, 0.100575 )
 
-[node name="2DSlider" type="Spatial"]
+[node name="2DSlider" type="Node3D"]
 script = ExtResource( 2 )
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( 2.5, 0, 0, 0, 2.5, 0, 0, 0, 0.5, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D( 2.5, 0, 0, 0, 2.5, 0, 0, 0, 0.5, 0, 0, 0 )
 mesh = SubResource( 1 )
 material/0 = SubResource( 2 )
 
-[node name="Cursor" type="Spatial" parent="."]
+[node name="Cursor" type="Node3D" parent="."]
 script = ExtResource( 1 )
 
-[node name="MeshInstance" type="MeshInstance" parent="Cursor"]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Cursor"]
+transform = Transform3D( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
 mesh = SubResource( 3 )
 material/0 = SubResource( 4 )
 
-[node name="StaticBody" type="StaticBody" parent="Cursor"]
+[node name="StaticBody3D" type="StaticBody3D" parent="Cursor"]
 
-[node name="CollisionShape" type="CollisionShape" parent="Cursor/StaticBody"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Cursor/StaticBody3D"]
 shape = SubResource( 5 )
 
 [node name="SimpleLine" parent="." instance=ExtResource( 3 )]
@@ -51,14 +51,14 @@ _pointB_path = NodePath("../Position3D_X_2")
 _pointA_path = NodePath("../Position3D_Y_1")
 _pointB_path = NodePath("../Position3D_Y_2")
 
-[node name="Position3D_X_1" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0 )
+[node name="Position3D_X_1" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0 )
 
-[node name="Position3D_X_2" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 )
+[node name="Position3D_X_2" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 )
 
-[node name="Position3D_Y_1" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
+[node name="Position3D_Y_1" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
 
-[node name="Position3D_Y_2" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
+[node name="Position3D_Y_2" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
diff --git a/techniques/control/2DSlider/2DSliderParent.gd b/techniques/control/2DSlider/2DSliderParent.gd
index e2c07cdc98b8cad992c9767d201bbc0baa0de645..71f88df51272ec503a2bc5fb19aa3df1b4cb4565 100644
--- a/techniques/control/2DSlider/2DSliderParent.gd
+++ b/techniques/control/2DSlider/2DSliderParent.gd
@@ -1,23 +1,23 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-onready var _pos_x_1 = get_node("Position3D_X_1")
-onready var _pos_x_2 = get_node("Position3D_X_2")
-onready var _pos_y_1 = get_node("Position3D_Y_1")
-onready var _pos_y_2 = get_node("Position3D_Y_2")
+@onready var _pos_x_1 = get_node("Position3D_X_1")
+@onready var _pos_x_2 = get_node("Position3D_X_2")
+@onready var _pos_y_1 = get_node("Position3D_Y_1")
+@onready var _pos_y_2 = get_node("Position3D_Y_2")
 
-onready var _cursor = get_node("Cursor")
+@onready var _cursor = get_node("Cursor")
 
 func _ready():
 	_add_property("value",[0,0])
 	
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		"value":
 			var _value = _cursor.get_property("value")
 			if !(_value[0] == vals[0] and _value[1] == vals[1]):
 				_cursor.set_property("value", vals)
-			_pos_x_1.translation.y = _cursor.translation.y
-			_pos_x_2.translation.y = _cursor.translation.y
-			_pos_y_1.translation.x = _cursor.translation.x
-			_pos_y_2.translation.x = _cursor.translation.x
+			_pos_x_1.position.y = _cursor.position.y
+			_pos_x_2.position.y = _cursor.position.y
+			_pos_y_1.position.x = _cursor.position.x
+			_pos_y_2.position.x = _cursor.position.x
diff --git a/techniques/control/3DSlider/3DSlider.gd b/techniques/control/3DSlider/3DSlider.gd
index 95ed622d21e7dcaba568966fe72a2722496c6007..f975d438e85d08a01ec5c8d95da0aeb0f9ea5c23 100644
--- a/techniques/control/3DSlider/3DSlider.gd
+++ b/techniques/control/3DSlider/3DSlider.gd
@@ -1,23 +1,23 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-onready var _surface_mat = get_node("MeshInstance").get_surface_material(0)
-onready var _parent = get_parent()
-onready var _parent_scale = get_parent().scale
+@onready var _surface_mat = get_node("MeshInstance3D").get_surface_override_material(0)
+@onready var _parent = get_parent()
+@onready var _parent_scale = get_parent().scale
 
 func _ready():
 	_can_be_rotated = false
 	_add_property("value", [0,0,0])
 
 func set_property(prop, vals) :
-	.set_property(prop, vals)
+	super.set_property(prop, vals)
 	match prop:
 		"position":
-			translation.x = clamp(translation.x,-_parent_scale.x,_parent_scale.x)
-			translation.y = clamp(translation.y,-_parent_scale.y,_parent_scale.y)
-			translation.z = clamp(translation.z,-_parent_scale.z,_parent_scale.z)
-			var value = [pos_to_val(translation.x,_parent_scale.x),
-						 pos_to_val(translation.y,_parent_scale.y),
-						 pos_to_val(translation.z,_parent_scale.z)]
+			position.x = clamp(position.x,-_parent_scale.x,_parent_scale.x)
+			position.y = clamp(position.y,-_parent_scale.y,_parent_scale.y)
+			position.z = clamp(position.z,-_parent_scale.z,_parent_scale.z)
+			var value = [pos_to_val(position.x,_parent_scale.x),
+						 pos_to_val(position.y,_parent_scale.y),
+						 pos_to_val(position.z,_parent_scale.z)]
 			_parent.set_property("value",value)
 			update_color()
 		"value":
@@ -34,6 +34,6 @@ func val_to_pos(val,upper_lower_bound):
 	return (val*upper_lower_bound*2)-upper_lower_bound
 
 func update_color():
-	_surface_mat.albedo_color.h= ((translation.x + _parent_scale.x)/(_parent_scale.x*2))
-	_surface_mat.albedo_color.s= ((translation.y + _parent_scale.y)/(_parent_scale.y*2))
-	_surface_mat.albedo_color.v= ((translation.z + _parent_scale.z)/(_parent_scale.z*2))
+	_surface_mat.albedo_color.h= ((position.x + _parent_scale.x)/(_parent_scale.x*2))
+	_surface_mat.albedo_color.s= ((position.y + _parent_scale.y)/(_parent_scale.y*2))
+	_surface_mat.albedo_color.v= ((position.z + _parent_scale.z)/(_parent_scale.z*2))
diff --git a/techniques/control/3DSlider/3DSlider.tscn b/techniques/control/3DSlider/3DSlider.tscn
index b256929276dcc415c6a017d21aebecd668017fc5..fe25d81550dd18da24b8e4c8b0e3e2f4afe4199d 100644
--- a/techniques/control/3DSlider/3DSlider.tscn
+++ b/techniques/control/3DSlider/3DSlider.tscn
@@ -2,10 +2,10 @@
 
 [ext_resource path="res://addons/ivmi-builder/techniques/control/3DSlider/3DSlider.gd" type="Script" id=1]
 [ext_resource path="res://addons/ivmi-builder/techniques/control/3DSlider/3DSliderParent.gd" type="Script" id=2]
-[ext_resource path="res://addons/ivmi-builder/visualization/box_slider.shader" type="Shader" id=3]
+[ext_resource path="res://addons/ivmi-builder/visualization/box_slider.gdshader" type="Shader" id=3]
 [ext_resource path="res://addons/ivmi-builder/visualization/SimpleLine.tscn" type="PackedScene" id=4]
 
-[sub_resource type="CubeMesh" id=1]
+[sub_resource type="BoxMesh" id=1]
 size = Vector3( 1, 1, 1 )
 subdivide_width = 10
 subdivide_height = 10
@@ -14,21 +14,21 @@ subdivide_depth = 10
 [sub_resource type="ShaderMaterial" id=2]
 shader = ExtResource( 3 )
 
-[sub_resource type="CubeMesh" id=3]
+[sub_resource type="BoxMesh" id=3]
 
-[sub_resource type="SpatialMaterial" id=4]
+[sub_resource type="StandardMaterial3D" id=4]
 albedo_color = Color( 0.25, 0.458333, 0.5, 1 )
 
-[sub_resource type="BoxShape" id=5]
-extents = Vector3( 0.100379, 0.0983211, 0.100575 )
+[sub_resource type="BoxShape3D" id=5]
+size = Vector3( 0.100379, 0.0983211, 0.100575 )
 
 [sub_resource type="GDScript" id=6]
-script/source = "extends ImmediateGeometry
+script/source = "extends ImmediateMesh
 
 
-export(NodePath) var _pointA_path
-export(NodePath) var _pointB_path
-export(Curve) var remove_me
+@export var _pointA_path: NodePath
+@export var _pointB_path: NodePath
+@export var remove_me: Curve
 var _pointA
 var _pointB
 
@@ -40,8 +40,8 @@ func _process(delta):
 	if (_pointA and _pointB):
 		clear()
 		begin(1, null) 
-		add_vertex(_pointA.translation)
-		add_vertex(_pointB.translation)
+		add_vertex(_pointA.position)
+		add_vertex(_pointB.position)
 		end()
 
 func update_points(_new_pointA, _new_pointB):
@@ -52,25 +52,25 @@ func update_points(_new_pointA, _new_pointB):
 [sub_resource type="Curve" id=7]
 _data = [ Vector2( 0, 0 ), 0.0, 4.16674, 0, 1, Vector2( 0.146179, 0.609091 ), 0.0, 0.0, 0, 0, Vector2( 0.152824, 0.136364 ), 0.291102, 0.291102, 0, 0, Vector2( 0.352159, 0.709091 ), 0.0, 0.0, 0, 0, Vector2( 0.378738, 1 ), 0.0, 0.0, 0, 0, Vector2( 1, 0 ), -1.60963, 0.0, 1, 0 ]
 
-[node name="3DSlider" type="Spatial"]
+[node name="3DSlider" type="Node3D"]
 script = ExtResource( 2 )
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( 2.5, 0, 0, 0, 2.5, 0, 0, 0, 2.5, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D( 2.5, 0, 0, 0, 2.5, 0, 0, 0, 2.5, 0, 0, 0 )
 mesh = SubResource( 1 )
 material/0 = SubResource( 2 )
 
-[node name="Cursor" type="Spatial" parent="."]
+[node name="Cursor" type="Node3D" parent="."]
 script = ExtResource( 1 )
 
-[node name="MeshInstance" type="MeshInstance" parent="Cursor"]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Cursor"]
+transform = Transform3D( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
 mesh = SubResource( 3 )
 material/0 = SubResource( 4 )
 
-[node name="StaticBody" type="StaticBody" parent="Cursor"]
+[node name="StaticBody3D" type="StaticBody3D" parent="Cursor"]
 
-[node name="CollisionShape" type="CollisionShape" parent="Cursor/StaticBody"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Cursor/StaticBody3D"]
 shape = SubResource( 5 )
 
 [node name="SimpleLine" parent="." instance=ExtResource( 4 )]
@@ -89,20 +89,20 @@ script = SubResource( 6 )
 _pointA_path = NodePath("../Position3D_Z_1")
 _pointB_path = NodePath("../Position3D_Z_2")
 
-[node name="Position3D_X_1" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0 )
+[node name="Position3D_X_1" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, -1, 0, 0 )
 
-[node name="Position3D_X_2" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 )
+[node name="Position3D_X_2" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0 )
 
-[node name="Position3D_Y_1" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
+[node name="Position3D_Y_1" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0 )
 
-[node name="Position3D_Y_2" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
+[node name="Position3D_Y_2" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -1, 0 )
 
-[node name="Position3D_Z_1" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1 )
+[node name="Position3D_Z_1" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 1 )
 
-[node name="Position3D_Z_2" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
+[node name="Position3D_Z_2" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
diff --git a/techniques/control/3DSlider/3DSliderParent.gd b/techniques/control/3DSlider/3DSliderParent.gd
index 3013ebb29e067a122e154205e6314c8f1d358a95..4f5dc2d4767a1090904a8877a76985b24c5f72fa 100644
--- a/techniques/control/3DSlider/3DSliderParent.gd
+++ b/techniques/control/3DSlider/3DSliderParent.gd
@@ -1,39 +1,39 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-onready var _pos_x_1 = get_node("Position3D_X_1")
-onready var _pos_x_2 = get_node("Position3D_X_2")
-onready var _pos_y_1 = get_node("Position3D_Y_1")
-onready var _pos_y_2 = get_node("Position3D_Y_2")
-onready var _pos_z_1 = get_node("Position3D_Z_1")
-onready var _pos_z_2 = get_node("Position3D_Z_2")
+@onready var _pos_x_1 = get_node("Position3D_X_1")
+@onready var _pos_x_2 = get_node("Position3D_X_2")
+@onready var _pos_y_1 = get_node("Position3D_Y_1")
+@onready var _pos_y_2 = get_node("Position3D_Y_2")
+@onready var _pos_z_1 = get_node("Position3D_Z_1")
+@onready var _pos_z_2 = get_node("Position3D_Z_2")
 
-onready var _cursor = get_node("Cursor")
+@onready var _cursor = get_node("Cursor")
 
 func _ready():
 	_add_property("value",[0,0,0])
 	
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		"value":
 			var _value = _cursor.get_property("value")
 			if !(_value[0] == vals[0] and _value[1] == vals[1] and _value[2] == vals[2]):
 				_cursor.set_property("value", vals)
 				
-			_pos_x_1.translation.y = _cursor.translation.y
-			_pos_x_1.translation.z = _cursor.translation.z
+			_pos_x_1.position.y = _cursor.position.y
+			_pos_x_1.position.z = _cursor.position.z
 			
-			_pos_x_2.translation.y = _cursor.translation.y
-			_pos_x_2.translation.z = _cursor.translation.z
+			_pos_x_2.position.y = _cursor.position.y
+			_pos_x_2.position.z = _cursor.position.z
 			
-			_pos_y_1.translation.x = _cursor.translation.x
-			_pos_y_1.translation.z = _cursor.translation.z
+			_pos_y_1.position.x = _cursor.position.x
+			_pos_y_1.position.z = _cursor.position.z
 			
-			_pos_y_2.translation.x = _cursor.translation.x
-			_pos_y_2.translation.z = _cursor.translation.z
+			_pos_y_2.position.x = _cursor.position.x
+			_pos_y_2.position.z = _cursor.position.z
 			
-			_pos_z_1.translation.x = _cursor.translation.x
-			_pos_z_1.translation.y = _cursor.translation.y
+			_pos_z_1.position.x = _cursor.position.x
+			_pos_z_1.position.y = _cursor.position.y
 			
-			_pos_z_2.translation.x = _cursor.translation.x
-			_pos_z_2.translation.y = _cursor.translation.y
+			_pos_z_2.position.x = _cursor.position.x
+			_pos_z_2.position.y = _cursor.position.y
diff --git a/techniques/control/Button.tscn b/techniques/control/Button.tscn
index 2f686cfe930b8f7ffea9db7db14d575392aa71d6..da03bf21b2a457b9b2bf253842c0e6f4e2aa7c88 100644
--- a/techniques/control/Button.tscn
+++ b/techniques/control/Button.tscn
@@ -24,7 +24,7 @@ func released():
 	emit_signal(\"button_released\")
 	print(\"r\")
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		\"triggered\" :
 			if vals[0]:
@@ -35,15 +35,15 @@ func _set_property(prop, vals) :
 			
 "
 
-[sub_resource type="CubeMesh" id=2]
+[sub_resource type="BoxMesh" id=2]
 
 [sub_resource type="GDScript" id=3]
-script/source = "extends RigidBody
+script/source = "extends RigidBody3D
 
-export var button_spring_force = 5
-export(NodePath) var end_point_node_path
-export(NodePath) var start_point_node_path
-export(NodePath) var button_mesh_node_path
+@export var button_spring_force = 5
+@export var end_point_node_path: NodePath
+@export var start_point_node_path: NodePath
+@export var button_mesh_node_path: NodePath
 var _end_point
 var _start_point
 var _parent
@@ -57,21 +57,21 @@ func _ready():
 	_start_point = get_node(start_point_node_path)
 	_parent = get_parent()
 	_button_mesh =  get_node(button_mesh_node_path)
-	initial_v = _button_mesh.get_surface_material(0).albedo_color.v
+	initial_v = _button_mesh.get_surface_override_material(0).albedo_color.v
 
 func _integrate_forces(state):
-	if translation.z < _end_point.translation.z:
-		add_central_force(global_transform.basis.z * button_spring_force)
+	if position.z < _end_point.position.z:
+		apply_central_force(global_transform.basis.z * button_spring_force)
 
 
 func _on_pressed():
-			_button_mesh.get_surface_material(0).albedo_color.v=initial_v + 50
+			_button_mesh.get_surface_override_material(0).albedo_color.v=initial_v + 50
 func _on_released():
-			_button_mesh.get_surface_material(0).albedo_color.v=initial_v
+			_button_mesh.get_surface_override_material(0).albedo_color.v=initial_v
 
 func press():
 	linear_velocity = Vector3.ZERO
-	translation = _start_point.translation
+	position = _start_point.position
 	if _pressed == false:
 		_pressed = true
 		_parent.pressed()
@@ -79,47 +79,47 @@ func press():
 
 func release():
 	linear_velocity = Vector3.ZERO
-	translation = _end_point.translation
+	position = _end_point.position
 	if _pressed == true:
 		_pressed = false
 		_parent.released()
 		_on_released()	
 	
 func _physics_process(delta):
-	if translation.x > MARGIN:
-		translation.x = 0
-	if translation.y > MARGIN:
-		translation.y = 0
-	if translation.z >= (_end_point.translation.z + MARGIN):
+	if position.x > MARGIN:
+		position.x = 0
+	if position.y > MARGIN:
+		position.y = 0
+	if position.z >= (_end_point.position.z + MARGIN):
 		release()
-	if translation.z <= (_start_point.translation.z-MARGIN):
+	if position.z <= (_start_point.position.z-MARGIN):
 		press()
 	
 
 		
 "
 
-[sub_resource type="CubeMesh" id=4]
+[sub_resource type="BoxMesh" id=4]
 
-[sub_resource type="SpatialMaterial" id=5]
+[sub_resource type="StandardMaterial3D" id=5]
 albedo_color = Color( 1, 0, 0, 1 )
 
-[sub_resource type="BoxShape" id=6]
-extents = Vector3( 0.757024, 0.750126, 0.300778 )
+[sub_resource type="BoxShape3D" id=6]
+size = Vector3( 0.757024, 0.750126, 0.300778 )
 
 [sub_resource type="SphereMesh" id=7]
 
-[node name="Button" type="Spatial"]
-transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
+[node name="Button" type="Node3D"]
+transform = Transform3D( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
 script = SubResource( 1 )
 
-[node name="ButtonBase" type="MeshInstance" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
+[node name="ButtonBase" type="MeshInstance3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
 mesh = SubResource( 2 )
 material/0 = null
 
-[node name="Body" type="RigidBody" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.25 )
+[node name="Body" type="RigidBody3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.25 )
 gravity_scale = 0.0
 axis_lock_angular_x = true
 axis_lock_angular_y = true
@@ -129,29 +129,29 @@ end_point_node_path = NodePath("../EndPoint")
 start_point_node_path = NodePath("../StartPoint")
 button_mesh_node_path = NodePath("Button")
 
-[node name="Button" type="MeshInstance" parent="Body"]
-transform = Transform( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0 )
+[node name="Button" type="MeshInstance3D" parent="Body"]
+transform = Transform3D( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0 )
 mesh = SubResource( 4 )
 material/0 = SubResource( 5 )
 
-[node name="CollisionShape" type="CollisionShape" parent="Body"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Body"]
 shape = SubResource( 6 )
 
-[node name="EndPoint" type="Spatial" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
+[node name="EndPoint" type="Node3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
 visible = false
 
-[node name="MeshInstance" type="MeshInstance" parent="EndPoint"]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="EndPoint"]
+transform = Transform3D( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
 mesh = SubResource( 7 )
 material/0 = null
 
-[node name="StartPoint" type="Spatial" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
+[node name="StartPoint" type="Node3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
 visible = false
 
-[node name="MeshInstance" type="MeshInstance" parent="StartPoint"]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="StartPoint"]
+transform = Transform3D( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
 visible = false
 mesh = SubResource( 7 )
 material/0 = null
diff --git a/techniques/control/Button/Button.gd b/techniques/control/Button/Button.gd
index 1c7330f8d396bbab6231f93d4a635d8635fb750e..384b714c6d00fdfba2d3232340534d532c5c93a6 100644
--- a/techniques/control/Button/Button.gd
+++ b/techniques/control/Button/Button.gd
@@ -1,32 +1,36 @@
-extends "res://addons/ivmi-builder/core/IvmiNode.gd"
+extends IvmiNode
 
 signal button_pressed
 signal button_released
 
-onready var _button = get_node("Button")
-onready var _pressed_position = get_node("Pressed").translation
-onready var _released_position = get_node("Released").translation
-onready var initial_v = _button.get_surface_material(0).albedo_color.v
-export var release_speed = 8
+@onready var _button = get_node("Button")
+@onready var _pressed_position = get_node("Pressed").position
+@onready var _released_position = get_node("Released").position
+@onready var initial_v = _button.get_surface_override_material(0).albedo_color.v
+@export var release_speed = 8
 
 func _ready():
+	super._ready()
 	_add_property("triggered", [0])
 
+func _process(delta):
+	super._process(delta)
+
 func _physics_process(delta): 
 	if get_property("triggered")[0]:
-		_button.translation = lerp(_button.translation,_released_position,delta * release_speed)
-		if (_button.translation-_released_position).length_squared()<0.0005:
+		_button.position = lerp(_button.position,_released_position,delta * release_speed)
+		if (_button.position-_released_position).length_squared()<0.0005:
 			set_property("triggered",[0])
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		"triggered" :
 			if vals[0]:
-				_button.get_surface_material(0).albedo_color.v=initial_v + 50
-				_button.translation = _pressed_position
+				_button.get_surface_override_material(0).albedo_color.v=initial_v + 50
+				_button.position = _pressed_position
 				emit_signal("button_pressed")
 			else:
-				_button.get_surface_material(0).albedo_color.v=initial_v
-				_button.translation = _released_position
+				_button.get_surface_override_material(0).albedo_color.v=initial_v
+				_button.position = _released_position
 				emit_signal("button_released")
diff --git a/techniques/control/Button/Button.tscn b/techniques/control/Button/Button.tscn
index 7a207565ff4f55a4c964b916be6052bef003d93c..d50bdfd099b62d53c414250b2da567afd2630717 100644
--- a/techniques/control/Button/Button.tscn
+++ b/techniques/control/Button/Button.tscn
@@ -23,7 +23,7 @@ func released():
 	emit_signal(\"button_released\")
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		\"triggered\" :
 			if vals[0]:
@@ -34,15 +34,15 @@ func _set_property(prop, vals) :
 			
 "
 
-[sub_resource type="CubeMesh" id=2]
+[sub_resource type="BoxMesh" id=2]
 
 [sub_resource type="GDScript" id=3]
-script/source = "extends RigidBody
+script/source = "extends RigidBody3D
 
-export var button_spring_force = 5
-export(NodePath) var end_point_node_path
-export(NodePath) var start_point_node_path
-export(NodePath) var button_mesh_node_path
+@export var button_spring_force = 5
+@export var end_point_node_path: NodePath
+@export var start_point_node_path: NodePath
+@export var button_mesh_node_path: NodePath
 var _end_point
 var _start_point
 var _parent
@@ -56,21 +56,21 @@ func _ready():
 	_start_point = get_node(start_point_node_path)
 	_parent = get_parent()
 	_button_mesh =  get_node(button_mesh_node_path)
-	initial_v = _button_mesh.get_surface_material(0).albedo_color.v
+	initial_v = _button_mesh.get_surface_override_material(0).albedo_color.v
 
 func _integrate_forces(state):
-	if translation.z < _end_point.translation.z:
-		add_central_force(global_transform.basis.z * button_spring_force)
+	if position.z < _end_point.position.z:
+		apply_central_force(global_transform.basis.z * button_spring_force)
 
 
 func _on_pressed():
-			_button_mesh.get_surface_material(0).albedo_color.v=initial_v + 50
+			_button_mesh.get_surface_override_material(0).albedo_color.v=initial_v + 50
 func _on_released():
-			_button_mesh.get_surface_material(0).albedo_color.v=initial_v
+			_button_mesh.get_surface_override_material(0).albedo_color.v=initial_v
 
 func press():
 	linear_velocity = Vector3.ZERO
-	translation = _start_point.translation
+	position = _start_point.position
 	if _pressed == false:
 		_pressed = true
 		_parent.pressed()
@@ -78,47 +78,47 @@ func press():
 
 func release():
 	linear_velocity = Vector3.ZERO
-	translation = _end_point.translation
+	position = _end_point.position
 	if _pressed == true:
 		_pressed = false
 		_parent.released()
 		_on_released()	
 	
 func _physics_process(delta):
-	if translation.x > MARGIN:
-		translation.x = 0
-	if translation.y > MARGIN:
-		translation.y = 0
-	if translation.z >= (_end_point.translation.z + MARGIN):
+	if position.x > MARGIN:
+		position.x = 0
+	if position.y > MARGIN:
+		position.y = 0
+	if position.z >= (_end_point.position.z + MARGIN):
 		release()
-	if translation.z <= (_start_point.translation.z-MARGIN):
+	if position.z <= (_start_point.position.z-MARGIN):
 		press()
 	
 
 		
 "
 
-[sub_resource type="CubeMesh" id=4]
+[sub_resource type="BoxMesh" id=4]
 
-[sub_resource type="SpatialMaterial" id=5]
+[sub_resource type="StandardMaterial3D" id=5]
 albedo_color = Color( 1, 0, 0, 1 )
 
-[sub_resource type="BoxShape" id=6]
-extents = Vector3( 0.757024, 0.750126, 0.300778 )
+[sub_resource type="BoxShape3D" id=6]
+size = Vector3( 0.757024, 0.750126, 0.300778 )
 
 [sub_resource type="SphereMesh" id=7]
 
-[node name="Button" type="Spatial"]
-transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
+[node name="Button" type="Node3D"]
+transform = Transform3D( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
 script = SubResource( 1 )
 
-[node name="ButtonBase" type="MeshInstance" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
+[node name="ButtonBase" type="MeshInstance3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
 mesh = SubResource( 2 )
 material/0 = null
 
-[node name="Body" type="RigidBody" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.25 )
+[node name="Body" type="RigidBody3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.25 )
 gravity_scale = 0.0
 axis_lock_angular_x = true
 axis_lock_angular_y = true
@@ -128,29 +128,29 @@ end_point_node_path = NodePath("../EndPoint")
 start_point_node_path = NodePath("../StartPoint")
 button_mesh_node_path = NodePath("Button")
 
-[node name="Button" type="MeshInstance" parent="Body"]
-transform = Transform( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0 )
+[node name="Button" type="MeshInstance3D" parent="Body"]
+transform = Transform3D( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0 )
 mesh = SubResource( 4 )
 material/0 = SubResource( 5 )
 
-[node name="CollisionShape" type="CollisionShape" parent="Body"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Body"]
 shape = SubResource( 6 )
 
-[node name="EndPoint" type="Spatial" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
+[node name="EndPoint" type="Node3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
 visible = false
 
-[node name="MeshInstance" type="MeshInstance" parent="EndPoint"]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="EndPoint"]
+transform = Transform3D( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
 mesh = SubResource( 7 )
 material/0 = null
 
-[node name="StartPoint" type="Spatial" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
+[node name="StartPoint" type="Node3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
 visible = false
 
-[node name="MeshInstance" type="MeshInstance" parent="StartPoint"]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="StartPoint"]
+transform = Transform3D( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
 visible = false
 mesh = SubResource( 7 )
 material/0 = null
diff --git a/techniques/control/Button/Button_v2.tscn b/techniques/control/Button/Button_v2.tscn
index 5e931aa730803a007a8cecad590524cd74ddfb26..47d6f99b392ce9ab56f94ddc02d58d4b55cbd719 100644
--- a/techniques/control/Button/Button_v2.tscn
+++ b/techniques/control/Button/Button_v2.tscn
@@ -2,37 +2,37 @@
 
 [ext_resource path="res://addons/ivmi-builder/techniques/control/Button/Button.gd" type="Script" id=1]
 
-[sub_resource type="CubeMesh" id=1]
+[sub_resource type="BoxMesh" id=1]
 
-[sub_resource type="CubeMesh" id=2]
+[sub_resource type="BoxMesh" id=2]
 
-[sub_resource type="SpatialMaterial" id=3]
+[sub_resource type="StandardMaterial3D" id=3]
 albedo_color = Color( 1, 0, 0, 1 )
 
-[sub_resource type="BoxShape" id=4]
-extents = Vector3( 1, 1, 0.553743 )
+[sub_resource type="BoxShape3D" id=4]
+size = Vector3( 1, 1, 0.553743 )
 
-[node name="Button" type="Spatial"]
-transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
+[node name="Button" type="Node3D"]
+transform = Transform3D( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
 script = ExtResource( 1 )
 
-[node name="ButtonBase" type="MeshInstance" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
+[node name="ButtonBase" type="MeshInstance3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
 mesh = SubResource( 1 )
 material/0 = null
 
-[node name="Button" type="MeshInstance" parent="."]
-transform = Transform( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0.35 )
+[node name="Button" type="MeshInstance3D" parent="."]
+transform = Transform3D( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0.35 )
 mesh = SubResource( 2 )
 material/0 = SubResource( 3 )
 
-[node name="Released" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
+[node name="Released" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
 
-[node name="Pressed" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
+[node name="Pressed" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
 
-[node name="StaticBody" type="StaticBody" parent="."]
+[node name="StaticBody3D" type="StaticBody3D" parent="."]
 
-[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
 shape = SubResource( 4 )
diff --git a/techniques/control/Button/Button_v3.gd b/techniques/control/Button/Button_v3.gd
index aa67f85d656c8a06ab8a5145df7dc3f64ec6ea38..3b54c86ae7dfe1a1cc1e64c48b91c9f074782bb3 100644
--- a/techniques/control/Button/Button_v3.gd
+++ b/techniques/control/Button/Button_v3.gd
@@ -1,30 +1,34 @@
-extends "res://addons/ivmi-builder/core/IvmiNode.gd"
+extends IvmiNode
 
-onready var _button = get_node("Button")
-onready var _pressed_position = get_node("Pressed").translation
-onready var _released_position = get_node("Released").translation
-onready var initial_v = _button.get_surface_material(0).albedo_color.v
-export var release_speed = 8
+@onready var _button = get_node("Button")
+@onready var _pressed_position = get_node("Pressed").position
+@onready var _released_position = get_node("Released").position
+@onready var initial_v = _button.get_surface_override_material(0).albedo_color.v
+@export var release_speed = 8
 
 var _moving = false
 
 func _ready():
+	super._ready()
 	_add_property("triggered", [0])
 
+func _process(delta):
+	super._process(delta)
+
 func _physics_process(delta): 
 	if !get_property("triggered")[0] and _moving:
-		_button.translation = lerp(_button.translation,_released_position,delta * release_speed)
-		if (_button.translation-_released_position).length_squared()<0.0005:
+		_button.position = lerp(_button.position,_released_position,delta * release_speed)
+		if (_button.position-_released_position).length_squared()<0.0005:
 			_moving = false
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		"triggered" :
 			if vals[0]:
-				_button.get_surface_material(0).albedo_color.v=initial_v + 50
-				_button.translation = _pressed_position
+				_button.get_surface_override_material(0).albedo_color.v=initial_v + 50
+				_button.position = _pressed_position
 				_moving = true
 
 			else:
-				_button.get_surface_material(0).albedo_color.v=initial_v
+				_button.get_surface_override_material(0).albedo_color.v=initial_v
diff --git a/techniques/control/Button/Button_v3.tscn b/techniques/control/Button/Button_v3.tscn
index 7dd9146c442e89a2e50d4a41ee9397356805bfd3..d6994293ddacff5a8739d18f89a81950cab07985 100644
--- a/techniques/control/Button/Button_v3.tscn
+++ b/techniques/control/Button/Button_v3.tscn
@@ -2,37 +2,37 @@
 
 [ext_resource path="res://addons/ivmi-builder/techniques/control/Button/Button_v3.gd" type="Script" id=1]
 
-[sub_resource type="CubeMesh" id=1]
+[sub_resource type="BoxMesh" id=1]
 
-[sub_resource type="CubeMesh" id=2]
+[sub_resource type="BoxMesh" id=2]
 
-[sub_resource type="SpatialMaterial" id=3]
+[sub_resource type="StandardMaterial3D" id=3]
 albedo_color = Color( 1, 0, 0, 1 )
 
-[sub_resource type="BoxShape" id=4]
-extents = Vector3( 1, 1, 0.553743 )
+[sub_resource type="BoxShape3D" id=4]
+size = Vector3( 1, 1, 0.553743 )
 
-[node name="Button" type="Spatial"]
-transform = Transform( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
+[node name="Button" type="Node3D"]
+transform = Transform3D( 0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0 )
 script = ExtResource( 1 )
 
-[node name="ButtonBase" type="MeshInstance" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
+[node name="ButtonBase" type="MeshInstance3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 0.4, 0, 0, 0 )
 mesh = SubResource( 1 )
 material/0 = null
 
-[node name="Button" type="MeshInstance" parent="."]
-transform = Transform( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0.35 )
+[node name="Button" type="MeshInstance3D" parent="."]
+transform = Transform3D( 0.75, 0, 0, 0, 0.75, 0, 0, 0, 0.3, 0, 0, 0.35 )
 mesh = SubResource( 2 )
 material/0 = SubResource( 3 )
 
-[node name="Released" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
+[node name="Released" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.35 )
 
-[node name="Pressed" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
+[node name="Pressed" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.15 )
 
-[node name="StaticBody" type="StaticBody" parent="."]
+[node name="StaticBody3D" type="StaticBody3D" parent="."]
 
-[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
 shape = SubResource( 4 )
diff --git a/techniques/control/Knob/Knob.gd b/techniques/control/Knob/Knob.gd
index 3190344a86131813214e7537f223792e5cdd1c04..c123a18d30cd39264b49f39b646c15359d7b013f 100644
--- a/techniques/control/Knob/Knob.gd
+++ b/techniques/control/Knob/Knob.gd
@@ -1,6 +1,6 @@
 extends "res://addons/ivmi-builder/core/IvmiNode.gd"
 
-onready var _parent = get_parent()
+@onready var _parent = get_parent()
 
 func get_extent():
 	return Vector3(2.0, 2.0, 1)
@@ -10,7 +10,7 @@ func _ready():
 	_can_be_moved = false
 	
 func set_property(prop, vals) :
-	.set_property(prop, vals)
+	super.set_property(prop, vals)
 	match prop:
 		"quaternion":
 			rotation_degrees.x = 0
diff --git a/techniques/control/Knob/Knob.tscn b/techniques/control/Knob/Knob.tscn
index a43a91fc9ca7892f751ab35c6e5f836c6772b451..cc55c25e67562dcf0c17b89a758a32f246842612 100644
--- a/techniques/control/Knob/Knob.tscn
+++ b/techniques/control/Knob/Knob.tscn
@@ -3,45 +3,45 @@
 [ext_resource path="res://addons/ivmi-builder/techniques/control/Knob/KnobParent.gd" type="Script" id=1]
 [ext_resource path="res://addons/ivmi-builder/techniques/control/Knob/Knob.gd" type="Script" id=2]
 
-[sub_resource type="CubeMesh" id=1]
+[sub_resource type="BoxMesh" id=1]
 
 [sub_resource type="CylinderMesh" id=4]
 
-[sub_resource type="SpatialMaterial" id=5]
+[sub_resource type="StandardMaterial3D" id=5]
 albedo_color = Color( 1, 0, 0, 1 )
 
 [sub_resource type="CylinderMesh" id=2]
 
-[sub_resource type="SpatialMaterial" id=3]
+[sub_resource type="StandardMaterial3D" id=3]
 albedo_color = Color( 0, 0, 0, 1 )
 
-[sub_resource type="CylinderShape" id=6]
+[sub_resource type="CylinderShape3D" id=6]
 radius = 0.599106
 height = 0.378027
 
-[node name="Knob" type="Spatial"]
+[node name="Knob" type="Node3D"]
 script = ExtResource( 1 )
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 0.5, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 0.5, 0, 0, 0 )
 mesh = SubResource( 1 )
 material/0 = null
 
-[node name="Body" type="Spatial" parent="."]
+[node name="Body" type="Node3D" parent="."]
 script = ExtResource( 2 )
 
-[node name="MeshInstance" type="MeshInstance" parent="Body"]
-transform = Transform( 0.6, 0, 0, 0, -8.74228e-09, -0.6, 0, 0.2, -2.62268e-08, 0, 0, 0.684353 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Body"]
+transform = Transform3D( 0.6, 0, 0, 0, -8.74228e-09, -0.6, 0, 0.2, -2.62268e-08, 0, 0, 0.684353 )
 mesh = SubResource( 4 )
 material/0 = SubResource( 5 )
 
-[node name="MeshInstance2" type="MeshInstance" parent="Body"]
-transform = Transform( 0.1, 0, 0, 0, -0.5, 1.50996e-08, 0, -7.54979e-08, -0.1, 0, 0.379762, 0.669757 )
+[node name="MeshInstance2" type="MeshInstance3D" parent="Body"]
+transform = Transform3D( 0.1, 0, 0, 0, -0.5, 1.50996e-08, 0, -7.54979e-08, -0.1, 0, 0.379762, 0.669757 )
 mesh = SubResource( 2 )
 material/0 = SubResource( 3 )
 
-[node name="StaticBody" type="StaticBody" parent="Body"]
+[node name="StaticBody3D" type="StaticBody3D" parent="Body"]
 
-[node name="CollisionShape" type="CollisionShape" parent="Body/StaticBody"]
-transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0.687674 )
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Body/StaticBody3D"]
+transform = Transform3D( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 0.687674 )
 shape = SubResource( 6 )
diff --git a/techniques/control/Knob/KnobParent.gd b/techniques/control/Knob/KnobParent.gd
index 0f472c042ba8865ddd59df1da41627687a15ccb3..90416bfa94982dc957712eed07aa53f3a2ef3ff3 100644
--- a/techniques/control/Knob/KnobParent.gd
+++ b/techniques/control/Knob/KnobParent.gd
@@ -1,13 +1,13 @@
 extends "res://addons/ivmi-builder/core/IvmiNode.gd"
 
-onready var _body = get_node("Body")
+@onready var _body = get_node("Body")
 
 func _ready():
 	_add_property("value",[0])
 	_can_be_rotated = false
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		"value":
 			var _value = _body.get_property("value")
diff --git a/techniques/control/Switch/Switch.gd b/techniques/control/Switch/Switch.gd
index 3f1848056bd4b7f1c36f5bede06cd161ac7fd711..2b68fd20eaad90ccfc501633d2e236457fc236d3 100644
--- a/techniques/control/Switch/Switch.gd
+++ b/techniques/control/Switch/Switch.gd
@@ -1,37 +1,37 @@
 extends "res://addons/ivmi-builder/core/IvmiNode.gd"
 
-onready var _slider = get_node("Slider")
-onready var _ledOff = get_node("LedOff")
-onready var _ledOn = get_node("LedOn")
-onready var _on_position = get_node("PosOn").translation
-onready var _off_position = get_node("PosOff").translation
-export var switch_speed = 8
+@onready var _slider = get_node("Slider")
+@onready var _ledOff = get_node("LedOff")
+@onready var _ledOn = get_node("LedOn")
+@onready var _on_position = get_node("PosOn").position
+@onready var _off_position = get_node("PosOff").position
+@export var switch_speed = 8
 
 var _moving = false
 
-onready var base_albedo_v_led_On = _ledOn.get_surface_material(0).albedo_color.v
-onready var base_albedo_v_led_Off = _ledOff.get_surface_material(0).albedo_color.v
+@onready var base_albedo_v_led_On = _ledOn.get_surface_override_material(0).albedo_color.v
+@onready var base_albedo_v_led_Off = _ledOff.get_surface_override_material(0).albedo_color.v
 
 
 func _ready():
 	_add_property("triggered", [0])
 	_add_property("value", [0])
 	# Turn the ledOff ON
-	_ledOff.get_surface_material(0).albedo_color.v=base_albedo_v_led_Off + 50
+	_ledOff.get_surface_override_material(0).albedo_color.v=base_albedo_v_led_Off + 50
 
 func _physics_process(delta): 
 	if _moving:
 		if get_property("value")[0]:
-			_slider.translation = lerp(_slider.translation,_on_position,delta * switch_speed)
-			if (_slider.translation-_on_position).length_squared()<0.00005:
-				_ledOn.get_surface_material(0).albedo_color.v=base_albedo_v_led_On + 50
-				_ledOff.get_surface_material(0).albedo_color.v=base_albedo_v_led_Off
+			_slider.position = lerp(_slider.position,_on_position,delta * switch_speed)
+			if (_slider.position-_on_position).length_squared()<0.00005:
+				_ledOn.get_surface_override_material(0).albedo_color.v=base_albedo_v_led_On + 50
+				_ledOff.get_surface_override_material(0).albedo_color.v=base_albedo_v_led_Off
 				_moving = false
 		else:
-			_slider.translation = lerp(_slider.translation,_off_position,delta * switch_speed)
-			if (_slider.translation-_off_position).length_squared()<0.00005:
-				_ledOn.get_surface_material(0).albedo_color.v=base_albedo_v_led_On
-				_ledOff.get_surface_material(0).albedo_color.v=base_albedo_v_led_Off + 50
+			_slider.position = lerp(_slider.position,_off_position,delta * switch_speed)
+			if (_slider.position-_off_position).length_squared()<0.00005:
+				_ledOn.get_surface_override_material(0).albedo_color.v=base_albedo_v_led_On
+				_ledOff.get_surface_override_material(0).albedo_color.v=base_albedo_v_led_Off + 50
 				_moving = false	
 
 func _inverse_value(val):
@@ -41,7 +41,7 @@ func _inverse_value(val):
 		return 1
 
 func _set_property(prop, vals) :
-	._set_property(prop, vals)
+	super._set_property(prop, vals)
 	match prop:
 		"triggered" :
 			if vals[0]:
diff --git a/techniques/control/Switch/Switch.tscn b/techniques/control/Switch/Switch.tscn
index 71542219c1d83b2b8e845af97ded553f97df94d4..74485f597ad3367503637d110e31eb0f3e9c7332 100644
--- a/techniques/control/Switch/Switch.tscn
+++ b/techniques/control/Switch/Switch.tscn
@@ -2,66 +2,66 @@
 
 [ext_resource path="res://addons/ivmi-builder/techniques/control/Switch/Switch.gd" type="Script" id=1]
 
-[sub_resource type="CubeMesh" id=1]
+[sub_resource type="BoxMesh" id=1]
 
-[sub_resource type="CubeMesh" id=2]
+[sub_resource type="BoxMesh" id=2]
 
-[sub_resource type="SpatialMaterial" id=3]
+[sub_resource type="StandardMaterial3D" id=3]
 albedo_color = Color( 0.686275, 0.686275, 0.686275, 1 )
 
-[sub_resource type="SpatialMaterial" id=4]
+[sub_resource type="StandardMaterial3D" id=4]
 albedo_color = Color( 0.168627, 0.168627, 0.168627, 1 )
 
-[sub_resource type="CubeMesh" id=5]
+[sub_resource type="BoxMesh" id=5]
 material = SubResource( 4 )
 
 [sub_resource type="CylinderMesh" id=6]
 
-[sub_resource type="SpatialMaterial" id=7]
+[sub_resource type="StandardMaterial3D" id=7]
 albedo_color = Color( 0, 0.5, 0, 1 )
 
-[sub_resource type="SpatialMaterial" id=8]
+[sub_resource type="StandardMaterial3D" id=8]
 albedo_color = Color( 0.5, 0, 0, 1 )
 
-[sub_resource type="BoxShape" id=9]
-extents = Vector3( 1.13871, 0.54225, 0.383565 )
+[sub_resource type="BoxShape3D" id=9]
+size = Vector3( 1.13871, 0.54225, 0.383565 )
 
-[node name="Switch" type="Spatial"]
+[node name="Switch" type="Node3D"]
 script = ExtResource( 1 )
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( 1.1422, 0, 0, 0, 0.534412, 0, 0, 0, 0.279885, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D( 1.1422, 0, 0, 0, 0.534412, 0, 0, 0, 0.279885, 0, 0, 0 )
 mesh = SubResource( 1 )
 material/0 = null
 
-[node name="MeshInstance2" type="MeshInstance" parent="."]
-transform = Transform( 0.925302, 0, 0, 0, 0.194713, 0, 0, 0, 0.147171, 0, 0, 0.255825 )
+[node name="MeshInstance2" type="MeshInstance3D" parent="."]
+transform = Transform3D( 0.925302, 0, 0, 0, 0.194713, 0, 0, 0, 0.147171, 0, 0, 0.255825 )
 mesh = SubResource( 2 )
 material/0 = SubResource( 3 )
 
-[node name="Slider" type="MeshInstance" parent="."]
-transform = Transform( 0.18, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0.6, 0, 0.4 )
+[node name="Slider" type="MeshInstance3D" parent="."]
+transform = Transform3D( 0.18, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0.6, 0, 0.4 )
 mesh = SubResource( 5 )
 material/0 = null
 
-[node name="LedOn" type="MeshInstance" parent="."]
-transform = Transform( 0.1, 0, 0, 0, -4.37114e-09, -0.1, 0, 0.1, -4.37114e-09, -0.2, 0.4, 0.2 )
+[node name="LedOn" type="MeshInstance3D" parent="."]
+transform = Transform3D( 0.1, 0, 0, 0, -4.37114e-09, -0.1, 0, 0.1, -4.37114e-09, -0.2, 0.4, 0.2 )
 mesh = SubResource( 6 )
 material/0 = SubResource( 7 )
 
-[node name="LedOff" type="MeshInstance" parent="."]
-transform = Transform( 0.1, 0, 0, 0, -4.37114e-09, -0.1, 0, 0.1, -4.37114e-09, 0.2, 0.4, 0.2 )
+[node name="LedOff" type="MeshInstance3D" parent="."]
+transform = Transform3D( 0.1, 0, 0, 0, -4.37114e-09, -0.1, 0, 0.1, -4.37114e-09, 0.2, 0.4, 0.2 )
 mesh = SubResource( 6 )
 material/0 = SubResource( 8 )
 
-[node name="PosOn" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.6, 0, 0.4 )
+[node name="PosOn" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, -0.6, 0, 0.4 )
 
-[node name="PosOff" type="Position3D" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.6, 0, 0.4 )
+[node name="PosOff" type="Marker3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0.6, 0, 0.4 )
 
-[node name="StaticBody" type="StaticBody" parent="."]
+[node name="StaticBody3D" type="StaticBody3D" parent="."]
 
-[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.107878 )
+[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D"]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0.107878 )
 shape = SubResource( 9 )
diff --git a/techniques/control/Tunnel/Tunnel.gd b/techniques/control/Tunnel/Tunnel.gd
new file mode 100644
index 0000000000000000000000000000000000000000..724beca651879fbbde72e0bb7e531646d56b4785
--- /dev/null
+++ b/techniques/control/Tunnel/Tunnel.gd
@@ -0,0 +1,108 @@
+@tool
+extends "res://addons/ivmi-builder/techniques/control/Tunnel/TunnelPreset.gd"
+
+class_name Tunnel
+
+#Current Tunnel preset, 0 being the default tunnel preset
+@export var _preset_index = 0 : set = _set_preset_index
+var _slices = []
+var tunnel_preset_array = []
+@onready var _area : Area3D = get_node("Area3D")
+
+@onready var _nb_slices : int = $MultiSlice.multimesh.instance_count
+
+const NUMBER_OF_SLICES : int = 100
+const RADIUS : float = 0.1
+
+func _ready():
+	super._ready()
+	_update_tunnel_preset_array()
+	_update_multislice()
+
+func _update_tunnel_preset_array():
+	tunnel_preset_array = []
+	tunnel_preset_array.append(get_tunnel_preset_data())
+	var children = get_children()
+	for child in children:
+		if child.has_method("get_tunnel_preset_data"):
+			if child.active:
+				tunnel_preset_array.append(child.get_tunnel_preset_data())
+
+func _update_multislice() :
+	for s in range(_nb_slices) :
+		var col : Color
+		col.h = 0.5
+		col.s = 1.0
+		col.v = 0.5
+		var trans : Transform3D = Transform3D()
+		trans.origin = Vector3((s-_nb_slices/2)*(1.0/_nb_slices), 0, 0)
+		var rot : Vector3 = Vector3(0.0, 0.0, PI/2.0)
+		var sca : Vector3 = Vector3(0.9,1.0,1.0)
+		var ratio : float = float(s) / float(_nb_slices)
+		for param in tunnel_preset_array[_preset_index]:
+			var value : float = param.curve.sample(ratio)	
+			if value > 1.0 :
+				value/=127
+				
+			match param.name:
+				"tunnel_color_scale" :
+					col = col.from_hsv(fmod(value*5.0,1.0), 1.0 - abs(value*2.0-1.0), value)
+					pass
+				"tunnel_height" :
+					sca.y = value*0.9+0.1
+					sca.z = value*0.9+0.1
+				"tunnel_rotation" :
+					rot.x = value*PI/4.0
+				"tunnel_density" :
+					sca.x = value*0.8+0.1
+					pass
+		
+		trans.basis = Basis.from_euler(rot).scaled(sca)
+		$MultiSlice.multimesh.set_instance_transform(s, trans)
+		$MultiSlice.multimesh.set_instance_custom_data(s, Color(col.r,col.g,col.b,1.0))
+
+func _process(delta : float) -> void	:
+	super._process(delta)
+
+
+func _physics_process(delta):
+	if !Engine.is_editor_hint() :
+		if _ivmi._pd_mode!=IvmiScene.PdMode.NONE: 
+			var results = _area.get_overlapping_areas()
+			if results.size()>0:
+				for r in results:
+					var col = r.get_parent()
+					if col.is_in_group("ivmi_nodes"):
+						#if collision, compute position ratio
+						var col_pos = to_local(col.global_position)
+						var ratio = clamp(col_pos.x+0.5,0,1)
+						#set all active parameters
+						for param in tunnel_preset_array[_preset_index]:
+							var value : float = param.curve.sample(ratio)
+							if value > 1.0 :
+								value/=127
+							col.set_property(param.name, [value])
+
+func get_extent():
+	return Vector3(1.0, 0.2, 0.2)
+
+func _cycle_preset():
+	_preset_index = (_preset_index+1)%tunnel_preset_array.size()
+	_update_multislice()
+
+
+func _set_property(prop, vals) :
+	super._set_property(prop, vals)
+	match prop:
+		"triggered" :
+			if vals[0]:
+				_cycle_preset()
+
+func _update_tunnel():
+	_update_tunnel_preset_array()
+	_update_multislice()
+	
+func _set_preset_index(val):
+	if val < (get_child_count()-1) and val >= 0:
+		_preset_index = val
+		_update_multislice()
diff --git a/techniques/control/Tunnel/Tunnel.gdshader b/techniques/control/Tunnel/Tunnel.gdshader
new file mode 100644
index 0000000000000000000000000000000000000000..bcc7fe5b871c7b6402277600caa217562c98b632
--- /dev/null
+++ b/techniques/control/Tunnel/Tunnel.gdshader
@@ -0,0 +1,13 @@
+shader_type spatial;
+
+varying vec3 col;
+varying float dep;
+
+void vertex() {
+	col = INSTANCE_CUSTOM.rgb;
+	dep = VERTEX.x;
+}
+
+void fragment() {
+	ALBEDO = col*(dep*0.5+0.5);
+}
diff --git a/techniques/control/Tunnel/Tunnel.tscn b/techniques/control/Tunnel/Tunnel.tscn
index edfe64c733348bdffe0c0874320fa97ffb116483..a9e31d2a9ab5b6ccf8bdc4d394807f59e5fc287d 100644
--- a/techniques/control/Tunnel/Tunnel.tscn
+++ b/techniques/control/Tunnel/Tunnel.tscn
@@ -1,193 +1,45 @@
-[gd_scene load_steps=3 format=2]
+[gd_scene load_steps=7 format=3 uid="uid://bngkenwtwh5fg"]
 
-[sub_resource type="GDScript" id=1]
-script/source = "tool
-extends \"res://addons/ivmi-builder/techniques/technique.gd\"
+[ext_resource type="Script" path="res://addons/ivmi-builder/techniques/control/Tunnel/Tunnel.gd" id="1"]
+[ext_resource type="Shader" path="res://addons/ivmi-builder/techniques/control/Tunnel/Tunnel.gdshader" id="2_kaxyo"]
 
-export var _color_act=false setget _activate_color
-export var _height_act=false setget _activate_height
-export var _rot_act=false setget _activate_rotation
-
-var _nb_slices = 50
-var _radius = 0.1
-var _slices = []
-
-var _parameters = {}
-
-enum State {STOPPED, RECORDING, PLAYING}
-var _loop_state = State.STOPPED
-var _loop_time=0
-
-var _positions = []
-var _cur_pos = 0
-
-var _query
-
-class TunnelParam :
-	var _active = false
-	var _min = 0
-	var _max = 1
-
-
-func _ready() :
-	_set_ivmi_type(\"Tunnel\")
-
-	_query = PhysicsShapeQueryParameters.new()
-	_query.set_shape(get_node(\"StaticBody/CollisionShape\").shape)
-	_query.collide_with_bodies=true
-	_query.exclude.push_back(get_node(\"StaticBody\").get_rid())
-	
-	var sli = get_node(\"Slices\")
-	for s in range(0, _nb_slices) :
-		var new_slice = MeshInstance.new()
-		new_slice.translation = Vector3((s-_nb_slices/2)*(1.0/_nb_slices), 0, 0)
-		new_slice.mesh = CylinderMesh.new()
-		new_slice.mesh.rings = 1
-		new_slice.mesh.radial_segments = 5
-		new_slice.mesh.top_radius=_radius
-		new_slice.mesh.bottom_radius=_radius
-		new_slice.mesh.height=1.0/_nb_slices
-		new_slice.rotation_degrees = Vector3(0,0,90)
-		new_slice.set_surface_material(0, SpatialMaterial.new())
-		new_slice.get_surface_material(0).params_cull_mode  = SpatialMaterial.CULL_BACK 
-		#new_slice.get_surface_material(0).resource_local_to_scene = true
-		_slices.push_back(new_slice)
-		sli.add_child(new_slice)
-		
-		
-	_parameters[\"tunnel_color_scale\"] = TunnelParam.new()
-	_activate_color(_color_act)
-	
-	_parameters[\"tunnel_height\"] = TunnelParam.new()
-	_activate_height(_height_act)
-	
-	_parameters[\"tunnel_rotation\"] = TunnelParam.new()
-	_activate_rotation(_rot_act)
-
-func get_extent() :
-	return _extent
-
-func _activate_color(c) :
-	_color_act=c
-	if is_inside_tree() :
-		_parameters[\"tunnel_color_scale\"]._active = c
-		_update_slices()
-
-func _activate_height(h) :
-	_height_act=h
-	if is_inside_tree() :
-		_parameters[\"tunnel_height\"]._active = h
-		_update_slices()
-
-func _activate_rotation(r) :
-	_rot_act=r
-	if is_inside_tree() :
-		_parameters[\"tunnel_rotation\"]._active = r
-		_update_slices()
-		
-
-func _update_slices() :
-	if is_inside_tree() :
-		var i=0.0
-		for s in _slices :
-			var ratio = i / _slices.size()
-			s.get_surface_material(0).albedo_color.s=0.1
-			s.get_surface_material(0).albedo_color.h=0.5
-			s.get_surface_material(0).albedo_color.v=0.5
-			s.scale.x = 0.5
-			s.scale.z = 0.5
-			s.rotation_degrees.x = 0
-			for p in _parameters.keys() :
-				if _parameters[p]._active :
-					match p:
-						\"tunnel_color_scale\" :
-							s.get_surface_material(0).albedo_color.h = fmod(ratio*5.0,1.0)
-							s.get_surface_material(0).albedo_color.s = 1.0 - abs(ratio*2.0-1.0)
-							
-							s.get_surface_material(0).albedo_color.v = ratio
-						\"tunnel_height\" :
-							s.scale.x = ratio*0.9+0.1
-							s.scale.z = ratio*0.9+0.1
-						\"tunnel_rotation\" :
-							s.rotation_degrees.x = ratio*180
-			i+=1.0
-	
-
-func _process(delta): 
-	if !Engine.editor_hint: 
-		#play loop
-		match _loop_state:
-			State.RECORDING :
-				_loop_time+=delta
-			State.PLAYING :
-				_loop_time+=delta
-				if _positions.size()>0 :
-					while _positions[_cur_pos][0] < _loop_time :
-						self.translation = _positions[_cur_pos][1]
-						_cur_pos= _cur_pos + 1
-						if _cur_pos >= _positions.size() :
-							_cur_pos=0
-							_loop_time = _loop_time - _positions.back()[0]
-		
-		
-
-func _physics_process(delta):
-	if !Engine.editor_hint : 
-		var space_state = get_world().direct_space_state
-		_query.set_transform(self.global_transform)
-		var results = space_state.intersect_shape(_query)
-		if results.size() > 0 :
-			for r in results :
-				var col = r[\"collider\"].get_parent()
-				if !col.has_meta(\"Tunnel\"):
-					#if collision, compute position ratio
-					var col_pos = to_local(col.global_transform.origin)
-					var ratio =  (col_pos.x+1.0)/2.0
-					#set all active parameters
-					for p in _parameters.keys():
-						if _parameters[p]._active:
-							col.set_property(p, [ratio])
-		
-func _set_property(prop, vals) :
-	._set_property(prop, vals)
-	match prop:
-		\"position\":
-			if _loop_state == State.RECORDING :
-				_positions.push_back([_loop_time, Vector3(vals[0],vals[1],vals[2])])
-		\"selected\":
-			set_selected(vals[0])
-		\"looped\":
-			set_looped(vals[0])
-
-func set_selected(sel) :
-	pass
-
-func set_looped(lo) :
-	print(lo)
-	if lo :
-		_loop_state = State.RECORDING
-		_loop_time = 0
-		_positions.clear()
-		_cur_pos=0
-	else :
-		_loop_state = State.PLAYING
-		_loop_time = 0
-		_cur_pos=0
-"
-
-[sub_resource type="BoxShape" id=2]
+[sub_resource type="BoxShape3D" id="1"]
 resource_local_to_scene = true
-extents = Vector3( 0.5, 0.1, 0.1 )
+margin = 0.0
+size = Vector3(1, 0.1, 0.1)
+
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_mccv5"]
+render_priority = 0
+shader = ExtResource("2_kaxyo")
+
+[sub_resource type="CylinderMesh" id="CylinderMesh_3cymo"]
+material = SubResource("ShaderMaterial_mccv5")
+top_radius = 0.05
+bottom_radius = 0.05
+height = 0.01
+radial_segments = 5
+rings = 1
+
+[sub_resource type="MultiMesh" id="MultiMesh_5i54s"]
+resource_local_to_scene = true
+transform_format = 1
+use_custom_data = true
+instance_count = 100
+mesh = SubResource("CylinderMesh_3cymo")
+buffer = PackedFloat32Array(-3.93403e-08, -0.9, 0, -0.5, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.49, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.48, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.47, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.46, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.45, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.44, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.43, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.42, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.41, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.4, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.39, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.38, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.37, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.36, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.35, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.34, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.33, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.32, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.31, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.3, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.29, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.28, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.27, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.26, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.25, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.24, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.23, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.22, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.21, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.2, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.19, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.18, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.17, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.16, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.15, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.14, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.13, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.12, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.11, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.1, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.09, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.08, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.07, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.06, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.05, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.04, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.03, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.02, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, -0.01, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.01, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.02, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.03, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.04, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.05, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.06, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.07, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.08, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.09, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.1, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.11, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.12, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.13, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.14, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.15, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.16, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.17, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.18, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.19, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.2, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.21, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.22, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.23, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.24, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.25, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.26, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.27, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.28, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.29, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.3, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.31, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.32, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.33, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.34, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.35, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.36, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.37, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.38, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.39, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.4, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.41, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.42, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.43, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.44, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.45, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.46, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.47, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.48, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1, -3.93403e-08, -0.9, 0, 0.49, 1, -4.37114e-08, 0, 0, 0, 0, 1, 0, 0.5, 0.5, 0.5, 1)
+
+[node name="Tunnel" type="Node3D"]
+transform = Transform3D(0.5, 0, 0, 0, 0.5, 0, 0, 0, 0.5, 0, 0, 0)
+script = ExtResource("1")
 
-[node name="Tunnel" type="Spatial"]
-script = SubResource( 1 )
-__meta__ = {
-"Tunnel": true
-}
+[node name="Slices" type="Node3D" parent="."]
+visible = false
 
-[node name="Slices" type="Spatial" parent="."]
+[node name="Area3D" type="Area3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -0.01, 0, 0)
 
-[node name="StaticBody" type="StaticBody" parent="."]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D"]
+shape = SubResource("1")
 
-[node name="CollisionShape" type="CollisionShape" parent="StaticBody"]
-shape = SubResource( 2 )
+[node name="MultiSlice" type="MultiMeshInstance3D" parent="."]
+multimesh = SubResource("MultiMesh_5i54s")
diff --git a/techniques/control/Tunnel/TunnelParamData.gd b/techniques/control/Tunnel/TunnelParamData.gd
index 1838f0ff825e17225807d3c62b0ba6747bc8cf34..9b3322dfffc223d02a639c136c785c3a749cd29a 100644
--- a/techniques/control/Tunnel/TunnelParamData.gd
+++ b/techniques/control/Tunnel/TunnelParamData.gd
@@ -4,3 +4,4 @@ var name = "undefined"
 var data_type
 var array = []
 var curve
+var string : String
diff --git a/techniques/control/Tunnel/TunnelPreset.gd b/techniques/control/Tunnel/TunnelPreset.gd
index a36ced574178092008ad013655ed012bc8256160..76ca619f8f63dd1782e8a1ad8899a5e0e58ab49f 100644
--- a/techniques/control/Tunnel/TunnelPreset.gd
+++ b/techniques/control/Tunnel/TunnelPreset.gd
@@ -1,87 +1,87 @@
-tool
+@tool
 extends "res://addons/ivmi-builder/core/IvmiNode.gd"
 
-enum DATA_TYPE {curve,array}
+enum DATA_TYPE {curve,array,string}
 
 
 
-export var active = true 
+@export var active = true 
 
-export(bool) var _height_active = false setget _set_height_active
-export(DATA_TYPE) var _height_data_type = DATA_TYPE.array setget _set_height_data_type
-export(Curve) var _height_curve setget _set_height_curve
-export(Array,Vector2) var _height_array = [] setget _set_height_array
-
-export(bool) var _color_active = false setget _set_color_active
-export(DATA_TYPE) var _color_data_type = DATA_TYPE.array setget _set_color_data_type
-export(Curve) var _color_curve setget _set_color_curve
-export(Array,Vector2) var _color_array = [] setget _set_color_array
-
-export(bool) var _rotation_active = false setget _set_rotation_active
-export(DATA_TYPE) var _rotation_data_type = DATA_TYPE.array setget _set_rotation_data_type
-export(Curve) var _rotation_curve setget _set_rotation_curve
-export(Array,Vector2) var _rotation_array = [] setget _set_rotation_array
-
-export(bool) var _density_active = false setget _set_density_active
-export(DATA_TYPE) var _density_data_type = DATA_TYPE.array setget _set_density_data_type
-export(Curve) var _density_curve setget _set_density_curve
-export(Array,Vector2) var _density_array = [] setget _set_density_array
+@export var _height_curve: Curve : set = _set_height_curve
+@export var _color_curve: Curve : set = _set_color_curve
+@export var _rotation_curve: Curve : set = _set_rotation_curve
+@export var _speed_curve: Curve : set = _set_speed_curve
+@export var _density_curve: Curve : set = _set_density_curve
+@export var _brightness_curve: Curve : set = _set_brightness_curve
+@export var _noisiness_curve: Curve : set = _set_noisiness_curve
 
 var tunnel_param_data_script = preload("res://addons/ivmi-builder/techniques/control/Tunnel/TunnelParamData.gd")
 
 func _ready() :
+	super._ready()
 	if _height_curve:
-		_height_curve.connect("changed", self, "_on_height_curve_changed")
+		_height_curve.connect("changed",Callable(self,"_on_height_curve_changed"))
 	if _color_curve:
-		_color_curve.connect("changed", self, "_on_color_curve_changed")
+		_color_curve.connect("changed",Callable(self,"_on_color_curve_changed"))
 	if _rotation_curve:
-		_rotation_curve.connect("changed", self, "_on_rotation_curve_changed")
+		_rotation_curve.connect("changed",Callable(self,"_on_rotation_curve_changed"))
+	if _speed_curve:
+		_speed_curve.connect("changed",Callable(self,"_on_speed_curve_changed"))
 	if _density_curve:
-		_density_curve.connect("changed", self, "_on_density_curve_changed")
+		_density_curve.connect("changed",Callable(self,"_on_density_curve_changed"))
+	if _brightness_curve:
+		_brightness_curve.connect("changed",Callable(self,"_on_brightness_curve_changed"))
+	if _noisiness_curve:
+		_noisiness_curve.connect("changed",Callable(self,"_on_noisiness_curve_changed"))
+
+func _process(delta):
+	super._process(delta)
+
+func _set_property(prop, vals) :
+	super._set_property(prop, vals)
 
 func get_tunnel_preset_data():
 	var tunnel_param_data_array = []
-	if _height_active:
+	if _height_curve:
 		var tunnel_param_data = tunnel_param_data_script.new()
 		tunnel_param_data.name = "tunnel_height"
-		tunnel_param_data.data_type = _height_data_type
-		if _height_data_type == DATA_TYPE.array:
-			tunnel_param_data.array = _height_array
-		else:
-			tunnel_param_data.curve = _height_curve
-			#print(name)
-			#print(tunnel_param_data.curve)
-			#print(tunnel_param_data.curve.get_point_count())
+		tunnel_param_data.curve = _height_curve
 		tunnel_param_data_array.append(tunnel_param_data)
 		
-	if _rotation_active:
+	if _rotation_curve:
 		var tunnel_param_data = tunnel_param_data_script.new()
 		tunnel_param_data.name = "tunnel_rotation"
-		tunnel_param_data.data_type = _rotation_data_type
-		if _rotation_data_type == DATA_TYPE.array:
-			tunnel_param_data.array = _rotation_array
-		else:
-			tunnel_param_data.curve = _rotation_curve
+		tunnel_param_data.curve = _rotation_curve
 		tunnel_param_data_array.append(tunnel_param_data)
 		
-	if _color_active:
+	if _speed_curve:
+		var tunnel_param_data = tunnel_param_data_script.new()
+		tunnel_param_data.name = "tunnel_speed"
+		tunnel_param_data.curve = _speed_curve
+		tunnel_param_data_array.append(tunnel_param_data)
+		
+	if _color_curve:
 		var tunnel_param_data = tunnel_param_data_script.new()
 		tunnel_param_data.name = "tunnel_color_scale"
-		tunnel_param_data.data_type = _color_data_type
-		if _color_data_type == DATA_TYPE.array:
-			tunnel_param_data.array = _color_array
-		else:
-			tunnel_param_data.curve = _color_curve
+		tunnel_param_data.curve = _color_curve
 		tunnel_param_data_array.append(tunnel_param_data)
 		
-	if _density_active:
+	if _density_curve:
 		var tunnel_param_data = tunnel_param_data_script.new()
 		tunnel_param_data.name = "tunnel_density"
-		tunnel_param_data.data_type = _density_data_type
-		if _density_data_type == DATA_TYPE.array:
-			tunnel_param_data.array = _density_array
-		else:
-			tunnel_param_data.curve = _density_curve
+		tunnel_param_data.curve = _density_curve
+		tunnel_param_data_array.append(tunnel_param_data)
+		
+	if _brightness_curve:
+		var tunnel_param_data = tunnel_param_data_script.new()
+		tunnel_param_data.name = "tunnel_brightness"
+		tunnel_param_data.curve = _brightness_curve
+		tunnel_param_data_array.append(tunnel_param_data)
+		
+	if _noisiness_curve:
+		var tunnel_param_data = tunnel_param_data_script.new()
+		tunnel_param_data.name = "tunnel_noisiness"
+		tunnel_param_data.curve = _noisiness_curve
 		tunnel_param_data_array.append(tunnel_param_data)
 		
 	return tunnel_param_data_array
@@ -93,66 +93,44 @@ func _update_tunnel():
 			parent._update_tunnel()
 
 
-func _set_height_active(val):
-	_height_active = val
-	_update_tunnel()
-func _set_height_data_type(val):
-	_height_data_type = val
-	_update_tunnel()
 func _set_height_curve(val):
 	_height_curve = val
 	_update_tunnel()
 func _on_height_curve_changed() :
 	_update_tunnel()
-func _set_height_array(val):
-	_height_array = val
-	_update_tunnel()
 
-func _set_color_active(val):
-	_color_active = val
-	_update_tunnel()
-func _set_color_data_type(val):
-	_color_data_type = val
-	_update_tunnel()
 func _set_color_curve(val):
 	_color_curve = val
 	_update_tunnel()
 func _on_color_curve_changed() :
 	_update_tunnel()
-func _set_color_array(val):
-	_color_array = val
-	_update_tunnel()
 
-func _set_rotation_active(val):
-	_rotation_active = val
-	_update_tunnel()
-func _set_rotation_data_type(val):
-	_rotation_data_type = val
-	_update_tunnel()
 func _set_rotation_curve(val):
 	_rotation_curve = val
 	_update_tunnel()
 func _on_rotation_curve_changed() :
 	_update_tunnel()
-func _set_rotation_array(val):
-	_rotation_array = val
-	_update_tunnel()
-	
 
-func _set_density_active(val):
-	_density_active = val
+func _set_speed_curve(val):
+	_speed_curve = val
 	_update_tunnel()
-func _set_density_data_type(val):
-	_density_data_type = val
+func _on_speed_curve_changed() :
 	_update_tunnel()
+
 func _set_density_curve(val):
 	_density_curve = val
 	_update_tunnel()
 func _on_density_curve_changed() :
 	_update_tunnel()
-func _set_density_array(val):
-	_density_array = val
+
+func _set_brightness_curve(val):
+	_brightness_curve = val
 	_update_tunnel()
+func _on_brightness_curve_changed() :
+	_update_tunnel()	
 	
-	
-
+func _set_noisiness_curve(val):
+	_noisiness_curve = val
+	_update_tunnel()
+func _on_noisiness_curve_changed() :
+	_update_tunnel()
diff --git a/techniques/control/Tunnel/TunnelPreset.tscn b/techniques/control/Tunnel/TunnelPreset.tscn
index 106d55f631350c86047f18c218450deab33f49aa..89a083a4237a7d6c013c4256fd92e52784bfc2f5 100644
--- a/techniques/control/Tunnel/TunnelPreset.tscn
+++ b/techniques/control/Tunnel/TunnelPreset.tscn
@@ -1,6 +1,6 @@
-[gd_scene load_steps=2 format=2]
+[gd_scene load_steps=2 format=3 uid="uid://dnssxrdl7c38r"]
 
-[ext_resource path="res://addons/ivmi-builder/techniques/control/Tunnel/TunnelPreset.gd" type="Script" id=1]
+[ext_resource type="Script" path="res://addons/ivmi-builder/techniques/control/Tunnel/TunnelPreset.gd" id="1"]
 
-[node name="TunnelPreset" type="Spatial"]
-script = ExtResource( 1 )
+[node name="TunnelPreset" type="Node3D"]
+script = ExtResource("1")
diff --git a/techniques/control/Tunnel/Tunnel_v2.tscn b/techniques/control/Tunnel/Tunnel_v2.tscn
deleted file mode 100644
index b70085b3c35e1d07ec3c5cdd37fd58113fd2b2bb..0000000000000000000000000000000000000000
--- a/techniques/control/Tunnel/Tunnel_v2.tscn
+++ /dev/null
@@ -1,21 +0,0 @@
-[gd_scene load_steps=3 format=2]
-
-[ext_resource path="res://addons/ivmi-builder/techniques/control/Tunnel/Tunnel_v2.gd" type="Script" id=1]
-
-[sub_resource type="BoxShape" id=1]
-resource_local_to_scene = true
-margin = 0.001
-extents = Vector3( 0.5, 0.02, 0.02 )
-
-[node name="Tunnel" type="Spatial"]
-script = ExtResource( 1 )
-__meta__ = {
-"Tunnel": true
-}
-
-[node name="Slices" type="Spatial" parent="."]
-
-[node name="Area" type="Area" parent="."]
-
-[node name="CollisionShape" type="CollisionShape" parent="Area"]
-shape = SubResource( 1 )
diff --git a/techniques/manipulation/Cursor.gd b/techniques/manipulation/Cursor.gd
index 6ba07d2f8951072c1113ee6f450868a1d80acf67..64290013745ce59a957ee76e62d8bff48ed1b4ad 100644
--- a/techniques/manipulation/Cursor.gd
+++ b/techniques/manipulation/Cursor.gd
@@ -1,14 +1,14 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-export(NodePath) var _controller_node_path
-export(NodePath) var _camera_node_path
-export var _mouse_sensitivity = 1
-export var _scroll_sensitivity = 0.04
-export var _max_mouse_speed = 0.5
-
-onready var _controller = get_node(_controller_node_path)
-onready var _camera = get_node(_camera_node_path)
-onready var _last_pos = translation
+@export var _controller_node_path: NodePath
+@export var _camera_node_path: NodePath
+@export var _mouse_sensitivity = 1
+@export var _scroll_sensitivity = 0.04
+@export var _max_mouse_speed = 0.5
+
+@onready var _controller = get_node(_controller_node_path)
+@onready var _camera = get_node(_camera_node_path)
+@onready var _last_pos = position
 #onready var _last_rotation = rotation_degrees
 
 var _squared_max_mouse_speed = pow(_max_mouse_speed,2)
@@ -21,8 +21,8 @@ var _mouse_delta = Vector2(0,0)
 var _cursor_can_be_moved = true
 
 func _ready():
-	_controller.connect("button_pressed", self, "_on_Controller_button_pressed")
-	_controller.connect("button_release", self, "_on_Controller_button_release")
+	_controller.connect("button_pressed",Callable(self,"_on_Controller_button_pressed"))
+	_controller.connect("button_released",Callable(self,"_on_Controller_button_release"))
 
 func _input(event):
 	if event is InputEventMouseMotion :
@@ -30,28 +30,23 @@ func _input(event):
 	if event is InputEventMouseButton:
 		if event.is_pressed():
 			var _z_movement = _scroll_sensitivity * _camera.transform.basis.z.normalized()
-			if event.button_index == BUTTON_WHEEL_DOWN :
-				_controller.translation -= _z_movement
-			if event.button_index == BUTTON_WHEEL_UP :
-				_controller.translation += _z_movement
-			
-			#if  event.is_action("grab"):
-			if event.button_index == JOY_VR_GRIP :
+			if event.button_index == MOUSE_BUTTON_WHEEL_DOWN :
+				_controller.position -= _z_movement
+			if event.button_index == MOUSE_BUTTON_WHEEL_UP :
+				_controller.position += _z_movement
+			if  event.is_action("grab"):
 				_grabbing = true
 				for k in _selected.keys():
 					_grabbed[k] = true
-			#if event.is_action("trigger"):
-			if event.button_index == JOY_VR_TRIGGER :	
+			if event.is_action("trigger"):
 				for k in _selected.keys():
 					_selected[k].set_property("triggered", [1])
 		else:
-			#if  event.is_action("grab"):
-			if event.button_index == JOY_VR_GRIP :
+			if  event.is_action("grab"):
 				_grabbing = false
 				for k in _selected.keys():
 					_grabbed[k] = false
-			#if event.is_action("trigger"):
-			if event.button_index == JOY_VR_TRIGGER :
+			if event.is_action("trigger"):
 				for k in _selected.keys():
 					_selected[k].set_property("triggered", [0])
 #	if event is InputEventKey:
@@ -72,25 +67,25 @@ func _move_controller(delta):
 	var _mouse_speed = delta * _mouse_delta
 	if _mouse_speed.length_squared() <= _squared_max_mouse_speed:
 		var _coef = delta*_mouse_sensitivity
-		_controller.translation += _coef*_mouse_delta.x*_camera.transform.basis.x.normalized()
-		_controller.translation -= _coef*_mouse_delta.y*_camera.transform.basis.y.normalized()
+		_controller.position += _coef*_mouse_delta.x*_camera.transform.basis.x.normalized()
+		_controller.position -= _coef*_mouse_delta.y*_camera.transform.basis.y.normalized()
 	_mouse_delta = Vector2.ZERO
 
 func _move_cursor():
-	translation = _controller.translation	
+	position = _controller.position	
 
 func _move_grabbed_object():
 	_move_diff = global_transform.origin - _last_pos
 	for k in _selected.keys():
 		if _grabbed[k]:
-			_selected[k].set_property("position",_ivmi.vector3_to_array(_selected[k].translation+_move_diff))
+			_selected[k].set_property("position",_ivmi.vector3_to_array(_selected[k].position+_move_diff))
 
 func _rotate_grabbed_object():
 	pass
 	#_move_diff = global_transform.origin - _last_pos
 	#for k in _selected.keys():
 	#	if _grabbed[k]:
-	#		_selected[k].set_property("position",(_selected[k].translation+_move_diff))
+	#		_selected[k].set_property("position",(_selected[k].position+_move_diff))
 
 func _on_Area_body_entered(body):
 	_on_node_entered(body)
@@ -117,7 +112,7 @@ func _on_node_entered(node):
 		_grabbed[_parent.name] = false
 
 func _on_Controller_button_pressed(button):
-	if button == JOY_VR_GRIP :
+	if button == JOY_GR
 		_grabbing = true
 		for k in _selected.keys():
 			_grabbed[k] = true
diff --git a/techniques/manipulation/Cursor.tscn b/techniques/manipulation/Cursor.tscn
index be04c5543dbc3a01354d62d8de629150644e9ec6..619f08296e652ed3f2023c2504818df94f85bb50 100644
--- a/techniques/manipulation/Cursor.tscn
+++ b/techniques/manipulation/Cursor.tscn
@@ -6,26 +6,26 @@
 radius = 0.25
 height = 0.5
 
-[sub_resource type="SpatialMaterial" id=2]
+[sub_resource type="StandardMaterial3D" id=2]
 flags_transparent = true
 albedo_color = Color( 1, 1, 1, 0.6 )
 
-[sub_resource type="SphereShape" id=3]
+[sub_resource type="SphereShape3D" id=3]
 radius = 0.25
 
-[node name="Cursor" type="Spatial"]
+[node name="Cursor" type="Node3D"]
 script = ExtResource( 1 )
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
 mesh = SubResource( 1 )
 material/0 = SubResource( 2 )
 
-[node name="Area" type="Area" parent="."]
+[node name="Area3D" type="Area3D" parent="."]
 
-[node name="CollisionShape" type="CollisionShape" parent="Area"]
+[node name="CollisionShape3D" type="CollisionShape3D" parent="Area3D"]
 shape = SubResource( 3 )
 
-[connection signal="area_entered" from="Area" to="." method="_on_Area_area_entered"]
-[connection signal="area_exited" from="Area" to="." method="_on_Area_area_exited"]
-[connection signal="body_entered" from="Area" to="." method="_on_Area_body_entered"]
-[connection signal="body_exited" from="Area" to="." method="_on_Area_body_exited"]
+[connection signal="area_entered" from="Area3D" to="." method="_on_Area_area_entered"]
+[connection signal="area_exited" from="Area3D" to="." method="_on_Area_area_exited"]
+[connection signal="body_entered" from="Area3D" to="." method="_on_Area_body_entered"]
+[connection signal="body_exited" from="Area3D" to="." method="_on_Area_body_exited"]
diff --git a/techniques/manipulation/GO-GO.gd b/techniques/manipulation/GO-GO.gd
index 8358caec3fff7bdbb6567957b7e77b9940b089db..946926e28cbcbb87cadfb14f8db452dcb5e3c14a 100644
--- a/techniques/manipulation/GO-GO.gd
+++ b/techniques/manipulation/GO-GO.gd
@@ -1,15 +1,15 @@
 extends "res://addons/ivmi-builder/techniques/manipulation/Cursor.gd"
 
 var _body_offset = Vector3(0,-0.20,0)
-export var gogo_distance = 0.450
-export var gogo_multiplier = 100
+@export var gogo_distance = 0.450
+@export var gogo_multiplier = 100
 
 func _move_cursor():
 	if _controller:
-		if !_controller.translation.is_equal_approx (Vector3.ZERO):
-			var _body_controller_vec = _controller.translation - (_camera.translation + _body_offset)
+		if !_controller.position.is_equal_approx (Vector3.ZERO):
+			var _body_controller_vec = _controller.position - (_camera.position + _body_offset)
 			var _slen = _body_controller_vec.length()
 			if _slen > gogo_distance:
-				translation = _controller.translation + _body_controller_vec*gogo_multiplier*pow(_slen - gogo_distance,2)
+				position = _controller.position + _body_controller_vec*gogo_multiplier*pow(_slen - gogo_distance,2)
 			else:
-				translation = _controller.translation
+				position = _controller.position
diff --git a/techniques/manipulation/HOMER.gd b/techniques/manipulation/HOMER.gd
index 6d027935dd63579b7c47a3220b254222637a8a82..175dd4b784db25e98b8e3af0558109cba2abd986 100644
--- a/techniques/manipulation/HOMER.gd
+++ b/techniques/manipulation/HOMER.gd
@@ -1,18 +1,18 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-export(NodePath) var _controller_node_path
-export(NodePath) var _camera_node_path
-export(NodePath) var _arvr_origin_node_path
+@export var _controller_node_path: NodePath
+@export var _camera_node_path: NodePath
+@export var _arvr_origin_node_path: NodePath
 
-onready var _controller = get_node(_controller_node_path)
-onready var _camera = get_node(_camera_node_path)
-onready var _arvr_origin = get_node(_arvr_origin_node_path)
-onready var _raycast = get_node("ray/RayCast")
-onready var _ray = get_node("ray")
+@onready var _controller = get_node(_controller_node_path)
+@onready var _camera = get_node(_camera_node_path)
+@onready var _arvr_origin = get_node(_arvr_origin_node_path)
+@onready var _raycast = get_node("ray/RayCast3D")
+@onready var _ray = get_node("ray")
 
-export var _grab_sensibility = 5.0
-export var _mouse_sensitivity = 10.0
-export var _scroll_sensitivity = 0.04
+@export var _grab_sensibility = 5.0
+@export var _mouse_sensitivity = 1.0
+@export var _scroll_sensitivity = 0.04
 
 var _selected = null
 var _grabbed = null
@@ -39,16 +39,17 @@ var _rotating_clockwise = false
 var _rotating_counter_clockwise = false
 
 func _ready():
-	_controller.connect("button_pressed", self, "_on_HOMER_button_pressed")
-	_controller.connect("button_release", self, "_on_HOMER_button_release")
+	super._ready()
+	_controller.connect("button_pressed",Callable(self,"_on_HOMER_button_pressed"))
+	_controller.connect("button_released",Callable(self,"_on_HOMER_button_release"))
 
 	_highlight = get_node("highlight")
-	_highlight.set_as_toplevel(true)
+	_highlight.set_as_top_level(true)
 
 func _physics_process(delta):
 	# Rotate and move homer to match the position and
 	# rotation of the controller
-	translation = _controller.translation
+	position = _controller.position
 	rotation = _controller.rotation
 
 	if _grabbed:
@@ -68,10 +69,10 @@ func _grab_update(delta):
 		var new_grabbed_position = _start_grabbed_local_translation - _mouse_move_diff + _grabbed_depth_translation + _diff_arvr_global_origin
 		_grabbed.set_property("position",_ivmi.vector3_to_array(new_grabbed_position))
 		if _rotating_clockwise:
-			var new_rot = _grabbed.transform.basis.rotated(_camera.global_transform.basis.z.normalized(), PI*delta).get_rotation_quat()
+			var new_rot = _grabbed.transform.basis.rotated(_camera.global_transform.basis.z.normalized(), PI*delta).get_rotation_quaternion()
 			_grabbed.set_property("quaternion",[new_rot.x,new_rot.y,new_rot.z,new_rot.w])
 		if _rotating_counter_clockwise:
-			var new_rot = _grabbed.transform.basis.rotated(_camera.global_transform.basis.z.normalized(), -PI*delta).get_rotation_quat()
+			var new_rot = _grabbed.transform.basis.rotated(_camera.global_transform.basis.z.normalized(), -PI*delta).get_rotation_quaternion()
 			_grabbed.set_property("quaternion",[new_rot.x,new_rot.y,new_rot.z,new_rot.w])
 	else:
 		## MOVEMENT
@@ -85,8 +86,8 @@ func _grab_update(delta):
 		_grabbed.set_property("position",_ivmi.vector3_to_array(new_grabbed_position))
 		
 		##ROTATION
-		var _diff_arvr_global_quaternion = _start_arvr_global_quaternion * _arvr_origin.global_transform.basis.get_rotation_quat().inverse()
-		var _diff_controller_global_quaternion = _start_arvr_global_quaternion * _controller.global_transform.basis.get_rotation_quat().inverse()
+		var _diff_arvr_global_quaternion = _start_arvr_global_quaternion * _arvr_origin.global_transform.basis.get_rotation_quaternion().inverse()
+		var _diff_controller_global_quaternion = _start_arvr_global_quaternion * _controller.global_transform.basis.get_rotation_quaternion().inverse()
 		
 		var new_grabbed_quat = _start_grabbed_local_quaternion * _diff_arvr_global_quaternion * _diff_controller_global_quaternion
 		new_grabbed_quat = new_grabbed_quat.inverse()
@@ -97,13 +98,19 @@ func _grab_update(delta):
 func _select_update(delta):
 	var result = _raycast.get_collider()
 	if result and result.get_parent().is_in_group("ivmi_nodes") \
-			  and result.get_parent()._can_be_selected:
-			
-		#print(result.get_parent().name)
-		
+		and result.get_parent()._can_be_selected:
+				
 		var obj = result.get_parent()
 		var _selection_changed = false
 		
+		# place selection sphere and change ray size
+		var pnt = _raycast.get_collision_point()
+		$SelectionSphere.global_position = pnt
+		$SelectionSphere.visible = true
+		var dist = (_raycast.global_position).distance_to(pnt)
+		$ray.scale.z = dist
+		
+		
 		#update selected if needed
 		if _selected and _selected!=obj:
 			_selected.set_property("selected", [0])
@@ -114,11 +121,11 @@ func _select_update(delta):
 		_selected = obj
 		_target = obj
 
-		#Update highlight
-		if _selection_changed:
-			_highlight.global_transform.basis = _selected.global_transform.basis
-			_highlight.set_scale(_selected.get_extent())
-			_highlight.visible=true
+#		#Update highlight
+#		if _selection_changed:
+#			_highlight.global_transform.basis = _selected.global_transform.basis
+#			_highlight.set_scale(_selected.get_extent())
+#			_highlight.visible=true
 
 		# Started grabbing
 		if _grabbing :
@@ -129,14 +136,14 @@ func _select_update(delta):
 			#Starting pos of the selected object
 			_start_controller_global_origin = _controller.global_transform.origin
 			_start_arvr_global_origin  = _arvr_origin.global_transform.origin
-			_start_grabbed_local_translation  = _grabbed.translation
+			_start_grabbed_local_translation  = _grabbed.position
 			#Startiong rotation of the selected object
-			_start_controller_global_quaternion = _controller.global_transform.basis.get_rotation_quat()
-			_start_arvr_global_quaternion = _arvr_origin.global_transform.basis.get_rotation_quat()
-			_start_grabbed_local_quaternion = _grabbed.transform.basis.get_rotation_quat().inverse()
+			_start_controller_global_quaternion = _controller.global_transform.basis.get_rotation_quaternion()
+			_start_arvr_global_quaternion = _arvr_origin.global_transform.basis.get_rotation_quaternion()
+			_start_grabbed_local_quaternion = _grabbed.transform.basis.get_rotation_quaternion().inverse()
 			if _ivmi.is_2D():
 				#Starting pos of the mouse
-				_mouse_move_start = ((_controller.get_viewport().get_mouse_position()/_controller.get_viewport().size)-Vector2(0.5,0.5))/2.0
+				_mouse_move_start = ((_controller.get_viewport().get_mouse_position()/Vector2(_controller.get_viewport().size))-Vector2(0.5,0.5))/2.0
 				_mouse_move_diff = Vector3.ZERO
 				_grabbed_depth_translation = Vector3.ZERO
 	else :
@@ -145,31 +152,34 @@ func _select_update(delta):
 			_selected = null
 			_target = null
 			_highlight.visible=false
+		$SelectionSphere.visible = false
+		$ray.scale.z = 10.0
 
 func _unhandled_input(event):
 	if _ivmi.is_2D():
 		if event is InputEventMouseMotion :
+			
 			#move the ray
-			var rot = ((event.position/_controller.get_viewport().size)-Vector2(0.5,0.5))*2.0
+			var rot = ((event.position/Vector2(_controller.get_viewport().size))-Vector2(0.5,0.5))*2.0
 			_controller.rotation_degrees.y = -rot.x*90.0
 			_controller.rotation_degrees.x = -rot.y*90.0
 			
 			#move selected object according to new position
 			if _grabbed :
-				var pos = ((event.position/_controller.get_viewport().size)-Vector2(0.5,0.5))/2.0
+				var pos = ((event.position/Vector2(_controller.get_viewport().size))-Vector2(0.5,0.5))*2.0
 				_mouse_move_diff = Vector3.ZERO
 				_mouse_move_diff += -(pos.x-_mouse_move_start.x)*_camera.global_transform.basis.x.normalized()*_mouse_sensitivity
 				_mouse_move_diff += (pos.y- _mouse_move_start.y)*_camera.global_transform.basis.y.normalized()*_mouse_sensitivity
 
 		elif event is InputEventMouseButton :
-			if event.button_index == BUTTON_LEFT or event.button_index == BUTTON_RIGHT :
+			if event.button_index == MOUSE_BUTTON_LEFT or event.button_index == MOUSE_BUTTON_RIGHT :
 				_grabbing = event.pressed
 				if _grabbed:
 					_grabbed.set_property("grabbed", [0])
 					_grabbed=null
 					#back to select mode
 					_ray.visible=true
-			if event.button_index == BUTTON_RIGHT :
+			if event.button_index == MOUSE_BUTTON_RIGHT :
 				if _selected:
 					if event.is_pressed():
 						_selected.set_property("triggered", [1])
@@ -177,31 +187,31 @@ func _unhandled_input(event):
 						_selected.set_property("triggered", [0])
 			if event.is_pressed() and _grabbed:
 				var _z_movement = _scroll_sensitivity*(_camera.global_transform.origin-_grabbed.global_transform.origin).normalized()
-				if event.button_index == BUTTON_WHEEL_DOWN :
+				if event.button_index == MOUSE_BUTTON_WHEEL_DOWN :
 					_grabbed_depth_translation -= _z_movement
-				if event.button_index == BUTTON_WHEEL_UP :
+				if event.button_index == MOUSE_BUTTON_WHEEL_UP :
 					_grabbed_depth_translation += _z_movement
 		elif event is InputEventKey:
-			if event.scancode == KEY_LEFT :
+			if event.keycode == KEY_LEFT :
 				_rotating_clockwise = event.is_pressed()
-			if event.scancode == KEY_RIGHT :
+			if event.keycode == KEY_RIGHT :
 				_rotating_counter_clockwise = event.is_pressed()
 
 func _on_HOMER_button_pressed(button):
-	if button == JOY_VR_GRIP:
+	if button == "Grip":
 		_grabbing = true
-	if button == JOY_VR_TRIGGER:
+	if button == "Trigger":
 		if _selected:
 			_selected.set_property("triggered", [1])
 
 func _on_HOMER_button_release(button):
-	if button == JOY_VR_GRIP :
+	if button == "Grip" :
 		_grabbing = false
 		if _grabbed:
 			_grabbed.set_property("grabbed", [0])
 			_grabbed=null
 			#back to select mode
 			_ray.visible=true
-	if button == JOY_VR_TRIGGER :
+	if button == "Trigger" :
 		if _selected:
 			_selected.set_property("triggered", [0])
diff --git a/techniques/manipulation/HOMER.tscn b/techniques/manipulation/HOMER.tscn
index e53cdc43bf89d0586d281fd44237dcb1a1ba3b4d..b7648fbeb69b8cd7a07940bd00b8481e74de0eb0 100644
--- a/techniques/manipulation/HOMER.tscn
+++ b/techniques/manipulation/HOMER.tscn
@@ -1,36 +1,33 @@
-[gd_scene load_steps=7 format=2]
+[gd_scene load_steps=6 format=3 uid="uid://cp6bltsdhj3aw"]
 
-[ext_resource path="res://addons/ivmi-builder/techniques/manipulation/HOMER.gd" type="Script" id=1]
-[ext_resource path="res://addons/ivmi-builder/techniques/manipulation/box.shader" type="Shader" id=2]
+[ext_resource type="Script" path="res://addons/ivmi-builder/techniques/manipulation/HOMER.gd" id="1"]
+[ext_resource type="Shader" path="res://addons/ivmi-builder/visualization/box.gdshader" id="2_goum8"]
 
-[sub_resource type="CubeMesh" id=1]
-size = Vector3( 0.01, 0.01, 50 )
+[sub_resource type="BoxMesh" id="1"]
+size = Vector3(0.01, 0.01, 50)
 
-[sub_resource type="ShaderMaterial" id=2]
+[sub_resource type="ShaderMaterial" id="ShaderMaterial_mm0qr"]
+resource_local_to_scene = true
+render_priority = 0
+shader = ExtResource("2_goum8")
 
-[sub_resource type="CubeMesh" id=3]
-size = Vector3( 1, 1, 1 )
+[sub_resource type="BoxMesh" id="3"]
+material = SubResource("ShaderMaterial_mm0qr")
 subdivide_width = 10
 subdivide_height = 10
 subdivide_depth = 10
 
-[sub_resource type="ShaderMaterial" id=4]
-shader = ExtResource( 2 )
+[node name="HOMER" type="Node3D"]
+script = ExtResource("1")
 
-[node name="HOMER" type="Spatial"]
-script = ExtResource( 1 )
+[node name="ray" type="MeshInstance3D" parent="."]
+transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -25)
+mesh = SubResource("1")
 
-[node name="ray" type="MeshInstance" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -25 )
-mesh = SubResource( 1 )
-material/0 = SubResource( 2 )
-
-[node name="RayCast" type="RayCast" parent="ray"]
-transform = Transform( 1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 25 )
-enabled = true
-cast_to = Vector3( 0, -50, 0 )
+[node name="RayCast3D" type="RayCast3D" parent="ray"]
+transform = Transform3D(1, 0, 0, 0, -4.37114e-08, -1, 0, 1, -4.37114e-08, 0, 0, 25)
+target_position = Vector3(0, -50, 0)
 collide_with_areas = true
 
-[node name="highlight" type="MeshInstance" parent="."]
-mesh = SubResource( 3 )
-material/0 = SubResource( 4 )
+[node name="highlight" type="MeshInstance3D" parent="."]
+mesh = SubResource("3")
diff --git a/techniques/manipulation/box.shader b/techniques/manipulation/box.gdshader
similarity index 100%
rename from techniques/manipulation/box.shader
rename to techniques/manipulation/box.gdshader
diff --git a/techniques/navigation/Flying.gd b/techniques/navigation/Flying.gd
index 58e7f68da11c1d6c6a191e44c094af5906ebce3c..287b3df53264ddd538feb817063d20e4b92dc0b5 100644
--- a/techniques/navigation/Flying.gd
+++ b/techniques/navigation/Flying.gd
@@ -1,16 +1,16 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-export(NodePath) var _camera_node_path
-export(NodePath) var _controller_node_path
-export(NodePath) var _arvrorigin_node_path
+@export var _camera_node_path: NodePath
+@export var _controller_node_path: NodePath
+@export var _arvrorigin_node_path: NodePath
 
-export var _mouse_sensitivity = 50.0
-export var _minLookAngleX =  -80.0
-export var _maxLookAngleX =  80.0
+@export var _mouse_sensitivity = 50.0
+@export var _minLookAngleX =  -80.0
+@export var _maxLookAngleX =  80.0
 
-onready var _camera = get_node(_camera_node_path)
-onready var _controller = get_node(_controller_node_path)
-onready var _arvrorigin = get_node(_arvrorigin_node_path)
+@onready var _camera = get_node(_camera_node_path)
+@onready var _controller = get_node(_controller_node_path)
+@onready var _arvrorigin = get_node(_arvrorigin_node_path)
 
 var _mouseDelta = Vector3.ZERO
 var _direction = Vector3.ZERO
@@ -30,15 +30,15 @@ var _right = false
 var _joystick_axis_x = 0;
 var _joystick_axis_y = 0;
 
-export var _speed = 1
+@export var _speed = 1
 
 func _ready():
 	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
-	_controller.connect("button_pressed", self, "_on_Controller_button_pressed")
-	_controller.connect("button_release", self, "_on_Controller_button_release")
+	_controller.connect("button_pressed",Callable(self,"_on_Controller_button_pressed"))
+	_controller.connect("button_released",Callable(self,"_on_Controller_button_release"))
 
 func _physics_process(delta):
-	_arvrorigin.translation += _direction*_speed*delta
+	_arvrorigin.position += _direction*_speed*delta
 
 func _process(delta):
 	
@@ -71,25 +71,25 @@ func _move_using_joystick(dx,dy):
 func _input(event):
 	if event is InputEventKey:
 		if event.pressed:
-			if event.scancode==KEY_UP:
+			if event.keycode==KEY_UP:
 				_up = true
-			if event.scancode==KEY_DOWN:
+			if event.keycode==KEY_DOWN:
 				_down = true
-			if event.scancode==KEY_LEFT:
+			if event.keycode==KEY_LEFT:
 				_left = true
-			if event.scancode==KEY_RIGHT:
+			if event.keycode==KEY_RIGHT:
 				_right = true
 			#if event.is_action("toggle_manipulation_mode"):
 			#	_nagivation_enabled = false
 			#	Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
 		else:
-			if event.scancode==KEY_UP:
+			if event.keycode==KEY_UP:
 				_up = false
-			if event.scancode==KEY_DOWN:
+			if event.keycode==KEY_DOWN:
 				_down = false
-			if event.scancode==KEY_LEFT:
+			if event.keycode==KEY_LEFT:
 				_left = false
-			if event.scancode==KEY_RIGHT:
+			if event.keycode==KEY_RIGHT:
 				_right = false
 			#if event.is_action("toggle_manipulation_mode"):
 			#	_nagivation_enabled = true
diff --git a/techniques/navigation/FlyingController.tscn b/techniques/navigation/FlyingController.tscn
index e8d51798c903c569558cd82de75e8cd9c45e498c..f8086530f82e390c70cbea57fcbba32ad5582234 100644
--- a/techniques/navigation/FlyingController.tscn
+++ b/techniques/navigation/FlyingController.tscn
@@ -2,5 +2,5 @@
 
 [ext_resource path="res://addons/ivmi-builder/techniques/navigation/FlyingController.gd" type="Script" id=1]
 
-[node name="FlyingController" type="Spatial"]
+[node name="FlyingController" type="Node3D"]
 script = ExtResource( 1 )
diff --git a/techniques/navigation/FlyingGaze.tscn b/techniques/navigation/FlyingGaze.tscn
index 25d4baf7d6551bd2f06d0829b12086fded15fe25..f65250bfa96aa403dd7ecf4fb5e27c2d264cb727 100644
--- a/techniques/navigation/FlyingGaze.tscn
+++ b/techniques/navigation/FlyingGaze.tscn
@@ -2,5 +2,5 @@
 
 [ext_resource path="res://addons/ivmi-builder/techniques/navigation/FlyingGaze.gd" type="Script" id=1]
 
-[node name="FlyingGaze" type="Spatial"]
+[node name="FlyingGaze" type="Node3D"]
 script = ExtResource( 1 )
diff --git a/techniques/navigation/Teleport.gd b/techniques/navigation/Teleport.gd
index 3dc846cb27160a028371dc9dba30d69c523f57f0..148fb6f7961fb04d084ce8b32632cf3025f13443 100644
--- a/techniques/navigation/Teleport.gd
+++ b/techniques/navigation/Teleport.gd
@@ -1,20 +1,20 @@
 extends "res://addons/ivmi-builder/techniques/technique.gd"
 
-export(NodePath) var _controller_node_path
-export(NodePath) var _camera_node_path
-export(NodePath) var _arvr_origin_node_path
+@export var _controller_node_path: NodePath
+@export var _camera_node_path: NodePath
+@export var _arvr_origin_node_path: NodePath
 
-onready var _controller = get_node(_controller_node_path)
-onready var _camera = get_node(_camera_node_path)
-onready var _arvr_origin = get_node(_arvr_origin_node_path)
-onready var _raycast = get_node("MeshInstance/RayCast")
-onready var _target = get_node("Target")
+@onready var _controller = get_node(_controller_node_path)
+@onready var _camera = get_node(_camera_node_path)
+@onready var _arvr_origin = get_node(_arvr_origin_node_path)
+@onready var _raycast = get_node("MeshInstance3D/RayCast3D")
+@onready var _target = get_node("Target")
 
 
 
 func _ready():
-	_controller.connect("button_pressed", self, "_on_HOMER_button_pressed")
-	_controller.connect("button_release", self, "_on_HOMER_button_release")
+	_controller.connect("button_pressed",Callable(self,"_on_HOMER_button_pressed"))
+	_controller.connect("button_released",Callable(self,"_on_HOMER_button_release"))
 
 func _physics_process(delta):
 	
@@ -23,7 +23,7 @@ func _physics_process(delta):
 		_target.global_transform.origin = target_pos
 
 func _teleport():
-	_arvr_origin.translation = _target.translation
+	_arvr_origin.position = _target.position
 		
 
 func _on_Controller_button_pressed(button):
diff --git a/techniques/navigation/Teleport.tscn b/techniques/navigation/Teleport.tscn
index 2b67600353f55dc6401db412109f59406684b94f..ad35c1a249986bcd116b406cd3ee794d5eff998e 100644
--- a/techniques/navigation/Teleport.tscn
+++ b/techniques/navigation/Teleport.tscn
@@ -4,25 +4,25 @@
 
 [sub_resource type="SphereMesh" id=1]
 
-[sub_resource type="SpatialMaterial" id=2]
+[sub_resource type="StandardMaterial3D" id=2]
 albedo_color = Color( 0.054902, 1, 0, 1 )
 
 [sub_resource type="SphereMesh" id=3]
 
-[node name="Teleport" type="Spatial"]
+[node name="Teleport" type="Node3D"]
 script = ExtResource( 1 )
 
-[node name="Target" type="Spatial" parent="."]
+[node name="Target" type="Node3D" parent="."]
 
-[node name="MeshInstance" type="MeshInstance" parent="Target"]
-transform = Transform( 0.1, 0, 0, 0, 0.05, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="Target"]
+transform = Transform3D( 0.1, 0, 0, 0, 0.05, 0, 0, 0, 0.1, 0, 0, 0 )
 mesh = SubResource( 1 )
 material/0 = SubResource( 2 )
 
-[node name="MeshInstance" type="MeshInstance" parent="."]
-transform = Transform( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
+[node name="MeshInstance3D" type="MeshInstance3D" parent="."]
+transform = Transform3D( 0.1, 0, 0, 0, 0.1, 0, 0, 0, 0.1, 0, 0, 0 )
 mesh = SubResource( 3 )
 material/0 = null
 
-[node name="RayCast" type="RayCast" parent="MeshInstance"]
-transform = Transform( 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0 )
+[node name="RayCast3D" type="RayCast3D" parent="MeshInstance3D"]
+transform = Transform3D( 10, 0, 0, 0, 10, 0, 0, 0, 10, 0, 0, 0 )
diff --git a/techniques/packed_techniques/FlyingControllerGOGO.tscn b/techniques/packed_techniques/FlyingControllerGOGO.tscn
index 8532902a7817426c28626a5f186c62c4b303dd8e..24e3d405233869cf63eb3dec3066269fb94c8b53 100644
--- a/techniques/packed_techniques/FlyingControllerGOGO.tscn
+++ b/techniques/packed_techniques/FlyingControllerGOGO.tscn
@@ -3,23 +3,23 @@
 [ext_resource path="res://addons/ivmi-builder/techniques/navigation/FlyingController.tscn" type="PackedScene" id=1]
 [ext_resource path="res://addons/ivmi-builder/techniques/manipulation/GO-GO.tscn" type="PackedScene" id=2]
 
-[node name="FlyingControllerGOGO" type="ARVROrigin"]
+[node name="FlyingControllerGOGO" type="XROrigin3D"]
 
-[node name="LeftController" type="ARVRController" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5 )
+[node name="LeftController" type="XRController3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5 )
 
-[node name="RightController" type="ARVRController" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5 )
+[node name="RightController" type="XRController3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5 )
 controller_id = 2
 
-[node name="ARVRCamera" type="ARVRCamera" parent="."]
+[node name="XRCamera3D" type="XRCamera3D" parent="."]
 
 [node name="FlyingController" parent="." instance=ExtResource( 1 )]
-_camera_node_path = NodePath("../ARVRCamera")
+_camera_node_path = NodePath("../XRCamera3D")
 _controller_node_path = NodePath("../RightController")
 _arvrorigin_node_path = NodePath("..")
 
 [node name="GO-GO" parent="." instance=ExtResource( 2 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5 )
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -0.5 )
 _controller_node_path = NodePath("../LeftController")
-_camera_node_path = NodePath("../ARVRCamera")
+_camera_node_path = NodePath("../XRCamera3D")
diff --git a/techniques/packed_techniques/FlyingGazeCursor.tscn b/techniques/packed_techniques/FlyingGazeCursor.tscn
index fc32c0374e7e213942aa002c6bea3a847738bb3c..cfe948ede7ebaa42b95eb4e1089931bb0810f021 100644
--- a/techniques/packed_techniques/FlyingGazeCursor.tscn
+++ b/techniques/packed_techniques/FlyingGazeCursor.tscn
@@ -3,23 +3,23 @@
 [ext_resource path="res://addons/ivmi-builder/techniques/manipulation/Cursor.tscn" type="PackedScene" id=1]
 [ext_resource path="res://addons/ivmi-builder/techniques/navigation/FlyingGaze.tscn" type="PackedScene" id=2]
 
-[node name="FlyingGazeCursor" type="ARVROrigin"]
+[node name="FlyingGazeCursor" type="XROrigin3D"]
 
-[node name="LeftController" type="ARVRController" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
+[node name="LeftController" type="XRController3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
 
-[node name="RightController" type="ARVRController" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
+[node name="RightController" type="XRController3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
 controller_id = 2
 
 [node name="Cursor" parent="." instance=ExtResource( 1 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -1 )
 _controller_node_path = NodePath("../LeftController")
-_camera_node_path = NodePath("../ARVRCamera")
+_camera_node_path = NodePath("../XRCamera3D")
 
-[node name="ARVRCamera" type="ARVRCamera" parent="."]
+[node name="XRCamera3D" type="XRCamera3D" parent="."]
 
 [node name="FlyingGaze" parent="." instance=ExtResource( 2 )]
-_camera_node_path = NodePath("../ARVRCamera")
+_camera_node_path = NodePath("../XRCamera3D")
 _controller_node_path = NodePath("../RightController")
 _arvrorigin_node_path = NodePath("..")
diff --git a/techniques/packed_techniques/FlyingGazeHOMER.tscn b/techniques/packed_techniques/FlyingGazeHOMER.tscn
index f983ff28c0553ff43cae965d95edc485e660058c..7904616fe113a8b6c522c9f749e7a9662264bdad 100644
--- a/techniques/packed_techniques/FlyingGazeHOMER.tscn
+++ b/techniques/packed_techniques/FlyingGazeHOMER.tscn
@@ -3,24 +3,24 @@
 [ext_resource path="res://addons/ivmi-builder/techniques/manipulation/HOMER.tscn" type="PackedScene" id=1]
 [ext_resource path="res://addons/ivmi-builder/techniques/navigation/FlyingGaze.tscn" type="PackedScene" id=2]
 
-[node name="FlyingGazeHOMER" type="ARVROrigin"]
+[node name="FlyingGazeHOMER" type="XROrigin3D"]
 
-[node name="LeftController" type="ARVRController" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0 )
+[node name="LeftController" type="XRController3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0 )
 
-[node name="RightController" type="ARVRController" parent="."]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0 )
+[node name="RightController" type="XRController3D" parent="."]
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0 )
 controller_id = 2
 
-[node name="ARVRCamera" type="ARVRCamera" parent="."]
+[node name="XRCamera3D" type="XRCamera3D" parent="."]
 
 [node name="HOMER" parent="." instance=ExtResource( 1 )]
-transform = Transform( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0 )
+transform = Transform3D( 1, 0, 0, 0, 1, 0, 0, 0, 1, 0, -0.2, 0 )
 _controller_node_path = NodePath("../LeftController")
-_camera_node_path = NodePath("../ARVRCamera")
+_camera_node_path = NodePath("../XRCamera3D")
 _arvr_origin_node_path = NodePath("..")
 
 [node name="FlyingGaze" parent="." instance=ExtResource( 2 )]
-_camera_node_path = NodePath("../ARVRCamera")
+_camera_node_path = NodePath("../XRCamera3D")
 _controller_node_path = NodePath("../RightController")
 _arvrorigin_node_path = NodePath("..")
diff --git a/techniques/technique.gd b/techniques/technique.gd
index 48a9d4a9a76520ab4ddf509c5aacec3e182ef196..e14bb801ee4352956ee2327615b5e0a2251d5154 100644
--- a/techniques/technique.gd
+++ b/techniques/technique.gd
@@ -1,19 +1,21 @@
 extends IvmiNode
 
-export var _speed_evaluation_delay = 0.1
-onready var __last_pos = global_transform.origin
+@export var _speed_evaluation_delay = 0.1
+@onready var __last_pos = global_transform.origin
 
-var _speed_evalution_time = 0
+var _speed_evaluation_time = 0
 
 func _ready():
+	super._ready()
 	_set_ivmi_type("technique")
 	add_to_group("ivmi_techniques")
 	_add_property("speed", [0])
 
 func _process(delta):
+	super._process(delta)
 	if _properties["speed"]._listen:
-		_speed_evalution_time += delta
-		if _speed_evalution_time >= _speed_evaluation_delay:
+		_speed_evaluation_time += delta
+		if _speed_evaluation_time >= _speed_evaluation_delay:
 			var _speed = (global_transform.origin - __last_pos).length()
 			set_property("speed",[_speed])
-			_speed_evalution_time = 0
+			_speed_evaluation_time = 0
diff --git a/visualization/SimpleLine.tscn b/visualization/SimpleLine.tscn
index 7e88477a574bc4847d4a8c6e04f404062a635074..42be2ed0812078c2809812eb23f06dfa75ba26d2 100644
--- a/visualization/SimpleLine.tscn
+++ b/visualization/SimpleLine.tscn
@@ -1,31 +1,37 @@
-[gd_scene load_steps=2 format=2]
+[gd_scene load_steps=3 format=3 uid="uid://cbede1qesppcg"]
 
-[sub_resource type="GDScript" id=1]
-script/source = "extends ImmediateGeometry
+[sub_resource type="BoxMesh" id="BoxMesh_f2qkf"]
+size = Vector3(0, 0, 1)
 
+[sub_resource type="GDScript" id="1"]
+script/source = "extends Node3D
 
-export(NodePath) var _pointA_path
-export(NodePath) var _pointB_path
 
-var _pointA
-var _pointB
+@export_node_path var _pointA_path : set=set_pointA
+@export_node_path var _pointB_path : set=set_pointB
+
+var _pointA : Node3D
+var _pointB : Node3D
 
 func _ready():
-	_pointA = get_node(_pointA_path)
-	_pointB = get_node(_pointB_path)	
+	pass
 
 func _process(delta):
-	if (_pointA and _pointB):
-		clear()
-		begin(1, null) 
-		add_vertex(_pointA.translation)
-		add_vertex(_pointB.translation)
-		end()
-
-func update_points(_new_pointA, _new_pointB):
-	_pointA = _new_pointA
-	_pointB = _new_pointB
+	pass
+
+func _update_points():
+	look_at_from_position(_pointA.global_position, _pointB.global_position)
+	scale.z = (_pointA.global_position - _pointB.global_position).length()
+
+func set_pointA(p_path : NodePath) :
+	_pointA = get_node(p_path)
+	_update_points()
+
+func set_pointB(p_path : NodePath) :
+	_pointB = get_node(p_path)
+	_update_points()
 "
 
-[node name="SimpleLine" type="ImmediateGeometry"]
-script = SubResource( 1 )
+[node name="SimpleLine" type="MeshInstance3D"]
+mesh = SubResource("BoxMesh_f2qkf")
+script = SubResource("1")
diff --git a/visualization/box.shader b/visualization/box.gdshader
similarity index 100%
rename from visualization/box.shader
rename to visualization/box.gdshader
diff --git a/visualization/box_slider.shader b/visualization/box_slider.gdshader
similarity index 100%
rename from visualization/box_slider.shader
rename to visualization/box_slider.gdshader