Introduction I tried. I tried really hard to follow @DMagic's tutorial. I really did.  I have one problem though. I'm old.  How old am I?  Old enough that the first programming language I learned was on a TRS-80 model 1 (with the cassette drive).  I'm old enough that I know at least a dozen flavors of BASIC, to include GW Basic, Basic A, Commodore Basic, Amiga Basic, Visual Basic... and the list goes on.  Being that old, I come from the school of line numbers. Everything should happen in linear sequence with gosub's and goto's.   When look at what people today are calling object oriented and this callback and that callback and this get : set and... well... when I look at code like that I feel like I'm on a perpetual pogo stick and I can't get the hell off.  Unfortunately, when I tried DMagic's tutorial I found that pogo stick and it dropped me on my head.  Sorry D, you're way above my skills in coding. I needed something simple But, I really wanted a UI.  I first tried the popup thing with a few buttons on it.  And yea, that works, but it's not a "REAL" UI with cool things like sliders and buttons and checkboxes.  And I know that Unity and KSP can do it. I've seen it.  But the god awful examples I found were telling me I was doomed.  I had to create these UI's from positions, and coordinates and lines and a gobbledygook of code that I couldn't even begin to visualize. Surely, there had to be an easier way!? And here it is.  Proof that if you hate hard work, you can alway find a way to avoid it. The Lazy Coder's Guide to KSP UI Design This is no way a comprehensive tutorial on UI design. This tutorial is to give you the very basics.  If you follow these steps, you should be able to create a working UI within KSP without creating any scripts in Unity.  This is purely a Unity design-it, KSP execute-it method.  With this working example I hope you will have the basics for adding a few controls from the Unity UI and be able to read from and manipulate them at run-time.  This tutorial does make a few assumptions. That you have a basic working knowledge of Unity, that you have PartTools installed and working and that hopefully, you've created a few parts and a small plugin and you're ready to advance to UI's. In Unity In Unity, create a File/New Scene..  Up at the top of the scene, click on 2D.  In the hierarchy panel in an empty spot, right click to bring up the pop-up menu.  Scroll down to UI and in the pop-out menu, select Canvas.  The Canvas is simply a container to hold the UI you're going to be working on.  It's size is unimportant.  You should also have seen that it created a new item called EventSystem.  The default settings for both of these game objects is fine. Next, right click on the Canvas in the hierarchy and again, scroll down to UI and select Panel.  This panel is going to be the background for your UI.   Before we get into changing the background, we first need to set the size for our UI.  By default, Unity sets the anchors for the panel at Stretch/Stretch.  With the panel selected, look in the inspector and you'll see the anchors at the top left of the “Rect Transform”  With stretch/stretch as the anchor method, Unity expect you to size your UI by the screen size. The settings it allows you to change are top, left, bottom and right.  Those measurements are the distance from the edge of the canvas you created.  For this tutorial we're going to make a UI of a fixed size.  With the panel selected in the hierarchy, in the inspector click on the square with the blue plus symbol in it (one of the green arrows in the image points to it).  This will create a popup that will allow you to change the anchor method for the panel.  At the top left of that popup, select the image under the column 'top' and in the row 'left'.  This now tells the Panel that you want it to align to the top left of the canvas. More importantly, it changes the rect transform to allow you to put in a height and width.  There are two ways to adjust the height and width.  One is to manually enter the numbers in the rect transform height and width boxes.  The other is by using the mouse.  Up above the hierarchy, click on the icon of the square with the dots in each corner.  This will allow you to use the mouse and drag the corners to get the proper size. To change the background, with the panel selected in the hierarchy you should see in the inspector an 'Image (Script)'.  The two important parts of this Image are the Source Image and the Color.  By changing and adjusting those, you can choose the type of background you want for your UI, including how transparent it is by setting the color's alpha. This image shows some of the controls I've mentioned up till now and where to find them.
A quick note. There's one very good reason to get in the habit of setting your anchors at least, to the same location.  Once you get into more complex UI's it's becomes real handy to place groups of components onto even more panels.  By anchoring to say, top left, you can always drag those panels around and all of the components under them stay in the same position. Next, we're going to add some controls to the panel.  Select the panel in the hierarchy.  Right click, scroll down to UI and select “Text”.  This should put a new text object in the center of your panel.  Let's change it's anchor to the same we used for the panel. With the text selected, in the inspector for the rect transform, open the anchor pop-up and select top left.  Now you can either drag your text object around to where you want it placed or you can enter a Pos X and a Pos Y in the rect transform to place it.  Following that basic procedure, place a toggle and a slider.  Be sure to set the anchors to top left and make sure they're all under the panel in the  hierarchy.   Once you have them place, we need to change the names on these game objects.  Rename the panel to “MyCoolUIPanel”.  Rename the Text to “ImportantText.”  While you're there and have it selected in inspector you'll see a “Text (Script)”  In the box named “Text” change that to “We need to change this.”   Next, rename the Toggle to “CheckThisOut” and rename the slider to “YouMoveMe”.  At this point, your scene should look a lot like this: Next, in your assets folder, create 2 new folders.  Call one UI Save and the other UI Export.  Now, file/save your scene into the UI Save folder.  You can name it whatever you like. In the project list, click on the UI Export folder which should be empty.  Click and hold on the MyCoolUIPanel and drag it down to that empty folder.  It should create a blue cube in that folder.  That's the prefab for the UI.  With that blue cube selected, at the very bottom right where it says “AssetBundle None”, click on the None and then select “New”  It will expect a name so call it mycoolui.  Your screen should look like this. (minus  the day-glow arrows and such). A brief explanation.  The reasons we put the saved scene and the prefab into separate folders is to prevent a collision.  You CAN give the folder an Asset Bundle name and, in theory, it will try to take everything in that folder and create an asset. If you have the saved scene in there, it will promptly crash and burn.  Therefore, the safest way I've found is to create two separate folders and everything that needs to get bundled goes into a specific folder.  If this doesn't make sense now, just trust me.  I'm saving you much pain. So, now we have our UI created and we've assigned it an asset bundle name. It's time to export it. In the main menu, select KSPAssets/Asset Compiler.  A new window should pop up with some buttons.  With any luck, you should see one that says mycoolui with a button that says “Create” beside it.  Click on the create button.  That hopefully made some new buttons available.  If you want to see what files are being included in the prefab you can click on view.  Click on Show All to get back to this menu.  The two important buttons here are Update and Build.  First, get in the habit of clicking the update first and then, click the build. A brief explanation.  What we just did was we created an asset bundle that KSP will recognize.  Any time you make changes to your UI or you add new items like graphics, you need to place them in the folder that holds the export and assign the asset bundle name.  For example, if you change an item in the UI you'll need to delete the old panel prefab, drag the panel back down to the export folder to create a new prefab, set the asset bundle name and then, in the asset compiler, click update then build. Update: DMagic, the master of the KSP UI has informed me that replacing the prefab as I have been doing isn't necessary.  His comments on how to update the prefabs are here: Once you click on the build, it will likely take a second or two.  First, make sure that nothing went wrong.  Click on the console tab at the bottom of Unity and make sure that you don't have any red exclamation marks.  If you do, click clear on the console and try to build again.  I'm not going to go into the possible errors but if you do have one, I warn you, they will often be cryptic and I wish you luck figuring out what you did wrong. So, assuming everything went right, you have a new bundle.  The problem is, you're not going to be able to find it in Unity.  So, close out Unity and open your favorite file explorer/manager.  Navigate to the folder where your project is and along with the Assets folder, you should see a folder called AssetBundles.  Open that folder and, if you were successful, you have a new file there called mycoolui.ksp.  That my dear pupil, is your UI ready for use. The Code Now we're going to dive into the ugly part.  The coding.  But before we do, we need to get a few things set up.  We're going to need to create a new plugin and, we're going to create a very simple partmodule.  So, in your GameData directory for your KSP install, create a new folder and call it “mycoolplugin.”  Open that folder and create two more folders,  Parts and Plugins.   Go back to your Unity project / AssetBundles folder and copy the mycoolui.ksp file into the Plugins folder you just created.  Now, change the file extension on the mycoolui from .ksp to something else, like .dat.  More on the reason for that in a bit. Now, let's get busy coding.  (At the end of this tutorial is the full code needed for both the partmodule and the monobehaviour.) I'm not going to go into depth on how to set up to code.  This is a tutorial about making a UI so some knowledge of your IDE and how to set up references is assumed.  The only thing out of the ordinary that you'll need to add is the UnityEngine.UI as a reference.
First we'll need a part.  I have conveniently appropriated one from the Squad repository and repurposed it for our needs.  Here's the .cfg info.  Copy this and save it into the part folder as... oh... part.cfg.   PART { name = CoolUITestPart module = Part author = RoverDude rescaleFactor = 1.0 node_attach = 0.3, 0.0, 0.0, 1.0, 0.0, 0.0, 0 TechRequired = precisionPropulsion entryCost = 1200 cost = 50 category = Propulsion subcategory = 0 title = Cool UI Test Part manufacturer = #autoLOC_501633 //#autoLOC_501633 = Probodobodyne Inc description = #autoLOC_501812 //#autoLOC_501812 = Often, and mistakenly used for playing ball games. attachRules = 0,1,0,1,0 mass = 0.01375 dragModelType = default maximum_drag = 0.2 minimum_drag = 0.3 angularDrag = 2 crashTolerance = 5 breakingForce = 50 breakingTorque = 50 maxTemp = 2000 // = 3000 fuelCrossFeed = True bulkheadProfiles = srf tags = #autoLOC_501813 //#autoLOC_501813 = fueltank ?lfo liquid oxidizer propellant rocket MODEL { model = Squad/Parts/FuelTank/FoilTanks/RadialTank_Round } MODULE { name = CoolUIPM } } You probably noticed that I chopped out most of what we won't need and added in a couple of lines to call our plugin. The partmodule is going to be really simple.  We only really need it to do one thing. Open the UI.  But, I'm also going to add in a progress bar and a few lines of code that we can play around with. The first bit we'll add in are two KSP fields. One is our toggle button to open the main UI and the other is the progress bar. namespace mycoolplugin { public class CoolUIPM : PartModule { //Create a copule of cool things for the part UI that we can play with //a button to toggle the UI on and off [KSPField(guiName = "Open UI", guiActiveEditor = true, guiActive = true, isPersistant = false), UI_Toggle(controlEnabled = true, disabledText = "Closed", enabledText = "Open", invertButton = false, scene = UI_Scene.All)] public bool openUI = false; //and a progress bar that we can play with [KSPField(guiName = "Cool Slider", guiActiveEditor = true, guiActive = true, isPersistant = true), UI_ProgressBar(minValue = 0f, maxValue = 1f, scene = UI_Scene.All)] public float PartUICoolSlider = 0.0f; In the OnStart, we need to create a callback.  These few lines of code are going to perform a critical function.  Any time the part UI toggle button is clicked, it's going to call the function to either show the UI or destroy it. Wait? Destroy it?  Why would we want to do that?  Simple. The UI's are very persistent ... really persistent.  If you open a UI in the editor and then launch, it stays open. If you open one then switch from the SPH, to the VAB, it stays open.  It'll even stay open when you exit out to KSC.  For our purposes, we don't want that.  We only want it to show the UI when the user is where that part is.  So, whenever the user clicks on the partmodule toggle button, we want to either open or destroy the UI.  This chunk of code triggers that. NOTICE:  This callback is set up to work in the editor only.  Note the .uiControlEditor.  That prevents that callback from working anywhere BUT the editor.  If you want your UI to be available in flight, you'll have to change that to .uiControlFlight. public override void OnStart(StartState state) { //This creates a callback so that whenver the UI_Toggle openUI is clicked, it either opens or closes the main UI Fields[nameof(openUI)].uiControlEditor.onFieldChanged = delegate (BaseField a, System.Object b) { if (CoolUI.CoolUICanvas == null) { CoolUI.ShowGUI(); //if the UI doesn't exist, create one and show it. } else { CoolUI.Destroy(); //if it does exist. they're closing it so get rid of it. } }; } Next, the FixedUpdate. The first thing we need to do here is check and see if the UI is already open.  The reason we do that is because we may have a bunch of parts on the vessel with our same partmodule on them.  If the UI is open, then that means someone clicked on the button to open it.  We need to set all the UI_Toggle buttons on all of our parts to true. For this example if the UI isn't open (it's null) then leave FixedUpdate.  Otherwise, trying to get info from a non-existent UI will create a null reference error. In the final 2 lines are were we're going to manipulate things on the UI.  First, we're going to set the value of our progress bar to the same value as the UI slider.  Next, we're going to update the UI text so that it shows us a text value of the slider's position. public void FixedUpdate() { //This checks to see if the UI is being shown. If so, it will update any other CoolUIPm partmodules so that they show the button as being clicked. if (CoolUI.CoolUICanvas != null) { openUI = true; } else { return; } //if not, we don't want to call UI functions because they'll create a null ref. //This is going to take the partmodule UI_ProgressBar and make it the same as the UI slider. PartUICoolSlider = CoolUI.CoolSliderPosition(); //This calls the procedure to update the main UI text give a number representation of the slider position. CoolUI.UpdateText(PartUICoolSlider.ToString()); } } } Ok, that's it for the partmodule. See, it was easy.  Now for the harder part, the Monobehavour. The first thing we need to do is to create a loader.  This monobehaviour, CoolUILoader, has the sole responsibility of finding the asset bundle and loading it up as a gameobject.  We're going to do this in StartupInstantly so that it gets loaded early.  This code is looking for the bundle in the same directory that the plugin is in. So hopefully, when you create this plugin, you put both it and the bundle in the same folder. Update: DMagic, the master of the KSP UI, has informed me that loading the prefab manually as I do in the code below and with the .ksp extension may not be necessary and may even cause issues.  He also suggest renaming the extension from .ksp to something else which makes perfect sense.  KSP loads a number of files automatically, like .cfg files.  By changing the extension of the file name, you can guarantee that KSP won't load it before you do and thus, create a problem when your code tries to load it and can't because it's already loaded.   Therefore, if you remember, we renamed the bundle file to mycoolui.dat.   Here's where we load it.  You can read his comments here: using System.Collections.Generic; using System.IO; using System.Reflection; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; namespace mycoolplugin { [KSPAddon(KSPAddon.Startup.Instantly, true)] public class CoolUILoader : MonoBehaviour { private static GameObject panelPrefab; public static GameObject PanelPrefab { get { return panelPrefab; } } private void Awake() { //The way I was doing this which does seem to work. //AssetBundle prefabs = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "mycoolui.ksp")); //DMagic's method without the .ksp file extension AssetBundle prefabs = AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "mycoolui.dat")); panelPrefab = prefabs.LoadAsset("MyCoolUIPanel") as GameObject; } } Next, the meat, the UI code itself. Taking a look at the code, the first thing you should notice is that it's a Startup.Editor only.  This matches the code in the partmodule that indicates we only want to show our UI in the editor.  You'll need to change this if you want users to see it anywhere else. First, we declare some variables.  I'll explain them as we get to them. The first function is the Awake function.  This has one line but an important one.  This creates a callback so that any time the KSP scene changes, our code can be notified. The next function is what that callback calls and it's really simple. If the UI exists, call the Destroy function.  This ensures that any time we switch scenes in KSP, the UI gets destroyed and the canvas gets set to null. The Destroy function also does one other small task.  It looks for all of our partmodules and sets the UI_Toggle button to off.  This makes sure that when the user opens the partmodule UI that all of the 'open ui' buttons look the way they should. [KSPAddon(KSPAddon.Startup.EditorAny, true)] public class CoolUI : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler { public static GameObject CoolUICanvas = null; public static GameObject CoolUIText = null; public static List<CoolUIPM> CoolUIParts = new List<CoolUIPM>(); private static Vector2 dragstart; private static Vector2 altstart; private void Awake() { //this creates a callback so that whenever the scene is changed we can destroy the UI GameEvents.onGameSceneSwitchRequested.Add(OnSceneChange); } //If we don't get rid of the UI, it'll stay where it is indefinitely. So, every time the scene is changed, we need to get rid of it. void OnSceneChange(GameEvents.FromToAction<GameScenes, GameScenes> fromToScenes) { if (CoolUICanvas != null) { Destroy(); } } //This actually destroys the UI. But it also goes through the partmodule's toggle buttons and turns them all off. public static void Destroy() { CoolUICanvas.DestroyGameObject(); CoolUICanvas = null; foreach (CoolUIPM thisPart in CoolUIParts) { thisPart.openUI = false; } } The next function shows the UI.  The first thing we need to check is whether the UI is already on the screen. If so, we need to stop. The next 3 lines handle calls our loader and assigns the prefab to the CoolUICanvas.  The easy way to think of this, the CoolUICanvas is the main panel we created in Unity where all of the controls are placed.  The next line tells the canvas that it should make the main screen canvas it's parent.  Then, it ads the UI to the screen. public static void ShowGUI() { if (CoolUICanvas != null) //if the UI is already showing, don't show another one. return; //Load up the UI and show it CoolUICanvas = (GameObject)Instantiate(CoolUILoader.PanelPrefab); CoolUICanvas.transform.SetParent(MainCanvasUtil.MainCanvas.transform); CoolUICanvas.AddComponent<CoolUI>(); The next 4 lines in the ShowGUI are setting some information we need.  The first one locates the text object we put on the UI and assigns it a variable, CoolUIText.   The next 3 lines create yet another callback.  This callback will fire any time the user clicks on the main UI toggle button (the check box). You'll see the words AddListener and then delegate.  Basically, any time the checkbox is clicked on, it will fire off the function OnToggleClicked and pass a variable,  isOn.  This isOn variable is read from the Unity prefab and tells us if the checkbox is checked or not. //Find the game objects that we gave cool names to in Unity CoolUIText = (GameObject)GameObject.Find("ImportantText"); //This is a toggle so we need to create a callback for when it gets clicked on GameObject checkToggle = (GameObject)GameObject.Find("CheckThisOUt"); Toggle toggleButton = checkToggle.GetComponent<Toggle>(); toggleButton.onValueChanged.AddListener(delegate { OnToggleClicked(toggleButton.isOn); }); } One thing to take note of in these lines of code:  We're telling Unity to find certain game objects.  The name you pass to this has to match the name you gave them in Unity. For example, if you remember, we renamed our text object “ImportantText” in the Unity prefab.  Here, we're telling the code to find that object by name and assign it to CoolUIText. If we look at the next few lines of code, the OnToggleClicked function, it starts to make sense.  If the checkbox in the UI is checked (ison=true) we send a screen message.  Otherwise, we send a different one. //this is the callback we created for when the toggle button is clicked. static void OnToggleClicked(bool ison) { if (ison) //ison is determines if the checkbox is toggled. In Unity it's in the "Toggle (Script)" as "Is On" { ScreenMessages.PostScreenMessage("Hey, you turned it on!"); } else { ScreenMessages.PostScreenMessage("Bummer, you turned it off."); } } The next small function allows us to set the text in the UI to whatever we want.  We take the text gameobject, get the text component from it, and change the .text field. //this function is where we update the text component on the UI. public static void UpdateText(string message) { CoolUIText.GetComponent<Text>().text = message; } The next 3 functions are all about moving the UI around.  If you were observant, you probably notice that at the beginning of the monobehaviour declaration there were a few extras: IBeginDragHandler, IDragHandler, IendDragHandler.  These are basically telling this monobehaviour that we're going to be doing some UI dragging.  And that's handled in the next 2 functions. OnBeginDrag sets a couple of vectors to remember where the drag started in relation to the screen and where our UI was located. In the OnDrag event, two more vectors are calculated to determine where the UI is moving from, where it's moving to and  how far the UI should be moved.  Then, it plops the UI in the new position.  While this at first seems like an odd way to do it, that it's constantly picking up, moving and dropping the UI.  But, it happens so fast that it appears extremely smooth. There are other drag events that you can tie into.  I included the OnEndDrag event with just a comment and give you something to think about.  If the drag event is ended, the UI position will be at the CoolUICanvas.transform.position.  The code I have here creates the new UI and essentially plops it down screen center every single time it's opened.  Could you possibly use the transform's position and the OnEndDrag event to save it's position and then, when the ShowGUI event is run again and the UI is created, it's restored it to the position where it was last dropped? //this event fires when a drag event begins public void OnBeginDrag(PointerEventData data) { dragstart = new Vector2(data.position.x - Screen.width / 2, data.position.y - Screen.height / 2); altstart = CoolUICanvas.transform.position; } //this event fires while we're dragging. It's constantly moving the UI to a new position public void OnDrag(PointerEventData data) { Vector2 dpos = new Vector2(data.position.x - Screen.width / 2, data.position.y - Screen.height / 2); Vector2 dragdist = dpos - dragstart; CoolUICanvas.transform.position = altstart + dragdist; } //this event fires when we let go of the mouse and stop dragging public void OnEndDrag(PointerEventData data) { //humm... this would be a good place to record the UI position after it moved } Finally, a short function to handle our slider.  This function looks for a slider gameobject on the UI named “YouMoveMe” and gets the slider component.  It then returns the value, which is the position of the slider in a range from 0 to 1. In Unity, you can change the slider range easily by changing the min and max values.  You can also make it slide right to left, return whole numbers... just a whole range of options. //This function grabs the position of the UI slider public static float CoolSliderPosition() { GameObject slider = (GameObject)GameObject.Find("YouMoveMe"); Slider thisSlider = slider.GetComponent<Slider>(); return thisSlider.value; } } } As a matter of fact, you can easily create a UI to look pretty much any way you want.  Each component of the Unity UI has the ability to change the way it looks, not only by color but by adding in custom graphics.  If you do decide to play around and add your own graphics, you need to remember to add them to the asset bundle.   Which is another reason I suggested the export folder.  Drag your graphics to the export folder and add them to the asset bundle  (remember, Unity, bottom right, mycoolui).  When you update and build your asset bundle, the Asset Compiler will include those graphics in the bundle and... like magic they get included in your cool UI. So, if you got all of your UI right and you got the asset bundle created and in the right spot, and you create this plugin and have it run flawlessly, you should see something like this in KSP I hope I've done a reasonable job of explaining what I think is the easiest method for creating a Unity UI.  If you have any questions or if I didn't explain something well enough, ask me.   Be sure to @ me or quote me for a faster response.  I'll attempt to give you a reply without using line numbers.   If you see any glaring mistakes in my code. TELL me so I can fix them.   If you have an urge to update, upgrade, refactor, optimize or otherwise 'improve' my code and then tell me that I did such and such when instead I should have.... allow me to give you an old coder's axiom. “When the only tool you have is a hammer, everything begins to look like a nail.” I really like my hammer. It's simple. I understand it.  It works.  And it'll beat the crap out of a pogo stick. *snort* And finally, here's an example of a UI I'm using on a current project.  These are all Unity controls but I've replace the graphics with some very simple ones I created.  But, 5 simple images that took me 15 minutes to create,  it completely changed the look of the UI from the stock controls we're all  familiar with. I'm looking forward to seeing some of your cool UI's in the future.     Complete PartModule Code   Complete MonoBehaviour code   Spoiler.  How to save and load your UI's position so that it always reappears where the user put it.