Giter Site home page Giter Site logo

jdryg / vg-renderer Goto Github PK

View Code? Open in Web Editor NEW
473.0 41.0 53.0 2.22 MB

A vector graphics renderer for bgfx, based on ideas from NanoVG and ImDrawList (Dear ImGUI)

License: BSD 2-Clause "Simplified" License

C 60.79% SuperCollider 0.20% Makefile 0.02% C++ 38.97% Scala 0.02%
vector-graphics

vg-renderer's Introduction

vg-renderer

A vector graphics renderer for bgfx, based on ideas from NanoVG and ImDrawList (Dear ImGUI)

Includes some small changes to FontStash. Optionally uses libtess2 for concave polygon decomposition.

Path and Stroker classes

Paths are tesselated using the Path struct (src/vg/path.cpp, .h). You can use vg::pathXXX() functions to convert your SVG commands to a polyline for uses outside this renderer.

Strokes and fills are generated using the Stroker struct (src/vg/stroker.cpp, .h). You can use vg::strokerXXX() functions to generate strokes and fills for your polylines for uses outside this renderer.

Compared to NanoVG/FontStash

  1. Generates fewer draw calls by batching multiple paths together (if they share the same state)
  2. Separate shader programs for gradients and image patterns to reduce uniform usage (NanoVG's bgfx backend uses a single program for all cases)
  3. Concave polygons are decomposed on the CPU.
  4. Command lists with support for tesselation caching.
  5. Clip in/out with the stencil buffer
  6. User-specified indexed triangle list rendering (i.e. for complex gradients and sprite atlases).
  7. Fills with image patterns can be colored.
  8. FontStash: glyph hashing uses BKDR (seems to give better distribution of glyphs in the LUT; fewer collisions when searching for cached glyphs)
  9. FontStash: optional (compile-time flag) caching of glyph indices and kerning info for ASCII chars in order to avoid repeated calls to stbtt functions.

What's not supported compared to NanoVG

  1. Miter limit (i.e miter joins never convert to bevel joins)
  2. Polygon holes (they can be emulated using clip in/out regions)
  3. Variable text line height
  4. Skew transformation matrix

Images

DLS

DLS

SVG (using simple-svg)

Tiger

Demo

Demo

Custom gradients (indexed triangle lists w/ per-vertex colors)

Gradients

vg-renderer's People

Contributors

dschnee avatar hugoam avatar jdryg 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  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

vg-renderer's Issues

Draw bgfx texture directly

I need the ability to send a draw command using a bgfx::Texture that I own (not one created by vg).

This is, as far as I know, the only way to draw multiple 3D viewports inside of UI widgets. (as in this video, for reference : https://twitter.com/hugoamnov/status/978444939959898112)
It's pretty nice as this way you send the draw commands of the viewports exactly in the same way you send the rest of the UI graphics.

I implemented the change locally and it works fine. API changes are minor : it just needs a function to create an Image with a bgfx texture handle.

Note : I opted for a uint16_t instead of directly a bgfx::TextureHandle : it is less explicit in term of the function signature, but it was the only way to not depend on bgfx in vg's header. In my opinion depending on bgfx in the header would be kind of okay since vg works only with bgfx anyway, but all this is up to you ;)
Another option would be to make the name explicit like : createBgfxImage or registerBgfxImage.

ImageHandle createImage(Context* ctx, uint32_t flags, uint16_t bgfx_texture)
{
	ImageHandle handle = allocImage(ctx);
	if(!isValid(handle)) {
		return VG_INVALID_HANDLE;
	}

	Image* tex = &ctx->m_Images[handle.idx];

	uint32_t bgfxFlags = BGFX_TEXTURE_NONE;

#if BX_PLATFORM_EMSCRIPTEN
	if(!bx::isPowerOf2(w) || !bx::isPowerOf2(h)) {
		flags = ImageFlags::Filter_NearestUV | ImageFlags::Filter_NearestW;
		bgfxFlags |= BGFX_TEXTURE_U_CLAMP | BGFX_TEXTURE_V_CLAMP | BGFX_TEXTURE_W_CLAMP;
	}
#endif

	if(flags & ImageFlags::Filter_NearestUV) {
		bgfxFlags |= BGFX_TEXTURE_MIN_POINT | BGFX_TEXTURE_MAG_POINT;
	}
	if(flags & ImageFlags::Filter_NearestW) {
		bgfxFlags |= BGFX_TEXTURE_MIP_POINT;
	}
	tex->m_Flags = bgfxFlags;

	tex->m_bgfxHandle = { bgfx_texture };

	return handle;
}

Segmentation fault in stroker.cpp vg::addPosColor

A few people have been reporting a segmentation faults when using toy/mud, on some specific platforms, happening inside stroker.cpp.
https://github.com/hugoam/mud-sample/issues/1
This error dates from before you made some changes to that code recently, but I also have a more recent stacktrace from after your recent changes to stroker.cpp (see after).
The first one seems like a Ubuntu 16.04 64 bits build, and the second is a macOS 64 bits build.

It's hard for me to guess what's going wrong (there's a looot of potentially unsafe manual pointer operations in there), but my first feeling is that for something like that to happen, while mud otherwise works fine on other platforms/architecture, it's probably a problem internal to vg-renderer and not an issue in the calling code. But it's hard to know for sure though, so I'd be happy to get your input on this :)

Do you know how we could investigate why this error is happening ?

2018-08-10 01:13:02.878388-0400 00_cube_d[38160:1599409] ../../../mud/3rdparty/bgfx/src/renderer_gl.cpp (4439): BGFX attr a_texcoord0: 1 Process 38160 stopped * thread #1, name = 'bgfx - renderer backend thread', queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT) frame #0: 0x000000010183cc0f 00_cube_d`void vg::addPosColor<3u>(stroker=0x0000000103347e80, srcPos=0x00007ffeefbfe070, srcColor=0x00007ffeefbfe0f0) at stroker.cpp:2560
   2557                 *dstPos128 = *srcPos128; // x0, y0, x1, y1
   2558                 *dstColor64 = *srcColor64; // c0, c1
   2559         } else if (N == 3) {
-> 2560                 *dstPos128 = *srcPos128; // x0, y0, x1, y1
   2561                 dstPos64[2] = srcPos64[2]; // x2, y2
   2562                 *dstColor64 = *srcColor64; // c0, c1
   2563                 dstColor[2] = srcColor[2]; // c2
Target 0: (00_cube_d) stopped.
(lldb) bt
* thread #1, name = 'bgfx - renderer backend thread', queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
  * frame #0: 0x000000010183cc0f 00_cube_d`void vg::addPosColor<3u>(stroker=0x0000000103347e80, srcPos=0x00007ffeefbfe070, srcColor=0x00007ffeefbfe0f0) at stroker.cpp:2560 frame #1: 0x000000010183546e 00_cube_d`void vg::polylineStrokeAAThin<(vg::LineCap::Enum)0, (vg::LineJoin::Enum)0>(stroker=0x0000000103347e80, mesh=0x00007ffeefbfe1c8, vtx=0x0000000103618500, numPathVertices=4, color=4281611316, closed=true) at stroker.cpp:2332
    frame #2: 0x0000000101834b8e 00_cube_d`vg::strokerPolylineStrokeAAThin(stroker=0x0000000103347e80, mesh=0x00007ffeefbfe1c8, vertexList=0x0000000103618500, numPathVertices=4, isClosed=true, color=4281611316, lineCap=Butt, lineJoin=Miter) at stroker.cpp:319 frame #3: 0x000000010184cf12 00_cube_d`vg::ctxStrokePathColor(ctx=0x0000000109b80000, color=4281611316, width=1, flags=16) at vg.cpp:3213
    frame #4: 0x0000000101850bdb 00_cube_d`vg::ctxSubmitCommandList(ctx=0x0000000109b80000, handle=(idx = 1)) at vg.cpp:4191 frame #5: 0x000000010184539e 00_cube_d`vg::submitCommandList(ctx=0x0000000109b80000, handle=(idx = 1)) at vg.cpp:1716
    frame #6: 0x0000000100b9ce05 00_cube_d`mud::VgVg::draw_layer(this=0x00000001033144a0, layer=0x000000011e620cc0, position=0x00000001019bca98, scale=1)0> const&, float) at VgVg.cpp:374 frame #7: 0x0000000100c6d648 00_cube_d`mud::Typed<std::__1::vector<mud::Index*, std::__1::allocator<mud::Index*> > >::type() - 18446744069401553335
    frame #8: 0x0000000100c6d5ed 00_cube_d`mud::Typed<std::__1::vector<mud::Index*, std::__1::allocator<mud::Index*> > >::type() - 18446744069401553426 frame #9: 0x0000000100c6d579 00_cube_d`mud::Typed<std::__1::vector<mud::Index*, std::__1::allocator<mud::Index*> > >::type() - 18446744069401553542
    frame #10: 0x0000000100c41158 00_cube_d`std::__1::function<void (mud::Layer&)>::operator(this=0x00007ffeefbfea40, __arg=0x000000011e620cc0)(mud::Layer&) const at functional:1916 frame #11: 0x0000000100c40f63 00_cube_d`mud::Layer::visit(this=0x000000011e620cc0, visitor=0x00007ffeefbfea40)> const&) at Layer.cpp:72
    frame #12: 0x0000000100c410e6 00_cube_d`mud::Layer::visit(this=0x000000010581a300, visitor=0x00007ffeefbfea40)> const&) at Layer.cpp:75 frame #13: 0x0000000100c65a0a 00_cube_d`mud::Typed<std::__1::vector<mud::Index*, std::__1::allocator<mud::Index*> > >::type() [inlined] std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >::basic_string(this="\fb\x1e\x01\0\0\0e\x01, __s="p7a\x1e\x01") - 18446744069401585141
    frame #14: 0x0000000100cb10e2 00_cube_d`mud::UiWindow::render_frame(this=0x00000001033467a0) at UiWindow.cpp:157 frame #15: 0x00000001000d41b4 00_cube_d`mud::Shell::pump(this=0x00007ffeefbfec40) at Shell.cpp:85
    frame #16: 0x00000001000d4044 00_cube_d`mud::Shell::run(this=0x00007ffeefbfec40, func=0x00007ffeefbfec10, iterations=0)> const&, unsigned long) at Shell.cpp:77 frame #17: 0x000000010008e667 00_cube_d`main(argc=1, argv=0x00007ffeefbff6e0) at 00_cube.cpp:57

viewID at context creation is too restrictive

I'm just now looking into multi-window rendering, so for the first time I will need more than one UI, and it would be much more convenient if viewID was specified when submitting instead of at context creation.
I'll change my local copy and try this, but if you want to start thinking about it and giving me your thoughts :)

Questions

I have couple questions, sorry if they seem stupid sometimes, but maybe you can clear my mind:

  1. What type of Matrix to supply to ApplyTransform (3x2, 4x4?).

  2. Is the matrix supplied is global to the IRenderer or relative to the current state in tree (PopState/PushState) methods?

  3. What are pros/cons using Shapes instances? are they faster? Are they suited only for static shapes or can be animated?

  4. Is this library suited for complex animations? (dynamic shapes+ dynamic colors)

  5. Is it possible to rasterize a Shape into a texture?

  6. Are the shapes vertices stored in the vertexBuffer, or are they just a quads, with the shaders responsible of drawing the outline?

  7. What is the best approach to implement colliders/mouse input detection?

Thank you

Crazy idea #1: Stroke/fill colors in texture

Reason

Being able to draw the same cached command list with different colors per-instance. E.g. in an editor you can change the color of the selected shape without needing a separate command list with the same shape but with different colors.

Idea

Instead of baking the actual color per vertex, use the RGB channels of the vertex color as an index into a color texture (alpha should still be calculated for AA fringes). In the vertex shader, decode the RGB part of the color into UV coordinates and in the fragment shader sample the color texture using these UV coords.

Pros

  • Allows using the same cached command list with different colors per instance.

Cons

  • 2 texture lookups in the fragment shader

Extras

  • Requires a way to submit a command list with variable stroke/fill arguments. E.g. in addition to clStrokePath(..., Color col) also have clStrokePath(..., ParamID param) where the ParamID will point to a parameter buffer which will be passed to submitCommandList().

Update code to work with bgfx master

bgfx changed some texture flags from BGFX_TEXTURE_ to BGFX_SAMPLER_
Could you update these so I can use vg-renderer with latest version of bgfx ? I would like to continue using vg-renderer without maintaining a fork :)

VG does not discard state since bgfx commit 0881d98b

bgfx::submit() old preserveState parameter has been changed to a semantically opposite meaning, it is now a discard parameter, since this commit: bkaradzic/bgfx@0881d98
This causes vg-renderer to silently always preserve state, when it intends to always discard it.
All instances of bgfx::submit() with two last arguments being 0, false should be fixed. (those parameters have default values, so in the future it is actually safer to omit them, to avoid a similar issue happening in the future)

Make alpha blending optional

When using vg-renderer to "compose" viewports on the screen, there is currently no control on the blend mode, which right now is hardcoded to alpha blending.
It would be nice if vg-renderer exposed a way to change that blend mode :)

Unable to cleanly shutdown

Hi,
Just started playing around with this library and bgfx for the first time and having trouble getting it to shutdown cleanly. It seems like vg and bgfx are each dependent on the other shutting down first and I'm not sure how to resolve it.

Here's the essence of what I'm trying. First, initialization:

bgfx::init(...);
_vgContext = vg::createContext(...);

Then render a square:

bgfx::setViewRect(0, 0, 0, _width, _height);
bgfx::touch(0);

vg::beginFrame(_vgContext, GetWidth(), GetHeight(), 1.0f);
vg::beginPath(_vgContext);
vg::moveTo(_vgContext, 0.0f, 0.0f);
vg::lineTo(_vgContext, 0.0f, 100.0f);
vg::lineTo(_vgContext, 100.0f, 100.0f);
vg::lineTo(_vgContext, 100.0f, 0.0f);
vg::closePath(_vgContext);
vg::fillPath(_vgContext, vg::color4f(1.0f, 0.0f, 0.0f, 1.0f), vg::FillFlags::Enum::Convex);
vg::endFrame(_vgContext);

bgfx::frame();

Finally, shutdown:

vg::destroyContext(_vgContext);
bgfx::shutdown();

If I destroy the vg context first, then bgfx's render thread tries to release (via releaseIndexBufferCallback) an index buffer that vg has already freed. If I shutdown bgfx first, then vg::destroyContext tries to destroy programs that bgfx has already freed. If I don't destroy the vg context, then bgfx complains about a bunch of leaked handles on shutdown.

Any assistance sorting this out is much appreciated. Thanks!

Emscripten command buffer error

I took half a day to track down a nasty error that happened only when compiling to Emscripten + WebAssembly.

Apparently the problem is an alignment issue : in WebAssembly it seems you can't have commands aligned on 2 bytes, and it happens that the CreateImagePattern is the only one that has a total size that is not a multiple of 4. (it's 30 bytes large)

As a result, in WebAssembly, any call to CreateImagePattern completely messes up the rest of the command list.

Here is a raw git diff of a workaround to fix that, which is padding the command with another uint16_t.
This is not a really nice solution, it's just a quick fix, so I suppose you can think of a nicer one (like forcing all commands to be padded to a multiple of 4 ?)

diff --git a/src/vg.cpp b/src/vg.cpp
index 79ab4d3..2a4a103 100644
--- a/src/vg.cpp
+++ b/src/vg.cpp
@@ -4242,6 +4242,9 @@ static void ctxSubmitCommandList(Context* ctx, CommandListHandle handle)
                        const float* params = (float*)cmd;
                        cmd += sizeof(float) * 5;
                        const ImageHandle img = CMD_READ(cmd, ImageHandle);
+#ifdef BX_PLATFORM_EMSCRIPTEN
+                       CMD_READ(cmd, uint16_t);
+#endif
                        ctxCreateImagePattern(ctx, params[0], params[1], params[2], params[3], params[4], img);
                } break;
                case CommandType::Text: {
@@ -5804,6 +5807,9 @@ static void clCacheRender(Context* ctx, CommandList* cl)
                        const float* params = (float*)cmd;
                        cmd += sizeof(float) * 5;
                        const ImageHandle img = CMD_READ(cmd, ImageHandle);
+#ifdef BX_PLATFORM_EMSCRIPTEN
+                       CMD_READ(cmd, uint16_t);
+#endif
                        ctxCreateImagePattern(ctx, params[0], params[1], params[2], params[3], params[4], img);
                } break;
                case CommandType::Text: {
@@ -6333,13 +6339,20 @@ static ImagePatternHandle clCreateImagePattern(Context* ctx, CommandList* cl, fl
 {
        VG_CHECK(isValid(image), "Invalid image handle");

+#ifdef BX_PLATFORM_EMSCRIPTEN
+       uint8_t* ptr = clAllocCommand(ctx, cl, CommandType::CreateImagePattern, sizeof(float) * 5 + sizeof(uint16_t) + sizeof(uint16_t));
+#else
        uint8_t* ptr = clAllocCommand(ctx, cl, CommandType::CreateImagePattern, sizeof(float) * 5 + sizeof(uint16_t));
+#endif
        CMD_WRITE(ptr, float, cx);
        CMD_WRITE(ptr, float, cy);
        CMD_WRITE(ptr, float, w);
        CMD_WRITE(ptr, float, h);
        CMD_WRITE(ptr, float, angle);
        CMD_WRITE(ptr, uint16_t, image.idx);
+#ifdef BX_PLATFORM_EMSCRIPTEN
+       CMD_WRITE(ptr, uint16_t, uint16_t(0));
+#endif

        const uint16_t patternHandle = cl->m_NumImagePatterns;
        cl->m_NumImagePatterns++;

Any examples?

I can't find examples about i8080_vg_renderer.png.

Error in vertex calculation

I tried to make a minimal example to demonstrate the problem.

Let's take a bezier curve made in inkscape:
image
If I try render with vg I see what:
image

Code:

vg::beginPath(vgContext);
float x = 84.889012f; 
float y = 71.749671f;
vg::moveTo(vgContext, x, y);

vg::cubicTo(vgContext,
          x - 2.59f, y + 3.04f,
          x - 6.31f, y + 4.89f,
          x - 10.12f, y + 5.88f);
x = x - 10.12f; y = y + 5.88f;

vg::cubicTo(vgContext,
          x - 3.62f, y + 1.4f,
          x - 6.86f, y + 3.58f,
          x - 10.37f, y + 5.21f);
x = x - 10.37f; y = y + 5.21f;

vg::cubicTo(vgContext,
          x - 2.07f, y + 1.0f,
          x - 4.25f, y + 1.78f,
          x - 6.24f, y + 2.96f);
x = x - 6.24f; y = y + 2.96f;

vg::cubicTo(vgContext, 
          x - 0.509996f, y + 0.1f,
          x + 0.96f, y - 0.67f,
          x + 1.29f, y - 0.85f);
x = x + 1.29f; y = y - 0.85f;

vg::cubicTo(vgContext,
          x + 2.62f, y - 1.3f,
          x + 5.35f, y - 2.37f,
          x + 7.92f, y - 3.78f);
x = x + 7.92f; y = y - 3.78f;

vg::cubicTo(vgContext,
          x + 3.19f, y - 1.6f, 
          x + 6.23f, y - 3.58f,
          x + 9.71f, y - 4.52f);
x = x + 9.71f; y = y - 4.52f;

vg::cubicTo(vgContext,
          x + 2.57f, y - 0.72f,
          x + 4.94f, y - 2.11f,
          x + 6.79f, y - 4.03f);
x = x + 6.79f; y = y - 4.03f; 

vg::cubicTo(vgContext,
          x + 0.34f, y - 0.29f,
          x + 0.58f, y - 0.71f,
          x + 1.02f, y - 0.87f);

vg::closePath(vgContext);
vg::strokePath(vgContext, vg::Colors::Black, 4.0f, vg::StrokeFlags::ButtMiterAA); // Error also with vg::StrokeFlags::ButtMiter

Also the problem is easy to reproduce it to output svg on a small scale (0.1f or less) with AA enabled:
image
image

In an imperial way, I tried to change the kMaxExtrusionScale parameter here:

static const float kMaxExtrusionScale = 1.0f / 100.0f;
and there are fewer chaotic lines. But there are small inaccuracies elsewhere. Any ideas on how to fix this?

Instancing

Hello,

I was wondering if I can use hardware instancing somehow with vg-rendering?

Thanks

LineCap and LineJoin

I've seen it's not supported, but I wonder why ?
What is the default cap and join them ? Butt and Miter ?
Would it be difficult to implement it?

As I understand it, concerning line cap, except for round, it's just a coordinate offset.
For round, which is quite rare, one could draw a filled ellipse there, so it's possible to do it.

Line joins either need to support clipping (with scissors) or adding a line for the bevel case.

Nasty crash if scale happens to be zero.

A call to textBox if the scale happens to be zero result in a terrible crash: vg-renderer keeps allocating new text atlases until the app everything explodes, basically.

The core of the problem seems to be the logic here: https://github.com/jdryg/vg-renderer/blob/master/src/vg.cpp#L1934
Fons doesn't find the glyph because size is equal to zero, and vg's reaction to fons not finding the glyph is to allocate a new atlas :/

I don't know enough about vg-renderer internals to say where a security should be added, but something needs to be done somewhere :)

Also, the fact that the scale was set to zero is problematic: I didn't set a zero scale anywhere myself, it's something related to command lists. I'll let you know if I find the cause of that.

Vg-renderer Usage Example/Documentation for BGFX.

Hello! Is there any working example/documentation/code sample for how to use this inside BGFX? I am new to BGFX, currently I a rendering the simple geometry using BGFX. If I want to use this renderer, how can I use this inside my sample code? I also tried to go through the previous issue regarding the example but was not able to make much out of it. Any help is appreciated.

Rendering issue

Hello,

First of all, thanks for making this available. I've converted a project of mine to it and got a nice performance improvement over NanoVG (from 20% usage to 10% usage), and given I'm only rendering rectangles I think I can get that much lower, but I digress.

My project is a reimplementation of https://github.com/movAX13h/Binmap which is a really nice tool. Normally, the tool looks like this:

BinmapCpp

However, I'm hitting some kind of bug and after playing a bit the image becomes this:

BinmapCppBug

Actually, I think it's flashing every frame between the 2 states. The thing is, the exact same commands are being sent in those 2 cases (and I've verified everything is balanced), so there must be some internal state that's getting out of whack.

I understand helping without more info is impossible, but I'd like to ask if you had any ideas of where I should be looking for debugging this issue. I also think it might be text related, as removing all text makes the issue disappear, but that might be a red herring.

I've also removed the CommandListCache just to test, but that wasn't it either.

Thanks in advance.

vg::textBox() broken

vg::textBox() implementation doesn't match it's declaration anymore so you get link error if you use that function.
Quickest fix I is changing the declaration in vg.h to (also defaulted to not break the API, but who cares :) ) :

void textBox(Context* ctx, const TextConfig& cfg, float x, float y, float breakWidth, const char* text, const char* end, uint32_t flags = 0U);

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.