react-mol

šŸ”A molecular chemistry based simulation library

Stats

StarsIssuesVersionUpdatedCreatedSize
react-mol
602.2.2a year ago2 years agoMinified + gzip package size for react-mol in KB

Readme

https://tsei.jp/rmol






build-āœ” types-āœ”- demos-āœ” license-MIT npm-package tweet

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

Atom Mol Flow Tile Spring

Recipes of Atom


šŸ”<Mol/> is a molecular chemistry based simulation component that covers most cases of organic molecule simulation. (More Recipes)

View Code
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}/>
})

Mol

šŸ­<Flow/> (More Recipes)

View Code
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}/>
})

Points

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')
)
Show Recursion Example
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


Mol


Hierarchy


Recurtion


Results

Methyl alcohol

CH3 OH

<C>
  <H/>
  <H/>
  <H/>
  <OH/>
</C>
<Recursion>
  <CH3/>
  <OH/>
</Recursion>

CH3OH

Acetil acid

CH3 COOH

<C>
  <CH3/>
  <O double/>
  <OH/>
</C>
<Recursion>
  <CH3/>
  <COOH/>
</Recursion>

CH3COOH

Poly ethylene

Poly CH2

<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>

Polyethylene






Recipes of Flow


Flow


Code


Results

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>

Points

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>

Boxes

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>

Spheres

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>

Dodecas






Recipes of Spring


Spring


Results

Pieces

Pieces

Bounds

Bounds

Pipes

Pipes

Recipes of Tile


Tile


Code






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>

If you find any bugs or have a feature request, please open an issue on github!

The npm package download data comes from npm's download counts api and package details come from npms.io.