malison 0.8.0

  • README.md
  • CHANGELOG.md
  • Example
  • Installing
  • Versions
  • 81

Malison is a small Dart library for drawing old school ASCII terminals in the browser. I harvested it from my roguelike game, Hauberk and it's aimed primarily at web games ASCII graphics. Think of it like curses for the web.

Using it

Add it to your package's pubspec:

dependencies:
  malison: any

Then use the library:

import 'dart:html';

import 'package:malison/malison.dart';

void main() {
  // Create or query a <canvas> element to bind it to.
  var canvas = new CanvasElement();
  document.body.children.add(canvas);

  // Create a new terminal. CanvasTerminal uses your browser's fonts.
  // RetroTerminal uses a built in DOS-style Code Page 437 font.
  var terminal = new RetroTerminal.dos(80, 40, canvas);

  // You can draw strings at given positions.
  terminal.writeAt(0, 0, "This is a terminal!");

  // You can control the foreground and background color.
  terminal.writeAt(0, 1, "This is blue on green", Color.blue, Color.green);

  // You can also draw individual glyphs -- character+color units.
  terminal.drawGlyph(3, 4, new Glyph.fromCharCode(CharCode.blackHeartSuit,
      Color.red, Color.white));

  // When you're done drawing, tell it to render all of the changes. It renders
  // in batches for performance.
  terminal.render();
}

0.8.0

  • Change Color.blend() to take a value from (0, 1.0) instead of a percent.
  • Add Color.add().

0.7.0

  • Fill in the rest of the character codes to CharCode.
  • Add Color.blend() and store colors as RGB.
  • Add foreColor, backColor, and fill() to Terminal.

0.6.0

  • Split into two libraries. The core malison library does not import "dart:html" and can be used in command-line applications. It's not useful outside of the web, but it lets you test code in a "headless" fashion that uses malison on the standalone VM.

0.5.1

  • Get rid of implicit casts and dynamic.

0.5.0

  • Add type parameters to UserInterface, KeyBindings, and Screen so that the bound objects can be precisely typed.

0.4.3

  • Make strong mode clean.

0.4.2

  • Widen constraint on piecemeal.

0.4.1

  • Fix semicolon handling on Firefox.

0.4.0

  • Add constants to CharCode for every character in code page 437.
  • Make constants lowerCamelCase.

0.3.0

  • Automatically create a canvas if not given one.
  • Allow creating a UserInterface without an initial terminal.
  • Add an example app.

0.2.1

  • Fix bad assert in Screen._bind().

0.2.0

  • Redo key input handling. Instead of a (mostly broken) Keyboard class, it exposes raw key down events as they happen and also allows user-defined key bindings.

  • Refactor UserInterface and clean up how opaque/transparent screens are handled.

  • Remove (useless) write() method.

  • Handle semicolon keyCode difference between Firefox (59) and Chrome (186).

example/main.dart

import 'dart:html' as html;
import 'dart:math' as math;

import 'package:malison/malison.dart';
import 'package:malison/malison_web.dart';

const width = 80;
const height = 30;

final ui = new UserInterface<String>();

/// A few different terminals to choose from.
final terminals = <RenderableTerminal Function()>[
  () => new RetroTerminal.dos(width, height),
  () => new RetroTerminal.shortDos(width, height),
  () => new CanvasTerminal(width, height,
      new Font('Menlo, Consolas', size: 12, w: 8, h: 14, x: 1, y: 11)),
  () => new CanvasTerminal(
      width, height, new Font('Courier', size: 13, w: 10, h: 15, x: 1, y: 11)),
  () => new CanvasTerminal(
      width, height, new Font('Courier', size: 12, w: 8, h: 14, x: 1, y: 10))
];

/// Index of the current terminal in [terminals].
int terminalIndex = 0;

void main() {
  // Set up the keybindings.
  ui.keyPress.bind("next terminal", KeyCode.tab);
  ui.keyPress.bind("prev terminal", KeyCode.tab, shift: true);
  ui.keyPress.bind("animate", KeyCode.space);

  updateTerminal();

  ui.push(new MainScreen());

  ui.handlingInput = true;
  ui.running = true;
}

void updateTerminal() {
  html.document.body.children.clear();
  ui.setTerminal(terminals[terminalIndex]());
}

class MainScreen extends Screen<String> {
  final List<Ball> balls = [];

  MainScreen() {
    var colors = [
      Color.red,
      Color.orange,
      Color.gold,
      Color.yellow,
      Color.green,
      Color.aqua,
      Color.blue,
      Color.purple
    ];

    var random = new math.Random();

    for (var char in [CharCode.bullet, CharCode.asterisk, "O".codeUnitAt(0)]) {
      for (var color in colors) {
        balls.add(new Ball(
            color,
            char,
            random.nextDouble() * Ball.pitWidth,
            random.nextDouble() * (Ball.pitHeight / 2.0),
            random.nextDouble() + 0.2,
            0.0));
      }
    }
  }

  bool handleInput(String input) {
    switch (input) {
      case "next terminal":
        terminalIndex = (terminalIndex + 1) % terminals.length;
        updateTerminal();
        ui.refresh();
        break;

      case "prev terminal":
        terminalIndex = (terminalIndex - 1) % terminals.length;
        updateTerminal();
        ui.refresh();
        break;

      case "animate":
        ui.running = !ui.running;
        break;

      default:
        return false;
    }

    return true;
  }

  void update() {
    for (var ball in balls) {
      ball.update();
    }

    dirty();
  }

  void render(Terminal terminal) {
    terminal.clear();

    void colorBar(int y, String name, Color light, Color medium, Color dark) {
      terminal.writeAt(2, y, name, Color.gray);
      terminal.writeAt(10, y, "light", light);
      terminal.writeAt(16, y, "medium", medium);
      terminal.writeAt(23, y, "dark", dark);

      terminal.writeAt(28, y, " light ", Color.black, light);
      terminal.writeAt(35, y, " medium ", Color.black, medium);
      terminal.writeAt(43, y, " dark ", Color.black, dark);
    }

    terminal.writeAt(0, 0, "Predefined colors:");
    terminal.writeAt(59, 0, "switch terminal [tab]", Color.darkGray);
    terminal.writeAt(75, 0, "[tab]", Color.lightGray);
    colorBar(1, "gray", Color.lightGray, Color.gray, Color.darkGray);
    colorBar(2, "red", Color.lightRed, Color.red, Color.darkRed);
    colorBar(3, "orange", Color.lightOrange, Color.orange, Color.darkOrange);
    colorBar(4, "gold", Color.lightGold, Color.gold, Color.darkGold);
    colorBar(5, "yellow", Color.lightYellow, Color.yellow, Color.darkYellow);
    colorBar(6, "green", Color.lightGreen, Color.green, Color.darkGreen);
    colorBar(7, "aqua", Color.lightAqua, Color.aqua, Color.darkAqua);
    colorBar(8, "blue", Color.lightBlue, Color.blue, Color.darkBlue);
    colorBar(9, "purple", Color.lightPurple, Color.purple, Color.darkPurple);
    colorBar(10, "brown", Color.lightBrown, Color.brown, Color.darkBrown);

    terminal.writeAt(0, 12, "Code page 437:");
    var lines = [
      " ☺☻♥♦♣♠•◘○◙♂♀♪♫☼",
      "►◄↕‼¶§▬↨↑↓→←∟↔▲▼",
      " !\"#\$%&'()*+,-./",
      "0123456789:;<=>?",
      "@ABCDEFGHIJKLMNO",
      "PQRSTUVWXYZ[\\]^_",
      "`abcdefghijklmno",
      "pqrstuvwxyz{|}~⌂",
      "ÇüéâäàåçêëèïîìÄÅ",
      "ÉæÆôöòûùÿÖÜ¢£¥₧ƒ",
      "áíóúñѪº¿⌐¬½¼¡«»",
      "░▒▓│┤╡╢╖╕╣║╗╝╜╛┐",
      "└┴┬├─┼╞╟╚╔╩╦╠═╬╧",
      "╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀",
      "αßΓπΣσµτΦΘΩδ∞φε∩",
      "≡±≥≤⌠⌡÷≈°∙·√ⁿ²■"
    ];

    var y = 13;
    for (var line in lines) {
      terminal.writeAt(3, y++, line, Color.lightGray);
    }

    terminal.writeAt(22, 12, "Simple game loop:");
    terminal.writeAt(66, 12, "toggle [space]", Color.darkGray);
    terminal.writeAt(73, 12, "[space]", Color.lightGray);

    for (var ball in balls) {
      ball.render(terminal);
    }
  }
}

class Ball {
  static const pitWidth = 56.0;
  static const pitHeight = 17.0;

  final Color color;
  final int charCode;

  double x, y, h, v;

  Ball(this.color, this.charCode, this.x, this.y, this.h, this.v);

  void update() {
    x += h;
    if (x < 0.0) {
      x = -x;
      h = -h;
    } else if (x > pitWidth) {
      x = pitWidth - x + pitWidth;
      h = -h;
    }

    v += 0.03;
    y += v;
    if (y > pitHeight) {
      y = pitHeight - y + pitHeight;
      v = -v;
    }
  }

  void render(Terminal terminal) {
    terminal.drawChar(24 + x.toInt(), 13 + y.toInt(), charCode, color);
  }
}

1. Depend on it

Add this to your package's pubspec.yaml file:


dependencies:
  malison: "^0.8.0"

2. Install it

You can install packages from the command line:

with pub:


$ pub get

with Flutter:


$ flutter packages get

Alternatively, your editor might support pub get or packages get. Check the docs for your editor to learn more.

3. Import it

Now in your Dart code, you can use:


import 'package:malison/malison.dart';
        
Version Uploaded Documentation Archive
0.8.0 Dec 16, 2017 Go to the documentation of malison 0.8.0 Download malison 0.8.0 archive
0.7.0 Sep 16, 2017 Go to the documentation of malison 0.7.0 Download malison 0.7.0 archive
0.6.0 Jan 8, 2017 Go to the documentation of malison 0.6.0 Download malison 0.6.0 archive
0.5.1+1 Jan 4, 2017 Go to the documentation of malison 0.5.1+1 Download malison 0.5.1+1 archive
0.5.1 Jan 4, 2017 Go to the documentation of malison 0.5.1 Download malison 0.5.1 archive
0.5.0 Apr 15, 2016 Go to the documentation of malison 0.5.0 Download malison 0.5.0 archive
0.4.3 Oct 27, 2015 Go to the documentation of malison 0.4.3 Download malison 0.4.3 archive
0.4.2 Oct 23, 2015 Go to the documentation of malison 0.4.2 Download malison 0.4.2 archive
0.4.1 Oct 22, 2015 Go to the documentation of malison 0.4.1 Download malison 0.4.1 archive
0.4.0 Oct 22, 2015 Go to the documentation of malison 0.4.0 Download malison 0.4.0 archive

All 15 versions...

Analysis

This feature is new.
We welcome feedback.
More details: scoring.

We analyzed this package, and provided a score, details, and suggestions below.

  • completed on Feb 3, 2018
  • Dart: 2.0.0-dev.20.0
  • pana: 0.10.1

Scores

Popularity:
Describes how popular the package is relative to other packages. [more]
62 / 100
Health:
Code health derived from static analysis. [more]
100 / 100
Maintenance:
Reflects how tidy and up-to-date the package is. [more]
100 / 100
Overall score:
Weighted score of the above. [more]
81

Platforms

Detected platforms: Flutter, web, other

No platform restriction found in primary library package:malison/malison.dart.

Suggestions

  • The description is too short.

    Add more detail about the package, what it does and what is its target use case. Try to write at least 60 characters.

  • Package is pre-v1 release.

    While there is nothing inherently wrong with versions of 0.*.*, it usually means that the author is still experimenting with the general direction API.

  • Use analysis_options.yaml.

    Rename old .analysis_options file to analysis_options.yaml.

Dependencies

Package Constraint Resolved Available
Direct dependencies
Dart SDK >=1.24.0 <2.0.0
piecemeal >=0.2.0 <0.4.0 0.3.6
Dev dependencies
browser any
unittest any