Short version: Unity can’t create a real “.asset” file at runtime in a build. The AssetDatabase API is Editor-only. You’ve got two workable paths:
-
Editor/Play-mode only (OK to use UnityEditor): show a popup, get a name, create a ScriptableObject asset in your project.
-
True runtime (player build): you can instantiate a ScriptableObject in memory and save its data to disk (e.g., JSON in persistentDataPath). Later you load that JSON and reconstruct the object. (It won’t be a .asset in the Project window.)
Below are complete, paste-ready examples for both.
public class MyItem : ScriptableObject
public string displayName;
// Simple popup that asks for a name and creates a .asset
public class CreateMyItemWindow : EditorWindow
string assetName = "New MyItem";
string folder = "Assets/Data";
[MenuItem("Tools/Create MyItem…")]
public static void Open()
var win = CreateInstance<CreateMyItemWindow>();
win.titleContent = new GUIContent("Create MyItem");
win.position = new Rect(Screen.width/2, Screen.height/2, 360, 130);
EditorGUILayout.LabelField("Create ScriptableObject Asset", EditorStyles.boldLabel);
assetName = EditorGUILayout.TextField("Name", assetName);
folder = EditorGUILayout.TextField("Folder", folder);
using (new EditorGUI.DisabledScope(string.IsNullOrWhiteSpace(assetName)))
if (GUILayout.Button("Create"))
CreateAsset(assetName, folder);
static void CreateAsset(string name, string folder)
if (!AssetDatabase.IsValidFolder(folder))
Directory.CreateDirectory(folder);
var so = ScriptableObject.CreateInstance<MyItem>();
var safe = MakeSafeFileName(name);
var path = AssetDatabase.GenerateUniqueAssetPath($"{folder}/{safe}.asset");
AssetDatabase.CreateAsset(so, path);
AssetDatabase.SaveAssets();
EditorUtility.FocusProjectWindow();
Selection.activeObject = so;
Debug.Log($"Created asset at: {path}");
static string MakeSafeFileName(string input)
foreach (char c in Path.GetInvalidFileNameChars())
input = input.Replace(c, '_');
Use it from the menu: Tools → Create MyItem…. This opens a small popup, you type the name, and it creates Assets/Data/<name>.asset.
Here we show a lightweight runtime UI popup (UGUI) to capture a name, create an in-memory ScriptableObject, and save its data to JSON in Application.persistentDataPath.
A. Scriptable data & save/load helpers
public string displayName;
public class MyItemRuntime : ScriptableObject
public string displayName;
public MyItemDTO ToDTO() => new MyItemDTO { displayName = displayName, power = power };
public static MyItemRuntime FromDTO(MyItemDTO dto)
var so = CreateInstance<MyItemRuntime>();
so.displayName = dto.displayName;
public static void SaveToJson(MyItemRuntime item)
var json = JsonUtility.ToJson(dto, true);
var file = Path.Combine(Application.persistentDataPath, MakeSafeFileName(dto.displayName) + ".json");
File.WriteAllText(file, json);
Debug.Log($"Saved: {file}");
public static MyItemRuntime LoadFromJson(string filePath)
var json = File.ReadAllText(filePath);
var dto = JsonUtility.FromJson<MyItemDTO>(json);
static string MakeSafeFileName(string input)
foreach (char c in Path.GetInvalidFileNameChars())
input = input.Replace(c, '_');
B. Minimal runtime popup (UGUI)
- Create a Canvas with a Panel, a
TMP_InputField (or InputField), and two Buttons (Create/Cancel).
- Hook up this script to the Panel. Assign references in the Inspector.
public class NamePopup : MonoBehaviour
public TMP_InputField nameInput; // or InputField if not using TMP
public Button createButton;
public Button cancelButton;
createButton.onClick.AddListener(OnCreate);
cancelButton.onClick.AddListener(() => gameObject.SetActive(false));
nameInput.ActivateInputField();
var nameText = string.IsNullOrWhiteSpace(nameInput.text) ? "New Item" : nameInput.text.Trim();
var item = ScriptableObject.CreateInstance<MyItemRuntime>();
item.displayName = nameText;
item.power = Random.Range(1, 11);
MyItemRuntime.SaveToJson(item);
// Keep it alive if you need it now:
gameObject.SetActive(false);
Usage at runtime
// Show the popup (e.g., from a button)
public class ShowPopup : MonoBehaviour
public GameObject popupPanel; // the Panel that has NamePopup
public void Open() => popupPanel.SetActive(true);
This gives you a “name me” popup in a build, creates the ScriptableObject instance, and writes a JSON file like:
%USERPROFILE%/AppData/LocalLow/<Company>/<Product>/<name>.json (Windows)
~/Library/Application Support/<Company>/<Product>/<name>.json (macOS)
- If you need a real asset in the Project for designers to edit and include in builds → use the Editor approach.
- If you need players to create things during gameplay and keep them between sessions → use the runtime JSON approach (or a database). You can later import those JSON files in the Editor to make assets, if desired.
If you tell me whether you want Editor only or works in builds, I can tailor the popup/UI further (UI Toolkit vs UGUI, validation, duplicate-name checks, etc.).