GithubHelp home page GithubHelp logo

rojo-rbx / remodel Goto Github PK

View Code? Open in Web Editor NEW
169.0 11.0 37.0 358 KB

Scriptable Roblox multitool: Manipulate instances, model files, places, and assets on Roblox.com

License: MIT License

Rust 79.21% Lua 19.90% Shell 0.89%
roblox lua rbxmx rojo rbxm rbxl rbxlx

remodel's Introduction




Remodel Logo

Remodel

Remodel on crates.io Actions Status

Remodel is a command line tool for manipulating Roblox files and the instances contained within them. It's a scriptable tool designed to enable workflows where no other tool will do.

Remodel can be used to do almost anything with Roblox files. Some uses include:

Remodel is still in early development, but much of its API is already stable. Feedback is welcome!

Installation

With Foreman

Remodel can be installed with Foreman, a toolchain manager for Roblox projects:

[tools]
remodel = { source = "rojo-rbx/remodel", version = "0.11.0" }

From GitHub Releases

You can download pre-built binaries from Remodel's GitHub Releases page.

From crates.io

You'll need Rust 1.56.0 or newer.

cargo install remodel

Quick Start

Most of Remodel's interface is its Lua API. Users write Lua 5.3 scripts that Remodel runs, providing them with a special set of APIs.

One use for Remodel is to break a place file apart into multiple model files. Imagine we have a place file named my-place.rbxlx that has some models stored in ReplicatedStorage.Models.

We want to take those models and save them to individual files in a folder named models.

local game = remodel.readPlaceFile("my-place.rbxlx")

-- If the directory does not exist yet, we'll create it.
remodel.createDirAll("models")

local Models = game.ReplicatedStorage.Models

for _, model in ipairs(Models:GetChildren()) do
	-- Save out each child as an rbxmx model
	remodel.writeModelFile("models/" .. model.Name .. ".rbxmx", model)
end

For more examples, see the examples folder.

Supported Roblox API

Remodel supports some parts of Roblox's API in order to make code familiar to existing Roblox users.

  • Instance.new(className) (0.5.0+)
    • The second argument (parent) is not supported by Remodel.
  • <Instance>.Name (read + write)
  • <Instance>.ClassName (read only)
  • <Instance>.Parent (read + write)
  • <Instance>:Destroy() (0.5.0+)
  • <Instance>:Clone() (0.6.0+)
  • <Instance>:GetChildren()
  • <Instance>:GetDescendants() (0.8.0+)
  • <Instance>:FindFirstChild(name)
    • The second argument (recursive) is not supported by Remodel.
  • <DataModel>:GetService(name) (0.6.0+)

Remodel API

Remodel has its own API that goes beyond what can be done inside Roblox.

remodel.readPlaceFile

remodel.readPlaceFile(path: string): Instance

Load an rbxlx file from the filesystem.

Returns a DataModel instance, equivalent to game from within Roblox.

Throws on error.

remodel.readModelFile

remodel.readModelFile(path: string): List<Instance>

Load an rbxmx or rbxm (0.4.0+) file from the filesystem.

Note that this function returns a list of instances instead of a single instance! This is because models can contain mutliple top-level instances.

Throws on error.

remodel.readPlaceAsset (0.5.0+)

remodel.readPlaceAsset(assetId: string): Instance

Reads a place asset from Roblox.com, equivalent to remodel.readPlaceFile.

This method requires web authentication for private assets! See Authentication for more information.

Throws on error.

remodel.readModelAsset (0.5.0+)

remodel.readModelAsset(assetId: string): List<Instance>

Reads a model asset from Roblox.com, equivalent to remodel.readModelFile.

This method requires web authentication for private assets! See Authentication for more information.

Throws on error.

remodel.writePlaceFile

remodel.writePlaceFile(path: string, instance: DataModel)

Saves an rbxlx file out of the given DataModel instance.

If the instance is not a DataModel, this method will throw. Models should be saved with writeModelFile instead.

Throws on error.

remodel.writeModelFile

remodel.writeModelFile(path: string, instance: Instance)

Saves an rbxmx or rbxm (0.4.0+) file out of the given Instance.

If the instance is a DataModel, this method will throw. Places should be saved with writePlaceFile instead.

Throws on error.

remodel.writeExistingPlaceAsset (0.5.0+)

remodel.writeExistingPlaceAsset(instance: Instance, assetId: string)

Uploads the given DataModel instance to Roblox.com over an existing place.

If the instance is not a DataModel, this method will throw. Models should be uploaded with writeExistingModelAsset instead.

This method always requires web authentication! See Authentication for more information.

Throws on error.

remodel.writeExistingModelAsset (0.5.0+)

remodel.writeExistingModelAsset(instance: Instance, assetId: string)

Uploads the given instance to Roblox.com over an existing model.

If the instance is a DataModel, this method will throw. Places should be uploaded with writeExistingPlaceAsset instead.

This method always requires web authentication! See Authentication for more information.

Throws on error.

remodel.getRawProperty (0.6.0+)

remodel.getRawProperty(instance: Instance, name: string): any?

Gets the property with the given name from the given instance, bypassing all validation.

This is intended to be a simple to implement but very powerful API while Remodel grows more ergonomic functionality.

Throws if the value type stored on the instance cannot be represented by Remodel yet. See Supported Roblox Types for more details.

remodel.setRawProperty (0.6.0+)

remodel.setRawProperty(
	instance: Instance,
	name: string,
	type: string,
	value: any,
)

Sets a property on the given instance with the name, type, and value given. Valid values for type are defined in Supported Roblox Types in the left half of the bulleted list.

This is intended to be a simple to implement but very powerful API while Remodel grows more ergonomic functionality.

Throws if the value type cannot be represented by Remodel yet. See Supported Roblox Types for more details.

remodel.readFile (0.3.0+)

remodel.readFile(path: string): string

Reads the file at the given path.

Throws on error, like if the file did not exist.

remodel.readDir (0.4.0+)

remodel.readDir(path: string): List<string>

Returns a list of all of the file names of the children in a directory.

Throws on error, like if the directory did not exist.

remodel.writeFile (0.3.0+)

remodel.writeFile(path: string, contents: string)

Writes the file at the given path.

Throws on error.

remodel.removeFile

remodel.removeFile(path: string)

Removes the file at the given path.

This is a thin wrapper around Rust's fs::remove_file function.

Throws on error.

remodel.createDirAll

remodel.createDirAll(path: string)

Makes a directory at the given path, as well as all parent directories that do not yet exist.

This is a thin wrapper around Rust's fs::create_dir_all function. Similar to mkdir -p from Unix.

Throws on error.

remodel.removeDir

remodel.removeDir(path: string)

Removes a directory at the given path.

This is a thin wrapper around Rust's fs::remove_dir_all function.

Throws on error.

remodel.isFile (0.7.0+)

remodel.isFile(path: string): bool

Tells whether the given path is a file.

This is a thin wrapper around Rust's fs::metadata function.

Throws on error, like if the path does not exist.

remodel.isDir (0.7.0+)

remodel.isDir(path: string): bool

Tells whether the given path is a directory.

This is a thin wrapper around Rust's fs::metadata function.

Throws on error, like if the path does not exist.

JSON API

json.fromString (0.7.0+)

json.fromString(source: string): any

Decodes a string containing JSON.

Throws on error, like if the input JSON is invalid.

json.toString (0.7.0+)

json.toString(value: any): string

Encodes a Lua object as a JSON string. Can only encode Lua primitives like tables, strings, numbers, bools, and nil. Instances cannot be encoded to JSON.

Throws on error, like if the input table cannot be encoded.

json.toStringPretty (Unreleased)

json.toStringPretty(value: any, indent?: string = "  "): string

Encodes a Lua object as a prettified JSON string. If an indent is passed, will use that for indentation, otherwise will default to two spaces.

Throws on error, like if the input table cannot be encoded.

Supported Roblox Types

When interacting with Roblox instances, Remodel doesn't support all value types yet and may throw an error.

Supported types and their Lua equivalents:

  • String: string
  • Content: string
  • Bool: boolean
  • Float64: number
  • Float32: number
  • Int64: number
  • Int32: number

More types will be added as time goes on, and Remodel will slowly begin to automatically infer correct types in more contexts.

Authentication

Some of Remodel's APIs access the Roblox web API and need authentication in the form of a .ROBLOSECURITY cookie to access private assets. Auth cookies look like this:

_|WARNING:-DO-NOT-SHARE-THIS.--Sharing-this-will-allow-someone-to-log-in-as-you-and-to-steal-your-ROBUX-and-items.|<actual cookie stuff here>

Auth cookies are very sensitive information! If you're using Remodel on a remote server like Travis CI or GitHub Actions, you should create a throwaway account with limited permissions in a group to ensure your valuable accounts are not compromised!

On Windows, Remodel will attempt to use the cookie from a logged in Roblox Studio session to authenticate all requests.

To give a different auth cookie to Remodel, use the --auth argument:

remodel run foo.lua --auth "$MY_AUTH_COOKIE"

You can also define the REMODEL_AUTH environment variable to avoid passing --auth as an argument.

Remodel vs rbxmk

Remodel is similar to rbxmk:

  • Both Remodel and rbxmk use Lua
  • Remodel and rbxmk have a similar feature set and use cases
  • Remodel is imperative, while rbxmk is declarative
  • Remodel emulates Roblox's API, while rbxmk has its own, very unique API

License

Remodel is available under the terms of the MIT license. See LICENSE.txt for details.

Logo source.

remodel's People

Contributors

alihsaas avatar basicer avatar boegie19 avatar cliffchapmanrbx avatar filiptibell avatar guidojw avatar jeparlefrancais avatar kampfkarren avatar lpghatguy avatar nezuo avatar ryan-c-scott avatar unix-system avatar vorlias avatar wicked7000 avatar wingysam avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

remodel's Issues

Expose rbx-reflection to scripts

I am writing something that will produce .model.json files from existing instances. It would be nice to know what properties are defaults, but there is no way to get properties. I would like to be able to get the properties through rbx-reflection.

Add FindFirstChildOfClass method

This method is used from time to time, but especially when it comes to compiling the artistic content like our maps. It's a lot safer because it is not prone to typos when you know there's a single child instance of that type (for example the skybox).

Exit Code 1 should be set if a script fails

I'm currently trying to use Remodel as part of my GitHub Workflow CI. The existing behaviour is unintended, where the pipeline continues on error even with continue-on-error: false. I believe that instead exit code 1 should occur, resulting in both the step and pipeline failing.

Current work-around: using grep for 'error' and set exit code = 1

image

remodel.writePlaceFile and remodel.writeModelFile do not write Part0 and Part1 properties

When reading a .rbxmx or .rbxlx (xml) file and writing it as a .rbxm or .rbxl (binary) file, any WeldConstraint inside the .rbxmx or .rbxlx file will lose their Part0 and Part1 property values.

This is not an issue with other instance types containing Part0 and Part1 properties like NoCollisionConstraint, but I have not tested many others.

I noticed that exporting xml files from Roblox Studio will use Part0Internal and Part1Internal as property names for WeldConstraint's, so it might be related to this issue.

Let me know if you need any more detail.

Separate API reference from README?

It'd be nice to organize the API reference in README to MkDocs or something like that. The API reference takes up most of README's contents, with the Supported Types, Authentication, Remodel vs rbxmk, and licensing sections all below it.

Order of SharedStrings section changes in each time a rbxmx is generated

I've noticed that the order of the SharedStrings part of the file changes at random each time the remodel script runs. This leads to spurious changes in the files, which messes up diffs and causes more conflicts than necessary in git. This doesn't appear to affect other sections of the file, which seem to be generated deterministically.

I can write my own script to post-process these files and sort these shared strings by the md5, which should keep them consistent - but I think this would be a useful step to do anyway.

More specific load/save API

remodel.save can be renamed to remodel.writePlaceFile and remodel.writeModelFile.

remodel.load can be renamed to remodel.readPlaceFile and remodel.readModelFile.

This opens the door for adding APIs that deal with regular files as well as web content, instead of making one big overloaded function.

Add remodel.removeFile(path: string) and remodel.removeFolder(path: string)

I think the addition of remodel.removeFile(path: string) and remodel.removeFolder(path: string) would be great for managing workflows.

In my case, I currently have a remodel command that reads individual models within a place file and exports them as individual .rbxmx files to the file system. However, when I remove (:Destroy()) a model within the place, remodel is unable to also remove the corresponding .rbxmx file.

These two new functionalities could be implemented with fs::remove_file(path) and fs::remove_dir_all(path) internally.

If you'd like me to, I can open a pull request.

Error when iterating through place instances.

Im trying to interate through place instances and this is what I get

[WARN ] Unknown value type ID 0x1f (31) in Roblox binary model file. Found in property AnalyticsService.UniqueId.
[ERROR] runtime error: [string "run.lua"]:13: bad argument #1 to 'for iterator' (table expected, got userdata)
stack traceback:
[C]: in ?
[C]: in function 'next'
[string "run.lua"]:13: in main chunk

Code:

local game = remodel.readPlaceFile("game.rbxl")

for i, val in pairs(game) do
print(val.Name)
end

Add method to write single instance without its children

I would like to write individual instances without writing their children so that I can have remove any merge conflicts that may arise. I know you can do this by closing the instance then deleting all the children then blah blah blah, but it would be nice if it was a standalone method.

"Unexpected token inside qualified name: !:" from remodel.readModelAsset

When running the following line:

local model_root = remodel.readModelAsset(rbxmx_path)
[ERROR] callback error: external error: line 1, column 0: 1:8 Unexpected token inside qualified name: !: stack traceback:
                [C]: in ?
                [C]: in field 'readModelAsset'
                [string "vet.lua"]:45: in main chunk

        Caused by:
            0: external error: line 1, column 0: 1:8 Unexpected token inside qualified name: !
            1: line 1, column 0: 1:8 Unexpected token inside qualified name: !
            2: 1:8 Unexpected token inside qualified name: !

This error seems to sometimes resolve itself - I have no idea what causes it - the value for rbxmx_path is a valid assetId string, and sometimes I don't change the code and it just happens. I can't debug it any further because the stack trace is super cryptic.

I'm using the latest version of remodel from Foreman.

Fixed function commands

I've been considering starting a tool that operates like a fixed-function version of Remodel. Instead, I think a better idea is to expand the scope of Remodel slightly to have those operations included within it.

remodel script.lua will become remodel run script.lua to free up this namespace, and then new commands can be added like remodel convert, remodel slice, remodel combine, or whatever.

First script argument to 'remodel run' is ignored (0.7.0)

When running remodel run in 0.7.0, the first argument passed to the script is completely discarded.


Example repro:

remodel run test.lua ONE TWO THREE

Where test.lua is:

local args = { ... }
for i, v in pairs(args) do
    print(i, v)
end

Will output:

1 TWO
2 THREE

The expected output should be

1 ONE
2 TWO
3 THREE

Add MD5 check function

I wrote a script that automatically creates parity between the build.rbxlx and the filesystem. That is to say that if I delete a file in Roblox then it is automatically deleted in the filesystem as-well and vise versa.

The primary issue here is that in order to delete files in the filesystem I have to use FindFirstChild which does not guarantee that the file it's trying to delete is the same as the model in the roblox file. A way around this would be a way to compare the MD5 of the rbxmx file and the actual model in-game.

Compound datatypes

Most properties on Roblox instances are interesting types that Remodel doesn't support yet, like CFrame, Vector3, or ColorSequence. We can slowly start filling those out!

A good comparison point would be Lemur, which has a similar scope to Remodel, but implemented in Lua for a different use case.

Types

We should come back through and prioritize these. Some types like Ray and Region3 aren't serialized anywhere useful in practice.

  • Axes
  • BrickColor
  • CFrame
  • Color3/Color3uint8 (#14)
  • ColorSequence
  • Enum
  • Faces
  • NumberRange
  • NumberSequence
  • PhysicalProperties
  • Ray
  • Rect
  • Ref
  • Region3
  • Region3int16
  • UDim
  • UDim2
  • Vector2
  • Vector2int16
  • Vector3
  • Vector3int16

On master, can't write to binary places

[ERROR] callback error: external error: Writing rbxl place files is not supported yet.: stack traceback:
                [C]: in ?
                [C]: in field 'writePlaceFile'
                [string "update.lua"]:20: in main chunk

Scripts in `.remodel` don't run if matching directory exists in CWD

If a script such as .remodel/build.lua exists, but a directory named build also exists, remodel will fail because it first finds build, but build is a directory.

Result (build directory exists, but .remodel/build.lua also exists):
image

The behaviour I would expect is that remodel would still find the script and run it.

Add a function which checks if X is a service

At the moment, it's very tedious to identify that is and isn't a Roblox service. It may more sense to add some form of functionality which confirms if that's the case or not. Some possible examples:

  • bool :IsAService()
  • string :IsA() -> "Service"

Not sure what's the best method but feels like a decent addition.

How to use remodel?

I've just install remodel from Foreman. I type remodel -h in the command prompt to get some help but don't know what to do next.

Improve guidance for examples & tests

It took me a few tries to figure out how to run the Lua files in the examples directory. I think some adjustments could have avoided this. I wonder if other people had a similar experience or weren't able to figure it out outright. Here's what I learned by trial & error:

  1. I needed to download the entire set of directories on GitHub, i.e., remodel-master.

  2. I needed a temp directory in remodel-master to avoid an error, such as the following.

    image


Here are a few ideas that might help:

  1. Explicitly explain in the README or somewhere else what a person should do to prepare their device to run the example scripts. For example, "To try the example scripts, download the entire repository to a location on your device, such as your C: drive."

  2. Instruct the user to create an empty temp directory or (if possible) include this directory in the repository so it doesn't need to be created. (If tests/scripts.rs is designed to do this for the user, then explain what the user needs to do to run this file, e.g., install Rust, and how/when they should run it.)

  3. Adjust the error message(s) to provide additional detail. For example:

    The system cannot find the path specified ("C:\remodel-master\temp\")

  4. A walk-through tutorial would also be nice-to-have, but it's understandable that the effort required to do this may not be available. Not yet anyway.

Remodel no longer able to pull Roblox auth from studio

I logged into Roblox Studio on a new computer and when trying to run remodel it says it wasn't able to find authentication cookie from studio. It seems like a recent version of studio changed how authentication is stored in studio.

Add GetFullName() method

I use this method commonly, especially when printing out information to the user.

My use case is that I'm writing a Remodel script to import assets to a location in the DataModel. When this is done, I want to log the full path to where it ended up in the place file so that the user can easily find it.

I've written a shim in Lua to do this, but I would much prefer an implementation in Remodel itself:

local function getFullName(instance)
	local parents = { instance }
	local current = instance

	while current.Parent do
		table.insert(parents, current.Parent)
		current = current.Parent
	end

	local path = ""
	for i=#parents, 1, -1 do
		local parent = parents[i]

		if parent == instance then
			path = path .. parent.Name
		else
			if parent.Name == "DataModel" then
				path = path .. "game."
			else
				path = path .. parent.Name .. "."
			end
		end
	end

	return path
end

Provide an API for hashing Roblox files

I currently have a workflow for validating the authenticity of the production game on Roblox. Without going into major detail, this works by generating a hash of the final build file at publish-time and then periodically checking that against the live place automatically. The purpose of doing this is to make sure that the production game has always gone through the deployment pipeline and not published to directly (and by extension skipping all code review and unit tests).

I've tried different ways of accomplishing this. This first was a pure Lua implementation, but hashing algorithms written in Lua are slow and resource hungry. This doesn't work for large build files because I need to keep workflow times as low as possible. My current implementation is a mix of Lua and Node.js, with Lua (Remodel) handling the publishing/downloading of the game, and Node handling the actual hashing. This does work, but having to interface between Lua and Node (by invoking CLI commands from Node) is very clunky and error-prone.

Ideally, Remodel would provide an API to hash game files, utilizing the speed and efficiency of Rust to do it. This would vastly improve the speed (no need to download the Node runtime every time), efficiency, and readability of my workflow over my current implementation.

rbxlx readPlaceFile Error

I get an error when I try to read my (new and working) place file with local game = remodel.readPlaceFile("place.rbxlx"):
powershell_Ze8OtKdqTl

Add Terrain CopyRegion method

We compile our maps including our terrain to a model file using TerrainRegion instances. It would be great to be able to generate that TerrainRegion through our remodel script. We also need Terrain.MaxExtents for it to work.

Thank you :)

Add v0.9.0 to cargo

I am having problems running remodel with foreman issue And my workaround was to use cargo.
But sadly it does not contains latest version.
Can you please add it to cargo?

JSON library

While I think it's technically possible to pull in an existing Lua JSON library like dkjson, it'd be great to ship with one since it's such a common format for tools.

Add Instance.new

Fabricating new Roblox instances should be a core part of Remodel.

Require paths don't account for `.remodel` directory

Problem I ran into is that keeping my Remodel scripts in the .remodel directory to make it easier to run them results in issues with require().

This is because all paths are relative to the CWD, so you have to write require(".remodel/modulename") from your scripts, but the problem with this is that dots in pathnames cause issues with requiring.

Would be great if Remodel added the .remodel path to where Lua looks for modules so we can simply write require("moduleName").

Add APIs to upload places/models as a new asset

Currently we can only upload places and models to existing assets.

There are some cases where you would need to upload to a new asset.
A good example of this would be transferring a model from one group to another (or animations if they get support).

An potential API could be:
remodel.writePlaceAsset(instance: DataModel)
remodel.writeModelAsset(instance: Instance)

Source

How can I get it to read the source of a script?

Add Model:GetBoundingBox()

https://developer.roblox.com/en-us/api-reference/function/Model/GetBoundingBox

This is useful as a system I have relies on the bounding boxes of possible zones that it can allocate to create a grid with cells of the biggest size.

This can be done at runtime, but this would require the server to then replicate this information to the client (which also needs to know the cell size, for different purposes), making it an asynchronous operation, which is not ideal. The better solution is to pre-compute this and store that information in a ModuleScript. I can do this with a plugin, but it is preferable that remodel does this to limit manual work.

Property access

We should be able to use the reflection database from rbx_reflection to make accessing properties possible.

Support CSRF Negotiation

The Roblox API that Remodel uses for uploads has recently gained CSRF protection, which means that uploading with Remodel is no longer functional.

setRawProperty not working

local test = Instance.new("StringValue")
remodel.setRawProperty(test, "Value", string, test)

(or)

local test = Instance.new("StringValue")
remodel.setRawProperty(test, "Value", "string", test)
[ERROR] callback error: error converting Lua table to String (expected string or number): stack traceback:
                [C]: in ?
                [C]: in field 'setRawProperty'
                [string "remodel.lua"]:2: in main chunk

        Caused by:
            error converting Lua table to String (expected string or number)

Upon attempting to read and write script objects, I encountered an error using setRawProperty, and upon further testing, it seems to be impacting it as a whole above. Failing code is above, with the error below it.

Calling :Clone() on a DataModel instance will produce a corrupted result

This can be replicated with this simple code snippet if input.rbxl is a default Baseplate template. As far as I'm aware, I don't think it's possible to successfully clone any DataModel without getting a corrupted file as a result.

local inputGame = remodel.readPlaceFile("input.rbxl")
local outputGame = inputGame:Clone()

remodel.writePlaceFile(outputGame, "output.rbxl")

When opening the output.rbxl file, I get this error from Roblox Studio:

Could not open the place "PATH/output.rbxl" with exception: "readIntVector offset is out of bounds while reading 4 bytes, offset=20, datasize=20 << refs vector, size=1 << property values, name=Attachment0, type=Attachment0 << chunk#110[PROP], property with typeIndex=104, type=AlignOrientation".

Arguments to scripts

It'd be much easier to share and reuse Remodel scripts if they could accept parameters.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.