Code Monkey home page Code Monkey logo

stream-cli's Introduction

Stream Cli

Stream CLI


๐Ÿšจ Breaking changes in v1.0 <

We have completely rewritten the Node.JS CLI to Go in 2022 Q1. Some of the changes:

  • The installation process is easier since it doesn't have any prerequisites (such as NPM). You can just simply download the executable and run it.
  • The name of the executable is stream-cli instead of stream to avoid conflicts with an existing tool (imagemagick). But you can rename it if you want to.
  • The command invocation is stream-cli chat [verb-noun] [args] [options] instead of stream [verb:noun] [args] [options]. The most obvious change is using dash instead of colon. We also added the chat keyword to preserve domain for our other product Feeds.
  • The 1.0.0 Go version's feature set is matching the old one. But if you miss anything, feel free to open an issue.

Stream's Command Line Interface (CLI) makes it easy to create and manage your Stream apps directly from the terminal. Currently, only Chat is supported; however, the ability to manage Feeds will be coming soon.

๐Ÿ“š Documentation

The full documentation is deployed to GitHub Pages.

๐Ÿ—’ Issues

If you're experiencing problems directly related to the CLI, please add an issue on GitHub.

For other issues, submit a support ticket.

๐Ÿ“ Changelog

As with any project, things are always changing. If you're interested in seeing what's changed in the Stream CLI, the changelog for this project can be found here.

๐Ÿ— Installation

The Stream CLI is written in Go and precompiled into a single binary. It doesn't have any prerequisites.

Download the binaries

You can find the binaries in the Release section of this repository. We also wrote a short script to download them and put it to your $PATH.

Bash (MacOS and Linux)

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/GetStream/stream-cli/master/install/install.sh)"

PowerShell (Windows)

$ Invoke-WebRequest -Uri "https://raw.githubusercontent.com/GetStream/stream-cli/master/install/install.ps1" -OutFile "install.ps1"; powershell.exe -ExecutionPolicy Bypass -File ./install.ps1

Homebrew

For MacOS users, it's also available via Homebrew:

$ brew tap GetStream/stream-cli https://github.com/GetStream/stream-cli
$ brew install stream-cli

Compile yourself

$ git clone [email protected]:GetStream/stream-cli.git
$ cd stream-cli
$ go build ./cmd/stream-cli
$ ./stream-cli --version
stream-cli version 1.0.0

๐Ÿš€ Getting Started

In order to initialize the CLI, it's as simple as:

Stream

Note: Your API key and secret can be found on the Stream Dashboard and is specific to your organization.

๐Ÿšจ Warning

We purposefully chose the executable name stream-cli to avoid conflict with another tool called imagemagick which already has a stream executable.

If you do not have imagemagick installed, it might be more comfortable to rename stream-cli to stream. Alternatively you can set up a symbolic link:

$ ln -s ~/Downloads/stream-cli /usr/local/bin/stream
$ stream --version
stream-cli version 1.0.0

๐Ÿ”จ Syntax

Basic commands use the following syntax:

$ stream-cli [chat|feeds] [command] [args] [options]

Example:

$ stream-cli chat get-channel -t messaging -i redteam

The --help keyword is available every step of the way. Examples:

$ stream-cli --help
$ stream-cli chat --help
$ stream-cli chat get-channel --help

๐Ÿ’ฌ Auto completion

We provide autocompletion for the most popular shells (PowerShell, Bash, ZSH, Fish).

$ stream-cli completion --help

๐Ÿ“ฃ Feedback

If you have any suggestions or just want to let us know what you think of the Stream CLI, please send us a message at [email protected] or create a GitHub Issue.

๐Ÿ”ง Development

We welcome code changes that improve this library or fix a problem, please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github. We are very happy to merge your code in the official repository. Make sure to sign our Contributor License Agreement (CLA) first. See our license file for more details.

๐Ÿง‘โ€๐Ÿ’ป We are hiring!

We've recently closed a $38 million Series B funding round and we keep actively growing. Our APIs are used by more than a billion end-users, and you'll have a chance to make a huge impact on the product within a team of the strongest engineers all over the world.

Check out our current openings and apply via Stream's website.

stream-cli's People

Contributors

anatolyrugalev avatar astrotars avatar bdandy avatar bogy0 avatar dependabot[bot] avatar dmeechan avatar ferhatelmas avatar frivalszkyp avatar github-actions[bot] avatar goreleaserbot avatar guerinoni avatar gumuz avatar jeevcat avatar link512 avatar liooo avatar peterdeme avatar tbarbugli avatar thesyncim avatar tsirlucas avatar yaziine 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

Watchers

 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

stream-cli's Issues

Create a token

Is there no way to create a chat token for a user with stream-cli?

Add support for app auth settings

Auth Check (dev token)

// disable auth checks, allows dev token usage
await client.updateAppSettings({
    disable_auth_checks: true,
});

// re-enable auth checks
await client.updateAppSettings({
    disable_auth_checks: false,
});

Permission checking

// disable permission checks
await client.updateAppSettings({
	disable_permissions_checks: true,
});

// re-enable permission checks
await client.updateAppSettings({
	disable_permissions_checks: false,
});

Cannot set auto_translation_enabled via update-app

I'm trying to enable auto translation for my app via the following command:
stream-cli chat update-app --properties '{"auto_translation_enabled": true}'

This returns the message Successfully updated app settings.

But when I retrieve the app settings via stream-cli config list I do not see the auto_translation_enabled property in the resulting object.

Can this be done via the CLI? Are there other ways to set it without the CLI?

Promote user as moderator

Add support for promoting a user as moderator on a channel (note: the user must be a member on that channel)

Demote moderator

Add support for demoting a moderator to regular user on a channel (note: the user must be a member on that channel)

CLI deletes custom fields when updating channel

Hello,

I was trying to update a channel's image field via the CLI:

stream chat:channel:update -t 'messagingMembersOnly' -c "chatRoom_9nuDGTNQoEpF7NFzHhQ71U" --image=null

But that command had an unintended effect as it cleared most of the channel's other fields (like name, daisieRoomType, etc)

Feature request :
Is there a way to update custom fields (like daisieRoomType) using the CLI?

Additionally, is there a way to non-destructively update a field using the CLI?

Translation support

Chat API now has support for message translation ๐ŸŽ‰

Let's make sure the CLI simplify the configuration setup:

  • enable/disable auto translate (application level)
  • enable/disable auto translate (channel level)
  • add an option to set the user language

unable to add custom data fields when creating a channel

I always get a parsing error on trying to add a JSON string as custom data fields.

For example:
stream chat:channel:create -c=qsfm-general -d='{"vtag":"qsfm"}' -t=pxtype -n=#general

I have tried every format for the json string that i can think of.

Can you provide an example of a functional --data argument to chat:channel:create?

stream is an imagemagick command

$ stream
Version: ImageMagick 6.8.9-9 Q16 x86_64 2019-11-12 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2014 ImageMagick Studio LLC
Features: DPC Modules OpenMP
Delegates: bzlib cairo djvu fftw fontconfig freetype jbig jng jpeg lcms lqr ltdl lzma openexr pangocairo png rsvg tiff wmf x xml zlib

Usage: stream [options ...] input-image raw-image

Image Settings:
  -authenticate password
                       decipher image with this password
  -channel type        apply option to select image channels
  -colorspace type     alternate image colorspace
  -compress type       type of pixel compression when writing the image
  -define format:option
                       define one or more image format options
  -density geometry    horizontal and vertical density of the image
  -depth value         image depth
  -extract geometry    extract area from image
  -identify            identify the format and characteristics of the image
  -interlace type      type of image interlacing scheme
  -interpolate method  pixel color interpolation method
  -limit type value    pixel cache resource limit
  -map components      one or more pixel components
  -monitor             monitor progress
  -quantize colorspace reduce colors in this colorspace
  -quiet               suppress all warning messages
  -regard-warnings     pay attention to warning messages
  -respect-parentheses settings remain in effect until parenthesis boundary
  -sampling-factor geometry
                       horizontal and vertical sampling factor
  -seed value          seed a new sequence of pseudo-random numbers
  -set attribute value set an image attribute
  -size geometry       width and height of image
  -storage-type type   pixel storage type
  -synchronize         synchronize image to storage device
  -taint               declare the image as modified
  -transparent-color color
                       transparent color
  -verbose             print detailed information about the image
  -virtual-pixel method
                       virtual pixel access method

Miscellaneous Options:
  -debug events        display copious debugging information
  -help                print program options
  -list type           print a list of supported option arguments
  -log format          format of debugging information
  -version             print version information

By default, the image format of `file' is determined by its magic
number.  To specify a particular image format, precede the filename
with an image format name and a colon (i.e. ps:image) or specify the
image type as the filename suffix (i.e. image.ps).  Specify 'file' as
'-' for standard input or output.

obviously this prevents me from using the cli

Unexpected token o in JSON at position 1 (firebase test)

I'm trying to test Firebase push notifications and am getting the following output:

stream chat:push:test -u <user-id>                                                                                                                                                                โ”€โ•ฏ
Here is the rendered Firebase notification that will be sent to your devices:
{
    "data": {
        "channel": {
            "id": "fun-1",
            "type": "messaging"
        },
        "message": "very-fake-message",
        "sender": "john_doe"
    },
    "notification": {
        "body": "The quick fox brown lazies over the jumpy dog",
        "click_action": "OPEN_ACTIVITY_1",
        "sound": "default",
        "title": "Jonathan Doelowski @ The fun squad"
    },
    "priority": "high"
}
Here is the rendered notification payload that will be sent to your devices:
 โ€บ   Error: Unexpected token o in JSON at position 1

No push notifications are sent. I verified that I'm using the correct user id.

Handle missing channel nicely

stream chat:channel:get -c xxx -t yyy

should say something channel does not exist instead it errors:

Error: Cannot read property 'data' of undefined

Feature request: ability to generate bulk test data

Objective

During the testing on frontend, we generally need some quick way to populate the app or channel with some bulk data.

For example:

  1. I am testing or building the UI for unread channels and I need to quickly add some messages to the channel which are sent by other users (so that they are unread for me). Also I want to add specific number of messages so that I can check the UI (scroll behavior) for low or high unread count.
  2. Since we have 100 member limit on some backend features, I want to test UI behaviour for such channels. In this case I want to quickly add 100 members to current channel.
  3. I just created a new app for using our tutorial. And I want to see chat features quickly in action for which I want to create 10 channels with 50 messages each. And some reactions, attachments, thread replies, giphy spread across those messages.

These are just few examples. We have such functionality in stream-chat-test-data-cli. And we also allow user to fine tune the frequency of reactions, attachments etc in test data using config.

If we can add such functionality to stream-cli, then we can simply deprecate the other repo and have everything at one place here.

chat:user:mute crashes

It should ask for two user (ie. Tommaso mutes Jake).

Error: StreamChat error code 4: Mute failed with error: "either user or user_id must be provided when using server side auth."
    at StreamChat.errorFromResponse (~/.config/yarn/global/node_modules/stream-chat/dist/index.js:4245:15)
    at StreamChat.handleResponse (~/.config/yarn/global/node_modules/stream-chat/dist/index.js:4259:20)
    at StreamChat._callee8$ (~/.config/yarn/global/node_modules/stream-chat/dist/index.js:4044:56)
    at tryCatch (~/.config/yarn/global/node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:45:40)
    at Generator.invoke [as _invoke] (~/.config/yarn/global/node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:271:22)
    at Generator.prototype.(anonymous function) [as throw] (~/.config/yarn/global/node_modules/@babel/runtime/node_modules/regenerator-runtime/runtime.js:97:21)
    at asyncGeneratorStep (~/.config/yarn/global/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24)
    at _throw (~/.config/yarn/global/node_modules/@babel/runtime/helpers/asyncToGenerator.js:29:9)

Conflict with imagemagick

I know this was already raised in #33, but it is not a good recommendation for end users to just deal with imagemagick already being installed.

The rule of thumb in the global bin namespace is that if the name has been taken, find another one. How about streamio...or anything really? The burden of installing a program, then wondering why none of the config options work, then discovering oh, I have stream installed already? I have no idea what that is...let's start searching on Google, etc etc.

gz#11106

Ability to supporrt multiple environments / configs

In our use case, we have multiple environments, and to switch environments, we need to rename file ~/.config/getstream-cli/config.json , and copy over file for the new environment.

Is there a simpler way that this can be achieved? (Possibly a CLI option to pass config location or may be setting up different profiles like AWS CLI) ?

gz#10827

UpdateUsers failed with error: "api_key is invalid"

Can't log chats

stream chat:log ๎‚ฒ โœ” ๎‚ฒ 5146 ๎‚ฒ 18:56:29 โœ” What is the unique identifier for the channel? ยท 1 โœ” What type of channel is this? ยท livestream โœ” What event would you like to filter on? ยท all Error: StreamChat error code 2: UpdateUsers failed with error: "api_key is invalid" at StreamChat.errorFromResponse (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/dist/index.js:3034:15) at StreamChat.handleResponse (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/dist/index.js:3048:20) at StreamChat._callee7$ (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/dist/index.js:2896:56) at tryCatch (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/node_modules/regenerator-runtime/runtime.js:62:40) at Generator.invoke [as _invoke] (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/node_modules/regenerator-runtime/runtime.js:288:22) at Generator.prototype.(anonymous function) [as throw] (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/node_modules/regenerator-runtime/runtime.js:114:21) at asyncGeneratorStep (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/node_modules/@babel/runtime/helpers/asyncToGenerator.js:3:24) at _throw (/usr/local/lib/node_modules/getstream-cli/node_modules/stream-chat/node_modules/@babel/runtime/helpers/asyncToGenerator.js:29:9)

CLI not doing what is expected

According to the CLI, I would hope to get a channel if I ran a query like :

stream chat:channel:query -c league-event-15890211145eb689baeab6c

From the CLI help:
$ stream chat:channel:query

OPTIONS
-c, --channel=channel The unique identifier for the channel you want to query.

however, the result I got was for another channel:
{ id: 'league-event-15863469465e8dbbc208999',
type: 'gaming',
cid: 'gaming:league-event-15863469465e8dbbc208999',
created_at: '2020-05-18T13:08:37.770551Z',
updated_at: '2020-05-18T13:08:37.770552Z',
created_by:
{ id: 'smitty',
role: 'user',
created_at: '2020-04-20T11:17:41.28747Z',
updated_at: '2020-05-18T13:08:37.768163Z',
banned: false,
online: false,
image: '/files/gallery/misc/thumbs/shawnpic_scout1580827099.png',
name: 'smitty' },
frozen: false,
member_count: 1,
config:
{ created_at: '2020-04-18T19:06:32.264792Z',
updated_at: '2020-05-03T18:38:19.081114Z',
name: 'gaming',
typing_events: true,
read_events: true,
connect_events: false,
search: true,
reactions: false,
replies: false,
mutes: false,
uploads: true,
url_enrichment: true,
message_retention: 'infinite',
max_message_length: 300,
automod: 'disabled',
automod_behavior: 'flag',
commands: [ [Object], [Object], [Object], [Object] ] },
members:
{ aeryith:
{ user: [Object],
role: 'member',
created_at: '2020-05-18T13:08:37.907648Z',
updated_at: '2020-05-19T13:28:11.959162Z' } } }

after the channel with ID "league-event-15890211145eb689baeab6c" was created, then it returned the correct channel.

stream chat:channel:query -c league-event-15890211145eb689baeab6c
{ id: 'league-event-15890211145eb689baeab6c',
type: 'gaming',
cid: 'gaming:league-event-15890211145eb689baeab6c',
created_at: '2020-05-19T13:56:08.640606Z',
updated_at: '2020-05-19T13:56:08.640607Z',
created_by:
{ id: 'GyoScore',
role: 'admin',
created_at: '2020-04-19T22:51:31.029074Z',
updated_at: '2020-05-19T13:56:08.636721Z',
banned: false,
online: false,
image: 'https://gyo.gg/images/letters/p.png',
name: 'GyoScore' },
frozen: false,
member_count: 2,
config:
{ created_at: '2020-04-18T19:06:32.264792Z',
updated_at: '2020-05-03T18:38:19.081114Z',
name: 'gaming',
typing_events: true,
read_events: true,
connect_events: false,
search: true,
reactions: false,
replies: false,
mutes: false,
uploads: true,
url_enrichment: true,
message_retention: 'infinite',
max_message_length: 300,
automod: 'disabled',
automod_behavior: 'flag',
commands: [ [Object], [Object], [Object], [Object] ] },
event: 'league-event-15890211145eb689baeab6c',
name: 'aeryith v. noahhankinson',
season: 'season-1-1589019460',
members:
{ dphunct:
{ user: [Object],
is_moderator: true,
role: 'moderator',
created_at: '2020-05-19T13:56:08.880307Z',
updated_at: '2020-05-19T13:56:08.880307Z' },
aeryith:
{ user: [Object],
role: 'member',
created_at: '2020-05-19T13:57:21.162494Z',
updated_at: '2020-05-19T13:57:21.162494Z' } } }

and just because:

gyo-webcomponents % stream chat:channel:query -c should-not-work { id: 'league-event-15890211145eb689baeab6c',
type: 'gaming',
cid: 'gaming:league-event-15890211145eb689baeab6c',
created_at: '2020-05-19T13:56:08.640606Z',
updated_at: '2020-05-19T13:56:08.640607Z',
created_by:
{ id: 'GyoScore',
role: 'admin',
created_at: '2020-04-19T22:51:31.029074Z',
updated_at: '2020-05-19T13:56:08.636721Z',
banned: false,
online: false,
name: 'GyoScore',
image: 'https://gyo.gg/images/letters/p.png' },
frozen: false,
member_count: 2,
config:
{ created_at: '2020-04-18T19:06:32.264792Z',
updated_at: '2020-05-03T18:38:19.081114Z',
name: 'gaming',
typing_events: true,
read_events: true,
connect_events: false,
search: true,
reactions: false,
replies: false,
mutes: false,
uploads: true,
url_enrichment: true,
message_retention: 'infinite',
max_message_length: 300,
automod: 'disabled',
automod_behavior: 'flag',
commands: [ [Object], [Object], [Object], [Object] ] },
event: 'league-event-15890211145eb689baeab6c',
name: 'aeryith v. noahhankinson',
season: 'season-1-1589019460',
members:
{ dphunct:
{ user: [Object],
is_moderator: true,
role: 'moderator',
created_at: '2020-05-19T13:56:08.880307Z',
updated_at: '2020-05-19T13:56:08.880307Z' },
aeryith:
{ user: [Object],
role: 'member',
created_at: '2020-05-19T13:57:21.162494Z',
updated_at: '2020-05-19T13:57:21.162494Z' } } }

Is this appropriate behavior? Should I get an error if the channel does not exist?

event not found: members when retrieving channel by type & ID

I created a unique channel with two members by leaving the channel ID empty.

When using the CLI to list channels, this channel was returned. However, when using the CLI to get this channel by its type and ID, I get the following error:
zsh: event not found: members

stream-cli chat get-channel -t TYPE -i ID

Is there any kind of multi-config/multi-app support

I'm trying to use this tool with a number of different stream apps. I've figured out that one can set the XDG_CONFIG_HOME env var to use different directories for the config file-- but before I dive deeper, I was curious if you've already built something in that allows config file overwriting?

If not, I'll do some kind of wrapper script for the short-term and maybe submit a PR in the future with a better baked-in solution.

gz#8486

Chat Development Tokens toggle

// disable auth checks, allows dev token usage
await client.updateAppSettings({
    disable_auth_checks: true,
});

// re-enable auth checks
await client.updateAppSettings({
    disable_auth_checks: false,
});

Unable to set config using flags

The docs mention that the stream config:set command should work with the following flags:

OPTIONS
  -e, --email=email    Email for configuration.
  -j, --json           Output results in JSON. When not specified, returns output in a human friendly format.
  -k, --key=key        API key for configuration.
  -m, --mode=mode      Environment to run in (production or development for token and permission checking).
  -n, --name=name      Full name for configuration.
  -s, --secret=secret  API secret for configuration.
  -t, --telemetry      Enable error reporting for debugging purposes.
  -u, --url=url        API base URL for configuration.

But regardless of how I call it, the command ignores the flags and instead prompts for them individually:

$ stream config:set --name "name" --email "email" --key "key" --secret "secret" --url "url"
? What is your full name? โ€บ
$ stream config:set --name=name --email=email --key=key --secret=secret --url=url
? What is your full name? โ€บ
stream config:set -n name -e email -k key -s secret -u url
? What is your full name? โ€บ

Using version: getstream-cli/0.0.61 darwin-x64 node-v12.10.0

CLI updating channel with image null doesn't work (bug)

Hello,

I was trying to update a channel's image field via the CLI:

stream chat:channel:update -t 'messagingMembersOnly' -c "chatRoom_9nuDGTNQoEpF7NFzHhQ71U" --image=null

But that command had an unintended effect it set the image to "null" instead of null

I tried to undo this by updating all the fields:

stream chat:channel:update -t 'messagingMembersOnly' -c "chatRoom_9nuDGTNQoEpF7NFzHhQ71U" --daisieChatRoomUuid="chatRoom_9nuDGTNQoEpF7NFzHhQ71U"
--daisieIsBlocked=false
--daisieIsEmptyRoom=false
--daisieProjectUuid="project_xspmfR3Q6UdsSnjNa44tgE"
--daisieRoomType="project"
--name="my image is null :o"
--image=null

But then I get an 'Unexpected arguments' error for our custom fields (like daisieRoomType).

Is there a way to set a field to null instead of "null" ?

Updating channel data properties

First off, this is a wonderful tool! My company is working on getting integrated with Stream and we were looking for a tool just like this to help bootstrap the process. Curious if I am missing something or if this feature is yet missing/planned:

  • When updating a channel, is it possible to add channel data key:values to an existing channel through this CLI tool?

I may be able to contribute the patch if you can point me in the right direction and any pointers you might have.

Running get-app command throws an error

When I try running the command stream-cli chat get-app --app stream-test to get the application setting for the stream-test app I have created on my local system I get:

cannot unmarshal body: illegal base64 data at input byte 0

Chat Permission Checking

// disable permission checks
await client.updateAppSettings({
	disable_permissions_checks: true,
});

// re-enable permission checks
await client.updateAppSettings({
	disable_permissions_checks: false,
});

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.