[BAD VIBES CODING] Script Exporter Pro + Free web based Roblox visual project mapper

I created a plugin that lets you extract your full GUI and script hierarchy for easy ai assistance. Designed for fast AI integration (Claude, GPT, Gemini Playground version can handle the whole shebang), it maps properties, remotes, attributes, and more. Ideal for rapid debugging or documentation.

Includes a free web tool for visualizing your game structure and script connections. The web based tool is accessible whether or not you buy the plugin. If you have some existing export you want to try out. By means go ahead.

Demo videos below.

Price: $5 or use the free pastable command version ive shared at the bottom of this page
Link: https://create.roblox.com/store/asset/103991125687866/
Web Tool: https://www.scriptexporter.com

Includes demo video on landing page showing the script exporter plugin working in unison with the web based project mapper.

Built this for personal use, now public. Feedback welcome.

Some screenshots below

You can chose which parts to export. The collated file will be exported to a module script in ServerStorage. Plugin has options to pretty export or soft minify for the likes of claude where you are going to want to save your tokens. Additionally there is the option of mapping the attributes of your GUI which comes in handy when you are trying to use a chatbot to help you find out what is causing your mobile responsiveness to break!

Once pasted into the companion web based mapper. You will have a searchable, color coordinated UI that will help you copy groups of associated files.

One of the major headaches when dealing with ai assisted vibe coding is chabots tenancy to either create their own remote events/functions or for them to leave them out of the equation. Here we have visual mapper that helps you understand what files are connected. Additionally, clicking these links in the ui will again highlight the linked files so you can easily copy and paste the problem files for debugging.

Mapping your gui attributes visually can sometimes help, since the Studio interface for this is a massive pain.

Lastly on the UI we have a visual mind mapper that is color coordinated and again will link with clicks onto the files that are selected in the script explorer to help you visualize the structure of the code. I can see this being very useful for visual learners like myself when dealing with brand new projects.


Update

Due to a lot of the feedback focusing negatively on the ai aspect, ive decided to give a barebones pasteable version the plugin here in the thread. Thereby showcasing the web based tools utility as a learning, mapping and visualizing aid. I want to help the next generation of roblox builders as best I can so here is a pastable command script that you can then dump into the web based tool on the main website above to get the benefits of the paid plugin completely for free.

Open your command bar

Paste the command and press enter, you will get every user generated script in your project mapped.
You will now have a file module file created in ServerStorage called CombinedUserScripts_1xxxxx

You can then use the web based tool on the main website without paying a thing. Minus the GUI mapping.

command_paste

FULL SCRIPT EXPORTER PASTABLE COMMAND SCRIPT MINUS GUI MAPPING, FILTERING AND BEAUTIFYING



local function exportScripts()
	-- Configuration
	local REMOVE_LARGE_COMMENTS = true  -- Set to false to keep all comments
	local MAX_COMMENT_LINES = 4  -- Comments longer than this will be removed if REMOVE_LARGE_COMMENTS is true
	local INCLUDE_DISABLED_SCRIPTS = false  -- Set to true to include disabled scripts, false to exclude them
	local SOFT_MINIFY = false  -- Set to true to enable soft minification of the output
	local TYPICAL_MINIFY = true  -- Set to true to enable typical minification of the output

	local scripts = {}
	local filterList = {} -- This is kept from your script, but you mentioned it's not needed for the basic.
	                      -- For a truly basic version matching only the *output style* you might remove filterList logic.
	local maxScriptLength = 190000  -- Buffer below 200000 limit
	local remoteEvents = {}

	-- Read the filter list from the StringValue object (Kept from your script)
	local filterListObject = workspace:FindFirstChild("FileList")
	if filterListObject and filterListObject:IsA("StringValue") then
		for line in filterListObject.Value:gmatch("[^\r\n]+") do
			filterList[line:lower()] = true
		end
	else
		warn("Filter list 'Workspace>FileList' (StringValue) not found or not a StringValue. No filtering will be applied from it.")
	end

	-- Function to check if a script should be included
	local function shouldInclude(scriptPath, instance)
		local isDisabled = false
		if instance:IsA("Script") or instance:IsA("LocalScript") then
			isDisabled = not instance.Enabled
		end

		-- Check against filterList if it has entries
		local isFilteredOut = false
		if next(filterList) then -- Check if filterList is not empty
			isFilteredOut = filterList[scriptPath:lower()]
		end

		return not isFilteredOut and
			not scriptPath:lower():match("^coregui>") and
			scriptPath ~= "Workspace>FileList" and -- Explicitly exclude the FileList StringValue itself
			(INCLUDE_DISABLED_SCRIPTS or not isDisabled)
	end

	-- Function to get full path of an instance
	local function getFullPath(instance)
		local path = instance.Name
		local current = instance.Parent
		while current and current ~= game do
			path = current.Name .. ">" .. path
			current = current.Parent
		end
		return path
	end

	-- Function to remove large comments, stray closing brackets, and triple backticks (Your function)
	local function removeLargeCommentsAndClean(source)
		if not REMOVE_LARGE_COMMENTS then
			return source:gsub("```", ""):gsub("%]=*%]", "")
		end

		local lines = {}
		local originalLines = source:split("\n")
		local inBlockComment = false
		local blockCommentLevel = 0
		local blockCommentStartLine = 0

		for i = 1, #originalLines do
			local line = originalLines[i]
			line = line:gsub("```", "")

			local blockStartMatch = line:match("^%s*%-%-%[(=*)%[")
			if blockStartMatch then
				if not inBlockComment then
					inBlockComment = true
					blockCommentLevel = #blockStartMatch
					blockCommentStartLine = #lines + 1
					table.insert(lines, line)
				else
					table.insert(lines, line)
				end
			elseif inBlockComment then
				table.insert(lines, line)
				local blockEndMatch = line:match("%]" .. string.rep("=", blockCommentLevel) .. "%]")
				if blockEndMatch then
					inBlockComment = false
					local currentCommentLineCount = (#lines) - blockCommentStartLine + 1
					if currentCommentLineCount > MAX_COMMENT_LINES then
						for j = 1, currentCommentLineCount do
							table.remove(lines, blockCommentStartLine)
						end
					end
					blockCommentLevel = 0
				end
			else
				line = line:gsub("%]=*%]", "")
				table.insert(lines, line)
			end
		end
		return table.concat(lines, "\n")
	end

	-- Function to find remote events (Your function)
	local function findRemoteEvents(source, scriptPath)
		if not source then
			warn("Empty source for script: " .. scriptPath)
			return
		end
		for line in source:gmatch("[^\r\n]+") do
			if line:match("Instance%.new%(%s*[\"']RemoteEvent[\"']%s*%)") then
				local eventName = line:match("local%s+(%w+)%s*=")
				if eventName then
					table.insert(remoteEvents, {name = eventName, path = scriptPath})
				else
					table.insert(remoteEvents, {name = "Unnamed RemoteEvent", path = scriptPath})
				end
			end
		end
	end

	-- Function to soft minify content (Your function)
	local function softMinify(content)
		if not SOFT_MINIFY or TYPICAL_MINIFY then -- Typical takes precedence
			return content
		end
		local lines = {}
		for line in content:gmatch("[^\r\n]+") do
			line = line:gsub("^%s+", ""):gsub("%s+$", "")
			line = line:gsub("%-%-[^\n]*", "")
			if not line:match("^%s*$") then
				table.insert(lines, line)
			end
		end
		local result = table.concat(lines, "\n")
		result = result:gsub("\n+", "\n")
		return result
	end

	-- Function to typically minify content (Your function)
	local function typicalMinify(content)
		if not TYPICAL_MINIFY then
			return content
		end
		local result = content
		result = result:gsub("%-%-%[%[.-%]%]", "")
		result = result:gsub("%-%-[^\n]*\n", "\n")
		result = result:gsub("%-%-[^\n]*$", "")
		result = result:gsub("\n%s*\n", "\n")
		result = result:gsub("^\n*", ""):gsub("\n*$", "")
		result = result:gsub("%s+", " ")
		result = result:gsub("^%s*(.-)%s*$", "%1")
		result = result:gsub(";%s*}", "}")
		result = result:gsub("%s*([%{%}%(%)=%[%];,])%s*", "%1")
		result = result:gsub("([\n])%s+", "%1")
		return result
	end

	-- Recursively find all scripts
	local function findScripts(obj)
		for _, child in ipairs(obj:GetChildren()) do
			if child:IsA("LocalScript") or child:IsA("ModuleScript") or child:IsA("Script") then
				local scriptPath = getFullPath(child)
				if shouldInclude(scriptPath, child) then
					local success, source = pcall(function() return child.Source end)
					if success and source and source:match("%S") then
						local cleanSource = removeLargeCommentsAndClean(source)
						findRemoteEvents(cleanSource, scriptPath)
						table.insert(scripts, {type = child.ClassName, name = scriptPath, source = cleanSource})
						print("Including file:", child.ClassName .. ": " .. scriptPath)
					else
						if not success then warn("Could not read source for: " .. scriptPath .. " Error: " .. tostring(source))
						else print("Skipping empty script:", child.ClassName .. ": " .. scriptPath) end
					end
				else
					print("Excluding file:", child.ClassName .. ": " .. scriptPath)
				end
			end
			if #child:GetChildren() > 0 then
				findScripts(child)
			end
		end
	end

	print("--- Starting Script Export ---")
	findScripts(game) -- Scan entire game

	if #scripts == 0 then
		print("--- No scripts found to export. ---")
		return
	end

	-- Create multiple ModuleScripts for combined content
	local scriptIndex = 1
	local parentService = game:GetService("ServerStorage")
	local currentScript = Instance.new("ModuleScript")
	currentScript.Name = "CombinedUserScripts_1"
	currentScript.Parent = parentService
	local currentSource = ""

	-- Add remote event mappings as comments at the top
	local eventComments = "-- Remote Event Mappings (based on 'Instance.new(\"RemoteEvent\")' detection):\n"
	if #remoteEvents > 0 then
		for _, event in ipairs(remoteEvents) do
			eventComments = eventComments .. string.format("--   %s: (found in %s)\n", event.name, event.path)
		end
	else
		eventComments = eventComments .. "--   No RemoteEvents explicitly created with Instance.new(\"RemoteEvent\") found.\n"
	end
	currentSource = eventComments .. "\n"

	for _, scriptItem in ipairs(scripts) do
		local processedSource = scriptItem.source
		if TYPICAL_MINIFY then
			processedSource = typicalMinify(processedSource)
		elseif SOFT_MINIFY then
			processedSource = softMinify(processedSource)
		end

		-- THIS IS THE CHANGED LINE TO MATCH THE SYSTEM PROMPT'S EXPORT STYLE
		local scriptContent = string.format("-- %s: %s\n%s\n\n",
			scriptItem.type, scriptItem.name,
			processedSource)

		if #currentSource + #scriptContent > maxScriptLength and #currentSource > #eventComments + 5 then
			currentScript.Source = currentSource
			scriptIndex = scriptIndex + 1
			currentScript = Instance.new("ModuleScript")
			currentScript.Name = "CombinedUserScripts_" .. scriptIndex
			currentScript.Parent = parentService
			currentSource = eventComments .. "\n"  -- Add event mappings to each new script
			print("Creating new combined script: " .. currentScript.Name)
		end

		currentSource = currentSource .. scriptContent
	end

	if #currentSource > #eventComments + 5 then
		currentScript.Source = currentSource
	elseif currentScript.Parent then -- If it only has comments, destroy it
		currentScript:Destroy()
		scriptIndex = math.max(0, scriptIndex - 1)
		print("Last combined script was empty or contained only headers; removed.")
	end

	if scriptIndex > 0 then
		print("--- Export Complete: Created " .. scriptIndex .. " combined script(s) in ServerStorage, containing " .. #scripts .. " original scripts. ---")
	elseif #scripts > 0 then
		print("--- Scripts processed, but no combined script files were generated (likely due to all being empty after processing). ---")
	else
		print("--- No scripts were exported. ---")
	end
end

-- Run the export function
exportScripts()


This effectively makes the paid plugin donation based. Exports multiple files if your project goes over 200000 lines (will split into various modules)

7 Likes

Vibe coding :broken_heart: :broken_heart: :broken_heart: :broken_heart:

I understand occasionally using AI for some things but having a whole workflow built around AI…

15 Likes

I was a Rails developer for 7 years before ai came out. Ive barely written any code over the last two years manually :sweat_smile: its not pretty but here we are

Vibe coding :wilted_flower:

1 Like

I think if you presented this resource as a way to integrate, NOT focus on AI in your workflow it would be alot more popular and generally accepted.

Vibe coding is looked down upon because it inherently produces lower quality results compared to “manual” coding.

1 Like

Selling a ai generated plugin is diabolical, its like selling someone’s work without paying them then selling it.

Yea, ive used ai before but not this lazy.

4 Likes

Surely isn’t the recipe for the disaster in the long run.

There is reason why AI is used as a tool to assist you writing code and not as a thing that does all the work for you.

If anyone’s actually tested or viewed the exporter or visualizer, I’d be interested in feedback on the tool itself.

i dont get what the point of this is to be honest. it just traces the calls for each script and copies everything to your clipboard? i am not a vibe coder so i dont know how that helps the average joe. whenever i really need help with an issue copying 3-4 lines does the job for me and worst case scenario i just provide more info later on if needed

image
its also a bit misleading to say “try the free code mapper” in the website when one requires to pay for the proprietary parser plugin that spits out the data to feed into the mapper

The plugin exports all user scripts and GUI properties in one click. The companion web tool maps connections, attributes, and structure visually. It’s for full-project context, not just isolated bugfixing. Check the screenshots/video.

You can export your own project code into the web app and use it without paying for the plugin. I released the best part of the project entirely for free.

Is there a format you have to follow? How do you export without the plugin?

I can send you a command script that does that or you could script that part yourself. If you had a small project you could manually paste the scripts you’ve made in that field in it would map files that call one another, Additionally showing you the connections to remote events and a mind map, again all color coordinated to select.

are you sure thats faster than just copy pasting your problem into the ai? unless you are a vibe coder this wont come in handy for developers who just want a quick issue with their code fixed.

Please see the edit and try the pastable command free version ive added to the main thread and let me know what you think.