Giter Site home page Giter Site logo

ode4j's Introduction

ode4j

Java 8 Java 9+

ode4j is a Java port of ODE.

ODE is an open source, high performance library for simulating rigid body dynamics. It is fully featured, stable, mature and platform independent with an easy to use C/C++ API. It has advanced joint types and integrated collision detection with friction. ODE is useful for simulating vehicles, objects in virtual reality environments and virtual creatures.

The latest released version of ode4j is 0.5.3, but the master branch may contain fixes and improvements. Release 0.5.0 contains all changes up to ODE 0.16.3.

Resources

There is also a GWT compatible fork of ode4j.

The following artifact contains the complete physics engine (examples etc. are not included):

<dependency>
    <groupId>org.ode4j</groupId>
    <artifactId>core</artifactId>
    <version>0.5.3</version>
</dependency>

News

2024-04-28: Release 0.5.3:

  • Bug fix for possible INTERNAL ERROR in DLCP/FastSolver + some minor improvements

2023-10-07: Release 0.5.2:

  • Bug fix for DVector3.cross() + some minor improvements

2023-09-17: Release 0.5.1:

  • Bug fix for demos running on Apple Silicon/Retina

2023-05-27: Release 0.5.0. Full update to ODE 0.16.3 + Java 8 as baseline:

  • Port of all changes up to ODE 0.16.3
  • Java 8 required
  • LWJGL 3.x for demos
  • Tested Android compatibility with API level 24 (Android 7 / Nougat)
  • CI for Java 8 + 9
  • Improved API (mostly in math package)
  • Cleanup (e.g. full JUnit 4 style test, fixed most lint warnings up to Java 17)
  • Bug fixes
  • BREAKING CHANGE: DSpace.getGeoms() now returns DGeom instead of DxGeom.

2023-03-31: Release 0.4.1 & 0.4.2. Mostly a bugfix release + some API helper methods:

  • Fix OSGI bundle info to require Java 1.7 instead of 7.0
  • New helper methods: `
    • DBody : addLinearVelocity()
    • DVector3: reAdd(), eqToRadians(), eqToDegrees() (convert angles in a DVector3, eq prefix means that the object is set equal to the result)
    • DQuaternion: ZERO, IDENTITY, isEq(), length(), lengthSquared(), toEuler(), fromEuler(), toEulerDegrees(), fromEulerDegrees(), eqInverse(), reInverse().
  • 0.4.2 fixes some small regressions with 0.4.1

2019-01-03: Release 0.4.0. This release contains most of the changes that happened between ODE 0.13.1 and ODE 0.16.0, plus some original features:

  • Java 9 / modularization (generated jar files are Java 7) (io7m)
  • Implemented/migrated multi-threading for the stepper (Pjotr)
  • SAP-Space optimization: Avoid collision detection for immobile bodies (Pjotr)
  • New BVH tree for better scalability with 10'000 bodies or more, ported from the Turbulenz Engine (Pjotr)
  • Fixed javadoc to compile without warnings

2018-03-26: Snapshot release 0.4.0

  • Java 9 / modularization (generated jar files are Java 7) (io7m)

2017-11-16: Snapshot release 0.4.0

2017-10-06: Release of ode4j 0.3.1

  • Numerous bugfixes and improvement, see CHANGELOG
  • This is the last release built with Java 6.

Project overview

  • The "core" package contains the main library code. The public API is in:

    • org.ode4j.math
    • org.ode4j.ode
    • org.ode4j.ode.ragdoll

    All other packages are "internal" and should normally not be used.

  • The "demo" package contains demo application for various simulation problems. The package contains the "drawstuff" library which is handy for visualizing simple physics simulation but should not be used for real applications (it is slow and clunky). Please use proper library such as lwjgl for your own games or simulations.

  • The "core-cpp" and "demo-cpp" packages are legacy packages and should be ignored.

General recommendations

  • Please use DWorld.quickStep(...) instead of DWorld.step(). The latter is slower and appears to be less stable.
  • Consider disabling geometries that do not move. For an example, refer to DemoCrash. The demo disables boxes that have not moved for a few steps. If a whole "island" of bodies is disabled, it is automatically excluded from simulation (bodies are automatically re-enabled when necessary), see also ODE wiki.
  • Set OdeConfig.dDEBUG = true for debugging and = false for best performance.
  • When compiling with JDK 9 or later, mvn will automatically use theon-jdk-9-plus profile and create modules.
  • In case of GC problems (e.g. on Android): There may be excessive garbage collection due to frequent allocation of DContact objects. To avoid this, these objects can be nullified and reused. See PerfCards.nearCallback() for an example.

ODE vs od4j

While ode4j is a pretty literal port from ODE, there are some considerable differences (besides one being Java and the other being C++). Some differences concern the API, others are mostly internal.

ode4j supported ODE features

  • ode4j ist mostly similar to ODE when compiling ODE with ./configure --enable-double-precision --with-trimesh=gimpact --enable-libccd. That means:
    • ode4j uses double precision throughout
    • ode4j supports only GIMPACT trimeshes, OPCODE is not supported
    • ode4j always uses libccd for collisions
  • ode4j has multithreading support (ODE's "island" solver), however, ode4j does not support ODE's cooperative solver.
  • ode4j has no special memory management (ODE has a "memory arena" concept).

Additional features in ode4j

ode4j contains some custom features that are not present in ODE (see also Wiki):

ode4j API vs ODE API

ode4j's API is very similar to ODE's API, so most tutorials / demos should be easily translatable. However, there are some notable differences:

  • Almost all objects in ode4j are created via the OdeHelper class.

  • Math functions are located in ode4j.math and OdeMath. ode4j has different versions for some math objects, e.g. DVector3 and DVector3C where the trailing C indicates an immutable or Const version of the object.

  • Class names in ode4j start with D instead of d in ODE. d...ID classes have been removed, use d... instead, e.g. dBodyID becomes DBody.

  • ODE uses almost exclusively static methods. ode4j uses instead methods on objects where possible and methods have been renamed accordingly and their signature changed. Some examples:

    • dGeomSetRotation(geom, ...) becomes geom.setRotation(...)
    • dJointSetHingeAxis(hingeJoint, ...) becomes hingeJoint.setAxis(...)

    Many ODE methods have a skip parameter, this has been removed in ode4j.

  • dCollide becomes OdeHelper.collide() and takes as argument a DContactGeomBuffer. This can be created via:

    DContactBuffer contacts = new DContactBuffer(MAX_CONTACTS); 
    OdeHelper.collide (o1, o2, MAX_CONTACTS, contacts.getGeomBuffer());
    
  • Many classes have a "DESTRUCTOR" that replicates some C++ features, however this can usually be ignored.

ode4j internal differences

  • ode4j's DLCP uses ROWPTRS = false
  • SAP-Space uses different merge-sort instead of radix-sort
  • ...

Version overview

ode4j versions and corresponding ODE versions:

  • ode4j 0.5.0 contains all changes up to ODE 0.16.3.
  • ode4j 0.4.0 contains most changes between 0.13.1 and 0.16.0.
  • ode4j 0.3.1 is a port of ODE 0.13.1.
  • ode4j 0.2.4 up to 0.2.9 are ports of ODE 0.12.1

Legal

ode4j: Copyright (c) 2009-2023 Tilmann Zäschke <ode4j(AT)gmx.de>. All rights reserved.

Like the original ODE, ode4j is licensed under LGPL v2.1 and BSD 3-clause. Choose whichever license suits your needs.

ode4j contains Java ports of the following software

  • ODE/OpenDE: Copyright (c) 2001,2002 Russell L. Smith All rights reserved.

  • GIMPACT (part of ODE/OpenDE): Copyright of GIMPACT (c) 2006 Francisco Leon. C.C. 80087371. email: projectileman(AT)yahoo.com

  • LIBCCD: Copyright (c) 2010 Daniel Fiser <danfis(AT)danfis.cz>; 3-clause BSD License

  • Turbulenz Engine: Copyright (c) 2009-2014 Turbulenz Limited; MIT License

ode4j uses the following libraries

Contact

Tilmann Zaeschke ode4j (AT) gmx.de

Special thanks to contributors

Please let me know if I missed anyone!

ode4j's People

Contributors

dependabot[bot] avatar fommil avatar io7m avatar namek avatar neduard avatar peterkir avatar ppiastucki avatar tzaeschke avatar valb3r 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

ode4j's Issues

Move to lwjgl 3?

lwjgl 2.x does not work well with newer Java version. Investigate lwjgl 3.

DTriCallback is unused

After setting up a DTriCallback, I found that it does nothing. Looking into the code, it's never called.

dJointSetTransmissionAxis2() does faulty assert

The method DxJointTransmission.dJointSetTransmissionAxis2(...) performs an assignment instead of equality check.

dUASSERT(mode = TRANSMISSION.dTransmissionIntersectingAxes, "can't set individual axes in current mode" );
should be changed to:
dUASSERT(mode == TRANSMISSION.dTransmissionIntersectingAxes, "can't set individual axes in current mode" );

Observer falls throught triangle terrain

Hi, in my WalkOnTheMoon Applet, the observer is a sphere object.
Unfortunately, if I do not set damping on the observer, it can happen,
that he falls through the terrain. I can help fix this, but I need to know,
which files are to be touched.
Sincerely
Thorsten

Weird behavior in DemoCrash

There are two issues, both point to a (two?) problems in the collider:

  • Letting DemoCrash sit still for a few second will occasionally show the box stack becoming "active", as if one of the boxes moved slightly or was brushed by another object.
  • Choosing ReorderingMethod.REORDERING_METHOD__DONT_REORDER in DxQuickStep line 147 causes DemoCrash to become unstable.

Both could be a good starting point for debugging a problem in DxQuickStep.

Common.__ASSERT methods check incorrectly for 'false' and '0'

The ASSERT in the Common class all check for arg==null. However, only certain cases verify (Boolean)arg == false. No method checks for (Integer)arg == 0.
Moreover, many checks are redundant in Java because the code in the proxomity of the check would trivially throw an NPE.

Switch to Java 7 compatibility

Android supports Java 7 since Android KitKat (4.4 / buildToolsVersion 19).
However, maybe we should not switch to soon, because of legacy Androids

Trimesh to Trimesh Collisions

What can I do (in general) to improve these types of collisions? I have a vehicle and a pilot that will sit inside the vehicle. The cockpit in the vehicle is open so the pilot is visible and I plan to animate the pilot while inside the vehicle. But it should have a "ragdoll" behavior when colliding with other objects. So I can't use a box geom for the vehicle or it will be difficult to place the pilot inside the vehicle.

Thanks!
Jeff

Garbage collection - step()

As mentioned in issue #35, ode4j appears to allocate significant amounts of memory in some situations/systems ("3-4 MB/s").

The problem may be in the stepper which allocates large arrays for the solver during each step.

A solution could involve array pooling.

Incorrect assert

Hi,

It looks like the following assertion is not correct:
public void dGeomSetBody (DxBody b)
{
//dAASSERT (g);
dUASSERT (b == null || (_gflags & GEOM_PLACEABLE) == 0,
"geom must be placeable");

Instead it should be:
dUASSERT (b == null || (_gflags & GEOM_PLACEABLE) != 0,

Respective line of code in ODE:

dUASSERT (b == NULL || (g->gflags & GEOM_PLACEABLE),"geom must be placeable");

Move to Java 8

Move to Java 8.

This should be easy, and if Android compatibility is "fine" we may to Java 9 or later soon afterwards (i.e. before the next major release).

See also #62..

Comparing to other Java physics engines?

More out of curiosity than anything else, has anyone compared ode4j to jBullet?

There is PAL (http://www.adrianboeing.com/pal/index.html) which has some comparisons of C/C++ engines. However, I've seen a number of folks using jBullet these days, and was just curious if there is any comparative information out there.

I recall that there were some arguments that ODE was better than Bullet for realistic physical simulation, which is what brought me to ode4j in the first place (for robots).

quickstep may cause NPE

Quickstep may sometimes cause an NPE:

java.lang.NullPointerException
    at org.ode4j.ode.internal.DxQuickStep.dxQuickStepIsland_Stage1(DxQuickStep.java:1323)
    at org.ode4j.ode.internal.DxQuickStep.dxQuickStepIsland(DxQuickStep.java:1006)
    at org.ode4j.ode.internal.DxQuickStep.run(DxQuickStep.java:2037)
    at org.ode4j.ode.internal.processmem.DxIslandsProcessingCallContext.ThreadedProcessIslandStepper(DxIslandsProcessingCallContext.java:235)
    at org.ode4j.ode.internal.processmem.DxIslandsProcessingCallContext.access$3(DxIslandsProcessingCallContext.java:233)
    at org.ode4j.ode.internal.processmem.DxIslandsProcessingCallContext$4.run(DxIslandsProcessingCallContext.java:228)
    at org.ode4j.ode.threading.ThreadingTemplates$dxThreadedJobInfo.InvokeCallFunction(ThreadingImplTemplates.java:388)
    at org.ode4j.ode.threading.ThreadingTemplates$dxtemplateJobListSelfHandlertemplate.PerformJobProcessingSession(ThreadingImplTemplates.java:1105)
    at org.ode4j.ode.threading.ThreadingTemplates$dxtemplateJobListSelfHandlertemplate.PerformJobProcessingUntilExhaustion(ThreadingImplTemplates.java:1084)
    at org.ode4j.ode.threading.ThreadingTemplates$dxtemplateJobListSelfHandlertemplate.PrepareForWaitingAJobCompletion(ThreadingImplTemplates.java:1056)
    at org.ode4j.ode.threading.ThreadingTemplates$dxtemplateThreadingImplementation.WaitJobCompletion(ThreadingImplTemplates.java:1403)
    at org.ode4j.ode.threading.ThreadingImpl_H$dxSelfThreadedThreading.WaitJobCompletion(ThreadingImpl_H.java:1)
    at org.ode4j.ode.threading.DxThreadingImplementation$10.run(DxThreadingImplementation.java:342)
    at org.ode4j.ode.threading.DxThreadingBase.WaitThreadedCallExclusively(DxThreadingBase.java:179)
    at org.ode4j.ode.internal.DxWorld.dxProcessIslands(DxWorld.java:844)
    at org.ode4j.ode.internal.DxWorld.dWorldQuickStep(DxWorld.java:472)
    at org.ode4j.ode.internal.DxWorld.quickStep(DxWorld.java:1131)
    at org.ode4j.tests.TestIssue_0018.simLoop(TestIssue_0018.java:72)
    at org.ode4j.tests.TestIssue_0018.step(TestIssue_0018.java:192)
    at org.ode4j.tests.TestIssue_0018.test(TestIssue_0018.java:227)

NPE in AMotorJoint.setTorques()

setTorques() can cause an NPE:

  DAMotorJoint j = OdeHelper.createAMotorJoint(world);
  j.setNumAxes(3);
  j.addTorques( 1, 2, 3 );

DxQuickStep: incorrect avel computation: tacc is scaled multiple times

Found this after comparing ode4j behaviour with VRep (using the C implementation of ODE):
I was applying an off-cenetered force to a body, but it caused a VERY slow increase in angular momentum compared to VRep.
So I checked the ode4j source code and found this line:
https://github.com/tzaeschke/ode4j/blob/master/core/src/main/java/org/ode4j/ode/internal/DxQuickStep.java#L1886

Which scales the whole tacc vector three times. Compare to the C++ version (quickstep.cpp):

for (dxBody *const *bodycurr = body; bodycurr != bodyend; invIrow += 12, bodycurr++) {
    dxBody *b = *bodycurr;
    dReal body_invMass_mul_stepsize = stepsize * b->invMass;
    for (unsigned int j=0; j<3; j++) {
        b->lvel[j] += body_invMass_mul_stepsize * b->facc[j];
        b->tacc[j] *= stepsize;
    }
    dMultiplyAdd0_331 (b->avel, invIrow, b->tacc);
}

Trouble compiling to Java 7/8

From the comments that were made, I understood that we can compile ode4j to Java 7. But I'm having trouble compiling to Java 7. Can someone explain how with the new changes in place?

Wiki should include complete HOWTO for importing the whole project via Maven

Currently the according wiki page only describes how to use maven for the 'core' artifact.

The problem with importing the whole project is to get the import of native libraries to work, which are used by lwjgl.
For eclipse there is a special Maven-native plug-in, but seems to collide with the hierarchical project structure of ode4j.

Port OPCODE to Java

ODE uses by default the OPCODE trimesh collider. ode4j has currently only the GIMPACT collider which is a secondary option in ODE.

For more compatibility and to add flexibility, it would be nice to support OPCODE as well.

Change module names

It seems the module name for the core is just core instead of org.ode (as specified in the core module file).

It should be org.ode or org.ode.core.

Is this related to the module names specified in the pom?

missing helper methods?

While I can do...

	body.asInstanceOf[org.ode4j.ode.internal.DxBody].dBodyDestroy()
	geom.asInstanceOf[org.ode4j.ode.internal.DxGeom].dGeomDestroy()

wouldn't these be better in the helper object - or even in the body and geom front end classes

debug errors are unformatted.

v0.5.3
Error message appears as "LCP internal error, s <= 0 (s=%.4f)"

in src/main/java/org/ode4j/ode/internal/ErrorHdl.java I tried a version 0.5.4 with

	public static void dDebug (int num, String msg, Object ... ap) {
		//  va_list ap;
		//  va_start (ap,msg);
		if (debug_function != null) {
			debug_function.call (num,msg,ap);
		} else {
			// changed here
			logger.debug("ODE INTERNAL ERROR " + num + ": " + String.format(msg, ap));
		}
		// *((char *)0) = 0;   ... commit SEGVicide
		//abort();
		throw new RuntimeException("#"+num + ": " + String.format(msg, ap));
	}

but the error message came out the same. Perhaps I am failing to install the package?

Replace slf4j dependency

Can you remove slf4j dependency from core?

As I see it used only in ErrorHdl class.
Can you replace it with some interface, that can be implemented externaly, like as plugin?
For example you can create some global object like Log, which has static variable imp for storing logging interface implementation. This object may be used internaly in odej4. And users can implement any loggers that they like. For default implementation in core, can be simple System.out.println

slf4j internally using reflection, so I can't use ode4j with teavm.
Is odej4 using reflection?

Also I think the fewer dependencies the better.

Cannot download sources

When I look at a method in ODE4J I get (for example)

public interface DCylinder extends DGeom {
    void setParams(double var1, double var3);

but in the original source I see

public interface DCylinder extends DGeom {
	void setParams (double radius, double length);

which is way more informative. If I had source then maybe it would have kept radius and `length?

Also where is it worth it for me to add method description comments so the API is more intuitive?

DemoPlane2D behaves weird

DemoPlane2D behaves weird when using world.step(). Using world.quickStep() is fine. The problem occurs only in ode4j, not in ODE for C/C++.

Weird: the red block gets a high spinning rate, sometimes jumps around and the are errors on the console:

ODE Message 3: LCP internal error, s <= 0 (s=-2.3257e+01)

Citing ODE4J

What is the preferred way of citing ODE4J?

Thank you,
Kyle

Support for HiDPI screens

For HiDPI screens all demos are rendered in the lower left quarter of the screen:
Screenshot 2023-09-05 at 09 55 10

The PR: #125 fixes this issue for Java part

Testharness for issue #8

Issue #8 is fixed, but to avoid regressions, a test harness would be nice. I attempted a test harness, but it fails to reproduce the problem (TestIssue8_Gimpact.java).

Garbage collection - DContact

Hello,
I have looked over your port of ODE and I can see that you don't prevent from garbage collection.

In documentation I can read:
ode4j is in certain cases faster that ODE. I have investigated this only briefly, but I have the impression that Java can draw its advantage from using the garbage collector for arrays. This means de-allocation in Java occurs in a 2nd thread in parallel to computations, while in C/C++ de-allocation (which is expensive) occurs in the main thread.

what platforms have you considered? I think you weren't looking at Android or Web (after compilation to JavaScript using GWT, that's what libgdx does). Anyhow, allocation (of array of primities) itself is in fact fast but it's not the case for deallocation. Garbage collection takes CPU cycles and it's definetely not costless, especially when some more memory is allocated AFTER your array to be deallocated. 2nd thread does not help much since it causes memory fragmentation.

But enough about array of primitives. I see a problem about instantiating DContact too much.

private DNearCallback onCollisionCallback = new DNearCallback() {
    final int N = 100;
    DContactBuffer contacts = new DContactBuffer(N);

    @Override
    public void call(Object data, DGeom o1, DGeom o2) {
        int n = OdeHelper.collide(o1, o2, N, contacts.getGeomBuffer());
        for (int i = 0; i < n; ++i) {
            DContact contact = contacts.get(i);
            DJoint c = OdeHelper.createContactJoint(physics, contactGroup, contact);
            c.attach(contact.geom.g1.getBody(), contact.geom.g2.getBody());
        }
    }
}

I wanted to create contacts once but it's buggy, seems I can't reuse those DContact objects, so I have to allocate contacts every time a potential collision occurs (of course, N number would be smaller).Objects in DContactGeomBuffer could be reused but the class is final so I can't do much without modifying library.

I'd like to introduce possibility of reusing DContact/DContactGeom objects. Are those stored somewhere or just used for step simulation and forgotten?

DPlane.getQuaternion() fails with NullPointerException

public class ODEPhysicsTests {
	@Test
	public void planeGetQuaternionFail() {
		OdeHelper.initODE2(0);
		DSpace space = OdeHelper.createHashSpace(null);
		DPlane plane = OdeHelper.createPlane(space,0,0,1,0);
		DQuaternionC q = plane.getQuaternion();
	}
}

if getQuaternion exists for all DGeom it should succeed for all DGeom or documented that it is known to fail deliberately. Because DGeom/DPlane are interfaces what's going on behind (in DxPlane?) is invisible to me.

Move to Java 9 - User Poll/Question

ode4j now builds with Java 9.
Currently, the source code (except modularization/Maven) still builds with Java 7. The point is that Java 7 is compatible with most Android versions, whereas Java 9 is not. The poll is intended to be closed on April 30th 2018.

Question/Poll, what is your take on this?

  1. I'm in favor of moving to Java 9 source code?
  2. I'm undecided / don't care
  3. I require Java 7 source code to build for Android (or other reasons)

Please put your opinion in the comments, thank you!

Forum? Feedback requested

I believe we need a forum or something similar.
There are many options:

  • Google Forums
  • StackOverflow
  • Anything else?

What is you opinion on these options? Any other proposals?
Google forums would be a classical forums to discuss topics in length. However Stackoverflow would make it easier to cross-link related topics (they also list related topics in the sidebar).
What do you think?

Weird box behavior

Boxes sometimes fall very slow or not at all:

  • DemoTrimesh: If the fourth dropped body is a Box, it will land on an edge and then fall very slowly
  • DemoHeightfield: If the first item is a box, it will land on it's edge and just stay there until it is knocked over by another item.

In summary, box collision is recognized just fine, but the resulting forces on the box appear to be much too weak.

The DemoTrimesh problem is reproducible in ODE (16.3), the DemoHeightfield problem is not reproducible in ODE.

Preliminary findings

The DemoHeightfield problem goes away when using the ODE/C++ order for randomized position (x,y,z). Using the Java order in C++ does not reproduce the problem.

Even with identical starting positions, ODE and ode4j show slightly different initial contact positions. Also, ode4j reports around 803/806 collisions before the second contact appears while ODE shows only 527/529.
When counting only contact, for ode4j the 22nd contact is the first double-contact, while for ODE it is the 18th.

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.