Luau Visual Scripting App DevLog 3

v0.0.1-beta
Check out the previous DevLog here.

Dynamic Property List

I’ve finally started integrating the Roblox API with the app. Here you can see a dropdown menu with a list of properties for a player as well as its super class Instance. This list is dynamically generated and it will generate properties for all super classes which is super handy. There’s still a lot more work to do though!

Performance Issues

For the sake of things I decided to try and render every event as a node in the Roblox API. I found out there’s about 400 of them and let me tell you React does not like how I’m currently handling these nodes. I decided to run the Firefox profiler and at one point the FPS dropped to 4! I doubt anyone will ever have 400 nodes at a time but this is still something I intend on fixing in the future and I already have a few ideas of how to put optimizations in place.

TypeScript

I converted the entire codebase over to TypeScript. This wasn’t an easy task and is what I’ve spent most of the past week doing. I deserve that though for thinking JavaScript was reliable for such a large project. With everything now typed things are much more organized and I have sweet, sweet autocomplete.

Typed Nodes

I decided to type nodes. This is something I was against at the beginning of this project but I now realize it’s necessary and will provide an advantage to developers using this app. They won’t have to figure out what type something should be when passing in arguments to functions or when retrieving their outputs. It makes everything a lot safer and cleaner for beginners who have no experience programming.

There are also downsides to this though. For example this 4,000 character long type definition I dynamically generated from the Roblox API:

'bool' | 'string' | 'int' | 'Instance' | 'int64' | 'Vector3' | 'CFrame' | 'AccessoryType' | 'Content' | 'Animation' | 'float' | 'AnimationPriority' | 'AssetImportItemSettings' | 'Color3' | 'BinType' | 'BrickColor' | 'GuiObject' | 'ScreenOrientation' | 'VirtualCursorMode' | 'WrapLayerDebugMode' | 'WrapTargetDebugMode' | 'Attachment' | 'ColorSequence' | 'TextureMode' | 'NumberSequence' | 'BasePart' | 'Expression' | 'ScriptRef' | 'CameraType' | 'FieldOfViewMode' | 'Vector2' | 'BodyPart' | 'CommandPermission' | 'AlignType' | 'ActuatorRelativeTo' | 'ActuatorType' | 'VelocityConstraintMode' | 'MeshType' | 'StudioDataModelType' | 'TickCountSampleMethod' | 'double' | 'DialogBehaviorType' | 'DialogPurpose' | 'DialogTone' | 'DraggerCoordinateSpace' | 'DraggerMovementMode' | 'ExplosionType' | 'NormalId' | 'InOut' | 'LeftRight' | 'TopBottom' | 'Rect' | 'LocalizationTable' | 'AutomaticSize' | 'BorderMode' | 'UDim2' | 'SizeConstraint' | 'FrameStyle' | 'ButtonStyle' | 'ResamplerMode' | 'ScaleType' | 'Font' | 'FontSize' | 'TextTruncate' | 'TextXAlignment' | 'TextYAlignment' | 'ElasticBehavior' | 'ScrollBarInset' | 'ScrollingDirection' | 'VerticalScrollBarPosition' | 'ReturnKeyType' | 'TextInputType' | 'Camera' | 'ZIndexBehavior' | 'SurfaceGuiSizingMode' | 'PVInstance' | 'AdornCullingMode' | 'Axes' | 'Faces' | 'HandlesStyle' | 'Humanoid' | 'Folder' | 'HumanoidCollisionType' | 'HumanoidDisplayDistanceType' | 'Material' | 'HumanoidHealthDisplayType' | 'NameOcclusion' | 'HumanoidRigType' | 'MeshScaleUnit' | 'KeyCode' | 'UserInputState' | 'UserInputType' | 'Hole' | 'Technology' | 'ProtectedString' | 'Ray' | 'SurfaceType' | 'InputType' | 'PhysicalProperties' | 'FormFactor' | 'PartType' | 'SkateboardController' | 'TerrainAcquisitionMethod' | 'BinaryString' | 'Region3int16' | 'CollisionFidelity' | 'RenderFidelity' | 'Style' | 'ModelLevelOfDetail' | 'NewAnimationRuntimeSetting' | 'ClientAnimatorThrottlingMode' | 'HumanoidOnlySetCollisionsOnStateChange' | 'InterpolationThrottlingMode' | 'MeshPartHeadsAndAccessories' | 'PhysicsSimulationRate' | 'PhysicsSteppingMethod' | 'SignalBehavior' | 'StreamingPauseMode' | 'Terrain' | 'PackagePermission' | 'NumberRange' | 'ParticleOrientation' | 'PathStatus' | 'DebuggerPauseReason' | 'Breakpoint' | 'ThreadState' | 'EnviromentalPhysicsThrottle' | 'CameraMode' | 'Model' | 'ChatMode' | 'DevCameraOcclusionMode' | 'DevComputerCameraMovementMode' | 'DevComputerMovementMode' | 'DevTouchCameraMovementMode' | 'DevTouchMovementMode' | 'MembershipType' | 'SpawnLocation' | 'Team' | 'Player' | 'MultipleDocumentInterfaceInstance' | 'TriStateBoolean' | 'PoseEasingDirection' | 'PoseEasingStyle' | 'ProximityPromptExclusivity' | 'ProximityPromptStyle' | 'QualityLevel' | 'FramerateManagerMode' | 'GraphicsMode' | 'MeshPartDetailLevel' | 'RenderingTestComparisonMethod' | 'CreatorType' | 'GearGenreSetting' | 'Genre' | 'Workspace' | 'RollOffMode' | 'SoundGroup' | 'ReverbType' | 'GameAvatarType' | 'R15CollisionType' | 'LoadCharacterLayeredClothing' | 'AutoIndentRule' | 'QDir' | 'ListDisplayMode' | 'QFont' | 'HoverAnimateSpeed' | 'OutputLayoutMode' | 'PermissionLevelShown' | 'RuntimeUndoBehavior' | 'StudioScriptEditorColorPresets' | 'ServerAudioBehavior' | 'UITheme' | 'AlphaMode' | 'ThreadPoolConfig' | 'PlaybackState' | 'TweenInfo' | 'AspectType' | 'DominantAxis' | 'UDim' | 'FillDirection' | 'HorizontalAlignment' | 'SortOrder' | 'VerticalAlignment' | 'StartCorner' | 'EasingDirection' | 'EasingStyle' | 'TableMajorAxis' | 'ApplyStrokeMode' | 'LineJoinMode' | 'CustomCameraMode' | 'ComputerCameraMovementMode' | 'ComputerMovementMode' | 'ControlMode' | 'RotationType' | 'SavedQualitySetting' | 'TouchCameraMovementMode' | 'TouchMovementMode' | 'MouseBehavior' | 'OverrideMouseIconBehavior' | 'UserCFrame' | 'VoiceChatState'

The next step in this process is figuring out how I should show these types to users in a user-friendly manner. I’m thinking maybe in the properties pane I’ll display all input & outputs even if they aren’t editable with tags for types but I don’t know.

Full Node, Port, Input, and Output Class Rewrites

I rewrote the node.ts file which contained all these classes. Everything is a lot nicer now and that’s partly due to TypeScript. Using the public accessor in a constructor I’m able to neatly generate properties for classes:

class Port<T> {
    node: Node | null = null;
    isConnected: boolean = false;
    connection: Connection | LooseConnection | null = null;

    protected _value: T;

    constructor(public type: PortType, public label: string, public id: number, public defaultValue: T, public options: PortOpts) {
        this._value = defaultValue;
    }

    setValue(value: T) {
        this._value = value;
    }

    getValue(): T {
        return this._value;
    }

    updateValue(nodes: Node[], value: T) {}
}

Closing Remarks

Thanks for reading and providing your support. There’s a tremendous amount of work ahead but seeing people genuinely interested in the project pushes me to keep going. I’m currently looking for a name for the app! Feel free to leave suggestions in the replies to this post.

6 Likes

Dang that’s really interesting