react-mol
v2.2.2
Published
🍡A molecular chemistry based simulation library
Downloads
40
Maintainers
Readme
Installation
npm i three @react-three/fiber react-mol
Quick started
git clone https://github.com/tseijp/react-mol
cd react-mol
npm i
npm start
- open browser and visit localhost:3000
- Now you can go to our demo, and try its usage.
Recipes
Recipes of Atom
🍡<Mol/>
is a molecular chemistry based simulation component
that covers most cases of organic molecule simulation.
(More Recipes)
import React from 'react'
import { Atom } from 'react-mol'
export const Mol = React.forwardRef((props, ref) => {
const {index: i, angle: a, double:d} = props
const state = React.useMemo(() => {
const position = calcMolPos(i, a, d)
const rotation = eulerVec3(position, [0,1,0])
return {position, rotation}
}, [i, a, d])
const children = React.useMemo(() =>
React.Children.map(props.children, (child, index) =>
React.cloneElement(child, {index})
), [props.children])
return <Atom {...props} ref={ref}
{...state} children={children}/>
})
🍭<Flow/>
(More Recipes)
import React from 'react'
import { Atom } from 'react-mol'
import { useFrame } from ""
export const Flow = React.forwardRef((props, forwardRef) => {
const now = React.useRef(0)
const ref = React.useRef(null)
const fun = (value) => typeof value==="function"
useFrame((_, delta) => {
if (!ref.current) return
now.current += delta
const { position: p, scale: s, args: a,
rotation: r, color: c } = props
const args = fun(a)
? a(now.current,...ref.current.position.toArray())
: [ now.current,...(a || []) ]
p && ref.current.position.set(...(fun(p)? p(...args): p))
r && ref.current.rotation.set(...(fun(r)? r(...args): r))
s && ref.current.scale.set(...(fun(s)? s(...args): s))
c && ref.current.color.set(fun(c)? c(...args): c)
})
return <Atom ref={ref}/>
})
What does it look like?
🪐<Atom/>
(live demo).
import React from 'react'
import ReactDOM from 'react-dom'
import { Atom } from 'react-mol'
import { Canvas, useFrame } from ''
function Basic () {
// This reference will give us direct access to the last instance
const ref = React.useRef(null)
// Rotate instance every frame, this is outside of React without overhead
useFrame(() => {
ref.current.rotation.x =
ref.current.rotation.y =
ref.current.rotation.z += 0.025
})
return (
<Instanced>
<boxBufferGeometry attach="geometry" />
<meshPhongMaterial attach="material" />
<Atom color="red" position={[1, -2, -5]} rotation={[0, 0, Math.PI/3]}>
<Atom color="green" position={[2, 0, 1]} rotation={[0, 0, Math.PI/3]}>
<Atom color="green" position={[2, 0, 1]} rotation={[0, 0, Math.PI/3]}>
<Atom color="green" position={[2, 0, 1]} rotation={[0, 0, Math.PI/3]}>
<Atom color="green" position={[2, 0, 1]} rotation={[0, 0, Math.PI/3]}>
<Atom color="green" position={[2, 0, 1]} rotation={[0, 0, Math.PI/3]}>
<Atom color="blue" position={[2, 0, 0]} ref={ref}/>
</Atom>
</Atom>
</Atom>
</Atom>
</Atom>
</Atom>
</Instanced>
)
}
ReactDOM.render(
<Canvas>
<pointLight />
<ambientLight />
<Basic />
</Canvas>,
document.getElementById('root')
)
import React from 'react'
import ReactDOM from 'react-dom'
import { Atom } from 'react-mol'
import { Canvas, useFrame } from ''
function Basic () {
// This reference will give us direct access to the last instance
const ref = React.useRef(null)
// Rotate instance every frame, this is outside of React without overhead
useFrame(() => {
ref.current.rotation.x =
ref.current.rotation.y =
ref.current.rotation.z += 0.025
})
return (
<Instanced>
<Recursion>
<boxBufferGeometry/>
<meshPhongMaterial/>
<Atom color="red" position={[1, -2, -5]} rotation={[0, 0, Math.PI/3]}/>
{[...Array(5)].map((_, i) =>
<Atom color="green" position={[2, 0, 1]} rotation={[0, 0, Math.PI/3]} key={i}/>
)}
<Atom color="blue" position={[2, 0, 0]} ref={ref}/>
</Recursion>
</Instanced>
)
}
ReactDOM.render(
<Canvas>
<pointLight/>
<ambientLight/>
<Basic/>
</Canvas>,
document.getElementById('root')
)
Recipes of Mol
Methyl alcohol
<C>
<H/>
<H/>
<H/>
<OH/>
</C>
<Recursion>
<CH3/>
<OH/>
</Recursion>
Acetil acid
<C>
<CH3/>
<O double/>
<OH/>
</C>
<Recursion>
<CH3/>
<COOH/>
</Recursion>
Poly ethylene
<H>
<Poly n={100}}>
{next =>
<CH2>
<CH2>
{next||<H/>}
</CH2>
</CH2>
}
</Poly>
</H>
<Recursion>
<H/>
{Array(200)
.fill(0)
.map((_,i) =>
<C key={i}>
<H/>
<H/>
</C>
)}
<H/>
</Recursion>
Recipes of Flow
Points
<Instanced position={[-12.5,0,-25]} count={2500}>
<sphereBufferGeometry/>
<meshPhongMaterial />
{[...Array(2500)].map((_,i) =>
<Flow key={i} color={colors[i]}
args={(t,x,_,z) => [
sin((x+t)/3)+sin((z+t)/2)]}
position={r => [i%c,r,i/c%c]}
scale={r => [r/3,r/3,r/3]} />
)}
</Instanced>
Boxes
<Instanced count={10**3}>
<boxBufferGeometry />
<meshPhongMaterial/>
{[...Array(1000)].map((_,i) =>
<Flow key={i} color={colors[i]}
args={(t,x,y,z) => [
sin(x/4+t)+sin(y/4+t)+sin(z/4+t) ]}
position={[i%10-5,i/10%10-5,i/100-5]}
rotation={r => [0,r*2,r*3]}
scale={r => [r/4,r/4,r/4]}/>
)}
</Instanced>
Spheres
<Instanced count={1000}>
<sphereBufferGeometry args={[1,32,32]}/>
<meshPhongMaterial color={0xffffff}/>
{[...Array(1000)].map((_, i) =>
<Flow key={i} color={colors[i]}
args={[...Array(4)].map(() => rand())}
position={(t,s,x,y,z) => [
x*40-20 + cos(t*s*6) + sin(t*s*2),
y*40-20 + sin(t*s*4) + cos(t*s*4),
z*40-20 + cos(t*s*2) + sin(t*s*6),]}
scale={(t,s) => Array(3).fill(
max(.3, cos((t+s*10)*s))*s)}/>
)}
</Instanced>
Dodecas
<Instanced count={1000}>
<dodecahedronBufferGeometry args={[1,0]}/>
<meshStandardMaterial/>
{[...Array(1000)].map((_,i) =>
<Flow key={i} color={colors[i]}
args={[...Array(4)].map(() => rand())}
position={(t,s,x,y,z) => [
((x-.5)-cos(t*s+x)-sin(t*s/1))*x*100,
((y-.5)-sin(t*s+y)-cos(t*s/3))*y*100,
((z-.5)-cos(t*s+z)-sin(t*s/5))*z*100,]}
rotation={(t,s)=>Array(3).fill(cos(t*s))}
scale={(t,s)=>Array(3).fill(cos(t*s))}/>
)}
</Instanced>
Recipes of Spring
Pieces
Bounds
Pipes
Recipes of Tile
Recipes of Plant
TODO
Koch Curve
<F recursion LR={[90,90]}>
<F />
<F L/>
<F R/>
<F L/>
</F>
Meandering Snake
<F recursion
LR={[90,90]}>
<F />
<F LL/>
<F RR/>
<F L/>
<F R/>
</F>
Urban Charting
<F recursion
LR={[90,90]}>
<F/>
<F LL/>
<F RR/>
<F RR/>
<F LL/>
</F>