Unique Schema

Unique schema is a schema where all links and metadata are stored on-chain. It allows for flexible data and attribute storage with separate access settings for every NFT field. This enables, for example, the creation of live NFTs where some parts of the NFT can be securely changed with guarantees from the blockchain that other parts won't be changed.

NFTs created previously in schemaVersion 1.0.0 are returned in the new format.

Examples how to create collections NFTs 2.0.0

  • Schema 2.0.0

This metadata standard describes the data structure used to describe NFTs in JSON format. Example NFT 2.0.0open in new window The main interface that describes the metadata for a NFT.

schemaName string

The name of the schema used for the metadata. When creating new NFTs, this should be 'unique'. This property defines the specific set of rules and attributes that the NFT adheres to. For older NFTs, created before the implementation of the 'unique' schema, the schemaName might have values such as "old" or "ERC721Metadata". This ensures backward compatibility and helps in identifying the origin and structure of the metadata associated with the NFT.

schemaVersion: string

  • You need it: To ensure your NFT metadata is compatible with the current standards and features of the Unique Network.
  • Code example: "schemaVersion": "2.0.0"
  • Tips and best practices: Always check for the latest version before creating your NFTs to ensure compatibility and access to new features.

originalSchemaVersion: string

The original version of the schema. This property indicates the schema under which the NFT was initially created.

name: string

  • You need it: To provide a unique and identifiable title for your NFT.
  • Simplest use case: Naming a basic digital artwork.
  • Code example: "name": "Sunset Painting"
  • More advanced use case: Naming NFTs in a series where each name follows a pattern or storyline.
  • Code example: "name": "Mystic Forest: Chapter 1 - The Awakening"
  • Tips and best practices: Choose names that are memorable and descriptive of the NFT's content or theme. Avoid overly generic names.

description: string

  • You need it: To provide a narrative or context about the NFT, enhancing its appeal and storytelling.
  • Simplest use case: Describing a standalone digital artwork.
  • Code example: "description": "A beautiful landscape painting depicting a serene sunset."
  • More advanced use case: Story-driven collections where each NFT's description adds to an overarching narrative.
  • Code example: "description": "In the heart of the Mystic Forest, the Abyssal Dragon awakens, bringing ancient magic back to the land."
  • Tips and best practices: Keep the description engaging and relevant to the NFT.

image: string

URL to the main image associated with the NFT.

  • Avail: jpeg, jpg, gif, png.
  • You need it: To visually represent your NFT. It's the primary image that users see in the interfaces of wallets, marketplaces, and other applications.
  • Simplest use case: A single image representing a digital artwork.
  • Code example: "image": "https://example.com/artwork.jpg"
  • More advanced use case: NFTs where the image is a composite or dynamically generated based on certain criteria.
  • Code example: "image": "https://example.com/generate?params=dynamic"
  • Tips and best practices: Use high-quality images that are appropriately sized. Ensure the image URL is reliable and persistent.

image_details: ImageDetails

Additional details about the main image.

  • You need it if you want: To provide the applications with specific details about the primary image, like its format, dimensions, and file size.
  • Simplest use case: Providing basic information about a static artwork image.
  • Code example: { "format": "jpg", "width": 1920, "height": 1080, "bytes": 204800 }
  • More advanced use case: Secure the source image changes by using a sha256 image hash.
  • Code example: { "format": "png", "width": 960, "height": 720, "bytes": 512000, "type": "image", "sha256": "..." }
  • Tips and best practices: Provide accurate and detailed information. This aids in ensuring that images are displayed correctly across various platforms and devices.

An interface describing additional details about an image.

interface ImageDetails {
    name?: string;
    type?: 'image' | 'animation' | 'video' | 'audio' | 'spatial' | 'pdf' | 'document' | 'other';
    bytes?: number;
    format?: string;
    sha256?: string;
    width?: number;
    height?: number;
    order?: number;
}

attributes: Attribute[]

Array of attributes associated with the NFT.

  • You need it if you want: To provide additional information about the NFT in the form of key-value pairs, like color, size, or unique traits.
  • Simplest use case: Basic traits for a digital artwork, like color and theme.
  • Code example: [ { "trait_type": "Color", "value": "Blue" }, { "trait_type": "Theme", "value": "Ocean" } ]
  • More advanced use case: Detailed attributes for collectible items, each with a set of distinct traits.
  • Code example: [ { "trait_type": "Strength", "value": 10 }, { "trait_type": "Magic", "value": 7 }, { "trait_type": "Agility", "value": 5 } ]
  • Tips and best practices: Choose attributes that add value and interest to the NFT. Avoid overloading with irrelevant details.
interface Attribute {
    /** @example Color */
    trait_type: string;
    /** @example red */
    value: string | number;
    /** @example color */
    display_type?: string;
}

media: Record<string, Media>

The media property is a dictionary that allows the storage of multiple media elements associated with the NFT. Each media element is represented by a key-value pair, where the key is a string identifier and the value is an instance of the Media interface. This type of storage enables the specification of a clear order and priority for media files during loading.

An interface describing media content associated with the NFT.

interface Media {
    type: 'image' | 'animation' | 'video' | 'audio' | 'spatial' | 'pdf' | 'document' | 'other';
    url: string;
    name?: string;
    details?: MediaDetails;
    thumbnail?: ImageWithDetailsAndThumbnail;
    poster?: ImageWithDetailsAndThumbnail;
}

interface ImageWithDetails {
    url: string;
    details?: ImageDetails;
}

interface ImageWithDetailsAndThumbnail {
    url: string;
    details?: ImageDetails;
    thumbnail?: ImageWithDetails;
}

For instance, when incorporating media elements into the media property, you can use keys in the format media_{N}, where N is a numerical value representing the order or priority of the media file. Here's how this convention can be employed:

{
    // other NFT properties...
    media: {
        "media_1": {
            type: "image",
            url: "https://example.com/first_image.png",
            // additional media details...
        },
        "media_2": {
            type: "video",
            url: "https://example.com/second_video.mp4",
            // additional media details...
        },
        // additional media elements...
    }
}

Media Formats and Best Practices

To ensure optimal compatibility and performance, it's important to adhere to certain best practices and formats when specifying media elements for NFTs.

Image

  • Formats: JPEG, PNG, GIF, SVG, WebP
  • Best Practices: Use high-resolution images with appropriate compression to balance quality and file size. Provide alternative text descriptions for accessibility.

Animation

  • Formats: GIF, SVG, APNG, WebP
  • Best Practices: Use lightweight formats for animations to ensure quick loading times. Optimize frame rates to reduce file sizes without compromising quality.

Video

  • Formats: MP4, WebM
  • Best Practices: Use H.264 encoding for MP4 files for broad compatibility. Include a poster image to be displayed before the video loads. Ensure videos are not excessively long or large in file size.

Audio

  • Formats: MP3, WAV
  • Best Practices: Use MP3 for compatibility and smaller file sizes. Ensure the audio quality is high enough to avoid distortion but optimized for size.

Spatial

  • Formats: GLTF, GLB, USDZ
  • Best Practices: Use compressed 3D models to reduce loading times. Provide low-poly versions if possible for performance on less powerful devices.

PDF/Document

  • Formats: PDF
  • Best Practices: Ensure documents are optimized for web viewing. Include metadata within the PDF for accessibility and searchability.

Other

  • Formats: Depends on the content type.
  • Best Practices: Clearly define the content type and ensure it is supported by the platforms where the NFT will be viewed or interacted with.

animation_url: string

A URL to a multi-media attachment for the item. The file extensions GLTF, GLB, WEBM, MP4, M4V, OGV, and OGG are supported, along with the audio-only extensions MP3, WAV, and OGA.

Animation_url also supports HTML pages, allowing you to build rich experiences and interactive NFTs using JavaScript canvas, WebGL, and more. Scripts and relative paths within the HTML page are now supported. However, access to browser extensions is not supported

animation_details: MediaDetails

Additional details about the animation.

interface MediaDetails {
    name?: string;
    type?: 'image' | 'animation' | 'video' | 'audio' | 'spatial' | 'pdf' | 'document' | 'other';
    bytes?: number;
    format?: string;
    sha256?: string;
    width?: number;
    height?: number;
    order?: number;
    duration?: number;
    codecs?: string[];
    loop?: boolean;
}

youtube_url: string

URL to a YouTube video associated with the NFT.

created_by: string

Address of the creator of the NFT.

external_url: string

URL to an external resource providing more information about the NFT. It will appear below the asset's image and will allow users to leave Unique Marketplace and view the item on your site.

customizing: Customizing

Customizing options for the NFT.

  • You need it if you want: To allow users to visually enhance and modify base NFTs by equipping other NFTs, creating dynamic and interactive digital assets.

  • Use case: The process involves two types of collections:

    • Base Collection: This is the primary collection.
    • Equip Collections: These collections (one or more) are designed to interact with and modify the Base Collection.

    There are endless options for how Equip NFTs can customize a Base NFT:

    • Overlay Placement for the images: Placing the equip image over a specific part of the base image while:
      • Layering: Ordering and reordering layers.
      • Precise Placement: Placing at the desired point or area (Offset).
      • Scaling: Adjusting the size of both Base and Equip NFTs.
      • Rotation: Rotating both Base and Equip NFTs.
      • Opacity Adjustment: Adjusting the transparency of both Base and Equip NFTs.
    • Customizable Backgrounds: Setting specific backgrounds for the NFTs.
    • Pattern or Texture Application: Applying various patterns or textures.
    • Morphing or Transformation: Changing the shape or form of the images and other media types. Examples include:
      • Changing the character's hairstyle.
      • Morphing facial features.
      • Slowing the audio.
    • Audio/Video/3D Integration: Adding multimedia elements to images and other media types. Examples include:
      • Jingle sound with jewelry.
      • Theme music with a heroic cape.
      • Mixing audio tracks.
      • Adding subtitles to videos.
  • Tips and best practices: When using equip collections to enhance base NFTs, consider how each modification adds value and interest. Ensure that modifications are meaningful and enhance the overall user experience without overwhelming the base NFT.

Interfaces for customizing:

interface Customizing {
    self: CustomizingFileInfo;
    slots?: CustomizingSlot[];
    /** @example ["mutator1","mutator2"] */
    mutators?: any[][];
    mutator_reactions?: MutatorReaction[];
}

interface CustomizingFileInfo {
    type: 'image' | 'animation' | 'video' | 'audio' | 'spatial' | 'pdf' | 'document' | 'other';
    url: string;
    name?: string;
    details?: MediaDetails;
    image_overlay_specs?: CustomizingImageOverlaySpecs;
    placeholder?: ImageWithDetails;
    tag?: string;
}

interface CustomizingSlot {
    type: 'image' | 'animation' | 'video' | 'audio' | 'spatial' | 'pdf' | 'document' | 'other';
    collections?: (string | number)[];
    name?: string;
    image_overlay_specs?: CustomizingImageOverlaySpecs;
}

interface MutatorReaction {
    /** @example 1 */
    layer?: number;
    /** @example 1 */
    order_in_layer?: number;
    offset?: Coordinates;
    opacity?: number;
    rotation?: number;
    scale?: Scale;
    mount_point?: Coordinates;
    parent_mount_point?: Coordinates;
    url: string;
    details?: ImageDetails;
}

interface Coordinates {
    x: number;
    y: number;
}

interface Scale {
    x: number;
    y: number;
    unit?: 'px' | '%';
}

interface CustomizingImageOverlaySpecs {
    /** @example 1 */
    layer?: number;
    /** @example 1 */
    order_in_layer?: number;
    offset?: Coordinates;
    opacity?: number;
    rotation?: number;
    scale?: Scale;
    mount_point?: Coordinates;
    parent_mount_point?: Coordinates;
}

customizing_overrides: CustomizingOverrides

Overrides for customizing options.

interface CustomizingOverrides {
    self?: CustomizingFileInfo;
    slots?: CustomizingSlot[];
    mutators?: string[];
    mutator_reactions?: MutatorReaction[];
}

background_color: string

Background color of the NFT. Must be a six-character hexadecimal without a pre-pended #.

royalties: Royalty[]

Array of royalty information associated with the NFT.

  • You need it if you want: To define how creators or other stakeholders will receive a percentage of sales from secondary market sales of the particular NFT.
  • Simplest use case: A single creator receiving royalties.
  • Code example: [ { "address": "0x1234...", "percent": 5 } ]
  • More advanced use case: Splitting royalties between multiple parties, such as the artist, a charity, and a collaborator.
  • Code example: [ { "address": "0x1234...", "percent": 3 }, { "address": "0x5678...", "percent": 2 } ]
  • Most advanced use case: Using a smart contract address to achieve more complicated distribution models.
  • Code example: [ { "address": "0x1234..." } ]
  • Tips and best practices: Clearly define royalty percentages and ensure they are fair. Keep the royalty structure transparent to buyers and other stakeholders. An interface representing royalty information associated with the NFT.
interface Royalty {
    /**
     * The ss-58 encoded or Ethereum address
     * @example yGCyN3eydMkze4EPtz59Tn7obwbUbYNZCz48dp8FRdemTaLwm
     */
    address: string;
    /** @example 5 */
    percent?: number;
    isPrimaryOnly?: boolean;
}

locale: string (Optional)

  • You need it if you want: To tailor your NFT's language setting to specific regional or linguistic audiences, enhancing accessibility and user experience.
  • Simplest use case: A collection primarily targeting a specific language-speaking audience.
  • Code Example: {"locale": "en" }

collectionId: number

The ID of the collection to which the NFT belongs.

tokenId: number

The ID of the NFT.

owner: string

SS-58 encoded address of the owner of the NFT.

parsingError: string | null

Error message if there was a parsing error, otherwise null.

properties: PropertyWithHexValue[]

Array of properties with their hexadecimal values. Used for internal purposes and ensuring backward compatibility for tokens created under schema version 1.0.0. Generated automatically when creating a token based on the provided schemaName, schemaVersion, and attributes.

interface PropertyWithHexValue {
    key: string;
    value: string;
    /** @example 0x01 */
    valueHex: string;
}

nestingParentToken: NestingParentId

ID of the parent token in nesting.

interface NestingParentId {
    collectionId: number;
    tokenId: number;
}