Stage

The stage is what ties all the separate systems together. Subclasses of a base stage are used for different scenes in the game (title screen, levels, inter-chapter screen). Roughly, the structure is as follows:

  1. The stage specifies input handlers (via TouchRecord, see below).
  2. Input handlers call helper methods on the stage.
  3. Helper methods use semantics functions to decide what to change/how to change expressions, and may provide callbacks to these semantics functions.
  4. Helper methods dispatch Redux actions to the store to update the game state, or modify views to update the UI state.

Rendering

Reduct-Redux does not have a scenegraph, and so you need to explicitly specify what to render. This should be done by overriding drawContents. There are helper functions to render a view for a given expression, like drawProjection.

The rendering lifecycle is as follows:

  1. Redux store/animation is updated
  2. stage.draw() is called
  3. stage.draw uses requestAnimationFrame
  4. requestAnimationFrame callback fires, calling stage.drawImpl
  5. stage.drawImpl calls stage.drawContents

This allows Redux to avoid re-rendering when nothing is happening, saving CPU.

Effects

Input Handling: TouchRecord

Unlike most UI/GUI frameworks, where events are processed by handler functions attached to particular UI widgets, Reduct-Redux handles most events in a centralized location, the TouchRecord. This is a class with callbacks for when a touch/mouse is pressed, moved, or released, and keeps track of related state. Based on this state, it dispatches lower-level callbacks or changes as appropriate (reducing expressions, dragging them around, activating buttons, etc.). You specify the desired TouchRecord to use by overriding the touchRecordClass property getter of BaseStage.

Stages Reference

import BaseStage from "./stage/basestage";
import BaseTouchRecord from "./stage/touchrecord";
class module:BaseStage()

Handle drawing responsibilites for Reduct.

There’s a lot more stuff here, but I’m too lazy to document it all.

module:BaseStage.addEffect(fx)

Add an effect to the stage.

module:BaseStage.allocate(projection)

Allocate an ID for the given projection.

Used for projections that don’t directly correspond to nodes and are static (e.g. the text view for the arow in a lambda), but still need an ID.

module:BaseStage.allocateInternal(projection)

Note

This function is deprecated. Use allocate() instead.

module:BaseStage.color

The background color.

module:BaseStage.computeDimensions()

Compute and resize the canvas when the window is resized.

module:BaseStage.ctx

The canvas drawing context.

module:BaseStage.draw()

Request that the stage be redrawn. (Multiple calls have no effect if no redraw happens in between.)

module:BaseStage.drawContents()

Draw the contents of the stage. Override to customize.

module:BaseStage.drawInternalProjection(state, nodeId, exprId, offset)

Note

This function is deprecated. Use BaseStage.drawProjection() instead.

module:BaseStage.drawProjection(state, nodeId, offset)

Helper to draw a given view.

module:BaseStage.findSafePosition(x, y, w, h)

Given a rectangular area, move it minimally to fit within the stage bounds.

module:BaseStage.getMousePos(e)

Convert a mouse/touch event into an { x, y } position, accounting for scaling.

module:BaseStage.getNodeAtPos(pos, selectedId)

Get the node at the given position.

TODO: return all possible nodes?

module:BaseStage.getState()

Get the current Redux state.

module:BaseStage.getView(id)

Get the view with the given ID.

module:BaseStage.height

The usable width of the stage. (Things like the sidebar can change this.)

module:BaseStage.internalViews

Note

This attribute is deprecated.

A set of views.

module:BaseStage.isHovered(id)

Check whether the given view ID is hovered by any touch/mouse.

module:BaseStage.isSelected(id)

Check whether the given view ID is selected by any touch/mouse.

module:BaseStage.makeBaseOffset(opt)

Create a basic offset object for rendering.

module:BaseStage.semantics

The semantics module.

module:BaseStage.setCursor(cursor)

Set the mouse cursor.

module:BaseStage.store

The Redux store.

module:BaseStage.touchRecordClass

The TouchRecord class to use for touch/mouse events. Override to customize input handling.

module:BaseStage.updateCursor(touchRecord, moved)

Update the cursor based on the mouse/touch state.

module:BaseStage.views

A dictionary of view ID to view object.

module:BaseStage.width

The usable width of the stage. (Things like the sidebar can change this.)

class module:BaseTouchRecord()

Handle input for Reduct.

module:BaseTouchRecord.dragged

A flag indicating whether the user has dragged the selected view yet.

module:BaseTouchRecord.findHoverNode(pos)

Helper method to find the view under the current mouse position. Defers to BaseStage.getNodeAtPos(), but also tracks the previously hovered node (for things like mouse enter/exit events).

module:BaseTouchRecord.fromToolbox

A flag indicating whether the selected view came from the toolbox.

module:BaseTouchRecord.hoverNode

The ID of the view currently under the mouse (if any).

module:BaseTouchRecord.isExpr

A flag indicating whether the selected view belongs to an expression.

module:BaseTouchRecord.onend(state, mousePos)

Called when the mouse is released.

module:BaseTouchRecord.onmove(mouseDown, mousePos)

Called when the mouse is moved.

Arguments:
  • mouseDown – whether the mouse was pressed
  • mousePos
module:BaseTouchRecord.onstart(mousePos)

Called when the mouse is pressed.

module:BaseTouchRecord.prevHoverNode

The ID of the view previously under the mouse (if any).

module:BaseTouchRecord.reset()

Reset this TouchRecord. (The record for the mouse is not recreated, as it can have move events with not pressed.)

module:BaseTouchRecord.stage

The current stage.

module:BaseTouchRecord.targetNode

The targeted view ID that was clicked (if any). This may be the same as the top-level view. The Stage controls how these work.

module:BaseTouchRecord.topNode

The top-level view ID that was clicked (if any).