Usage guide (v1.x)

This is a tool for developers of text-based games to visualize characters dynamically based on their statistics. For the usage guide of a previous version, see 0.13

The tool comes in the form of a Javascript module named da, which the first thing you should do is to either include or copy the entire content of da.js to the top of your Javascript code.

If you're familiar with the concepts, skip to how-to for links to tutorials on doing specific things.

You need to use the module in this order:
  1. [optional] extend da.Player with your own gameplay statistics
  2. [optional] link your gameplay statistics to dimension calculations
  3. [optional] create additional assets (clothing, body parts, patterns)
  4. load the da module
  5. get canvas group to draw to
  6. draw and modify players at will in your game code (e.g. change clothing, modify stats, add/remove body parts)

Steps 1 and 2 is covered in the extension guide. Take a look if you need custom stats for the avatars, want to adjust how stats scale dimensions, or want to add more complex mechanics.

Steps 3 is covered in the content creation guide. Take a look if you want to create your own part or clothing templates.

The latter steps are covered on this page. First you need to include the da.js Javascript file in your project. Where you need to include it depends on your framework, but if it's a website then do something like below:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="UTF-8">
        <script src="da.js"></script>
    </head>
    <body>
        ...
    </body>
    </html>

Loading the module

Some assets require loading. You should define extensions to the library (such as implementing a combat system based on da.BodyParts) before loading. You must load before calling any drawing methods.

da.load().then(function() {
    // all drawing related functions in here
});

Working with the canvas

The canvas is where we draw to. We use a group of canvases, each representing a different layer (with different z-levels).

The following example shows how to get and create a canvas group.

// assume in your html you had
<div id="player"></div>

// create a canvas group (since it's the first time we're getting it)
var canvasGroup = da.getCanvasGroup("player", {
    // provide some styling options; width and height are particularly important
    border: "1px solid black",
    width: 900,
    height: 1200,
});


// you can also create the canvasGroup holder dynamically without the html in place
var canvasHolder = document.createElement("div");
canvasHolder.id = "something";
// place it somewhere on the web page
document.body.appendChild(canvasHolder);
canvasGroup = da.getCanvasGroup(canvasHolder, {
    width: 900,
    height: 1200,
});

When you create the canvas, the second argument is any CSS overrides you'd like to provide.

All functions accept either the canvas group ID (a string), or the actual group element itself. Working with the group ID is probably better for more users, but anytime you want the canvas group itself, you can call:

// assume the canvas group has been created, a second one won't be recreated
var canvasGroup = da.getCanvasGroup("player");

To toggle whether the canvas can be seen or not:

// hiding it and then immediately showing it again
da.hideCanvasGroup("player");
da.showCanvasGroup("player");

Using the Player object

This section just shows how to create a Player object and how to draw it. Later sections will describe how to extend it for your own game by adding stats and changing the way they're drawn.

The key components of a Player object which you need to know:

  • gameplay statistics - these are defined by you and are relevant to your game. physical dimensions can be partially calculated from these.
  • physical dimensions - values for each physical part of a body calculated from gameplay statistics, modifiers, and the Player's base dimensions.
  • Mods - modifiers either from temporary status effects, clothing worn, or genetic variation.

Creating the Player

To create a player, use new:

// EXAMPLE creating a specific Player object (either the PC or an NPC)
var PC = new da.Player({
    name : "HAL 9000",
    occupation : "Pod Bay Opener",
    // provide specific values here to override the default ones set
    age : 26,
    fem : 11,
    sub : 2,

    // base physical dimensions
    basedim        : {
        areolaSize    : 14.923766816143496,
        armThickness  : 58.468958260259555,
        armLength     : 45,
        breastSize    : 9.974887892376682,
        buttFullness  : 13.019992984917572,
        chinWidth     : 63.335671694142405,
        eyelashLength : 3.0305156085584004,
        eyeSize       : 13.019992984917572,
        faceFem       : 40,
        faceLength    : 212.32549982462294,
        faceWidth     : 82.74465099964925,
        hairLength    : 37.03963521571379,
        hairStyle     : 4,
        hairHue       : 0,
        hairSaturation: 19.081024202034374,
        hairLightness : 11.224131883549632,
        handSize      : 118.9757979656261,
        height        : 163.65022421524662,
        hipWidth      : 110.85584005612066,
        legFem        : 39.95790950543669,
        legFullness   : 4.489652753419852,
        legLength     : 98.79340582251841,
        lipSize       : 18.85654156436338,
        lowerMuscle   : 22.448263767099263,
        neckLength    : 72.73237460540162,
        neckWidth     : 39.489652753419854,
        penisSize     : 50,
        shoulderWidth : 64.28699551569507,
        skin          : -1.9291476674850934,
        testicleSize  : 60,
        upperMuscle   : 0,
        vaginaSize    : 40,
        waistWidth    : 102.32549982462294,
    },
    decorativeParts: [
        da.Part.create(da.BeautyMark, {side: null}),
    ],
    // overriding clothing (default to simple red underwear)
    clothes: [
        da.Clothes.create(da.Bra, da.Materials.sheerFabric),
        da.Clothes.create(da.Panties, da.Materials.sheerFabric)
    ],
});

You could also randomly generate a character with a femininity bias between -1 and 1, with positive values being more feminine, and an indication of how random you want the process to be (> 0).

var fembias = 0.5;
var randomness = 0.8;
PC = da.createRandomCharacter(fembias, randomness);

Drawing the Player

// make sure you called da.load() before this!
// assuming we got canvasGroup as above and created a player named PC
var exports = da.draw(canvasGroup, PC);

You can provide additional options to draw:

var viewConfig = {
    nameColor          : "#cf9fcc",
    genderColor        : "#de8cde",
    heightColor        : "#aaaaaa",
    heightBarColor     : "#aaaaaa",
    // whether the name and gender icon should be rendered
    printAdditionalInfo: false,
    // whether the height and height bar should be rendered
    printHeight        : false,
    // whether the side shoe view (if available) should be rendered
    renderShoeSideView : false,
    // where to place x=0 relative to the default (left is negative)
    offsetX            : 0,
    offsetY            : 0
};

var exports = da.draw(canvasGroup, PC, viewConfig);

The draw function returns an export containing locations of drawpoints (explained later).

Drawing a focused window

Sometimes you want to render only a part of the body. You can do this as below:

da.draw(canvasGroup, PC, viewConfigs).then(function (exports) {
    // draw just the head in a separate canvas
    // first retrieve/create the canvas if it's the first time we're getting it
    var portraitCanvas = da.getCanvas("portrait",
        {
            // size of the focused window/canvas
            width : 500,
            height: 500,
            // can add any CSS style here like border
            border: "none",
            // you can also position it absolutely
            // position: "absolute",
            // top     : "10px",
            // left    : "10px",
            // or relative to a parent
            // parent: document.getElementById("canvas_holder"),
        });

    // you can call this multiple times to draw different parts (with different canvases)
    da.drawFocusedWindow(portraitCanvas,
        exports,
        {
            center: exports[da.Part.RIGHT].neck.nape,
            width: 50,
            height: 70
        });
});

Having it in the then block after the original draw makes sure that the focused windows are synced to any changes. You can also hide the original canvas group without affecting focused windows. This will also speed up rendering.

da.hideCanvasGroup(canvasGroup);

You can also increase the original canvas's size to increase the resolution of the focused windows (without affecting the size).

// in the original retrieval, you can't call this after the initial call
canvasGroup = da.getCanvasGroup("player", {
    // increase these to increase the focused window's resolution without increasing their size
    width : 2000,
    height: 3000,
});

See the effects of changing original canvas size below:

Interacting with a Player object

You can modify gameplay stats, base dimensions, and Mods on the Player object directly.

PC.basedim.armLength += 2;
PC.fem += 1;

You can get modified statistics and dimensions. You should always use these methods to read stats.

var totalFem = PC.get("fem");
var totalLegFem = PC.getDim("legFem");

You can get body parts at specific locations.

var rightHand = PC.getPartInLocation("right hand");

// you can also search for parts of other part groups (decorations, face)
var rightHandDecoration = PC.getPartInLocation("right hand", PC.decorativeParts);

You can add or remove body parts.

// create the body parts
var rightLegFur = da.Part.create(da.LegFur, {
    side: "right",
});
var rightLeg = da.Part.create(da.LegHuman,
        {
            side: "right",
            stroke: da.brownFur.stroke,
            fill: da.brownFur.fill
        });
var myHoof = da.Part.create(da.HoofHorse,
        {
            side: "right",
            stroke: "black",
            fill: "#392613"
        });

// replace any body parts in those loctions
var replacedPart = PC.attachPart(myHoof);
PC.attachPart(rightLeg);

// fur is a decorative part and should live in the decorativeParts
PC.attachPart(rightLegFur, PC.decorativeParts);


// chop off their hand and we'll show a stump
PC.removePart("left hand");

// also removes their right hand
PC.removePart("right arm");

// chop off their entire leg (which will remove their feet as well)
// also will remove any decorative parts linked to these parts
PC.removePart("right leg");

// remember to redraw after modifying the player
da.draw(canvasGroup, PC);

Adding expressions

You can also apply facial expressions to the avatars. There are a number of these predefined in src/player/expression.js that you can try in the tester under More Customizations > Body > Facial Expression

Each expression is a set of modifiers. You can adjust how intense the expression is.

PC.applyExpression(da.Expression.create(da.Expression.happy, 1));

Clothing

All clothes is defined under da. The system is made up of Clothing objects, which hold clothing state, and ClothingPart objects that do the drawing and hold no state. You shouldn't have to deal with ClothingPart unless you're creating your own clothing templates.

Creating a piece of clothing involves instantiating a template with some overrides.

// sheerFabric is a predfined styling object
var sheerBra = da.Clothes.create(da.Bra, da.sheerFabric);

// you can just as easily override with an object of your own
var blackBra = da.Clothes.create(da.Bra, {stroke:"black", fill:"rgb(20,20,20)"});

// Clothing often have other properties that you can modify as you create it
var thickStrappedBra = da.Clothes.create(da.Bra, {strapWidth: 3});

Getting, wearing, and removing clothing are all pretty straightforward. When you wear a piece of clothing, any other clothing occupying shared parts will be removed if possible and returned (see reference for API).

// get an array of all clothing in this location
var chestWear = PC.getClothingInLocation("chest");

// remove everything here
chestWear.forEach(function (clothing) {
    PC.removeClothing(clothing);
});

// wear something else
PC.wearClothing(sheerBra);

Coloring and Patterns

You can select the fill and stroke for all assets (clothing and body parts). Some templates also allow additional colouring options. Each coloring option can either a normal colour with transparency specified by a string be any CSS compliant color string, such as "rgba(100, 23, 2, 0.5)", "black", "hsl(300, 25%, 23%)", or a function taking a contxt and the drawing exports and returning a CSS compliant color string.

You could instead use a pattern/texture in place of a flat colour. See below for an example of getting a pattern and creating a pattern.

// create the pattern so we know what we mean when we say "black leather"
da.addPattern("black leather", "http://www.textures123.com/free-texture/leather/leather-texture05.jpg");

// use pattern instead of flat colour for colouring
var myPants = da.Clothes.create(da.TightShorts,
    {
    // specify size to adjust how zoomed in the pattern is
    fill      : da.getPattern("black leather", 50),
    // we're using default stroke here, but it could also be a pattern
    });

You can also create gradient patterns or other functions taking in ctx and/or ex. See patterns post for more info.

da.addPattern("washed jeans", function (ctx) {
    var grd = ctx.createLinearGradient(0, 0, 100, 0);
    grd.addColorStop(0, "rgb(0,68,110)");
    grd.addColorStop(0.2, "rgb(0,110,160)");
    grd.addColorStop(0.5, "rgb(0,75,140)");
    grd.addColorStop(0.8, "rgb(0,110,160)");
    grd.addColorStop(1, "rgb(0,68,110)");
    return grd;
});

Examples and How-To

Look at the example code in test.html where there are lots of commented out code with comments explaining what they do if you uncommented them. The following is a list of links to tutorials on achieving a specific thing

Debugging

The generated source map doesn't seem to play well when you bundle the code together with story Javascript with tweego. You can resolve this by turning off devtool : 'inline-module-source-map' in webpack.config.js.