V2 AstraR

Pasted Oct 22, 2026, 9:24 PM1 file1,140 lines

Scan to open on your phone

Point a camera at the QR code - it opens this exact paste, no app needed.

https://codepastes.com/v2-astrar
V2 AstraR

--========================================================
-- ASTRAR v5.2 | ROBLOX CREATOR EDITION
-- Based on the user's original AstraR v5.1
--
-- FIXES:
-- • Reliable generated-code detection with UTF-8 emoji
-- • Correct script-title extraction
-- • Generated code uses a real editable multiline TextBox
-- • Code box has a dark background and supports selection
-- • No launcher hover animation
-- • No opening or closing animation
-- • Original GUI style and built-in templates preserved
--
-- PLACE IN:
-- StarterPlayer > StarterPlayerScripts
-- Use a LocalScript.
--========================================================

local Players = game:GetService("Players")

local Player = Players.LocalPlayer
local PlayerGui = Player:WaitForChild("PlayerGui")

local GUI_NAME = "AstraRInterface"

local BLACK = Color3.fromRGB(10, 10, 13)
local PANEL = Color3.fromRGB(20, 21, 26)
local GRAY = Color3.fromRGB(43, 45, 52)
local BLUE = Color3.fromRGB(25, 115, 255)
local RED = Color3.fromRGB(255, 45, 60)
local WHITE = Color3.fromRGB(245, 246, 250)
local MUTED = Color3.fromRGB(160, 165, 178)
local CODE_BG = Color3.fromRGB(13, 14, 18)

--========================================================
-- CLEAN UP OLD GUI
--========================================================

local old = PlayerGui:FindFirstChild(GUI_NAME)
if old then
    old:Destroy()
end

--========================================================
-- UI HELPERS
--========================================================

local function corner(object, radius)
    local c = Instance.new("UICorner")
    c.CornerRadius = UDim.new(0, radius)
    c.Parent = object
    return c
end

local function stroke(object, color, thickness)
    local s = Instance.new("UIStroke")
    s.Color = color
    s.Thickness = thickness
    s.ApplyStrokeMode = Enum.ApplyStrokeMode.Border
    s.Parent = object
    return s
end

local function makeLabel(parent, text, size, color, font)
    local label = Instance.new("TextLabel")
    label.BackgroundTransparency = 1
    label.Text = text
    label.TextColor3 = color or WHITE
    label.TextSize = size or 15
    label.Font = font or Enum.Font.Gotham
    label.TextWrapped = true
    label.Parent = parent
    return label
end

local function makeButton(parent, text, color)
    local button = Instance.new("TextButton")
    button.Text = text
    button.TextColor3 = WHITE
    button.TextSize = 16
    button.Font = Enum.Font.GothamBold
    button.BackgroundColor3 = color
    button.BorderSizePixel = 0
    button.AutoButtonColor = false
    button.Parent = parent
    corner(button, 10)
    return button
end

--========================================================
-- MAIN GUI
--========================================================

local Gui = Instance.new("ScreenGui")
Gui.Name = GUI_NAME
Gui.ResetOnSpawn = false
Gui.IgnoreGuiInset = true
Gui.DisplayOrder = 100
Gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling
Gui.Parent = PlayerGui

-- Launcher

local Launcher = Instance.new("TextButton")
Launcher.Name = "AstraRLauncher"
Launcher.Size = UDim2.fromOffset(56, 56)
Launcher.Position = UDim2.new(0, 18, 0.55, -28)
Launcher.BackgroundColor3 = BLACK
Launcher.BorderSizePixel = 0
Launcher.Text = "A"
Launcher.TextColor3 = BLACK
Launcher.TextSize = 32
Launcher.Font = Enum.Font.GothamBlack
Launcher.AutoButtonColor = false
Launcher.Parent = Gui

corner(Launcher, 100)
stroke(Launcher, RED, 3)

local AStroke = Instance.new("UIStroke")
AStroke.Color = RED
AStroke.Thickness = 1.5
AStroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Contextual
AStroke.Parent = Launcher

-- Main chat window

local Main = Instance.new("Frame")
Main.Name = "ChatWindow"
Main.AnchorPoint = Vector2.new(0.5, 0.5)
Main.Position = UDim2.fromScale(0.5, 0.5)
Main.Size = UDim2.new(0.88, 0, 0.78, 0)
Main.BackgroundColor3 = PANEL
Main.BorderSizePixel = 0
Main.Visible = false
Main.ClipsDescendants = true
Main.Parent = Gui

corner(Main, 18)
stroke(Main, Color3.fromRGB(65, 68, 78), 1.5)

local SizeLimit = Instance.new("UISizeConstraint")
SizeLimit.MinSize = Vector2.new(280, 330)
SizeLimit.MaxSize = Vector2.new(620, 680)
SizeLimit.Parent = Main

-- Header

local Header = Instance.new("Frame")
Header.Size = UDim2.new(1, 0, 0, 54)
Header.BackgroundColor3 = BLACK
Header.BorderSizePixel = 0
Header.Parent = Main

local Title = makeLabel(
Header, "AstraR", 20, WHITE, Enum.Font.GothamBold
)
Title.Position = UDim2.fromOffset(16, 0)
Title.Size = UDim2.new(1, -80, 1, 0)
Title.TextXAlignment = Enum.TextXAlignment.Left

local Subtitle = makeLabel(
Header,
"ROBLOX CREATOR ASSISTANT",
9,
MUTED,
Enum.Font.Gotham
)
Subtitle.Position = UDim2.new(0, 17, 0, 34)
Subtitle.Size = UDim2.new(1, -80, 0, 14)
Subtitle.TextXAlignment = Enum.TextXAlignment.Left

local Close = makeButton(Header, "×", GRAY)
Close.Size = UDim2.fromOffset(38, 38)
Close.Position = UDim2.new(1, -46, 0, 8)
Close.TextSize = 26

-- Message scrolling area

local Chat = Instance.new("ScrollingFrame")
Chat.Name = "Messages"
Chat.Position = UDim2.fromOffset(10, 62)
Chat.Size = UDim2.new(1, -20, 1, -132)
Chat.BackgroundTransparency = 1
Chat.BorderSizePixel = 0
Chat.ScrollBarThickness = 4
Chat.ScrollBarImageColor3 = BLUE
Chat.AutomaticCanvasSize = Enum.AutomaticSize.Y
Chat.CanvasSize = UDim2.new()
Chat.Parent = Main

local ChatLayout = Instance.new("UIListLayout")
ChatLayout.Padding = UDim.new(0, 12)
ChatLayout.SortOrder = Enum.SortOrder.LayoutOrder
ChatLayout.Parent = Chat

local ChatPadding = Instance.new("UIPadding")
ChatPadding.PaddingTop = UDim.new(0, 5)
ChatPadding.PaddingBottom = UDim.new(0, 12)
ChatPadding.PaddingLeft = UDim.new(0, 3)
ChatPadding.PaddingRight = UDim.new(0, 3)
ChatPadding.Parent = Chat

-- Input area

local InputArea = Instance.new("Frame")
InputArea.Name = "InputArea"
InputArea.Position = UDim2.new(0, 10, 1, -61)
InputArea.Size = UDim2.new(1, -20, 0, 49)
InputArea.BackgroundColor3 = GRAY
InputArea.BorderSizePixel = 0
InputArea.Parent = Main

corner(InputArea, 13)

local Input = Instance.new("TextBox")
Input.Name = "PromptInput"
Input.Position = UDim2.fromOffset(10, 5)
Input.Size = UDim2.new(1, -88, 1, -10)
Input.BackgroundTransparency = 1
Input.Text = ""
Input.PlaceholderText = "Ask AstraR to build something..."
Input.PlaceholderColor3 = MUTED
Input.TextColor3 = WHITE
Input.TextSize = 14
Input.Font = Enum.Font.Gotham
Input.TextXAlignment = Enum.TextXAlignment.Left
Input.ClearTextOnFocus = false
Input.TextWrapped = true
Input.MultiLine = false
Input.Parent = InputArea

local Send = makeButton(InputArea, "Send", BLUE)
Send.Position = UDim2.new(1, -73, 0, 5)
Send.Size = UDim2.fromOffset(67, 39)

local Status = makeLabel(
Main, "● Ready", 10, BLUE, Enum.Font.GothamBold
)
Status.Position = UDim2.new(0, 13, 0, 43)
Status.Size = UDim2.new(1, -100, 0, 14)
Status.TextXAlignment = Enum.TextXAlignment.Left

--========================================================
-- MESSAGE SYSTEM
--========================================================

local messageCount = 0

local function scrollToBottom()
    task.defer(function()
        if not Chat.Parent then
            return
        end
        
        task.wait()
        
        Chat.CanvasPosition = Vector2.new(
        0,
        math.max(
        0,
        Chat.AbsoluteCanvasSize.Y
        - Chat.AbsoluteWindowSize.Y
        )
        )
    end)
end

-- Parse generated code without relying on hard-coded
-- character positions for multibyte emoji.

local function parseGeneratedCode(text)
    local headerPrefix = "📄 "
    local placementPrefix = "📍 Place in: "
    
    if string.sub(text, 1, #headerPrefix) ~= headerPrefix then
        return nil
    end
    
    local firstNewline = string.find(text, "\n", 1, true)
    if not firstNewline then
        return nil
    end
    
    local secondNewline = string.find(
    text,
    "\n",
    firstNewline + 1,
    true
    )
    
    if not secondNewline then
        return nil
    end
    
    local codeTitle = string.sub(
    text,
    #headerPrefix + 1,
    firstNewline - 1
    )
    
    local placementLine = string.sub(
    text,
    firstNewline + 1,
    secondNewline - 1
    )
    
    local placement = placementLine
    
    if string.sub(
        placementLine, 1, #placementPrefix
        ) == placementPrefix then
        placement = string.sub(
        placementLine,
        #placementPrefix + 1
        )
    end
    
    local source = string.sub(text, secondNewline + 1)
    
    -- Remove one leading blank line if present.
    if string.sub(source, 1, 1) == "\n" then
        source = string.sub(source, 2)
    end
    
    return {
    title = codeTitle,
    placement = placement,
    source = source,
    }
end

local function addMessage(text, isUser)
    messageCount += 1
    
    local holder = Instance.new("Frame")
    holder.Name = isUser and "UserMessage" or "AstraRMessage"
    holder.BackgroundTransparency = 1
    holder.Size = UDim2.new(1, -4, 0, 10)
    holder.AutomaticSize = Enum.AutomaticSize.Y
    holder.LayoutOrder = messageCount
    holder.Parent = Chat
    
    -- IMPORTANT:
    -- Only responses with the generated-code header
    -- are displayed as editable code cards.
    
    local parsedCode = nil
    
    if not isUser then
        parsedCode = parseGeneratedCode(text)
    end
    
    local isCode = parsedCode ~= nil
    
    local bubble = Instance.new("Frame")
    bubble.Name = isCode and "GeneratedCodeBubble" or "Bubble"
    bubble.BackgroundColor3 = isUser and BLUE or GRAY
    bubble.BorderSizePixel = 0
    bubble.Size = UDim2.new(0.86, 0, 0, 10)
    bubble.Parent = holder
    
    if isUser then
        bubble.AnchorPoint = Vector2.new(1, 0)
        bubble.Position = UDim2.new(1, 0, 0, 0)
        bubble.AutomaticSize = Enum.AutomaticSize.Y
    elseif isCode then
        bubble.Position = UDim2.fromOffset(0, 0)
        bubble.Size = UDim2.new(0.98, 0, 0, 351)
    else
        bubble.Position = UDim2.fromOffset(0, 0)
        bubble.AutomaticSize = Enum.AutomaticSize.Y
    end
    
    corner(bubble, 14)
    
    if isCode then
        -- Inner padding
        
        local codePadding = Instance.new("UIPadding")
        codePadding.PaddingTop = UDim.new(0, 10)
        codePadding.PaddingBottom = UDim.new(0, 10)
        codePadding.PaddingLeft = UDim.new(0, 10)
        codePadding.PaddingRight = UDim.new(0, 10)
        codePadding.Parent = bubble
        
        -- Script title
        
        local titleLabel = makeLabel(
        bubble,
        "📄 " .. parsedCode.title,
        14,
        WHITE,
        Enum.Font.GothamBold
        )
        
        titleLabel.Size = UDim2.new(1, 0, 0, 22)
        titleLabel.TextXAlignment = Enum.TextXAlignment.Left
        
        -- Script placement
        
        local placementLabel = makeLabel(
        bubble,
        "📍 Place in: " .. parsedCode.placement,
        11,
        MUTED,
        Enum.Font.Gotham
        )
        
        placementLabel.Position = UDim2.fromOffset(0, 25)
        placementLabel.Size = UDim2.new(1, 0, 0, 34)
        placementLabel.TextXAlignment = Enum.TextXAlignment.Left
        placementLabel.TextYAlignment = Enum.TextYAlignment.Top
        
        -- Code section label
        
        local codeTitleLabel = makeLabel(
        bubble,
        "CODE  •  Tap the box to edit or select text",
        11,
        BLUE,
        Enum.Font.GothamBold
        )
        
        codeTitleLabel.Position = UDim2.fromOffset(0, 61)
        codeTitleLabel.Size = UDim2.new(1, 0, 0, 20)
        codeTitleLabel.TextXAlignment = Enum.TextXAlignment.Left
        
        -- REAL EDITABLE TEXTBOX
        -- TextBox text is editable, unlike TextLabel text.
        -- No unsupported clipboard API is used.
        
        local codeBox = Instance.new("TextBox")
        codeBox.Name = "EditableGeneratedCode"
        codeBox.Position = UDim2.fromOffset(0, 85)
        codeBox.Size = UDim2.new(1, 0, 0, 220)
        codeBox.BackgroundColor3 = CODE_BG
        codeBox.BorderSizePixel = 0
        codeBox.Text = parsedCode.source
        codeBox.TextColor3 = Color3.fromRGB(225, 232, 245)
        codeBox.PlaceholderText = ""
        codeBox.TextSize = 12
        codeBox.Font = Enum.Font.Code
        codeBox.TextXAlignment = Enum.TextXAlignment.Left
        codeBox.TextYAlignment = Enum.TextYAlignment.Top
        codeBox.TextWrapped = false
        codeBox.MultiLine = true
        codeBox.ClearTextOnFocus = false
        codeBox.TextEditable = true
        codeBox.Selectable = true
        codeBox.Active = true
        codeBox.ZIndex = 5
        codeBox.Parent = bubble
        
        corner(codeBox, 7)
        stroke(codeBox, Color3.fromRGB(65, 68, 78), 1)
        
        local codePaddingInside = Instance.new("UIPadding")
        codePaddingInside.PaddingTop = UDim.new(0, 8)
        codePaddingInside.PaddingBottom = UDim.new(0, 8)
        codePaddingInside.PaddingLeft = UDim.new(0, 8)
        codePaddingInside.PaddingRight = UDim.new(0, 8)
        codePaddingInside.Parent = codeBox
        
        -- Helpful mobile instructions
        
        local copyHint = makeLabel(
        bubble,
        "Tap the code box to edit. Use your device's text selection menu to copy.",
        10,
        MUTED,
        Enum.Font.Gotham
        )
        
        copyHint.Position = UDim2.new(0, 0, 0, 311)
        copyHint.Size = UDim2.new(1, 0, 0, 30)
        copyHint.TextXAlignment = Enum.TextXAlignment.Left
        copyHint.TextYAlignment = Enum.TextYAlignment.Top
        
        -- Fixed height keeps the message list layout predictable.
        
        bubble.AutomaticSize = Enum.AutomaticSize.None
        holder.AutomaticSize = Enum.AutomaticSize.None
        holder.Size = UDim2.new(1, -4, 0, 351)
    else
        local padding = Instance.new("UIPadding")
        padding.PaddingTop = UDim.new(0, 10)
        padding.PaddingBottom = UDim.new(0, 10)
        padding.PaddingLeft = UDim.new(0, 12)
        padding.PaddingRight = UDim.new(0, 12)
        padding.Parent = bubble
        
        local label = makeLabel(
        bubble,
        text,
        14,
        WHITE,
        Enum.Font.Gotham
        )
        
        label.Size = UDim2.new(1, 0, 0, 10)
        label.AutomaticSize = Enum.AutomaticSize.Y
        label.TextXAlignment = Enum.TextXAlignment.Left
        label.TextYAlignment = Enum.TextYAlignment.Top
    end
    
    scrollToBottom()
end

--========================================================
-- PROMPT NORMALIZATION
--========================================================

local function normalize(text)
    text = string.lower(text)
    text = text:gsub("[%p]", " ")
    text = text:gsub("%s+", " ")
    return text:match("^%s*(.-)%s*$") or ""
end

local function hasAny(text, words)
    for _, word in ipairs(words) do
        if string.find(text, word, 1, true) then
            return true
        end
    end
    
    return false
end

local function generateCode(title, placement, source)
    return "📄 " .. title
    .. "\n📍 Place in: " .. placement
    .. "\n\n" .. source
end

--========================================================
-- BUILT-IN SCRIPT TEMPLATES
--========================================================

local Templates = {}

Templates.KillBrick = [[
-- Kill Brick
-- Place this Script inside the dangerous Part.

local part = script.Parent

part.Touched:Connect(function(hit)
    local character = hit.Parent
    local humanoid = character
    and character:FindFirstChildOfClass("Humanoid")
    
    if humanoid then
        humanoid.Health = 0
    end
end)
]]

Templates.Leaderstats = [[
-- Leaderstats
-- Place this Script in ServerScriptService.

local Players = game:GetService("Players")

Players.PlayerAdded:Connect(function(player)
    local leaderstats = Instance.new("Folder")
    leaderstats.Name = "leaderstats"
    leaderstats.Parent = player
    
    local coins = Instance.new("IntValue")
    coins.Name = "Coins"
    coins.Value = 100
    coins.Parent = leaderstats
    
    local rebirths = Instance.new("IntValue")
    rebirths.Name = "Rebirths"
    rebirths.Value = 0
    rebirths.Parent = leaderstats
end)
]]

Templates.CoinPickup = [[
-- Coin Pickup
-- Make a Part named Coin in Workspace.
-- Place this Script inside that Part.

local Players = game:GetService("Players")
local coin = script.Parent
local available = true
local REWARD = 10

coin.Touched:Connect(function(hit)
    if not available then return end
    
    local character = hit.Parent
    local player = Players:GetPlayerFromCharacter(character)
    if not player then return end
    
    local stats = player:FindFirstChild("leaderstats")
    local coins = stats and stats:FindFirstChild("Coins")
    if not coins then return end
    
    available = false
    coins.Value += REWARD
    coin.Transparency = 1
    coin.CanTouch = false
    coin.CanCollide = false
    
    task.wait(3)
    
    coin.Transparency = 0
    coin.CanTouch = true
    coin.CanCollide = true
    available = true
end)
]]

Templates.Sprint = [[
-- Simple Sprint
-- Place this LocalScript in StarterPlayerScripts.
-- Keyboard controls: Left Shift.

local Players = game:GetService("Players")
local UserInputService = game:GetService("UserInputService")

local player = Players.LocalPlayer
local NORMAL_SPEED = 16
local SPRINT_SPEED = 25

local function setSpeed(speed)
    local character = player.Character
    local humanoid = character
    and character:FindFirstChildOfClass("Humanoid")
    
    if humanoid then
        humanoid.WalkSpeed = speed
    end
end

player.CharacterAdded:Connect(function(character)
    local humanoid = character:WaitForChild("Humanoid")
    humanoid.WalkSpeed = NORMAL_SPEED
end)

UserInputService.InputBegan:Connect(function(input, processed)
    if processed then return end
    
    if input.KeyCode == Enum.KeyCode.LeftShift then
        setSpeed(SPRINT_SPEED)
    end
end)

UserInputService.InputEnded:Connect(function(input)
    if input.KeyCode == Enum.KeyCode.LeftShift then
        setSpeed(NORMAL_SPEED)
    end
end)
]]

Templates.Shop = [[
-- Basic Shop GUI demo
-- Place this LocalScript in StarterPlayerScripts.
-- Visual example only; it does not make real purchases.

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local gui = Instance.new("ScreenGui")
gui.Name = "SimpleShop"
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")

local open = Instance.new("TextButton")
open.Size = UDim2.fromOffset(100, 44)
open.Position = UDim2.new(0, 20, 0.5, -22)
open.Text = "SHOP"
open.TextSize = 18
open.Parent = gui

local panel = Instance.new("Frame")
panel.Size = UDim2.new(0.7, 0, 0.5, 0)
panel.Position = UDim2.new(0.15, 0, 0.25, 0)
panel.BackgroundColor3 = Color3.fromRGB(30, 32, 40)
panel.Visible = false
panel.Parent = gui

local title = Instance.new("TextLabel")
title.Size = UDim2.new(1, 0, 0, 50)
title.BackgroundTransparency = 1
title.Text = "SHOP"
title.TextColor3 = Color3.new(1, 1, 1)
title.TextSize = 24
title.Parent = panel

local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(42, 42)
close.Position = UDim2.new(1, -46, 0, 4)
close.Text = "X"
close.Parent = panel

open.Activated:Connect(function()
    panel.Visible = true
end)

close.Activated:Connect(function()
    panel.Visible = false
end)
]]

Templates.Rebirth = [[
-- Rebirth demonstration
-- Place this LocalScript in StarterPlayerScripts.
-- This is a local UI demo, not secure multiplayer currency logic.

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local gui = Instance.new("ScreenGui")
gui.Name = "RebirthDemo"
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")

local button = Instance.new("TextButton")
button.Size = UDim2.fromOffset(180, 50)
button.Position = UDim2.new(0.5, -90, 0.8, 0)
button.Text = "REBIRTH (DEMO)"
button.TextSize = 18
button.Parent = gui

local rebirths = 0

button.Activated:Connect(function()
    rebirths += 1
    button.Text = "Rebirths: " .. rebirths
end)
]]

Templates.Inventory = [[
-- Basic Inventory GUI demo
-- Place this LocalScript in StarterPlayerScripts.
-- Example inventory entries are local to this client.

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local gui = Instance.new("ScreenGui")
gui.Name = "InventoryDemo"
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")

local open = Instance.new("TextButton")
open.Size = UDim2.fromOffset(120, 44)
open.Position = UDim2.new(0, 20, 0.5, -22)
open.Text = "INVENTORY"
open.Parent = gui

local panel = Instance.new("Frame")
panel.Size = UDim2.new(0.75, 0, 0.5, 0)
panel.Position = UDim2.new(0.125, 0, 0.25, 0)
panel.BackgroundColor3 = Color3.fromRGB(25, 25, 32)
panel.Visible = false
panel.Parent = gui

local list = Instance.new("TextLabel")
list.Size = UDim2.new(1, -20, 1, -20)
list.Position = UDim2.fromOffset(10, 10)
list.BackgroundTransparency = 1
list.TextColor3 = Color3.new(1, 1, 1)
list.TextWrapped = true
list.Text = "YOUR INVENTORY\n\nStarter Item\nExample Item"
list.Parent = panel

open.Activated:Connect(function()
    panel.Visible = not panel.Visible
end)
]]

Templates.Settings = [[
-- Basic Settings GUI demo
-- Place this LocalScript in StarterPlayerScripts.

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local gui = Instance.new("ScreenGui")
gui.Name = "SettingsDemo"
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")

local open = Instance.new("TextButton")
open.Size = UDim2.fromOffset(110, 44)
open.Position = UDim2.new(0, 20, 0.5, -22)
open.Text = "SETTINGS"
open.Parent = gui

local panel = Instance.new("Frame")
panel.Size = UDim2.new(0.75, 0, 0.45, 0)
panel.Position = UDim2.new(0.125, 0, 0.275, 0)
panel.BackgroundColor3 = Color3.fromRGB(25, 25, 32)
panel.Visible = false
panel.Parent = gui

local soundButton = Instance.new("TextButton")
soundButton.Size = UDim2.new(1, -20, 0, 45)
soundButton.Position = UDim2.fromOffset(10, 15)
soundButton.Text = "Sound: ON"
soundButton.Parent = panel

local soundOn = true

soundButton.Activated:Connect(function()
    soundOn = not soundOn
    soundButton.Text = soundOn and "Sound: ON" or "Sound: OFF"
end)

open.Activated:Connect(function()
    panel.Visible = not panel.Visible
end)
]]

Templates.Rewards = [[
-- Daily Reward demo
-- Place this LocalScript in StarterPlayerScripts.
-- Resets when this LocalScript is restarted; not saved.

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local gui = Instance.new("ScreenGui")
gui.Name = "RewardDemo"
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")

local button = Instance.new("TextButton")
button.Size = UDim2.fromOffset(190, 50)
button.Position = UDim2.new(0.5, -95, 0.8, 0)
button.Text = "CLAIM REWARD"
button.Parent = gui

local claimed = false

button.Activated:Connect(function()
    if claimed then return end
    claimed = true
    button.Text = "REWARD CLAIMED!"
end)
]]

Templates.Quest = [[
-- Quest progress demo
-- Place this LocalScript in StarterPlayerScripts.
-- Progress is local and not saved.

local Players = game:GetService("Players")
local player = Players.LocalPlayer

local gui = Instance.new("ScreenGui")
gui.Name = "QuestDemo"
gui.ResetOnSpawn = false
gui.Parent = player:WaitForChild("PlayerGui")

local label = Instance.new("TextLabel")
label.Size = UDim2.fromOffset(260, 60)
label.Position = UDim2.new(0.5, -130, 0.1, 0)
label.BackgroundColor3 = Color3.fromRGB(30, 32, 40)
label.TextColor3 = Color3.new(1, 1, 1)
label.Text = "QUEST: Collect 5 items (0/5)"
label.Parent = gui

local progress = 0

local button = Instance.new("TextButton")
button.Size = UDim2.fromOffset(180, 42)
button.Position = UDim2.new(0.5, -90, 0.1, 65)
button.Text = "Collect Demo Item"
button.Parent = gui

button.Activated:Connect(function()
    if progress >= 5 then return end
    
    progress += 1
    label.Text = "QUEST: Collect 5 items (" .. progress .. "/5)"
    
    if progress >= 5 then
        label.Text = "QUEST COMPLETE!"
    end
end)
]]

--========================================================
-- RESPONSE MATCHING
--========================================================

local function respond(rawPrompt)
    local prompt = normalize(rawPrompt)
    
    if prompt == "" then
        return "Type a question or describe a Roblox feature you want to create."
    end
    
    if hasAny(prompt, {
        "hello", "hi", "hey", "whats up", "what s up"
        }) then
        return "Hey! I'm AstraR. I can show built-in Roblox templates for shops, inventory, settings, rewards, quests, rebirths, coins, sprinting, and kill bricks."
    end
    
    if hasAny(prompt, {
        "who are you", "what are you", "your name"
        }) then
        return "I'm AstraR, a built-in Roblox creation assistant. I use local rules and script templates rather than a connected AI model."
    end
    
    if hasAny(prompt, {
        "what can you do", "examples", "commands", "help me"
        }) then
        return "Try prompts like:\n• Make a kill brick\n• Create leaderstats coins\n• Make a coin pickup\n• Add sprint\n• Create a shop GUI\n• Make a rebirth demo\n• Create an inventory GUI\n• Make settings\n• Create a reward button\n• Make a quest system\n\nYou can phrase these in different ways."
    end
    
    if hasAny(prompt, {
        "kill brick", "killbrick", "lava", "kills you",
        "damage brick", "touch it and die", "deadly part",
        "dangerous part"
        }) then
        return generateCode(
        "Kill Brick Script",
        "Inside the dangerous Part in Workspace",
        Templates.KillBrick
        )
    end
    
    if hasAny(prompt, {
        "leaderstats", "leaderboard", "leader board",
        "player stats", "coins stat"
        }) then
        return generateCode(
        "Leaderstats",
        "ServerScriptService",
        Templates.Leaderstats
        )
    end
    
    if hasAny(prompt, {
        "coin pickup", "collect coins", "coin collecting",
        "collect a coin", "pick up coins", "touch a coin",
        "coin part", "coin when touched"
        }) then
        return generateCode(
        "Coin Pickup",
        "Inside a Part named Coin in Workspace",
        Templates.CoinPickup
        )
    end
    
    if hasAny(prompt, {
        "sprint", "run faster", "running", "shift to run",
        "speed key", "faster when"
        }) then
        return generateCode(
        "Sprint System",
        "StarterPlayer > StarterPlayerScripts",
        Templates.Sprint
        )
    end
    
    if hasAny(prompt, {
        "rebirth", "rebirth system", "rebirth button",
        "reset for rewards", "rebirths"
        }) then
        return generateCode(
        "Rebirth Demo",
        "StarterPlayer > StarterPlayerScripts",
        Templates.Rebirth
        )
    end
    
    if hasAny(prompt, {
        "inventory", "item bag", "items menu", "my items"
        }) then
        return generateCode(
        "Inventory GUI Demo",
        "StarterPlayer > StarterPlayerScripts",
        Templates.Inventory
        )
    end
    
    if hasAny(prompt, {
        "settings", "settings menu", "sound toggle",
        "sound button", "options menu"
        }) then
        return generateCode(
        "Settings GUI Demo",
        "StarterPlayer > StarterPlayerScripts",
        Templates.Settings
        )
    end
    
    if hasAny(prompt, {
        "daily reward", "claim reward", "reward button",
        "free reward", "rewards menu"
        }) then
        return generateCode(
        "Reward Demo",
        "StarterPlayer > StarterPlayerScripts",
        Templates.Rewards
        )
    end
    
    if hasAny(prompt, {
        "quest", "quest system", "quest progress",
        "mission system", "missions"
        }) then
        return generateCode(
        "Quest Progress Demo",
        "StarterPlayer > StarterPlayerScripts",
        Templates.Quest
        )
    end
    
    if hasAny(prompt, {
        "shop", "store gui", "shop gui", "buy menu",
        "purchase menu", "store menu"
        }) then
        return generateCode(
        "Shop GUI Starter",
        "StarterPlayer > StarterPlayerScripts",
        Templates.Shop
        )
    end
    
    if hasAny(prompt, {
        "gui", "interface", "button", "menu", "screen"
        }) then
        return "I think you're asking for a Roblox GUI. I have built-in examples for a shop, inventory, settings, rewards, and quests. Try describing which one you want."
    end
    
    if hasAny(prompt, {
        "script", "code", "roblox", "build", "make",
        "create", "add", "system", "game", "part"
        }) then
        return "I couldn't match that request to a built-in template yet. I currently support kill bricks, leaderstats, coin pickups, sprint, shops, rebirth demos, inventory, settings, rewards, and quests. This offline version cannot intelligently invent unlimited new scripts."
    end
    
    return "I'm not sure how to answer that yet. I'm an offline, rule-based assistant, so I use the knowledge built into this script. Try asking for a shop, inventory, settings, rewards, quests, coins, sprint, or a kill brick."
end

--========================================================
-- SEND MESSAGE
--========================================================

local busy = false

local function sendMessage()
    if busy then
        return
    end
    
    local message = Input.Text
    
    if not message or message:match("^%s*$") then
        return
    end
    
    busy = true
    Send.Active = false
    Status.Text = "● Working..."
    Status.TextColor3 = BLUE
    
    Input.Text = ""
    addMessage(message, true)
    
    local success, reply = pcall(function()
        return respond(message)
    end)
    
    if success then
        addMessage(reply, false)
    else
        addMessage(
        "Something went wrong while processing that prompt. Please try again.",
        false
        )
        
        warn("AstraR response error:", reply)
    end
    
    Status.Text = "● Ready"
    Status.TextColor3 = BLUE
    Send.Active = true
    busy = false
end

Send.Activated:Connect(sendMessage)

Input.FocusLost:Connect(function(enterPressed)
    if enterPressed then
        sendMessage()
    end
end)

--========================================================
-- INSTANT OPEN AND CLOSE
-- No tweens, fades, resizing, or hover animations.
--========================================================

local function openChat()
    if Main.Visible then
        return
    end
    
    Main.BackgroundTransparency = 0
    Main.Visible = true
    Launcher.Visible = false
end

local function closeChat()
    if not Main.Visible then
        return
    end
    
    Main.Visible = false
    Main.BackgroundTransparency = 0
    Launcher.Visible = true
end

Launcher.Activated:Connect(openChat)
Close.Activated:Connect(closeChat)

--========================================================
-- WELCOME MESSAGE
--========================================================

addMessage(
"Hi! I'm AstraR. Ask me for a Roblox shop, inventory, settings, rewards, quests, leaderstats, coin pickup, sprint system, rebirth demo, or kill brick. I use built-in offline templates.",
false
)

print("AstraR v5.2 loaded. Code detection fixed; editable code boxes enabled; animations removed.")

31,294 chars · codepastes.com