Giter Site home page Giter Site logo

threlte / threlte Goto Github PK

View Code? Open in Web Editor NEW
1.8K 1.8K 109.0 220.82 MB

3D framework for Svelte

Home Page: https://threlte.xyz

License: MIT License

JavaScript 7.48% HTML 0.07% Svelte 44.98% TypeScript 18.75% CSS 1.52% Astro 3.91% GLSL 0.23% MDX 23.06%
3d hacktoberfest rapier svelte theatrejs threejs

threlte's People

Contributors

alexwarnes avatar amr3k avatar bluewinds avatar daevid66 avatar definitelymaybe avatar donmccurdy avatar edsunman avatar eerkmen avatar ethanlook avatar flo-bit avatar github-actions[bot] avatar grischaerbe avatar ivoilic avatar ixxie avatar jeffrice avatar jerzakm avatar jirihon avatar jpaquim avatar laszlokorte avatar lega0208 avatar luroc avatar mattferraro avatar michealparks avatar midanosi avatar mknadler avatar nemzyx avatar nicell avatar stijlmassi avatar sxxov avatar voiys 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

threlte's Issues

ERR_MODULE_NOT_FOUND when building static app

Hi,

I found when trying to build my threlte based app for static deployment that I got an error similar to the following: Error [ERR_MODULE_NOT_FOUND]: Cannot find module '<...>/node_modules/three/examples/jsm/postprocessing/EffectComposer' imported from <...>/.svelte-kit/output/server/entries/pages/index.svelte.js Did you mean to import three/examples/jsm/postprocessing/EffectComposer.js?

I saw that in threlte's svelte.config.js there are some extra vite options for threejs. It seems that adding the following "fixes" the issue:

		  ssr: {
		    noExternal: ['three']
		  }

However then index.svelte.js balloons to 1105.56KiB from 63.85KiB. This is not a big deal IMO. However are there any plans/ideas to fix this?

useThrelte crashes the app

Adding useThrelte to the list of imports works fine but as soon as you try to use it like the docs say, the app crashes and you get this error:

Cannot destructure property 'size' of 'vite_ssr_import_3.useThrelte(...)' as it is undefined.

Reproduction Environment
https://stackblitz.com/edit/sveltejs-kit-template-default-1fxljc?file=src/routes/index.svelte

I understand useThrelte uses a getContext/setContext under the hood but I don't fully grasp that aspect of Svelte so unfortunately I can't fix this myself.

Default `dracoDecoderPath` ?

Hi, I believe it's a common use case is to set the draco decoder path to https://www.gstatic.com/draco/v1/decoders/, Should threlte add it as default value?
specifically in this line:

export let dracoDecoderPath: GLTFProperties['dracoDecoderPath'] = undefined

This is a slightly improvement to help devs not to include that URL in every GLTF component in every project.

Changing scene background?

I was evaluating threlte due to its more complete documentation vs SvelteCubed and I can't really figure out how I can set the background color of the scene. SvelteCubed exposes this as a prop on canvas, but then is setting the background of the scene with that prop. I can't seem to find how/where I can set props (like background color) on the scene in threlte. So maybe this can be made more clear in the docs?

useTexture() js file size (500Kib)

I just ran my vite build and the file size of the useTexture function really stood out:

vite v2.9.14 building for production...
✓ 104 modules transformed.
dist/client.17d98c6c.js              0.42 KiB / gzip: 0.32 KiB
dist/assets/e3b0c442.9e659790.css    0.04 KiB / gzip: 0.05 KiB
dist/Wrapper.214e8078.js             2.12 KiB / gzip: 1.02 KiB
dist/Wrapper.991589b8.js             1.97 KiB / gzip: 0.93 KiB
dist/client.c29c847b.js              50.32 KiB / gzip: 20.35 KiB
dist/chunks/useTexture.37f8dbe3.js   507.74 KiB / gzip: 133.75 KiB

Does this have something to do with the texture/image file included in this file or something? Or might it have something to do with my setup? I'm running in Astro.

PS: is it okay to use .webp as input for useTexture?

Thanks! :)

Advanced control over the actual render call

Right now the frameloop calls ctx.renderer.render(ctx.scene, camera) and there's no way to intercept or hook onto that.

I guess a property in the renderContext would be great. Something like

const { useRender } = useThrelteRender()

// first argument is the con
useRender(({ renderer, camera, scene }) => {
  renderer.render(get(camera), scene)
})

react-three-fiber solves this with positive and negative indices on the respective property order of the useFrame hook. I'm not a huge fan of that as it's somewhat misleading and I like to think in "0 and up" to prioritize and convert that to "up to 0" is a bit of a stretch on the fly. Also computationally a bit more expensive. Also, and I think this is the huge difference: Compared to useFrame, this hook would only be called in the event of an invalidated frame.

I'm still undecided and I think the whole useFrame and invalidate pattern needs a bit of an overhaul.

Add recipes section

Hi, as we discussed earlier on discord, it would be awesome to have some recipes for frequently asked questions like #71

Is it suitable to put them in a separate section in the sidebar ?

Attempting to access navigator returns undefined

I'm working on getting a basic WebXR example working with threlte, but I'm having an issue importing the default VRButton from three.js. One of the functions in VRButton is supposed to check that navigator.xr exists, but trying to access navigator is returning undefined for some reason.

Unable to deploy or run with svelte preview

In a new sveltekit project, initialized with npm init svelte@latest, I'm unable to either preview the site or run the production build. The runtime throws an error stating that the RenderPass file doesn't exist, though I confirmed that it does exist. Running the site in the dev environment works as expected, though.

I'm using [email protected] and [email protected] on macOS 12.1.

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/christian/www/svtest/node_modules/three/examples/jsm/postprocessing/RenderPass' imported from /Users/christian/www/svtest/.svelte-kit/output/server/entries/pages/index.svelte.js
Did you mean to import [email protected]/node_modules/three/examples/jsm/postprocessing/RenderPass.js?
    at new NodeError (node:internal/errors:371:5)
    at finalizeResolution (node:internal/modules/esm/resolve:416:11)
    at moduleResolve (node:internal/modules/esm/resolve:932:10)
    at defaultResolve (node:internal/modules/esm/resolve:1044:11)
    at ESMLoader.resolve (node:internal/modules/esm/loader:422:30)
    at ESMLoader.getModuleJob (node:internal/modules/esm/loader:222:40)
    at ModuleWrap.<anonymous> (node:internal/modules/esm/module_job:76:40)
    at link (node:internal/modules/esm/module_job:75:36)
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/christian/www/svtest/node_modules/three/examples/jsm/postprocessing/RenderPass' imported from /Users/christian/www/svtest/.svelte-kit/output/server/entries/pages/index.svelte.js
Did you mean to import [email protected]/node_modules/three/examples/jsm/postprocessing/RenderPass.js?
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/Users/christian/www/svtest/node_modules/three/examples/jsm/postprocessing/RenderPass' imported from /Users/christian/www/svtest/.svelte-kit/output/server/entries/pages/index.svelte.js
Did you mean to import [email protected]/node_modules/three/examples/jsm/postprocessing/RenderPass.js?

Make contexts reactive

Currently, It's not possible to listen to camera changes or pointer position changes.

The proposed changes would change the ThrelteContext to this:

type ThrelteContext = {
  size: Writable<{ width: number; height: number }>
  pointer?: Writable<Vector2>
  clock: Clock
  camera?: Writable<Camera>
  scene: Scene
  renderer?: WebGLRenderer
  composer?: EffectComposer
  invalidate: (reason?: string) => void
}

So it's not the whole context that's a store but rather single properties. This makes it possible to destructure the result of useThrelte like const { invalidate } = useThrelte().

But listening to camera changes would make HUD visibility and general UI work easier and more performant.

Useframe causes error:=Unrecoverable HMR error in <Three>=

First of all, really well made plugin and docs!

I am experiencing issues with the useFrame hook. Error:
[HMR][Svelte] Unrecoverable HMR error in <Three>: next update will trigger a full reload

I got this when trying to make my mesh rotate. Howver, I found that a function like this gives the same error:

    useFrame(() => {
      console.log('frame')
    })

In case it's useful, here's my complete component:

<script>
  import { SphereGeometry, MeshStandardMaterial } from 'three'
  import {
    AmbientLight,
    Canvas,
    Mesh,
    PerspectiveCamera,
    PointLight,
    useTexture,
    useFrame,
  } from 'threlte'

  const geometry = new SphereGeometry(1, 32, 32)
  let rotation = {
    x: 0,
    y: 0,
    z: 0,
  }

  const textures = useTexture({
    map: '/assets/img/maps/colorMap.jpg',
    normalMap: '/assets/img/maps/NormalMap.jpg',
    roughnessMap: '/assets/img/maps/RougnessMap.jpg',
    displacementMap: '/assets/img/maps/DisplacementMap.jpg',
  })
  const material = new MeshStandardMaterial({ ...textures })
  material.displacementScale = 0.02

  useFrame(() => {
    console.log('frame')
  })
</script>

<div class="w-1/2 aspect-1">
  <Canvas>
    <PerspectiveCamera position={{ x: 0, y: 0, z: 2.4 }}>
      <!-- <OrbitControls autoRotate /> -->
    </PerspectiveCamera>

    <PointLight position={{ x: 50, y: 40, z: 50 }} intensity={0.5} />
    <AmbientLight color={0x0d1321} />

    <Mesh {geometry} {material} {rotation} />
  </Canvas>
</div>

[ERR_MODULE_NOT_FOUND] in SvelteKit

I am trying to build the project with SvelteKit for deployment. Using npm run dev everything works, but when I try and build, I get:

> Using @sveltejs/adapter-cloudflare
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '[PATH]/node_modules/three/examples/jsm/postprocessing/EffectComposer' imported from [PATH]/.svelte-kit/output/server/entries/pages/index.svelte.js
    at finalizeResolution (internal/modules/esm/resolve.js:276:11)
    at moduleResolve (internal/modules/esm/resolve.js:699:10)
    at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:810:11)
    at Loader.resolve (internal/modules/esm/loader.js:86:40)
    at Loader.getModuleJob (internal/modules/esm/loader.js:230:28)
    at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:56:40)
    at link (internal/modules/esm/module_job.js:55:36)
> 500 /
    at file:///[PATH]/node_modules/@sveltejs/kit/dist/chunks/index5.js:409:11
    at visit (file:///PATH]/node_modules/@sveltejs/kit/dist/chunks/index5.js:583:5)
    at processTicksAndRejections (internal/process/task_queues.js:93:5)
npm ERR! code 1
npm ERR! path [PATH]
npm ERR! command failed
npm ERR! command sh -c svelte-kit build

npm ERR! A complete log of this run can be found in:
npm ERR!   [USERPATH]npm/_logs/2022-02-18T04_48_45_935Z-debug.log

It does seem like this is a known issue from googling around, but the solution to lots of those was to move stuff from devDependencies to regular dependencies, but that hasn't worked. Any idea what's causing this?

Compatibility with other postprocessing solutions

The <Pass> component is quite handy in its ease of use. However, its implementation seems to depend on the post-processing examples in three.js, so if you want to use something like the postprocessing package it seems you're out of luck. Any thoughts on adding support for this?

In the case of the postprocessing package, the basic API is not quite drop-in but still pretty similar (there's an EffectComposer and a default RenderPass with the same constructor signatures as the three.js examples), so it probably wouldn't be too hard to specifically support this package as an alternative. In theory I suppose there could be other solutions with varied APIs, so one could argue for a more generic way to hook into the render cycle, but in practice I don't know of any other postprocessing solutions, so going that far might be overengineering.

Svelte update broke threlte

Hi, just updated svelte and found this error:

index.mjs:1857 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading '$$')
    at init (index.mjs:1857:50)
    at new Canvas (Canvas.svelte? [sm]:53:55)
    at createProxiedComponent (svelte-hooks.js:266:9)
    at new ProxyComponent (proxy.js:239:20)
    at new Proxy<Canvas> (proxy.js:346:11)
    at create_fragment (index.svelte? [sm]:32:40)
    at init (index.mjs:1877:37)
    at new Routes (index.svelte? [sm]:41:55)
    at createProxiedComponent (svelte-hooks.js:266:9)
    at new ProxyComponent (proxy.js:239:20)

My package.json

"devDependencies": {
	"@sveltejs/adapter-auto": "next",
	"@sveltejs/kit": "next",
	"@types/three": "^0.137.0",
	"svelte": "^3.46.4",
	"svelte-check": "^2.4.5",
	"svelte-preprocess": "^4.10.4",
	"tslib": "^2.3.1",
	"typescript": "^4.5.5",
}

Textureloader color way too light

I'm using the texture loader to load a map on a sphrere. Using this plugin it looks completely different than when I make the same thing on https://threejs.org/editor/ . It's just way lighter than the original image I use for my map.

This is supposed to happen:
image

this happens:
image

My component:

<script>
  import { MeshStandardMaterial, SphereGeometry } from 'three'
  import {
    PointLight,
    Canvas,
    Mesh,
    PerspectiveCamera,
    useTexture,
  } from 'threlte'

  const texture = useTexture('/assets/img/maps/ColorMap.jpg')
  const material = new MeshStandardMaterial({ map: texture })
</script>

<div>
  <Canvas>
    <PerspectiveCamera position={{ x: 0, y: 0, z: 3 }} />
    <PointLight intensity={0.9} position={{ x: 3, y: 10, z: 10 }} />
    <Mesh geometry={new SphereGeometry(1, 64, 64)} {material} />
  </Canvas>
</div>

Would really appreciate the help :)

Type 'typeof PerspectiveCamera' is not assignable to type 'LookAt'.js

Hello,
I read https://github.com/grischaerbe/threlte/discussions/39 but I didn't get how to get OrbitContols to work with useThrelte if camera is a submodule using CameraInstance or else.
So sticking with default objects I tried:

import {..., PerspectiveCamera} from 'threlte';
let camera = PerspectiveCamera;
...
<camera position={{ x: 1, y: 1, z: 1 }}
    <OrbitControls.../>
</camera>
<Mesh lookAt={camera}>

I don't get why the error: Type 'typeof PerspectiveCamera' is not assignable to type 'LookAt'.js(2322)

Would you please help me to get a lookAt and OrbitControls working with a camera?

Cannot destructure property 'registerInstance' of 'useInstancedMesh'

Hi, I'm trying to create a scene similar to this three.js example: https://github.com/mrdoob/three.js/blob/master/examples/webgl_instancing_dynamic.html

Given an array (particles) I use useFrame to change the position, rotation, and scale of each item in the array, and then I use that particle array like the following code:

<InstancedMesh {geometry} {material}>
  {#each particles as particle, index}
    <Instance id={String(index)} position={particle.position}
              rotation={particle.rotation}
              scale={particle.scale} />
  {/each}
</InstancedMesh>

However I get the error:

Uncaught (in promise) TypeError: Cannot destructure property 'registerInstance' of 'useInstancedMesh(...)' as it is undefined.
at instance_1 (Instance.svelte? [sm]:13:9)
at init (index.mjs:1876:11)
at new Instance (Instance.svelte? [sm]:29:18)
at createProxiedComponent (svelte-hooks.js:341:9)
at new ProxyComponent (proxy.js:242:7)
at new Proxy (proxy.js:349:11)
at create_each_block (Swarm.svelte:5:50)
at Array.create_default_slot (Swarm.svelte:67:9)
at create_slot (index.mjs:69:27)
at Array.create_default_slot (InstancedMesh.svelte? [sm]:179:28)

I don't understand what I'm doing wrong, someone please can help ?

Thanks

Option to use interactive objects without auto updating render

Just started trying out Threlte and like it a lot :)

I wonder what the reason is for making the scene auto-render if there is an interactive object in the scene? I tested to remove lines 47-48 in frameloop.js and using the orbit-control and clicking on objects works just fine. I have not tested hover states etc yet, though.

I really like that the default in threlte is to not render if nothing has changed in the scene, so if auto-update is needed for some but not all interactivity it would be great to be able to have a setting for this.

Cheers,

David

Postprocessing on specific layers

In three.js normally, it is possible to use selective passes (e.g. here and here) by rendering multiple layers.

Using the inbuilt postprocessing in Threlte is something similar possible natively (applying passes to specific layers ideally, but objects otherwise), or should I aim to recreate this effect the way it is done in examples?

Pass having no effect

Adding a glitch pass to the basic scene in your guide doesn't seem to work, possibly as a result of this line being deleted in ea2f5bf:

ctx.composer.addPass(new RenderPass(ctx.scene, ctx.camera ?? new Camera()))

The pass works when I reintroduce the line on lib/renderer right after ctx.composer = new EffectComposer(ctx.renderer);

Jae's first look notes

Hey :) As we discussed! Some of this is superficial, just wanted to have somewhere to put everything I thought along the way. (Note I'm commenting without using it yet).

I haven't yet had a go at playing with it :) Will have to wait for next weekend. Got some dark souls to fail at.

threlte vs svelte cubed vs svelthree

Hello! I've been using Svelte for a long time, but am very much still learning Three.js. I saw Svelte Cubed and tried out the demo and started working on an idea I had, and then discovered both threlte and svelthree.

My question (which also goes to @vatro and @Rich-Harris) is how I should pick which one of these libraries to use? What are the philosophical differences in how they structured or what are the fundamental differences and what about them might matter to developers wanting to use them?

This question isn't meant to be discouraging at all, I absolutely applaud all the work that is going here, they all look really amazing! However it feels like Svelte itself is a relatively small community and so then to have three competing Three.js Svelte libraries leaves me confused as to which one to pick and also maybe feels like precious energy is being used to compete when perhaps thrashing out the differences and then cooperating might also be a great way forward?

Tweakpane code repetition

I've noticed that we're copying the same(?) tweakpane code between examples. Should we just put it in one place and import?

Maybe we could use a @threlte/utils package where non-three related code lives. Like this tweapkane thing, but also Keyboard controller proposed by @AlexWarnes on discord?

ContextBridge

A component to bridge the context to be able to use it outside the <Canvas> element.

OBJ models load

hi, thanks for the brilliant work, tell pls if there are plans to add a similar GLTF, also an OBJ models?

`visible` prop doesn't have effect on the HTML child !

HTML is rendered no matter whether the parent is visible or not.

I made a demo that demonstrates this

And here's a quick example:

<script>
  import {Group} from '@threlte/core';
  import {HTML} from '@threlte/extras';
</script>

<Group visible={false}>
  <HTML transform>
    <h1>Hello world</h1>
  </HTML>
</Group>

Threlte will render Hello world

Recommended way of using LoadingManager?

Since threejs typically takes some time to load, it is good practice to add a loading overlay on pages where the object in included in the first section.

In ThreeJS we can listen with LoadingManager to the completion of the load. However, I can't get it to work using threlte. I tried putting the first piece of code from the Threejs website (https://threejs.org/docs/index.html#api/en/loaders/managers/LoadingManager) in component aswell as in my wrapper. However, nothing is heppening.

What would be the recommend way to doing this?

THREE.Points not available

While Mesh has been implemented fine, Points has not been put in. It can be bodged in very easily, but duplicating the Mesh.svelte, replacing

setup(new THREE.Mesh(geometry, material));

with

setup(new THREE.Points(geometry, material));

and fiddling around with exports, but there may well be a more efficient way of doing things.

Unclear how to use useFrame()

I've tried to use useFrame() but I get the issue

Function called outside component initialization

I see that the docs say to use it with Canvas, but I'm not entirely sure how. The examples given use it the same way I do.

Keeping images/textures cached

I need to load in 7 fairly large textures using

threlte.useTexture(imgPath);

where imgPath is calculated from Vite's import overloading for images, and exported in a component. Is there a better way of importing/loading the images that allows them to be cached, so it doesn't take 2-3 seconds to load them all in every time?

More control over the OrthographicCamera frustrum

As far as i can tell the frustrum is always linked to the size of the parent container/canvas, which probably is good enough in most cases. I would like to have more control over the frustrum like in vanilla three.js (left,right,top,bottom).

So could imagine having some sort of switch deciding the size based on the parent container (like now) or a custom frustrum.

I´m not sure which way is better as in extending the $size store in some way
https://github.com/grischaerbe/threlte/blob/087f26706481188bc159abaffa86f0f76beeabef/src/lib/Canvas.svelte#L76-L77
or adding new reactive props (left,right,top,bottom) just for the OrthographicCamera
https://github.com/grischaerbe/threlte/blob/087f26706481188bc159abaffa86f0f76beeabef/src/lib/cameras/OrthographicCamera.svelte#L22-L26

Some guidance which way would fit best would be appreciated :).

Animated GLTF are not interactive!

Hello @grischaerbe , thanks for your amazing work.

I updated threlte to 3.6.1 and some animated GLTFs don't support interactivity!

I have two different model components here and here, and a static model component here

The demo is here

The cursor should be pointer when hovering over any model, but it doesn't! work for the animated ones!

Line2 component errors for dynamic points

I am plotting around 2K to 5K lines dynamically. However, when the number of point varies I get this error in the console which makes the line disappear.

I believe this is due to not being able to preallocate a large enough buffer for points. Would be nice if this is handled behind the scenes.

[.WebGL-0x10004cab800] GL_INVALID_OPERATION: Vertex buffer is not big enough for the draw call

Disabling click events when dragging scene with orbit control

When dragging the scene and ending the drag above an interactive object, a click event is triggered from the object. When dragging on touch screen I don't get this behavior, and I would expect to only get the click handler if I have not initiated a drag.

In previous projects with three I have listened on movement from the orbit-control and stopped the propagation of the click events if the user has moved more than threshold values for distance or duration. I've also done the opposite, if a scene object is dragged the orbit-control is inactivated during the drag duration. Not sure how the interactivity works in threlte yet, though.

Cheers,

David

WebGLRenderTarget control/access

I have a project where i use WebGLRenderTarget´s as Textures for material kind of like this.

Is there a way to hook into the rendercall to render all renderTargets before the final image + control of the framebuffer?

I saw the that its possible to maybe use the EffectComposer for a similar result, but i never used that before so i will give this a try first. Maybe the Topic is also related to #29

br :)

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.