Switch to a monadic API.

Former-commit-id: 0c2706be2b4cf0a92a46f000cbd1da620f86a2e1
This commit is contained in:
David 2019-02-28 10:39:12 +01:00
commit 9707cca88b
11 changed files with 462 additions and 371 deletions

View file

@ -32,6 +32,12 @@ div.messages {
div.messages pre {
margin: 0;
}
.home {
color: white;
text-align: center;
float:right;
margin-right: 2em;
}
#editor {

View file

@ -10,24 +10,30 @@ import preset from './Presets';
class App extends Component {
connect = () => {
const ws = new WebSocket("wss://reanimate.clozecards.com:9160");
// const ws = new WebSocket("wss://localhost:9160");
// const ws = new WebSocket("ws://localhost:9161");
ws.onopen = event => {
this.setState(state => ({...state, message: "Connected."}));
this.setState(state => ({
...state,
message: "Connected."
}));
ws.send(this.state.program);
}
ws.onclose = event => {
this.setState(state => ({...state, message: "Disconnected."}));
this.setState(state => ({
...state,
message: "Disconnected."
}));
setTimeout(this.connect, 1000);
}
ws.onmessage = event => {
if( event.data === "Success!" ) {
if (event.data === "Success!") {
console.log("Success");
} else if( event.data === "Rendering" ) {
} else if (event.data === "Rendering") {
this.setState({message: "Rendering..."});
this.nFrames_new = 0;
this.svgs_new = [];
} else if( event.data === "Done" ) {
} else if (event.data === "Done") {
this.setState({message: "Success!"});
console.log("Done");
this.nFrames = this.nFrames_new;
@ -35,9 +41,9 @@ class App extends Component {
this.nFrames_new = 0;
this.svgs_new = [];
this.start = Date.now();
} else if( event.data.startsWith("Error") ) {
} else if (event.data.startsWith("Error")) {
console.log("Error");
this.setState({message: event.data.substring(5) });
this.setState({message: event.data.substring(5)});
} else {
this.setState({message: `Rendering: ${this.nFrames_new}`});
this.nFrames_new++;
@ -46,7 +52,11 @@ class App extends Component {
this.svgs_new.push(div);
}
}
this.setState(state => ({...state, socket: ws, message: "Connecting..."}));
this.setState(state => ({
...state,
socket: ws,
message: "Connecting..."
}));
}
constructor(props) {
super(props);
@ -54,7 +64,7 @@ class App extends Component {
this.state = {
program: preset[0].programs[0].code
};
setTimeout(this.connect,0);
setTimeout(this.connect, 0);
this.nFrames_new = 0;
this.svgs_new = [];
this.nFrames = 0;
@ -64,12 +74,11 @@ class App extends Component {
const animate = () => {
const now = Date.now();
const nFrames = self.nFrames;
const thisFrame = (Math.round((now-this.start)/1000*60))%nFrames
// const thisFrame = 0;
// console.log('Animation frame:', thisFrame, nFrames);
if(nFrames) {
const thisFrame = (Math.round((now - this.start) / 1000 * 60)) % nFrames
// const thisFrame = 0; console.log('Animation frame:', thisFrame, nFrames);
if (nFrames) {
// self.svg.innerHTML = self.svgs[thisFrame];
while(self.svg.firstChild)
while (self.svg.firstChild)
self.svg.removeChild(self.svg.firstChild);
self.svg.appendChild(self.svgs[thisFrame]);
} else {
@ -93,7 +102,10 @@ class App extends Component {
this.timeout = setTimeout(function() {
console.log('change', text);
self.setState(state => ({...state, message: "Compiling..."}));
self.setState(state => ({
...state,
message: "Compiling..."
}));
socket.send(text);
}, 500);
};
@ -106,14 +118,15 @@ class App extends Component {
<div className="App">
<div>
<select onChange={this.selectPreset}>
{ preset.map( (group, i) =>
<optgroup key={i} label={group.name}>
{ group.programs.map( (elt, i) =>
<option value={elt.code} key={i}>{elt.name}</option>
)}
</optgroup>
)}
{
preset.map(
(group, i) => <optgroup key={i} label={group.name}>
{group.programs.map((elt, i) => <option value={elt.code} key={i}>{elt.name}</option>)}
</optgroup>
)
}
</select>
<a className="home" href="https://github.com/Lemmih/reanimate">Return to GitHub page.</a>
</div>
<div className="editor">
<AceEditor
@ -131,9 +144,7 @@ class App extends Component {
$blockScrolling: true
}}/>
</div>
<div className="controls">
</div>
<div className="controls"></div>
<div className="viewer">
<div ref={node => this.svg = node}/>
<div className="messages">

View file

@ -1,46 +1,43 @@
const latex_draw =
`animation = pauseAtEnd 1 $ proc () -> do
emit -< toHtml $ mkBackground "black"
drawText msg \`andThen\` fillText msg -< ()
`animation :: Animation
animation =
bg \`sim\` (autoReverse $ drawText \`andThen\` fillText)
where
bg = mkAnimation 0 $ emit (mkBackground "black")
msg = "\\\\sum_{k=1}^\\\\infty {1 \\\\over k^2} = {\\\\pi^2 \\\\over 6}"
placement = translate (320/2) (180/2) . scale 5
fillText txt = proc () -> do
duration 1 -< ()
s <- signal 0 1 -< ()
emit -< toHtml $ placement $
withFillColor "white" $ withFillOpacity s $
center $ latexAlign txt
drawText txt = proc () -> do
duration 2 -< ()
s <- signal 0 1 -< ()
emit -< toHtml $ placement $
glyphs = center $ latexAlign msg
fillText = mkAnimation 1 $ do
s <- signal 0 1
emit $ scale 5 $ withFillColor "white" $ withFillOpacity s glyphs
drawText = mkAnimation 2 $ do
s <- signal 0 1
emit $ scale 5 $
withStrokeColor "white" $ withFillOpacity 0 $ withStrokeWidth (Num 0.1) $
partialSvg s $ center $ latexAlign txt`;
partialSvg s glyphs`;
const bbox =
`animation :: Ani ()
animation = proc () -> do
emit -< toHtml $ mkBackground "black"
duration 5 -< ()
annotate' bbox1 -< g_ [transform_ $ Lucid.translate (320/2-50) (180/2)]
annotate' bbox2 -< g_ [transform_ $ Lucid.translate (320/2+50) (180/2)]
`animation :: Animation
animation = bg \`sim\`
mapA (translate (-50) 0) bbox1 \`sim\`
mapA (translate 50 0) bbox2
where
bg = mkAnimation 0 $ emit $ mkBackground "black"
bbox1 :: Ani ()
bbox1 = proc () -> do
s <- signal 0 1 -< ()
emit -< do
toHtml $ mkBoundingBox $ rotate (360*s) svg
toHtml $ withFillColor "white" $ rotate (360*s) svg
bbox1 :: Animation
bbox1 = mkAnimation 5 $ do
s <- signal 0 1
emit $ mkGroup
[ mkBoundingBox $ rotate (360*s) svg
, withFillColor "white" $ rotate (360*s) svg ]
where
svg = scale 3 $ center $ latexAlign "\\\\sum_{k=1}^\\\\infty"
bbox2 :: Ani ()
bbox2 = proc () -> do
s <- signalOscillate 0 1 -< ()
emit -< do
toHtml $ mkBoundingBox $ partialSvg s heartShape
toHtml $ withStrokeColor "white" $ withFillOpacity 0 $ partialSvg s heartShape
bbox2 :: Animation
bbox2 = autoReverse $ mkAnimation 2.5 $ do
s <- signal 0 1
emit $ mkGroup
[ mkBoundingBox $ partialSvg s heartShape
, withStrokeColor "white" $ withFillOpacity 0 $ partialSvg s heartShape ]
mkBoundingBox :: Tree -> Tree
mkBoundingBox svg = withStrokeColor "red" $ withFillOpacity 0 $
@ -50,9 +47,9 @@ mkBoundingBox svg = withStrokeColor "red" $ withFillOpacity 0 $
heartShape =
center $ rotateAroundCenter 225 $ mkPathString
"M0.0,40.0 v-40.0 h40.0\
\a20.0 20.0 90.0 0 1 0.0,40.0\
\a20.0 20.0 90.0 0 1 -40.0,0.0 Z"`;
"M0.0,40.0 v-40.0 h40.0\\
\\a20.0 20.0 90.0 0 1 0.0,40.0\\
\\a20.0 20.0 90.0 0 1 -40.0,0.0 Z"`;
const sinewave =
`animation :: Ani ()
@ -77,15 +74,14 @@ animation = proc () -> do
wave idx = (idx*width, sin (idx*pi*2*freq) * 50)`;
const morph_wave =
`animation :: Ani ()
animation = proc () -> do
duration 5 -< ()
morph <- signalOscillate 0 1 -< ()
emit -< toHtml $ mkBackground "black"
emit -< toHtml $ withStrokeColor "white" $ mkGroup
[ translate 30 50 $ mkPathText $ renderPathText wave1
, translate 30 130 $ mkPathText $ renderPathText wave2
, translate 30 90 $ mkPathText $ renderPathText $ morphPath wave1 wave2 morph
`animation :: Animation
animation = autoReverse $ mkAnimation 2.5 $ do
morph <- signal 0 1
emit $ mkBackground "black"
emit $ withStrokeColor "white" $ translate (-320/2) (-180/2) $ mkGroup
[ translate 30 50 $ mkLinePath wave1
, translate 30 130 $ mkLinePath wave2
, translate 30 90 $ mkLinePath $ morphPath wave1 wave2 morph
, mkLine (Num 30, Num 10) (Num 30, Num 170)
, mkLine (Num 30, Num 90) (Num 290, Num 90) ]
where
@ -94,13 +90,12 @@ animation = proc () -> do
wave2 = approxFnData 100 $ \\idx -> (idx*width, sin (idx*pi*2*(freq*3)) * 20)`;
const morph_wave_circle =
`animation :: Ani ()
animation = proc t -> do
duration 5 -< ()
idx <- signalOscillate 0 1 -< ()
emit -< toHtml $ mkBackground "black"
emit -< toHtml $ withStrokeColor "white" $ mkGroup
[ translate 30 90 $ mkPathText $ renderPathText $ morphPath circle wave1 idx
`animation :: Animation
animation = autoReverse $ mkAnimation 2.5 $ do
idx <- signal 0 1
emit $ mkBackground "black"
emit $ withStrokeColor "white" $ translate (-320/2) (-180/2) $ mkGroup
[ translate 30 90 $ mkLinePath $ morphPath circle wave1 idx
, mkLine (Num 30, Num 10) (Num 30, Num 170)
, mkLine (Num 30, Num 90) (Num 290, Num 90) ]
where
@ -110,99 +105,46 @@ animation = proc t -> do
(cos (idx*pi*2+pi/2)*radius + width/2, sin (idx*pi*2+pi/2)*radius)`;
const progressMeters =
`animation :: Ani ()
animation = proc () -> do
emit -< rect_ [width_ "100%", height_ "100%", fill_ "black"]
annotate' (adjustSpeed 1.0 progressMeter) -< g_ [transform_ $ Lucid.translate 40 20]
annotate' (adjustSpeed 2.0 progressMeter) -< g_ [transform_ $ Lucid.translate 140 20]
annotate' (adjustSpeed 0.5 progressMeter) -< g_ [transform_ $ Lucid.translate 240 20]
emit -< do
text_ [x_ "55", y_ "150", font_size_ "20"
, text_anchor_ "middle"
, fill_ "white"] "1x"
text_ [x_ "155", y_ "150", font_size_ "20"
, text_anchor_ "middle"
, fill_ "white"] "2x"
text_ [x_ "255", y_ "150", font_size_ "20"
, text_anchor_ "middle"
, fill_ "white"] "0.5x"
progressMeter :: Ani ()
progressMeter = loop $ proc () -> do
duration 5 -< ()
h <- signal 0 100 -< ()
emit -< rect_ [ width_ "30", height_ "100", stroke_ "white", stroke_width_ "2", fill_opacity_ "0" ]
emit -< rect_ [ width_ "30", num_ height_ h, stroke_ "white", fill_ "white" ]
returnA -< ()`
const highlight =
`animation :: Ani ()
animation = proc () -> do
emit -< rect_ [width_ "100%", height_ "100%", fill_ "black"]
emit -< do
path_ (commonAttrs "white" ++ [d_ $ renderPathText rect1])
path_ (commonAttrs "white" ++ [d_ $ renderPathText rect2])
path_ (commonAttrs "white" ++ [d_ $ renderPathText rect3])
path_ (commonAttrs "lightblue" ++ [d_ $ renderPathText rect4])
path_ (commonAttrs "yellow" ++ [d_ $ renderPathText rect5])
path_ (commonAttrs "red" ++ [d_ $ renderPathText rect6])
follow
[ mkTransition highlight1 highlight2
, mkTransition highlight2 highlight3
, mkTransition highlight3 highlight4
, mkTransition highlight4 highlight5
, mkTransition highlight5 highlight6
, mkTransition highlight6 highlight1
] -< ()
`animation :: Animation
animation =
bg \`sim\` labels \`sim\`
mapA (translate (-100) 0) (adjustSpeed 1.0 progressMeter) \`simLoop\`
mapA (translate 0 0) (adjustSpeed 2.0 progressMeter) \`simLoop\`
mapA (translate 100 0) (adjustSpeed 0.5 progressMeter)
where
mkTransition from to = pauseAtEnd 1 $ proc () -> do
duration 1 -< ()
s <- signalSCurve 2 0 1 -< ()
let trans = morphPath from to s
emit -<
path_ (highlightAttrs "green" ++ [d_ $ renderPathText trans <> "Z"])
mkRect x y width height =
[ (x,y), (x+width, y), (x+width, y+height), (x,y+height) ]
rect1 = mkRect margin margin w h
rect2 = mkRect (320-margin-w*2) margin (w*2) h
rect3 = mkRect margin (180-margin-h) w h
rect4 = mkRect (320/3) (180-margin-h) w h
rect5 = mkRect (320/3*2-w) (180-margin-h) w h
rect6 = mkRect (320-margin-w) (180-margin-h) w h
highlight1 = mkRect (margin-b) (margin-b) (w+2*b) (h+2*b)
highlight2 = mkRect (320-margin-w*2-b) (margin-b) (w*2+2*b) (h+2*b)
highlight3 = mkRect (320-margin-w-b) (180-margin-h-b) (w+2*b) (h+2*b)
highlight4 = mkRect (320/3*2-w-b) (180-margin-h-b) (320/3+2*b) (h+2*b)
highlight5 = mkRect (320/3-b) (180-margin-h-b) (320/3+2*b) (h+2*b)
highlight6 = mkRect (margin-b) (180-margin-h-b) (320/3+2*b) (h+2*b)
b = 7; margin = 30; w = 30; h = 30
commonAttrs c = [stroke_width_ "2", stroke_ c, fill_ c]
highlightAttrs c = [stroke_width_ "2", stroke_ c, fill_opacity_ "0"]`;
bg = mkAnimation 0 $ emit $ mkBackground "black"
labels = mkAnimation 0 $ emit $ translate 0 70 $ withFillColor "white" $ mkGroup
[ translate (-100) 0 $ scale 2 $ center $ latex "1x"
, translate 0 0 $ scale 2 $ center $ latex "2x"
, translate 100 0 $ scale 2 $ center $ latex "0.5x"
]
progressMeter :: Animation
progressMeter = mkAnimation 3 $ do
h <- signal 0 100
emit $ center $ mkGroup
[ withStrokeColor "white" $ withStrokeWidth (Num 2) $ withFillOpacity 0 $
mkRect (Num 0, Num 0) (Num 30) (Num 100)
, withFillColor "white" $
mkRect (Num 0, Num 0) (Num 30) (Num h) ]`
const latex_basic =
`animation :: Ani ()
animation = proc () -> do
duration 2 -< ()
s <- signalOscillate 0 1 -< ()
emit -< toHtml $ mkGroup
[ mkBackground "black"
, translate (320/2) (180/2) $ mkGroup
[ withStrokeColor "white" $ withFillOpacity 0 $ withStrokeWidth (Num 0.1) text
, withFillColor "white" $ withFillOpacity s text] ]
`animation :: Animation
animation = autoReverse $ mkAnimation 2 $ do
s <- signal 0 1
emit $ mkGroup
[ mkBackground "black"
, withStrokeColor "white" $ withFillOpacity 0 $ withStrokeWidth (Num 0.1) text
, withFillColor "white" $ withFillOpacity s text ]
where
text = scale 4 $ center $ latexAlign
"\\\\sum_{k=1}^\\\\infty {1 \\\\over k^2} = {\\\\pi^2 \\\\over 6}"`
const latex_color =
`animation :: Ani ()
animation = proc () -> do
duration 0.1 -< ()
emit -< toHtml $ mkBackground "black"
emit -< toHtml $ translate (320/2) (180/2) $ withStrokeWidth (Num 0.2) $
`animation :: Animation
animation = mkAnimation 1 $ do
emit $ mkBackground "black"
emit $ withStrokeWidth (Num 0.2) $
withStrokeColor "white" $
withSubglyphs [0] (withFillColor "blue") $
withSubglyphs [1] (withFillColor "yellow") $
@ -221,7 +163,7 @@ export default [
, {name: "LaTeX Color", code: latex_color }
, {name: "LaTeX Basic", code: latex_basic }
, {name: "Bounding boxes", code: bbox }
, {name: "Sinewave", code: sinewave }
// , {name: "Sinewave", code: sinewave }
, {name: "Morphwave", code: morph_wave }
, {name: "Morphwave Circle", code: morph_wave_circle }
, {name: "Progress meters", code: progressMeters }