Asset Layer Docs
Asset LayerAPI Docs
  • 👋Welcome
  • Getting Started
    • Quick Start
      • Quick Start for Developers
      • Quick Start for Creators
      • Quick Start for Unity
    • Core Concepts
      • Users
      • Auth + Permissions
      • Teams
      • Apps
      • Slots
      • Expressions
      • Assets + Collections
      • Currencies
      • Marketplace and Shops
      • Core Concepts in Action
    • SDK Docs
      • Setup
      • Users
        • getUser()
      • Apps
        • info()
        • getApp()
        • getApps()
        • slots()
        • getAppSlots()
        • getAppSlotIds()
      • Slots
        • getSlot()
        • collections()
        • getSlotCollections()
        • getSlotCollectionIds()
        • getSlotExpressions()
        • createExpression()
        • updateExpression()
        • getExpressionTypes()
      • Collections
        • info()
        • getCollection()
        • getCollections()
        • assets()
        • getCollectionAssets()
        • getCollectionAssetIds()
        • createCollection()
        • updateCollection()
        • updateCollectionImage()
        • activateCollection()
        • deactivateCollection()
      • Assets
        • info()
        • getAsset()
        • getAssets()
        • user()
        • getUserAssets()
        • getUserAssetIds()
        • getUserAssetCounts()
        • getUserCollectionAssets()
        • getUserCollectionsAssets()
        • getUserSlotAssets()
        • getUserSlotsAssets()
        • mintAssets()
        • send()
        • sendAsset()
        • sendAssets()
        • sendCollectionAssets()
        • sendLowestAsset()
        • sendRandomAsset()
        • update()
        • updateAsset()
        • updateAssets()
        • updateCollectionAssets()
        • expressionValues()
        • updateAssetExpressionValue()
        • updateAssetsExpressionValue()
        • updateCollectionAssetsExpressionValue()
        • updateBulkExpressionValues()
      • Equips
        • getEquips()
        • setEquip()
        • removeEquip()
      • Currencies
        • info()
        • getCurrency()
        • balance()
        • getCurrencyBalance()
        • getCurrencySummary()
        • increaseCurrencyBalance()
        • decreaseCurrencyBalance()
        • transferCurrency()
      • Listings
        • getListing()
        • user()
        • getUserListings()
        • getUserListingsCounts()
        • getUserCollectionListings()
        • getUserCollectionListingsCounts()
        • getUserSales()
        • getUserSalesCounts()
        • getUserPurchases()
        • getUserPurchasesCounts()
        • collection()
        • getCollectionListings()
        • getCollectionsListings()
        • getCollectionListingsCounts()
        • getCollectionsListingsCounts()
        • getCollectionListingsStats()
        • getCollectionsListingsStats()
        • app()
        • getAppListings()
        • getAppListingsCounts()
        • getAppListingsStats()
        • new()
        • listAsset()
        • listAssets()
        • listCollectionAssets()
        • updateListing()
        • buyListing()
        • removeListing()
      • Shop
        • buyItem()
        • summary()
      • Core Types
        • User
        • App
        • Slot
        • Expression
        • Collection
        • Asset
        • Equip
        • Currency
        • Listing
        • Shop
        • Basic
      • SDK Repo
      • C# SDK for Unity
    • Guides
      • How to Integrate Asset Layer into your Unity Game
    • API Docs
    • Asset Layer GPT
  • Build an app
    • App Setup
      • Creating an App
      • Managing Apps
      • App Info
      • Manage Permissions
      • Manage Slots
      • Manage Collections
      • Manage Currencies
      • App Settings
    • App Development
    • Build With Unity
      • Unity App Setup
      • Advanced Unity Setup
        • WebGL App Setup
      • Asset Layer Unity SDK
        • Login + Authentication
        • Create Assets in Unity
        • Import Assets Into Your Scene
        • Inventory Manager
        • Sync Your Assets
        • Asset Layer Game Server
        • C# SDK
    • Sample App
      • Getting Started With Sample App Locally
      • Environment Variables
      • API Routes
      • Deployment
      • Default Pages
      • Deploying Your Unity WebGL Game Through Sample App
  • Create and Manage Assets
    • Create Assets With Code
    • Create Assets Without Code
      • Create Assets for My App
      • Submit a Collection for a 3rd Party App
      • Create an Independent Collection - Coming Soon!
    • Create Assets in Unity
    • Managing Collections from 3rd Party Creators
  • Manage Assets
    • My Assets
      • Listing Assets for Sale
      • Sending Assets as a Gift
      • My Listings
      • Marketplace History
    • Marketplace
  • Settings
    • Team Settings
    • Account Settings
    • Pricing
  • Details
    • Expression Types
      • Image
      • Audio
      • Video
      • Unity
      • Spine 4.0 (2D Animated Characters)
      • Additional Expression Types
Powered by GitBook
On this page
  • 2D Animated Character
  • Spine
  • Create Your Own Animated Character
  1. Details
  2. Expression Types

Spine 4.0 (2D Animated Characters)

PreviousUnityNextAdditional Expression Types

Last updated 1 year ago

This page contains the expression type description for Spine 4.0 as well as information about how we've used Spine 4.0 to create our flagship game .

2D Animated Character

Spine

The Duro Dog characters were created using the animation engine Spine. It is an animation tool that focuses specifically on 2D animation for games. Animation in Spine is done by attaching images to bones, then animating the bones. This is called skeletal or cutout animation and has numerous benefits over traditional, frame-by-frame animation. You can read about it here .

The Sample App provides an example of how to render 2D Spine animations in React. The code that renders a Duro Dog can be found in the Sample App at: /src/components/PixiNFT.js. The two main libraries used to render the dogs are pixi.js & pixi-spine.js.

Spine Expression Type

The Spine expression type includes the following expression attributes:

  • .json

  • .png

  • .atlas

All three of these attribute values (file locations in this case) are required to render a dog in Spine.

Getting The Expression Values

We get the expression values for each dog (NFT) with the following API Route: /pages/api/collection/nfts with "collectionId": "638665d8506da1c31926beef" as the input parameter. This API Route is calling the Asset Layer API with the following: You can also make calls directly to the API by using Postman.

GET https://api.assetlayer.com/api/v1/collection/nfts

The API response for the Duro Dog collection and Duro Dog serial number '0' will look like this:

"statusCode": 200,
    "success": true,
    "body": {
        "collection": {
            "collectionId": "638665d8506da1c31926beef",
            "collectionName": "Duro Dog",
            "collectionImage": "https://www.durodogs.com/static/home/logos/logo1_light.png",
            "slotId": "633b31a709d1ac7280c50dfc",
            "maximum": 10000000000,
            "minted": 1030000,
            "type": "Unique",
            "createdAt": 1669752280444,
            "updatedAt": 1670949060750,
            "nfts": [
                {
                    "expressionValues": [
                        {
                            "value": "https://asset-api-files-bucket.s3.amazonaws.com/487b8e2c-9cff-4e94-aca8-7b25896e96c7.atlas",
                            "expressionValueId": "6397fb6306ea8bc8c4bd3140",
                            "expressionAttribute": {
                                "expressionAttributeName": "Atlas",
                                "expressionAttributeId": "6340b0caa2b2f44da248211e"
                            },
                            "expression": {
                                "expressionName": "Front View",
                                "expressionId": "6340b22b0fd33e9fd518af70"
                            }
                        },
                        {
                            "value": "https://asset-api-files-bucket.s3.amazonaws.com/0f79c80e-c199-4e25-b2b3-5a44508e9cf6.atlas",
                            "expressionValueId": "6397fb6506ea8bc8c4bd3205",
                            "expressionAttribute": {
                                "expressionAttributeName": "Atlas",
                                "expressionAttributeId": "6340b0caa2b2f44da248211e"
                            },
                            "expression": {
                                "expressionName": "Three Quarter View",
                                "expressionId": "6340b21f0fd33e538d18af67"
                            }
                        },
                        {
                            "value": "https://asset-api-files-bucket.s3.amazonaws.com/0c8d3e6a-beba-442e-bb90-3789e79b627b.png",
                            "expressionValueId": "6397fb6606ea8bc8c4bd3289",
                            "expressionAttribute": {
                                "expressionAttributeName": "PNG",
                                "expressionAttributeId": "6340b0d1a2b2f44da248211f"
                            },
                            "expression": {
                                "expressionName": "Three Quarter View",
                                "expressionId": "6340b21f0fd33e538d18af67"
                            }
                        },
                        {
                            "value": "https://asset-api-files-bucket.s3.amazonaws.com/e75e0cdb-54b6-43a8-a879-b6636a7c819f.png",
                            "expressionValueId": "6397fb6606ea8bc8c4bd32a5",
                            "expressionAttribute": {
                                "expressionAttributeName": "Image",
                                "expressionAttributeId": "62f83b2482081d6f89953fa7"
                            },
                            "expression": {
                                "expressionName": "Menu View",
                                "expressionId": "6340abde0fd33e330f18af38"
                            }
                        },
                        {
                            "value": "https://asset-api-files-bucket.s3.amazonaws.com/f258c125-0de1-40a5-a3d7-104e4537252a.png",
                            "expressionValueId": "6397fb6606ea8bc8c4bd32bb",
                            "expressionAttribute": {
                                "expressionAttributeName": "PNG",
                                "expressionAttributeId": "6340b0d1a2b2f44da248211f"
                            },
                            "expression": {
                                "expressionName": "Front View",
                                "expressionId": "6340b22b0fd33e9fd518af70"
                            }
                        },
                        {
                            "value": "https://asset-api-files-bucket.s3.amazonaws.com/72dc2111-2e03-4204-bdac-66f5111f429b.json",
                            "expressionValueId": "6397fb6706ea8bc8c4bd32d4",
                            "expressionAttribute": {
                                "expressionAttributeName": "JSON",
                                "expressionAttributeId": "6340b0bfa2b2f44da248211d"
                            },
                            "expression": {
                                "expressionName": "Three Quarter View",
                                "expressionId": "6340b21f0fd33e538d18af67"
                            }
                        },
                        {
                            "value": "https://asset-api-files-bucket.s3.amazonaws.com/69da4d4a-6ac2-4016-90d0-da1cf6ad1bf4.json",
                            "expressionValueId": "6397fb6706ea8bc8c4bd32fa",
                            "expressionAttribute": {
                                "expressionAttributeName": "JSON",
                                "expressionAttributeId": "6340b0bfa2b2f44da248211d"
                            },
                            "expression": {
                                "expressionName": "Front View",
                                "expressionId": "6340b22b0fd33e9fd518af70"
                            }
                        }
                    ],
                    "location": "a198b520bdb2adff4b3ac57aec2ac08d7fb9dd732b4bedfef54e697325f829d8_o2",
                    "serial": 0,
                    "properties": {
                        "633b30ca09d1acacd0c50df4": {
                            "rarities": {
                                "fur": {
                                    "rarity": "Common",
                                    "color": "443F3F",
                                    "secondaryColor": "FFFFFF"
                                },
                                "eyes": {
                                    "rarity": "Common",
                                    "type": 0,
                                    "color": "7D4402"
                                },
                                "nose": {
                                    "rarity": "Common",
                                    "type": 2,
                                    "color": "77787B"
                                },
                                "head": {
                                    "rarity": "Normal",
                                    "type": 4,
                                    "spots": false
                                },
                                "tail": {
                                    "rarity": "Normal",
                                    "type": 4,
                                    "spots": false
                                },
                                "body": {
                                    "rarity": "Normal",
                                    "type": 4,
                                    "spots": false
                                },
                                "ears": {
                                    "rarity": "Normal",
                                    "type": 2
                                }
                            }
                        }
                    },
                    "nftId": "75641d9dcf78c4a40e16f283c3282cb6"
                },

NFT Expressions

Parsing Out Each Duro Dog

The following code parses out the expression attribute values which are received from the API.

function getExpressionValue(expressionValues, expressionName, expressionAttributeName, showAnimations) {
    return String(expressionValues?.find((expressionVal) => expressionVal?.expression?.expressionName === expressionName && expressionVal?.expressionAttribute?.expressionAttributeName === expressionAttributeName)?.value);
}

function parseNFT(nft, expression) {
    if (!nft) {
        return { parsedJson: null, parsedAtlas: null, parsedPng: null}
    }
    const parsedJson = getExpressionValue(nft.expressionValues || [], expression, 'JSON');
    const parsedAtlas = getExpressionValue(nft.expressionValues || [], expression, 'Atlas');
    const parsedImage = getExpressionValue(nft.expressionValues || [], expression, 'PNG');
    return { 
        parsedJson, 
        parsedAtlas,
        parsedImage, 
    };
}

useEffect(()=>{
        const { parsedJson, parsedAtlas, parsedImage } = parseNFT(assetlayerNFT, expression);
        if (parsedJson) {
            // setSpineJson('jsonNamehere.json'); // setting this do a local copy of any nfts, they are not nft specific, only the image is
            setSpineJson(parsedJson);  // using the parse Json from the nft.
        }
        if (parsedAtlas) {
            // setSpineAtlas('atlasNamehere.atlas');  // setting this do a local copy of any nfts, they are not nft specific, only the image is
            setSpineAtlas(parsedAtlas); // using the parse Atlas from the nft.
        }
        if (parsedImage) {
            setSpinePng(parsedImage); 
        }
    

}, [assetlayerNFT, expression])

Rendering Each Duro Dog

Each dog is then rendered using the following code:

function resourcesLoaded (loader, resources) {
        const nftSpine = new PIXISPINE.Spine(resources[(assetlayerNFT.nftId + expression)].spineData);
        if (nftSpine) {
            adjustSizeOfSpine(nftSpine);
            app.stage.addChild(nftSpine); 
            setAnimations(parseAnimations(nftSpine.spineData));
            setNftLoaded(true);
            setSpine(nftSpine);
            setCurrentAnimation(defaultAnimation);
        }
        }

    async function loadPixiNFT() {
        clearStage();
        const texture = await PIXI.Texture.fromURL(spinePng);
        let spineLoaderOptions = { metadata: { 
                    spineAtlasFile: spineAtlas,
                    image: texture }}; 
        // now load json skeleton
        if(!app.loader.resources[(assetlayerNFT.nftId + expression)]) {
            app.loader.add((assetlayerNFT.nftId + expression), spineJson , spineLoaderOptions);
            app.loader.load(resourcesLoaded);
        } else {
            resourcesLoaded(app.loader, app.loader.resources);
        }
    
  
    }

Create Your Own Animated Character

There will also be an area in the marketplace where Spine animators will be able to sell their own 2D character collections consisting of unique or common NFTs.

As you can see in the .json response above, each dog has 3 expressions: Front View, Three Quarter View, and Menu View. That's the power of the Asset Layer platform - one NFT can be expressed in multiple ways. Even though they both use the same NFTs, the game uses the Front View expression whereas the game uses the Three Quarter View. The Menu View is just a simple image of each NFT that is used in the Marketplace.

You can use the Duro Dog Spine output files in your app (by using Duro Dogs in your app as a foreign slot) or create your very own characters in Spine, and then upload the files using the No-code Tool. If you do not have the skills to create your own spine character & animations, then you can hire one of the talented animators here or here .

Duro Dogs
Spine
Duro Dogs
Ruff Runner
Fiverr
ArtStation