Found a GitHub repo that just copy-paste plagiarized ThreeJS, and may also contain malicious code

I was reading some discussion about WebGL on github, and one of the links took me to someone’s repository.
The library appears to be a direct copy of the ThreeJS framework.

Every single thing across many repositories on this person’s account are just refactored duplicates of ThreeJS’s library, and it’s claimed as their own. Is this legal?

From ThreeJS examples: three.js webgl - instancing - raycast

<!DOCTYPE html>
<html lang="en">
	<head>
		<title>three.js webgl - instancing - raycast</title>
		<meta charset="utf-8">
		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
		<link type="text/css" rel="stylesheet" href="main.css">
	</head>
	<body>
		<!-- Import maps polyfill -->
		<!-- Remove this when import maps will be widely supported -->
		<script async src="https://unpkg.com/es-module-shims@1.6.3/dist/es-module-shims.js"></script>

		<script type="importmap">
			{
				"imports": {
					"three": "../build/three.module.js",
					"three/addons/": "./jsm/"
				}
			}
		</script>

		<script type="module">

			import * as THREE from 'three';

			import Stats from 'three/addons/libs/stats.module.js';
			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

			let camera, scene, renderer, controls, stats;

			let mesh;
			const amount = parseInt( window.location.search.slice( 1 ) ) || 10;
			const count = Math.pow( amount, 3 );

			const raycaster = new THREE.Raycaster();
			const mouse = new THREE.Vector2( 1, 1 );

			const color = new THREE.Color();
			const white = new THREE.Color().setHex( 0xffffff );

			init();
			animate();

			function init() {

				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 );
				camera.position.set( amount, amount, amount );
				camera.lookAt( 0, 0, 0 );

				scene = new THREE.Scene();

				const light = new THREE.HemisphereLight( 0xffffff, 0x888888, 3 );
				light.position.set( 0, 1, 0 );
				scene.add( light );

				const geometry = new THREE.IcosahedronGeometry( 0.5, 3 );
				const material = new THREE.MeshPhongMaterial( { color: 0xffffff } );

				mesh = new THREE.InstancedMesh( geometry, material, count );

				let i = 0;
				const offset = ( amount - 1 ) / 2;

				const matrix = new THREE.Matrix4();

				for ( let x = 0; x < amount; x ++ ) {

					for ( let y = 0; y < amount; y ++ ) {

						for ( let z = 0; z < amount; z ++ ) {

							matrix.setPosition( offset - x, offset - y, offset - z );

							mesh.setMatrixAt( i, matrix );
							mesh.setColorAt( i, color );

							i ++;

						}

					}

				}

				scene.add( mesh );

				//

				const gui = new GUI();
				gui.add( mesh, 'count', 0, count );

				renderer = new THREE.WebGLRenderer( { antialias: true } );
				renderer.setPixelRatio( window.devicePixelRatio );
				renderer.setSize( window.innerWidth, window.innerHeight );
				renderer.useLegacyLights = false;
				document.body.appendChild( renderer.domElement );

				controls = new OrbitControls( camera, renderer.domElement );
				controls.enableDamping = true;
				controls.enableZoom = false;
				controls.enablePan = false;

				stats = new Stats();
				document.body.appendChild( stats.dom );

				window.addEventListener( 'resize', onWindowResize );
				document.addEventListener( 'mousemove', onMouseMove );

			}

			function onWindowResize() {

				camera.aspect = window.innerWidth / window.innerHeight;
				camera.updateProjectionMatrix();

				renderer.setSize( window.innerWidth, window.innerHeight );

			}

			function onMouseMove( event ) {

				event.preventDefault();

				mouse.x = ( event.clientX / window.innerWidth ) * 2 - 1;
				mouse.y = - ( event.clientY / window.innerHeight ) * 2 + 1;

			}

			function animate() {

				requestAnimationFrame( animate );

				controls.update();

				raycaster.setFromCamera( mouse, camera );

				const intersection = raycaster.intersectObject( mesh );

				if ( intersection.length > 0 ) {

					const instanceId = intersection[ 0 ].instanceId;

					mesh.getColorAt( instanceId, color );

					if ( color.equals( white ) ) {

						mesh.setColorAt( instanceId, color.setHex( Math.random() * 0xffffff ) );

						mesh.instanceColor.needsUpdate = true;

					}

				}

				render();

				stats.update();

			}

			function render() {

				renderer.render( scene, camera );

			}

		</script>
	</body>
</html>

This person’s code at https://github.com/Soft8Soft/verge3d-code-examples/blob/02e56932cb2a69bab8d85226dc91fe9372f2a8e7/webgl_instancing_raycast.html:

<!DOCTYPE html>
<html lang="en">
  <head>
    <title>Verge3D webgl - instancing - raycast</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
    <link type="text/css" rel="stylesheet" href="main.css">
  </head>
  <body>
    <!-- Import maps polyfill -->
    <!-- Remove this when import maps will be widely supported -->
    <script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>

    <script type="importmap">
      {
        "imports": {
          "v3d": "../build/v3d.module.js",
          "v3d/addons/": "./jsm/"
        }
      }
    </script>

    <script type="module">

      import * as v3d from 'v3d';

      import Stats from 'v3d/addons/libs/stats.module.js';
      import { GUI } from 'v3d/addons/libs/lil-gui.module.min.js';
      import { OrbitControls } from 'v3d/addons/controls/OrbitControls.js';

      let camera, scene, renderer, controls, stats;

      let mesh;
      const amount = parseInt(window.location.search.slice(1)) || 10;
      const count = Math.pow(amount, 3);

      const raycaster = new v3d.Raycaster();
      const mouse = new v3d.Vector2(1, 1);

      const color = new v3d.Color();
      const white = new v3d.Color().setHex(0xffffff);

      init();
      animate();

      function init() {

        camera = new v3d.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 100);
        camera.position.set(amount, amount, amount);
        camera.lookAt(0, 0, 0);

        scene = new v3d.Scene();

        const light = new v3d.HemisphereLight(0xffffff, 0x888888);
        light.position.set(0, 1, 0);
        scene.add(light);

        const geometry = new v3d.IcosahedronGeometry(0.5, 3);
        const material = new v3d.MeshPhongMaterial({ color: 0xffffff });

        mesh = new v3d.InstancedMesh(geometry, material, count);

        let i = 0;
        const offset = (amount - 1) / 2;

        const matrix = new v3d.Matrix4();

        for (let x = 0; x < amount; x ++) {

          for (let y = 0; y < amount; y ++) {

            for (let z = 0; z < amount; z ++) {

              matrix.setPosition(offset - x, offset - y, offset - z);

              mesh.setMatrixAt(i, matrix);
              mesh.setColorAt(i, color);

              i++;

            }

          }

        }

        scene.add(mesh);

        //

        const gui = new GUI();
        gui.add(mesh, 'count', 0, count);

        renderer = new v3d.WebGLRenderer({ antialias: true });
        renderer.setPixelRatio(window.devicePixelRatio);
        renderer.setSize(window.innerWidth, window.innerHeight);
        document.body.appendChild(renderer.domElement);

        controls = new OrbitControls(camera, renderer.domElement);
        controls.enableDamping = true;
        controls.enableZoom = false;
        controls.enablePan = false;

        stats = new Stats();
        document.body.appendChild(stats.dom);

        window.addEventListener('resize', onWindowResize);
        document.addEventListener('mousemove', onMouseMove);

      }

      function onWindowResize() {

        camera.aspect = window.innerWidth / window.innerHeight;
        camera.updateProjectionMatrix();

        renderer.setSize(window.innerWidth, window.innerHeight);

      }

      function onMouseMove(event) {

        event.preventDefault();

        mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
        mouse.y = - (event.clientY / window.innerHeight) * 2 + 1;

      }

      function animate() {

        requestAnimationFrame(animate);

        controls.update();

        raycaster.setFromCamera(mouse, camera);

        const intersection = raycaster.intersectObject(mesh);

        if (intersection.length > 0) {

          const instanceId = intersection[0].instanceId;

          mesh.getColorAt(instanceId, color);

          if (color.equals(white)) {

            mesh.setColorAt(instanceId, color.setHex(Math.random() * 0xffffff));

            mesh.instanceColor.needsUpdate = true;

          }

        }

        render();

        stats.update();

      }

      function render() {

        renderer.render(scene, camera);

      }

    </script>
  </body>
</html>

You can read the ThreeJS license agreement here : (https://github.com/mrdoob/three.js/blob/6710c984785a9f53e9910cfb109797239daa1966/LICENSE)

This just seems like plain copyright infringement.

Also, not sure what “keymanager.py” does (verge3d repo), it is very obviously intentionally obfuscated and reads/writes/executes things on the user’s computer, I would probably avoid downloading this repository.

For instance, what is the activate function writing?

def activate(path, key, l1ll_opy_=True):
    if l1ll_opy_ and not l111l_opy_(key):
        return False
    l1ll1_opy_ = l1_opy_ (u"ࠨࡡࡢ࡚࠸ࡊࡌࡠࡡࠪࠄ") + key[0:10]
    file = None
    with open(path, l1_opy_ (u"ࠩࡵࠫࠅ"),  encoding=l1_opy_ (u"ࠪࡹࡹ࡬࠭࠹ࠩࠆ")) as l1llll_opy_:
        file = l1llll_opy_.read()
    with open(path, l1_opy_ (u"ࠫࡼ࠭ࠇ"),  encoding=l1_opy_ (u"ࠬࡻࡴࡧ࠯࠻ࠫࠈ")) as l1l1l_opy_:
        l1l1l_opy_.write(l1lll_opy_.sub(l1ll1_opy_, file))
    return True

I almost downloaded the library thinking it’s from a legitimate company, but I honestly cannot tell if it’s malicious or not, but the obfuscation made me cautious.

yes. the license allows forking. unless they went and removed the license with a copyright line, since that’s the only thing the license does not allow:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
1 Like

I loaded one of there demos and it’s using THREE.REVISION 3.7.0

And I couldn’t find any copyright info in there v3d.js

I found no information on there GitHub that it was ever forked from anything.

This is there license
https://github.com/Soft8Soft/verge3d/blob/518e9d3e05945229241054f1306440b50598e82b/LICENSE.txt

well, providing this information is not required, although it would of course be convenient for their new users, you know, not having to figure it out themselves.

then, while they are required to keep original three.js license (as in “for people to read”, not in “as their whole sw package license”), I can see why they would not want to, e g people might be confused what another software license is doing there. I guess mrdoob’s lawyer could send them an email and force them to upload the file, but there is nothing to gain from them doing so :man_shrugging:

Verge3D is a paid service built on an open source library, I would guess this has something to do with how they’re enforcing payment for the service perhaps.

Okay, I was in the middle of writing a message saying that I find this really sketchy, since even their documentation page is 99% a rip-off, until I saw the actual homepage and came across this YouTube playlist that explains what the product really is.

I still find it unethical, since it does basically “sell” the engine as if it is their own.

I find it unnecessary. They could have just added 3js as a dependency.

2 Likes

They do extend three.js with some non-trivial features, to be fair! I think the potentially controversial issue is that their product competes directly with the open source work on which it is based, without contributing back (that I’m aware of …).

There’s an idealogical divide among open source people on this kind of thing… licenses like AGPL or Parity would prevent this behavior, whereas MIT and Apache 2.0 licenses choose to permit it. Lately the second group has been “winning” in the open source world, and many companies can’t/won’t touch dependencies under AGPL licensing.

2 Likes

Verge3D, as @donmccurdy is explaning, is the flagship product of Soft8Soft, the same group of devs behind blend4web (see here). From what I remember, blend4web was a toolkit for bringing blender content to web3d -based on threejs- which was shiped with ready-made materials and web3d templates for easy deployment. At some point GPL was an obstacle for selling their services, and stated to their potential clients that

GPL obliges you to share the source files of your products, including programming code, blend files and other resources (link)

so they stared offering the “pro” license as a comercial alternative to the “comunity edition” version, saying that

Commercial license allows you to create interactive 3D web content with no restrictions imposed by the GPL. The Blend4Web PRO license protects your intellectual property - only you are allowed to monetize your solutions. By purchasing a license, you are exempt from sharing your source files (link)

Ultimately, somewhere during early 2018 blend4web was sold to a big tech company for an undisclosed amount and they stoped working on it. A few months later they replicated the endeavour and started the verge3d project, with new features and improved content generation workflow, but with a twist on licencing options: free version is no longer offered - a “trial” mode can be used to test the product with a watermark although a licence is required to use it for production- and the freelance licence starts at $290. It’s interesting to note that only “Enterprise” licence ($2.990) have access to the source code (yes, threejs with modifications plus other things), and that open source licences seems to be no longer a problem under their licencing schema, because they say that

if you are a studio or freelancer and develop Verge3D applications for your own customers on the contract basis, you can transfer completed applications to them (link)

In the past I was aware of blend4web existence but never considered an option - in like “we programming people find fun in wrtiting things from scratch”- just asumed this product was oriented to a very specific target segment and that and that they would probably have been advised by lawyers, such as to found a company to sell open source software. I still believe that verge3d follows the same commercial pattern.

2 Likes

you seem to be misunderstanding :sweat_smile: gpl was b4w’s own weapon of choice to force people to pay if they did not want to share their own code.

haha yeah, sorry, english is not my ‘lingua franca’ :sweat_smile:; I was saying that GPL was presented as a problem -in quotation marks- for noting that this was a problem “according to their explanation”

a problem they themselves created - and then drew clients attention to it, so that the clients would not get ideas.

Very interesting insights @Antonio

I looked through their YouTube and even NASA is using Verge3d (Experience Curiosity), there are references in the page source code.

ThreeJS integrates very easily with blender, and its materials and animations so unless engineers at NASA are using their proprietary visual-programming tool I cannot imagine why they would pay for this. Do people really make money just re-selling open source software with their own license slapped on it?

Looking over their website some more they claim a lot of the “new features” Verge3d gets is literally just things that exist in ThreeJS.

For instance:

Create 3D content for interactive WebGL applications directly inside Blender
Verge3D integrates directly with Blender, enabling users to create 3D geometry, materials and animations inside the software, then export them in the JSON-based glTF format.
Soft8Soft ships Verge3D 2.0 | CG Channel

glTF export in blender has been around for ages though…?

Why do you care about any of this? How did you even encounter the repo? It’s open source, lot’s of companies have forked it.

I’m curious though about this scenario of “mr. doob’s lawyers”. I know these probably don’t exist, but if they did, what exactly would they do in this case, or some far worse case? Is three.js considered mr.doobs intellectual property when there were a thousand other contributors?

I only said that mrdoob could hire one to send them an email (a threat, actually, follow the license or meet us in court, lol) but obviously even if they add a notice like “this sw is based on three.js which is available under following license: bla bla” mrdoob stands to gain $0 from this, so he will not hire a lawyer

if you actually read 3js license, there is an answer to this part :wink:

While it is still very unclear in publicly available information that verge3d actually uses Threejs under the hood, here is a comparison of Object3D

v3d.Object3D https://raw.githubusercontent.com/Soft8Soft/verge3d/master/build/v3d.module.js

THREE.Object3D (r151) https://github.com/mrdoob/three.js/blob/d440449f6a0104e4095a6fee0b1a1e64df3f926a/build/three.module.min.js

I sympathise with anybody entering any agreement with them since they attempt to limit what you can do.

Below are excerpts from there EULA

You are not permitted to reproduce, copy, distribute, resell or otherwise use the Software for any purpose other than as integrated into the Applications.

You are not permitted to edit, alter, modify, adapt, translate or otherwise change the whole or any part of the Software nor decompile, disassemble or reverse engineer the Software or attempt to do any such things.

Soft8Soft shall at all times retain ownership of the Software as originally downloaded by you and all subsequent downloads of the Software by you. The Software (and the copyright, and other intellectual property rights of whatever nature in the Software, including any modifications made thereto) are and shall remain the property of Soft8Soft.

Despite being required to pay lots of money, the software and any provided services are still

provided “AS IS”, without warranty of any kind,

just like the MIT licence.

I get the impression that there has been a deliberate effort to obfuscate the origins of the code, and to prevent you from finding that out.

1 Like

Personally, I don’t understand why anyone would want to hide the fact that their product uses ThreeJS; I would be proud of it and more concerned if it’s worthy of the association.

Anyway, they only exposed themselves to a public shaming. I’m not a lawyer but I’m guessing, because of the permissive nature of the MIT license, the case would be complicated.

2 Likes

Wasn’t sketchfab or something like that also a fork of three?

Quite possibly, I’m wondering does __THREE__ in the console still expose these?

EDIT: looks like verge changed that as well to __V3D__

(tested in the console on this page)

image

I think 3.7.0 is probably referring to “their own version” of the build, further inspection reveals it’s built on r125+… three is still currently on 0.154.xx afaia…

I’m guessing they probably stopped somewhere around where three completely migrated over to module imports via importMaps, good luck changing all references from ‘three’ to something else…
nope they did do exactly that…


that’s just crazy long to do, they may as well just use the three namespace and credit three…

another shamelessly crazy thing about this is “their examples” page is quite literally a one for one clone of three’s… :man_facepalming:

5 Likes

Juicy thread. Now compare babylon next ! :smiley: JK
I’ve seen verg3d in the wild… people use/are using it for sure.
And yeah… there are quite a few orgs that are piggybacking on threejs.
A rising tide lifts all boats etc. agree tho it feels creepy.

4 Likes