Coder Social home page Coder Social logo

andrewprifer / react-three-editable Goto Github PK

View Code? Open in Web Editor NEW
361.0 361.0 36.0 3.34 MB

โš ๏ธ Moved! See @theatre/r3f and the theatre-js/theatre repo for the new version with animation tools! Link below ๐Ÿ‘‡ Edit your react-three-fiber scene with a visual editor without giving up control over your code.

Home Page: https://docs.theatrejs.com/extensions/r3f/

License: MIT License

CSS 0.66% JavaScript 2.24% HTML 1.68% TypeScript 95.37% Shell 0.06%
3d editor react react-three-fiber threejs webgl

react-three-editable's People

Contributors

andrewprifer 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

react-three-editable's Issues

Investigate SSR friendliness

Seems to work perfectly when using next/dynamic. I'm not sure if we can do much better now because even if we make rendering the editor conditional on the browser, there are ES modules in THREE used by drei that seem to generate a lot of Cannot use import statement outside a module errors. Although we could instruct rollup to bundle the offending external modules.

Add support for multiple canvases

An unnecessary limitation of the current implementation is that you can only use it with a single canvas. This could be solved by letting EditorConnector accept a uniqueName parameter to identify the canvas, and displaying a tab in the editor for each.

Fix phantom transform controls

Currently, transform controls don't seem to be cleaned up properly. Even though they are removed from the scene and are invisible as a result, they still respond to dragging, and set the transform of the proxy object. This might be a bug in Threejs, will have to see how Three Editor does it.

Implement implicit instancing of editable objects

For now, instancing is possible through having multiple editable objects in the scene with the same uniqueName. These Objects will share all editable properties. Since this is a dangerous thing to do (you won't get any warning if you unintentionally have duplicate uniqueNames), you'll have to opt into this by setting the allowImplicitInstancing prop of EditableManager to true, otherwise you get an error.

If you do opt into this behavior, only one instance will be visible in the editor.

This behavior is temporary until prefabs are implemented, and is discouraged, since you also opt out of any warnings for unintentional uniqueName duplicates. See #33.

Implement undo/redo

We are using immutable state so this should be fairly straightforward to implement in an incremental way.

Create bundler config with working tree-shaking

The production bundle doesn't get tree-shaken properly. After a little investigation I found that transitive deps are hoisted to the top, and won't get dropped for some reason even if their respective dependents (Editor in this case) do, adding quite some unnecessary weight. I need to somehow configure the bundler to properly tree-shake the production build.

Remove EditableManager and come up with a solution without implicit contracts

The problem with EditableManager is that it introduces an implicit contract. It is not really a hard requirement now, but you'd have to place it before all your other components, and there are also no guarantees that having two EditableManagers in the same canvas won't break r3e. This problem also doesn't go away if we make EditableManager a provider-style wrapper component. Does it have to wrap around all the components? Just the editable ones? What if you have two EditableManagers?

Replace using our own Canvas component

Having our own Canvas component would make this contract explicit and its use would be unambiguous and obvious. It would also allow us to forward any eventual r3e React contexts to the r3f renderer without any hassle.

The downside would be that this solution would not play nice with other tools that also export their own Canvas component for context forwarding purposes, like react-three-gui does. However while these tools arguably shouldn't do this and instead rely on the user to forward the context however they want, r3e does actually depend on the specific Canvas instance for the scene and the rendering context, so I feel like the API in this case is justified.

Replace using bind()

An arguably more composable alternative would be (suggested by @gsimone) to have a bind() function that you would call in Canvas' onCreated function.

If we make it curried, we could even simplify the case when r3e's bind function is the only thing using onCreated, and it could look like this:

<Canvas onCreated={bind(r3eConfig)}>
  // ...
</Canvas>

Otherwise you would have to pass the state explicitly:

<Canvas onCreated={state => {
  // ...
  bind(r3eConfig)(state)
  // ...
}}>
  // ...
</Canvas>

Add editor settings pane

Things like

  • display overlay icons
  • show/hide grid
  • show/hide axes
  • bounding box color
  • grid color
  • grid size
  • show/hide static (non-editable) objects in editor

Add support for prefabs

We could and we should support prefabs with overrides.

I was thinking of the following API:

const MyPrefab = prefab("My Prefab", ReactComponentContainingEditables);
const MyOtherPrefab = prefab("My Other Prefab", SomeOtherReactComponentContainingEditables);
<Canvas>
  <EditableManager prefabs=[MyPrefab, MyOtherPrefab] />
  <MyPrefab uniqueName="Prefab Instance" />
  <MyPrefab uniqueName="Prefab Instance 2" />
</Canvas>

What happens in the above code is that we create prefabs from two r3f React components. These prefabs themselves are also just React components. These are then registered with the EditableManager in the respective Canvases where they are used. From then on, they can be freely used wherever we want inside the Canvas, and a new instance will be created.

When we open the editor, there will be a separate section for prefabs, where they can be opened and edited. Instances in the normal scene editor will reflect changes made to the prefabs, and they themselves will be editable, with all their editable subelements, which will override the respective transform/property. These overrides can be reset or synced back to the prefab.

How does all this work?

When we create a prefab through the prefab() function, a React component is created. When this component is passed to EditableManager, it renders the prefab component in a portal, which lets it be part of the normal React component hierarchy, gaining access to context, while only actually showing it in the prefabs section of the editor, allowing it to be edited, without actually being part of the scene.

Better accommodate and test stripping the editor code in production

The library in its current form is quite huge, but 99% of that size is the editor. In principle the setup should allow tree shaking to strip all the editor-related code, but I haven't tested it, and it would also be nice to provide different packages for the editor functionality and the runtime functionality for those for whom tree-shaking doesn't work.

Support env maps and backgrounds

I didn't find it possible to just copy the env/background texture of the original scene because it is a resource that can't be shared between renderers, so we have to hustle a little bit. I was thinking I could use THREE's LoadingManager to listen for loading events, and if something looks like an environment map, I could offer it in the editor.

Explicitly providing env maps to r3e would also be an option, but I want to keep it as automagical and zero -config as possible, when possible.

Improve code and TypeScript typings

Currently the way editable.tsx looks is nasty. Ideally the entire thing could be abstracted as a single function. The reason it is currently not, is that I'm not familiar enough with the TypeScript typings of React and r3f to properly type it, and the current setup allows me to let the type checker infer most of the types. I still have to use @ts-ignore at a few places even now, so it is far from ideal.

Also need to export the State type so that imported editable states can be easily coerced to the correct type. Currently you get an error that string is not assignable to type EditableType.

Reference window only works after first rerender

This is really weird because everything seems to be the same on both renders, specifically the domElement that we are copying from, but everything else too for that matter. For now the current hack will have to do, but it is too strange not to investigate further.

Improve README

Add a gif to README illustrating its use, clarify API, add examples, etc.

GLTSFX integration

Love react-three editable. As noted in the documentation, it solves some of the same problems that GLTSFX was trying to solve, but with a different approach.
I'm finding it difficult to integrate the use of react-three-edtiable with GLTSFX. As far as I'm aware, you're able to make custom components editable, by wrapping them in editable, but I'm running into problems with this. Any best practice way to do this?

`/*
////Model.tsx

Auto-generated by: https://github.com/pmndrs/gltfjsx
*/

import * as THREE from 'three'
import React, { useRef } from 'react'
import { useGLTF } from '@react-three/drei/useGLTF'

import { GLTF } from 'three/examples/jsm/loaders/GLTFLoader'

type GLTFResult = GLTF & {
nodes: {
['A-1.001_1']: THREE.Mesh
['A-1.001_2']: THREE.Mesh
}
materials: {
['diffuse_0_0_0_255.001']: THREE.MeshStandardMaterial
['Wood-3 Ver.001']: THREE.MeshStandardMaterial
}
}

export default function Model(props: JSX.IntrinsicElements['group']) {
const group = useRef<THREE.Group>()
const { nodes, materials } = useGLTF('/A1.glb') as GLTFResult
return (
<group ref={group} {...props} dispose={null}>

<group name="A-1001" rotation={[Math.PI / 2, 0, 0]}>
<mesh name="A-1.001_1" material={materials['diffuse_0_0_0_255.001']} geometry={nodes['A-1.001_1'].geometry} />
<mesh name="A-1.001_2" material={materials['Wood-3 Ver.001']} geometry={nodes['A-1.001_2'].geometry} />



)
}

useGLTF.preload('/A1.glb')`

`
//App.tsx
import { editable as e } from 'react-three-editable';

import Model from './path/to/Model.tsx'

const EModel = e(Model, 'group');
<EModel uniqueName={'Emodel'} />

`

Remove Editor component

Whether the Editor is displayed or not shouldn't have to be micro-managed by the consumer of the library. The editor is a development time tool. It should automatically be displayed at development time, and excluded otherwise.

Temporary issue: installing @emotion/core breaks things

For now I decided to use Chakra UI to build the interface, and it might even stay that way because Chakra is awesome. However there's one tiny issue: if you add @emotion/core to your deps, things will break, and I can't even wrap my head around exactly how. See this issue: chakra-ui/chakra-ui#2414.

There are two paths out of this: either I find a way for r3e's deps to stop leaking, or I replace the UI with a different solution. This will all happen before 1.0.0. If you happen to know how all of this works and how exactly things are breaking, and what bandaid I can apply, if any until Chakra fixes this, please let me know. ๐Ÿ™

For now, however, I will keep using Chakra simply because it allows me to move extremely fast.

Remove "editable root" group and use code transforms as reset points

This got me thinking. If you want to apply an editor transform on top of a code transform, you can just use wrap the component in a group. If you want to do it vice versa, you can wrap your non-editable comp in an editable group.

Which means that the current setup of having an extra group per editable object doesn't in fact add much value. It does subtract however by introducing the extra complexity of having to use editableRootRef for reparenting and modifying the scene graph.

What we could do instead is use the transform provided in code (and parameters in general) as initial values and reset points. This would lend them actual value, make them less complex, and would make them more similar to how other editable properties will work in the future.

Another big reason to do this is also that it'd make it much easier to use with an existing code base. Right now if you start applying edited transforms on top of an existing object with existing transforms in the code, and you decide to remove the transforms from the code because it doesn't really make sense to have them there if you're going to use r3e anyway, your transforms will be messed up because the edits are applied on top, and not in place of the existing transform props.

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.