packages feed

shine-0.2.0.1: README.md

# Shine - Declarative Graphics for the Web

[![Build Status](https://travis-ci.org/fgaz/shine.svg?branch=master)](https://travis-ci.org/fgaz/shine)

Shine wraps javascript's drawing functions in a declarative API.

Heavily inspired by [gloss](http://gloss.ouroborus.net/).

**demo** (compiled tests) [here](http://fgaz.me/shine/tests)

## Compiling

You need [ghcjs](https://github.com/ghcjs/ghcjs)

## Usage

### `Picture`s

To represent your drawing you have to build a tree using the `Picture` datatype.

```haskell
pic :: Picture
pic = Rect 10 20 -- represents a 10x20 square
```

To compose multiple `Picture`s you can use `Over`, which accepts two `Picture`s
and overlaps them.

`Picture` is a monoid: `<>` is an alias for `Over` and `mempty` is the empty picture.

```haskell
-- draw some shapes on top of each other
pic :: Picture
pic = Rect 10 20
   <> Translate 30 30 (Circle 15)
   <> Colored (Color 255 0 0 0.2) (RectF 4 4)
   <> Text "Sans 12px" LeftAlign 200 "The quick brown fox jumps over the lazy dog."
```

Using `Foldable` you can do things like

```haskell
concentricCircles :: Picture
concentricCircles = foldMap Circle [1,10..100]
```

### Drawing `Picture`s

Before drawing anything you need to obtain a `CanvasRenderingContext2D` (and sometimes a `Document`).
For this purpose, shine provides two utility functions: `fullScreenCanvas` and `fixedSizeCanvas`

```haskell
{-# LANGUAGE CPP #-}

import Graphics.Shine
import Graphics.Shine.Input
import Graphics.Shine.Picture

import GHCJS.DOM (currentDocumentUnchecked)

-- This is how the ghcjs-dom hello-world does it.
-- It's boilerplate, so in the next shine version there
-- will probably be a ready-to-use run function
#if defined(ghcjs_HOST_OS)
run :: a -> a
run = id
#elif defined(MIN_VERSION_jsaddle_wkwebview)
import Language.Javascript.JSaddle.WKWebView (run)
#else
import Language.Javascript.JSaddle.WebKitGTK (run)
#endif

main :: IO ()
main = run $ do
    doc <- currentDocumentUnchecked -- use currentDocument to handle failure
    ctx <- fixedSizeCanvas doc 400 400
    -- do something with ctx (and maybe doc)
```

To render a `Picture` on a context you have three options:

#### `render`

You can draw it manually using `render` from `Graphics.Shine.Render`

```haskell
main :: IO ()
    {- get the context, see before -}
    draw ctx concentricCircles
```

#### `animate`

You can draw a `Picture` that depends on time. That is, a `Float -> Picture`.

```haskell
-- An expanding-and-contracting circle.
animation :: Float -> Picture
animation = Translate 200 200
          . Circle
          . (*100) . (+1) -- bigger positive oscillation
          . sin -- the circle's radius oscillates

main :: IO ()
main =  do
    {- get the context, see before -}
    animate ctx 30 animation
```

#### `play`

Finally, you can draw a `Picture` that depends on time, inputs
(keyboard and mouse) and an internal state. This is especially useful for games,
hence the name.

```haskell
-- this code draws a black rectangle in the center of the canvas only when the
-- left mouse button is pressed
main :: IO ()
main = do
    {- get the context and the document, see before -}
    play ctx doc 30 initialState draw handleInput step
  where
    -- our state represents the state of the left mouse button
    initialState = Up
    -- we draw a square only if the button is pressed
    draw Up = Empty
    draw Down = Translate 200 200 $ RectF 200 200
    -- when an event is fired we store the button state
    handleInput (MouseBtn BtnLeft buttonState _) = const buttonState
    handleInput _ = id -- catch-all for all other events
    step _ = id -- our state does not depend on time
```