diff --git a/Assets/Resources/LuaScriptExamples/PointerScript.Spirograph.lua b/Assets/Resources/LuaScriptExamples/PointerScript.Spirograph.lua new file mode 100644 index 0000000000..b032d9ec00 --- /dev/null +++ b/Assets/Resources/LuaScriptExamples/PointerScript.Spirograph.lua @@ -0,0 +1,22 @@ +Settings = { + description="Draws a spirograph pattern around the pointer." +} + +Parameters = { + outerRadius={label="Outer Radius", type="float", min=0.1, max=5, default=2}, + innerRadius={label="Inner Radius", type="float", min=0.1, max=5, default=1}, + penOffset={label="Pen Offset", type="float", min=0.1, max=5, default=1}, + speed={label="Speed", type="float", min=0.1, max=10, default=2}, +} + +function Main() + local t = App.time * Parameters.speed + local outerAngle = t + local innerAngle = t * Parameters.outerRadius / Parameters.innerRadius + + local x = (Parameters.outerRadius - Parameters.innerRadius) * Math:Cos(outerAngle) + Parameters.penOffset * Math:Cos(innerAngle) + local y = (Parameters.outerRadius - Parameters.innerRadius) * Math:Sin(outerAngle) - Parameters.penOffset * Math:Sin(innerAngle) + + local position = Vector2:New(x, y):OnZ() -- Convert 2D to 3D on the Z plane + return Transform:New(position) +end diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.RandomIcon.lua.meta b/Assets/Resources/LuaScriptExamples/PointerScript.Spirograph.lua.meta similarity index 86% rename from Assets/Resources/LuaScriptExamples/ToolScript.RandomIcon.lua.meta rename to Assets/Resources/LuaScriptExamples/PointerScript.Spirograph.lua.meta index 260fe131ef..54d1816150 100644 --- a/Assets/Resources/LuaScriptExamples/ToolScript.RandomIcon.lua.meta +++ b/Assets/Resources/LuaScriptExamples/PointerScript.Spirograph.lua.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 80781d49520c25e4c8fa58a9fa0b14bf +guid: 7c2e7ef0bac2e7c4082ead745cecd7a9 ScriptedImporter: internalIDToNameTable: [] externalObjects: {} diff --git a/Assets/Resources/LuaScriptExamples/SymmetryScript.PointSymSpin.lua b/Assets/Resources/LuaScriptExamples/SymmetryScript.PointSymSpin.lua new file mode 100644 index 0000000000..49dad458b8 --- /dev/null +++ b/Assets/Resources/LuaScriptExamples/SymmetryScript.PointSymSpin.lua @@ -0,0 +1,38 @@ +Settings = { + description="Point Symmetry Spin", space="widget" +} + +Parameters = { + symType={label="Symmetry Type", type=SymmetryPointType}, + symOrder={label="Symmetry Order", type="int", min=1, max=10, default=6}, + frequency={label="Frequency", type="float", min=0.01, max=10, default=5}, + size={label="Size", type="float", min=1, max=10, default=1}, +} + +symmetryHueShift = require "symmetryHueShift" + +function Start() + initialHsv = Brush.colorHsv +end + +function Main() + + mySymSettings = SymmetrySettings:NewPointSymmetry(Parameters.symType, Parameters.symOrder) + pointers = mySymSettings.matrices + + if Brush.triggerPressedThisFrame then + symmetryHueShift.generate(pointers.count, initialHsv) + end + + -- Rotate each matrix around the origin based on the current time + tx = Math:Cos(App.time * Parameters.frequency) * Parameters.size + ty = Math:Sin(App.time * Parameters.frequency) * Parameters.size + for i = 0, pointers.count - 1 do + pointers[i] = pointers[i] * Matrix:NewTranslation(Vector3:New(tx, ty, 0)) + end + return pointers +end + +function End() + -- TODO fix Brush.colorHsv = initialHsv +end diff --git a/Assets/Resources/LuaScriptExamples/SymmetryScript.AlongStroke.lua.meta b/Assets/Resources/LuaScriptExamples/SymmetryScript.PointSymSpin.lua.meta similarity index 86% rename from Assets/Resources/LuaScriptExamples/SymmetryScript.AlongStroke.lua.meta rename to Assets/Resources/LuaScriptExamples/SymmetryScript.PointSymSpin.lua.meta index c30431f063..ae90c29228 100644 --- a/Assets/Resources/LuaScriptExamples/SymmetryScript.AlongStroke.lua.meta +++ b/Assets/Resources/LuaScriptExamples/SymmetryScript.PointSymSpin.lua.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: dd430489d51c4644f978e009ad984a17 +guid: 755110f33e88f884dafee69d9cb67873 ScriptedImporter: internalIDToNameTable: [] externalObjects: {} diff --git a/Assets/Resources/LuaScriptExamples/SymmetryScript.AlongStroke.lua b/Assets/Resources/LuaScriptExamples/SymmetryScript.StrokePoints.lua similarity index 82% rename from Assets/Resources/LuaScriptExamples/SymmetryScript.AlongStroke.lua rename to Assets/Resources/LuaScriptExamples/SymmetryScript.StrokePoints.lua index fd95eae0bd..1f0fa638c3 100644 --- a/Assets/Resources/LuaScriptExamples/SymmetryScript.AlongStroke.lua +++ b/Assets/Resources/LuaScriptExamples/SymmetryScript.StrokePoints.lua @@ -1,39 +1,42 @@ -Settings = {space="pointer"} - -Parameters = { - copies={label="Copies", type="int", min=1, max=96, default=32}, -} - -symmetryHueShift = require "symmetryHueShift" - -function Start() - initialHsv = Brush.colorHsv - stroke = Sketch.strokes.last - updatePath() -end - -function Main() - - -- Update the path only when we change the number of copies - if Parameters.copies ~= previousCopies then - updatePath() - previousCopies = Parameters.copies - end - - return path - -end - -function updatePath() - - if stroke == nil then - App:Error("Please draw a stroke and then restart this plugin") - path = Path:New() - else - path = stroke.path - path:SampleByCount(Parameters.copies) - path:Center() - symmetryHueShift.generate(Parameters.copies, initialHsv) - end - -end +Settings = { + space="pointer", + description="Uses the points of the most recently drawn stroke to generate new strokes" +} + +Parameters = { + copies={label="Copies", type="int", min=1, max=96, default=32}, +} + +symmetryHueShift = require "symmetryHueShift" + +function Start() + initialHsv = Brush.colorHsv + stroke = Sketch.strokes.last + updatePath() +end + +function Main() + + -- Update the path only when we change the number of copies + if Parameters.copies ~= previousCopies then + updatePath() + previousCopies = Parameters.copies + end + + return path + +end + +function updatePath() + + if stroke == nil then + App:Error("Please draw a stroke and then restart this plugin") + path = Path:New() + else + path = stroke.path + path:SampleByCount(Parameters.copies) + path:Center() + symmetryHueShift.generate(Parameters.copies, initialHsv) + end + +end diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.CircularPath.lua.meta b/Assets/Resources/LuaScriptExamples/SymmetryScript.StrokePoints.lua.meta similarity index 86% rename from Assets/Resources/LuaScriptExamples/ToolScript.CircularPath.lua.meta rename to Assets/Resources/LuaScriptExamples/SymmetryScript.StrokePoints.lua.meta index ca9a986d98..ae21322235 100644 --- a/Assets/Resources/LuaScriptExamples/ToolScript.CircularPath.lua.meta +++ b/Assets/Resources/LuaScriptExamples/SymmetryScript.StrokePoints.lua.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: af717669ecb7c6f47abae70a5fab2408 +guid: e28cab510bba93b43a902b6496952864 ScriptedImporter: internalIDToNameTable: [] externalObjects: {} diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.CircularPath.lua b/Assets/Resources/LuaScriptExamples/ToolScript.CircularPath.lua deleted file mode 100644 index 305d38568d..0000000000 --- a/Assets/Resources/LuaScriptExamples/ToolScript.CircularPath.lua +++ /dev/null @@ -1,41 +0,0 @@ -Settings = { - description="Draws a circular camera path", - previewType="quad", previewAxis="y" -} - -Parameters = { - sides = {label="Sides", type="float", min=3, max=16, default=4}, -} - -function Main() - if Brush.triggerReleasedThisFrame then - - -- Create the camera path in one go by passing in a list of transforms - path = Path:New() - radius = Tool.vector.magnitude - angle = 360.0 / Parameters.sides - for a = 0, 360 - angle, angle do - position2d = Vector2:PointOnCircle(a) * radius - rotation = Rotation:New(0, -a, 0) - path:Insert(Transform:New(position2d:OnY(), rotation, ((Math.pi * 0.5) / Parameters.sides) * radius)) - end - path:TransformBy(Transform:New(Tool.startPoint.position, Tool.rotation)); - CameraPath:FromPath(path, true) - - ---- Create the camera path knot by knot - -- This code is here as an example and therefore has been commented out - --radius = Tool.vector.magnitude - --cameraPath = CameraPath:New() - --angle = 30 - --for a = 0, 360 - angle, angle do - -- position = Vector2:PointOnCircle(a):Multiply(radius):OnY() - -- rotation = Rotation:New(0, -a, 0) - -- cameraPath:Extend(position, rotation, 0.75 * radius) - --end - --cameraPath:Loop() - --cameraPath.transform = Transform:New(Tool.startPoint.position, Tool.rotation) - --cameraPath.active = true - - end -end - diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.Platonic.lua b/Assets/Resources/LuaScriptExamples/ToolScript.Platonic.lua new file mode 100644 index 0000000000..1e05af9a7e --- /dev/null +++ b/Assets/Resources/LuaScriptExamples/ToolScript.Platonic.lua @@ -0,0 +1,171 @@ +Settings = { + description = "Draws the wireframe of a chosen Platonic solid", + previewType = "cube" +} + +Parameters = { + solidType = { + label = "Solid Type", + type = "list", + items= {"Tetrahedron", "Cube", "Octahedron", "Dodecahedron", "Icosahedron"}, + default = "Icosahedron" + }, + spacing = {label="Point Spacing", type="float", min=0.1, max=1, default=0.1} +} + +-- Helper function to get vertices and faces of Platonic solids +function GetPlatonicSolidData(solidType) + local vertices = {} + local faces = {} + + if solidType == "Tetrahedron" then + vertices = { + Vector3:New(1, 1, 1), Vector3:New(-1, -1, 1), + Vector3:New(-1, 1, -1), Vector3:New(1, -1, -1) + } + faces = { + {1, 2, 3}, {1, 2, 4}, {1, 3, 4}, {2, 3, 4} + } + elseif solidType == "Cube" then + vertices = { + Vector3:New(-1, -1, -1), Vector3:New(1, -1, -1), + Vector3:New(1, 1, -1), Vector3:New(-1, 1, -1), + Vector3:New(-1, -1, 1), Vector3:New(1, -1, 1), + Vector3:New(1, 1, 1), Vector3:New(-1, 1, 1) + } + faces = { + {1, 2, 3, 4}, {5, 6, 7, 8}, {1, 2, 6, 5}, + {2, 3, 7, 6}, {3, 4, 8, 7}, {4, 1, 5, 8} + } + elseif solidType == "Octahedron" then + + vertices = { + Vector3:New(0, 0, 1), Vector3:New(0, 0, -1), + Vector3:New(1, 0, 0), Vector3:New(-1, 0, 0), + Vector3:New(0, 1, 0), Vector3:New(0, -1, 0) + } + faces = { + {1, 3, 5}, {1, 5, 4}, {1, 4, 6}, {1, 6, 3}, + {2, 3, 5}, {2, 5, 4}, {2, 4, 6}, {2, 6, 3} + } + + elseif solidType == "Dodecahedron" then + + local root5 = Math:Sqrt(5); + local phi = (1 + root5) / 2; + local phibar = (1 - root5) / 2; + local X = 1/(root5-1); + local Y = X*phi; + local Z = X*phibar; + local S = -X; + local T = -Y; + local W = -Z; + + vertices = { + Vector3:New(X, X, X), + Vector3:New(X, X, S), + Vector3:New(X, S, X), + Vector3:New(X, S, S), + Vector3:New(S, X, X), + Vector3:New(S, X, S), + Vector3:New(S, S, X), + Vector3:New(S, S, S), + Vector3:New(W, Y, 0), + Vector3:New(Z, Y, 0), + Vector3:New(W, T, 0), + Vector3:New(Z, T, 0), + Vector3:New(Y, 0, W), + Vector3:New(Y, 0, Z), + Vector3:New(T, 0, W), + Vector3:New(T, 0, Z), + Vector3:New(0, W, Y), + Vector3:New(0, Z, Y), + Vector3:New(0, W, T), + Vector3:New(0, Z, T), + } + + faces = { + {2, 9, 1, 13, 14}, + {5, 10, 6, 16, 15}, + {3, 11, 4, 14, 13}, + {8, 12, 7, 15, 16}, + {3, 13, 1, 17, 18}, + {2, 14, 4, 20, 19}, + {5, 15, 7, 18, 17}, + {8, 16, 6, 19, 20}, + {5, 17, 1, 9, 10}, + {3, 18, 7, 12, 11}, + {2, 19, 6, 10, 9}, + {8, 20, 4, 11, 12} + } + + elseif solidType == "Icosahedron" then + + local root5 = Math:Sqrt(5); + local n = 1/2; + local X = n * (1 + root5) / 2; + local Y = -X; + local Z = n; + local W = -n; + + vertices = { + Vector3:New(X, Z, 0), + Vector3:New(Y, Z, 0), + Vector3:New(X, W, 0), + Vector3:New(Y, W, 0), + Vector3:New(Z, 0, X), + Vector3:New(Z, 0, Y), + Vector3:New(W, 0, X), + Vector3:New(W, 0, Y), + Vector3:New(0, X, Z), + Vector3:New(0, Y, Z), + Vector3:New(0, X, W), + Vector3:New(0, Y, W), + } + + faces = { + {1, 9, 5}, + {1, 6, 11}, + {3, 5, 10}, + {3, 12, 6}, + {2, 7, 9}, + {2, 11, 8}, + {4, 10, 7}, + {4, 8, 12}, + {1, 11, 9}, + {2, 9, 11}, + {3, 10, 12}, + {4, 12, 10}, + {5, 3, 1}, + {6, 1, 3}, + {7, 2, 4}, + {8, 4, 2}, + {9, 7, 5}, + {10, 5, 7}, + {11, 6, 8}, + {12, 8, 6} + } + + end + + return vertices, faces +end + +function Main() + if Brush.triggerReleasedThisFrame then + local vertices, faces = GetPlatonicSolidData(Parameters.solidType) + local pathList = PathList:New() + + for _, face in ipairs(faces) do + local path = Path:New() + for _, vertexIndex in ipairs(face) do + path:Insert(Transform:New(vertices[vertexIndex])) + end + path:Insert(Transform:New(vertices[face[1]])) -- Close the loop + path:SampleByDistance(Parameters.spacing) -- Create evenly spaced points + pathList:Insert(path) + end + + return pathList + end +end diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.Platonic.lua.meta b/Assets/Resources/LuaScriptExamples/ToolScript.Platonic.lua.meta new file mode 100644 index 0000000000..cbf15202b3 --- /dev/null +++ b/Assets/Resources/LuaScriptExamples/ToolScript.Platonic.lua.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: e8e7026d52fee15408b9c20551d0b248 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 2d1920d65e755cf4f98a93b4a4e952e5, type: 3} diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.RandomAvatar.lua b/Assets/Resources/LuaScriptExamples/ToolScript.RandomAvatar.lua index 01a43ffccc..39de584214 100644 --- a/Assets/Resources/LuaScriptExamples/ToolScript.RandomAvatar.lua +++ b/Assets/Resources/LuaScriptExamples/ToolScript.RandomAvatar.lua @@ -1,29 +1,34 @@ -Settings = { - description="Calls an API to generate a random SVG icon using the Multiavatar library", - previewType="quad" -} - -function Start() - requestNewAvatar() -end - -function Main() - if Brush.triggerReleasedThisFrame then - requestNewAvatar() - if svg ~= nil then - local paths = Svg:ParseDocument(svg, 0.1, true) - paths:Normalize(2) -- Scale and center inside a 2x2 square - return paths - end - end -end - -function requestNewAvatar() - url = "https://bit.ly/multiavatar" - WebRequest:Get(url, onGetAvatar) -end - -function onGetAvatar(result) - svg = result -end - +Settings = { + description="Calls an API to generate a random SVG icon using the Multiavatar library", + previewType="quad" +} + +function Start() + requestNewAvatar() +end + +function Main() + if Brush.triggerReleasedThisFrame then + requestNewAvatar() + if svg ~= nil then + local paths = Svg:ParseDocument(svg, 0.1, true) + paths:Normalize(2) -- Scale and center inside a 2x2 square + return paths + end + end +end + +function requestNewAvatar() + randomString = "" + for i = 1, 8 do + randomString = randomString .. string.char(Random:Range(97, 122)) + end + url = "https://api.multiavatar.com/" .. randomString .. ".svg" + -- url = "https://bit.ly/multiavatar" + WebRequest:Get(url, onGetAvatar) +end + +function onGetAvatar(result) + svg = result +end + diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.RandomIcon.lua b/Assets/Resources/LuaScriptExamples/ToolScript.RandomIcon.lua deleted file mode 100644 index f608175a87..0000000000 --- a/Assets/Resources/LuaScriptExamples/ToolScript.RandomIcon.lua +++ /dev/null @@ -1,72 +0,0 @@ -Settings = { - description="Calls an API to generate a random SVG icon using the Iconify library", - previewType="quad" -} - -function onError(error) - print ("http error: " .. error) -end - -function onGetItem(result) - svg = result -end - -function onGetCollection(result, prefix) - if result == nil then - print ("Empty collection returned for: " .. prefix) - return - end - local collection = json:parse(result) - local categories = collection.categories - local randomCategory - if categories == nil then - randomCategory = collection.uncategorized - else - randomCategory = randomItem(categories) - end - local randomItem = randomItem(randomCategory) - local url = "https://api.iconify.design/".. prefix .. "/" .. randomItem .. ".svg" - WebRequest:Get(url, onGetItem, onError) -end - -function onGetAllCollections(result) - local collections = json:parse(result) - local randomCollection = randomKey(collections) - local url = "https://api.iconify.design/collection?prefix=" .. randomCollection - WebRequest:Get(url, onGetCollection , onError, {}, randomCollection) -end - -function randomItem(tbl) - return tbl[randomKey(tbl)] -end - -function randomKey(tbl) - local keyset = {} - for k in pairs(tbl) do - table.insert(keyset, k) - end - local key = keyset[math.random(#keyset)] - return key -end - -function requestNewIcon() - WebRequest:Get("https://api.iconify.design/collections", onGetAllCollections) -end - -function Start() - requestNewIcon() -end - -function Main() - if Brush.triggerReleasedThisFrame then - requestNewIcon() - if svg == nil then - return {} - else - local strokes = Svg:ParseDocument(svg) - strokes:Normalize(2) -- Scale and center inside a 2x2 square - strokes:SampleByDistance(0.1) -- Evenly space all the points - return strokes - end - end -end diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.Spirograph.lua b/Assets/Resources/LuaScriptExamples/ToolScript.Spirograph.lua new file mode 100644 index 0000000000..52cc022653 --- /dev/null +++ b/Assets/Resources/LuaScriptExamples/ToolScript.Spirograph.lua @@ -0,0 +1,59 @@ +Settings = { + description = "Generates a spirograph pattern.", + previewType = "quad" +} + +Parameters = { + innerRadius = {label = "Inner Radius", type = "int", min = 1, max = 64, default = 12}, + outerRadius = {label = "Outer Radius", type = "int", min = 1, max = 64, default = 32}, + penOffset = {label = "Pen Offset", type = "float", min = 0, max = 20, default = 5}, + cycles={label = "Cycles", type = "float", min = 0.5, max = 3, default = 1.1}, + depth={label = "Depth", type = "float", min = 0, max = 32, default = 6}, + points = {label = "Points", type = "int", min = 50, max = 3000, default = 1000} +} + +function Main() + if Brush.triggerReleasedThisFrame then + local path = Path:New() + local R = Parameters.outerRadius -- Fixed outer circle radius + local r = Parameters.innerRadius -- Rolling circle radius + local d = Parameters.penOffset -- Pen offset + local totalPoints = Parameters.points -- Number of points + + -- Ensure parameters are valid + if r >= R then + -- swap + r, R = R, r + end + + -- Calculate the number of cycles for a complete pattern + local gcd = function(a, b) + while b ~= 0 do + local temp = b + b = a % b + a = temp + end + return a + end + local cycles = R / gcd(R, r) + local t_end = Math.pi * cycles * Parameters.cycles + + -- Generate the spirograph pattern + for i = 0, totalPoints do + local t = i * t_end / totalPoints -- Spread points evenly over full cycles + local x = (R - r) * Math:Cos(t) + d * Math:Cos((R - r) / r * t) + local y = (R - r) * Math:Sin(t) - d * Math:Sin((R - r) / r * t) + -- weave in a third dimension in an mathemarically interesting way + local z = Math:Sin(t) * Math:Cos(t) * Math:Cos((R - r) / r * t) * Parameters.depth + + + + local position = Vector3:New(x, y, z) + path:Insert(Transform:New(position)) + end + + -- Normalize path to fit within the canvas + path:Normalize(2) + return path + end +end diff --git a/Assets/Resources/LuaScriptExamples/ToolScript.Spirograph.lua.meta b/Assets/Resources/LuaScriptExamples/ToolScript.Spirograph.lua.meta new file mode 100644 index 0000000000..220bff4203 --- /dev/null +++ b/Assets/Resources/LuaScriptExamples/ToolScript.Spirograph.lua.meta @@ -0,0 +1,10 @@ +fileFormatVersion: 2 +guid: 4b4c9602feaf5c743a2c31b4159be489 +ScriptedImporter: + internalIDToNameTable: [] + externalObjects: {} + serializedVersion: 2 + userData: + assetBundleName: + assetBundleVariant: + script: {fileID: 11500000, guid: 2d1920d65e755cf4f98a93b4a4e952e5, type: 3}