local Players=game:GetService("Players") local TweenService=game:GetService("TweenService") local RunService=game:GetService("RunService") local UIS=game:GetService("UserInputService") local player=Players.LocalPlayer local backpack=player:WaitForChild("Backpack") local GREEN=Color3.fromRGB(45,255,90) local LIGHT_GREEN=Color3.fromRGB(150,255,170) local BODY=Color3.fromRGB(150,150,145) local DARK=Color3.fromRGB(55,57,55) local GUN_SCALE=.45 -- Portal entry cooldown local PORTAL_COOLDOWN=1 local portalCooldown=false local portals={Portal1=nil,Portal2=nil} local connections={Portal1=nil,Portal2=nil} local selectedPortal="Portal1" local gunConnection=nil local gunEquipped=false local function removePortal(name) if connections[name] then connections[name]:Disconnect() connections[name]=nil end if portals[name] then portals[name]:Destroy() portals[name]=nil end end local function createPortal(name,pos) local character=player.Character if not character then return end local camera=workspace.CurrentCamera if not camera then return end local ray=camera:ViewportPointToRay(pos.X,pos.Y) local params=RaycastParams.new() params.FilterType=Enum.RaycastFilterType.Exclude params.FilterDescendantsInstances={character} local hit=workspace:Raycast( ray.Origin, ray.Direction*1000, params ) if not hit then return end removePortal(name) local position=hit.Position local normal=hit.Normal local up=Vector3.yAxis if math.abs(normal:Dot(up))>.95 then up=Vector3.xAxis end local portalCFrame=CFrame.lookAt( position+normal*.05, position+normal, up ) local model=Instance.new("Model") model.Name=name model.Parent=workspace portals[name]=model local portal=Instance.new("Part") portal.Name="Portal" portal.Size=Vector3.new(7,10,.4) portal.CFrame=portalCFrame portal.Color=GREEN portal.Material=Enum.Material.Neon portal.Transparency=.25 portal.Anchored=true portal.CanCollide=false portal.CanTouch=true portal.CanQuery=false portal.Parent=model local mesh=Instance.new("SpecialMesh") mesh.MeshType=Enum.MeshType.Sphere mesh.Scale=Vector3.new(.55,1,.07) mesh.Parent=portal local inner=Instance.new("Part") inner.Name="PortalCore" inner.Size=Vector3.new(6.2,9.2,.15) inner.CFrame=portalCFrame*CFrame.new(0,0,-.12) inner.Color=LIGHT_GREEN inner.Material=Enum.Material.Neon inner.Transparency=.35 inner.Anchored=true inner.CanCollide=false inner.CanTouch=false inner.CanQuery=false inner.Parent=model local innerMesh=Instance.new("SpecialMesh") innerMesh.MeshType=Enum.MeshType.Sphere innerMesh.Scale=Vector3.new(.55,1,.05) innerMesh.Parent=inner local light=Instance.new("PointLight") light.Color=GREEN light.Brightness=8 light.Range=18 light.Parent=portal local attachment=Instance.new("Attachment") attachment.Parent=portal local particles=Instance.new("ParticleEmitter") particles.Color=ColorSequence.new(GREEN) particles.LightEmission=1 particles.LightInfluence=0 particles.Rate=120 particles.Lifetime=NumberRange.new(.4,1) particles.Speed=NumberRange.new(1,4) particles.SpreadAngle=Vector2.new(180,180) particles.Size=NumberSequence.new{ NumberSequenceKeypoint.new(0,.2), NumberSequenceKeypoint.new(.5,.08), NumberSequenceKeypoint.new(1,0) } particles.Parent=attachment for i=1,4 do local ring=Instance.new("Part") ring.Name="EnergyRing" ring.Shape=Enum.PartType.Cylinder ring.Size=Vector3.new(.08,6+i*.55,6+i*.55) ring.CFrame= portalCFrame* CFrame.Angles( math.rad(90), 0, math.rad(i*45) ) ring.Color=GREEN ring.Material=Enum.Material.Neon ring.Transparency=.3 ring.Anchored=true ring.CanCollide=false ring.CanTouch=false ring.CanQuery=false ring.Parent=model end local start=os.clock() connections[name]=RunService.RenderStepped:Connect(function() if not model.Parent then return end local elapsed=os.clock()-start local pulse=1+math.sin(elapsed*5)*.06 portal.Size=Vector3.new(7,10,.4)*pulse local index=0 for _,object in ipairs(model:GetChildren()) do if object.Name=="EnergyRing" then index+=1 object.CFrame= portal.CFrame* CFrame.Angles( math.rad(90), elapsed*(index*.8), math.rad(index*45) ) end end end) portal.Touched:Connect(function(hitPart) -- 1 second global portal cooldown if portalCooldown then return end if not hitPart:IsDescendantOf(character) then return end local destination= name=="Portal1" and "Portal2" or "Portal1" local destinationModel=portals[destination] if not destinationModel then return end local destinationPortal= destinationModel:FindFirstChild("Portal") if not destinationPortal then return end local root= character:FindFirstChild("HumanoidRootPart") if not root then return end portalCooldown=true -- Small delay before teleport task.wait(.15) -- Teleport through the destination portal root.CFrame= destinationPortal.CFrame* CFrame.new(0,0,-4) -- Keep the player upright local position=root.Position root.CFrame=CFrame.new(position)*CFrame.Angles( 0, math.rad(root.Orientation.Y), 0 ) root.AssemblyLinearVelocity=Vector3.zero root.AssemblyAngularVelocity=Vector3.zero -- 1 second cooldown task.wait(PORTAL_COOLDOWN) portalCooldown=false end) -- Infinite portal lifetime end local function makePart(parent,name,size,color,material,cframe) local part=Instance.new("Part") part.Name=name part.Size=size part.Color=color part.Material=material part.CFrame=cframe part.CanCollide=false part.CanTouch=false part.CanQuery=false part.Massless=true part.CastShadow=false part.Parent=parent return part end local function weldPart(part,handle) local weld=Instance.new("WeldConstraint") weld.Part0=handle weld.Part1=part weld.Parent=part end local function createPortalGun() local tool=Instance.new("Tool") tool.Name="Portal Gun" tool.RequiresHandle=true tool.CanBeDropped=false tool.ToolTip="Tap/click a surface to place a portal" local handle=Instance.new("Part") handle.Name="Handle" handle.Size=Vector3.new(.72,2.35,.72) handle.Color=DARK handle.Material=Enum.Material.SmoothPlastic handle.CanCollide=false handle.CanTouch=false handle.CanQuery=false handle.Massless=true handle.CastShadow=false handle.Parent=tool -- Grip: 0, 90, 0 tool.Grip= CFrame.new(0,0,0)* CFrame.Angles( 0, math.rad(90), 0 ) local body=makePart( tool, "MainBody", Vector3.new(3.6,.75,2.1), BODY, Enum.Material.SmoothPlastic, handle.CFrame*CFrame.new(-1.55,1.4,0) ) weldPart(body,handle) local bottom=makePart( tool, "BottomBody", Vector3.new(3.25,.18,1.8), Color3.fromRGB(90,92,90), Enum.Material.SmoothPlastic, handle.CFrame*CFrame.new(-1.55,.97,0) ) weldPart(bottom,handle) local front=makePart( tool, "FrontPanel", Vector3.new(.15,.62,1.75), Color3.fromRGB(65,67,65), Enum.Material.SmoothPlastic, handle.CFrame*CFrame.new(-3.37,1.4,0) ) weldPart(front,handle) for i=-1,1 do local emitter=Instance.new("Part") emitter.Name="GreenEmitter" emitter.Shape=Enum.PartType.Cylinder emitter.Size=Vector3.new(.16,.43,.43) emitter.Color=GREEN emitter.Material=Enum.Material.Neon emitter.CanCollide=false emitter.CanTouch=false emitter.CanQuery=false emitter.Massless=true emitter.CFrame= handle.CFrame* CFrame.new(-3.46,1.4,i*.55)* CFrame.Angles( 0, math.rad(90), 0 ) emitter.Parent=tool weldPart(emitter,handle) local light=Instance.new("PointLight") light.Color=GREEN light.Brightness=1.5 light.Range=4 light.Parent=emitter end local top=makePart( tool, "TopPlate", Vector3.new(2.9,.12,1.75), Color3.fromRGB(170,170,165), Enum.Material.SmoothPlastic, handle.CFrame*CFrame.new(-1.4,1.83,0) ) weldPart(top,handle) local red=makePart( tool, "RedPanel", Vector3.new(.9,.08,.62), Color3.fromRGB(210,45,45), Enum.Material.Neon, handle.CFrame*CFrame.new(-.65,1.93,0) ) weldPart(red,handle) local chamber=Instance.new("Part") chamber.Name="EnergyGlass" chamber.Shape=Enum.PartType.Cylinder chamber.Size=Vector3.new(1.75,1.35,1.35) chamber.Color=Color3.fromRGB(170,255,190) chamber.Material=Enum.Material.Glass chamber.Transparency=.48 chamber.Reflectance=.08 chamber.CanCollide=false chamber.CanTouch=false chamber.CanQuery=false chamber.Massless=true chamber.CFrame= handle.CFrame* CFrame.new(-2.2,2.95,0)* CFrame.Angles( 0, 0, math.rad(90) ) chamber.Parent=tool weldPart(chamber,handle) local chamberTop=Instance.new("Part") chamberTop.Name="GlassTop" chamberTop.Shape=Enum.PartType.Cylinder chamberTop.Size=Vector3.new(.22,1.35,1.35) chamberTop.Color=Color3.fromRGB(180,180,175) chamberTop.Material=Enum.Material.SmoothPlastic chamberTop.CanCollide=false chamberTop.CanTouch=false chamberTop.CanQuery=false chamberTop.Massless=true chamberTop.CFrame= handle.CFrame* CFrame.new(-2.2,3.82,0)* CFrame.Angles( 0, 0, math.rad(90) ) chamberTop.Parent=tool weldPart(chamberTop,handle) local core=Instance.new("Part") core.Name="PortalCore" core.Shape=Enum.PartType.Ball core.Size=Vector3.new(.65,.85,.65) core.Color=GREEN core.Material=Enum.Material.Neon core.Transparency=.08 core.CanCollide=false core.CanTouch=false core.CanQuery=false core.Massless=true core.CFrame= handle.CFrame* CFrame.new(-2.2,2.97,0) core.Parent=tool weldPart(core,handle) local coreLight=Instance.new("PointLight") coreLight.Color=GREEN coreLight.Brightness=3 coreLight.Range=7 coreLight.Parent=core local coreAttachment=Instance.new("Attachment") coreAttachment.Parent=core local coreParticles=Instance.new("ParticleEmitter") coreParticles.Color=ColorSequence.new(GREEN) coreParticles.LightEmission=1 coreParticles.LightInfluence=0 coreParticles.Rate=18 coreParticles.Lifetime=NumberRange.new(.3,.7) coreParticles.Speed=NumberRange.new(.2,.8) coreParticles.SpreadAngle=Vector2.new(180,180) coreParticles.Size=NumberSequence.new{ NumberSequenceKeypoint.new(0,.09), NumberSequenceKeypoint.new(1,0) } coreParticles.Parent=coreAttachment local gripBottom=makePart( tool, "GripBottom", Vector3.new(.82,.65,.82), Color3.fromRGB(48,50,48), Enum.Material.SmoothPlastic, handle.CFrame* CFrame.new(.35,-1,0)* CFrame.Angles( 0, 0, math.rad(-18) ) ) weldPart(gripBottom,handle) local gripTop=makePart( tool, "GripTop", Vector3.new(.85,.75,.85), DARK, Enum.Material.SmoothPlastic, handle.CFrame* CFrame.new(-.4,.8,0)* CFrame.Angles( 0, 0, math.rad(-18) ) ) weldPart(gripTop,handle) local gripInsert=makePart( tool, "GripInsert", Vector3.new(.5,1.7,.75), Color3.fromRGB(35,37,35), Enum.Material.SmoothPlastic, handle.CFrame* CFrame.new(.02,0,-.38)* CFrame.Angles( 0, 0, math.rad(-18) ) ) weldPart(gripInsert,handle) local gripLight=makePart( tool, "GripLight", Vector3.new(.08,1.1,.2), GREEN, Enum.Material.Neon, handle.CFrame* CFrame.new(-.35,.1,-.43)* CFrame.Angles( 0, 0, math.rad(-18) ) ) weldPart(gripLight,handle) -- Scale the complete gun to 45% local parts={} for _,obj in ipairs(tool:GetChildren()) do if obj:IsA("BasePart") then table.insert(parts,obj) end end for _,part in ipairs(parts) do if part~=handle then local relative= handle.CFrame:ToObjectSpace(part.CFrame) local p= relative.Position*GUN_SCALE part.Size= part.Size*GUN_SCALE part.CFrame= handle.CFrame* CFrame.new(p)* CFrame.fromMatrix( Vector3.zero, relative.XVector, relative.YVector, relative.ZVector ) end end handle.Size= handle.Size*GUN_SCALE tool.Equipped:Connect(function() gunEquipped=true if gunConnection then gunConnection:Disconnect() end gunConnection= RunService.RenderStepped:Connect(function() if not core.Parent then return end local pulse= 1+math.sin(os.clock()*5)*.12 core.Size= Vector3.new(.65,.85,.65)* GUN_SCALE* pulse coreLight.Brightness= 3+math.sin(os.clock()*5) end) end) tool.Unequipped:Connect(function() gunEquipped=false if gunConnection then gunConnection:Disconnect() gunConnection=nil end end) tool.Parent=backpack end UIS.InputBegan:Connect(function(input,processed) if processed or not gunEquipped then return end local valid= input.UserInputType==Enum.UserInputType.MouseButton1 or input.UserInputType==Enum.UserInputType.Touch if not valid then return end local position= Vector2.new( input.Position.X, input.Position.Y ) createPortal( selectedPortal, position ) selectedPortal= selectedPortal=="Portal1" and "Portal2" or "Portal1" end) local function setup() local old= backpack:FindFirstChild("Portal Gun") if old then old:Destroy() end local character= player.Character if character then local equipped= character:FindFirstChild("Portal Gun") if equipped then equipped:Destroy() end end createPortalGun() end setup() player.CharacterAdded:Connect(function() removePortal("Portal1") removePortal("Portal2") gunEquipped=false portalCooldown=false task.wait(1) setup() end)