Asphalt

repository·main·Indexed 41 days ago

https://github.com/jacktabscode/asphalt

A command-line tool for uploading assets (images, audio, video, models, and animations) to Roblox and automatically generating Luau or TypeScript code to reference them. Version 2.0.2 supports syncing to cloud, studio, or debug targets, alpha bleeding for images, and lockfile management via asphalt.toml.

Tokens
6.7K
Snippets
24
Records
34
Agent score
49%

What's inside Asphalt

  1. Handle generated code in linters and formatters

    main

    Asphalt does not guarantee the formatting (spaces, tabs, width, semicolons) of its generated code. To prevent linting or formatting errors, add the generated output directories to your tool's ignore list.

    Common tools:

    • Stylua (use glob filtering)
    • Biome (configure via biome.json)
    • ESLint (configure via .eslintignore)
  2. Authenticate Asphalt with Roblox API

    main

    To upload assets, you must provide a Roblox API key. You can provide it via the --api-key CLI argument or the ASPHALT_API_KEY environment variable.

    Requirements:

    1. Obtain a key from the Roblox Creator Dashboard.
    2. Ensure the key has asset:read and asset:write permissions.
    3. Ensure the key is associated with the Creator (user or group) defined in your asphalt.toml.
    4. Select an appropriate IP for the key.
  3. Install Asphalt

    main

    Asphalt can be installed using several different package managers depending on your environment:

    • Mise: mise use ubi:jacktabscode/asphalt
    • Cargo (build from source): cargo install asphalt
    • Pesde: pesde add --dev pesde/asphalt --target lune
    • Rokit: rokit add jacktabscode/asphalt
    • Homebrew (macOS/Linux): brew tap jacktabscode/tap followed by brew install asphalt

    Note: Asphalt cannot be installed with Foreman.

    # Using Mise
    mise use ubi:jacktabscode/asphalt
    
    # Using Cargo
    cargo install asphalt
    
    # Using Pesde
    pesde add --dev pesde/asphalt --target lune
    
    # Using Rokit
    rokit add jacktabscode/asphalt
    
    # Using Homebrew
    brew tap jacktabscode/tap
    brew install asphalt
  4. Test asset uploads without network calls

    main

    If you want to test the upload logic without actually hitting the Roblox APIs, you can set the ASPHALT_TEST environment variable. When this variable is present, WebApiClient::upload will skip the network request and return the asset's hash as a u64 instead.

    ASPHALT_TEST=1 cargo test
  5. Configure Asphalt with asphalt.toml

    main

    Asphalt requires a asphalt.toml file in your project root. This file defines the Roblox creator, code generation settings, and asset inputs.

    Configuration Schema

    creator

    Defines the Roblox identity for uploads.

    • type: Either "user" or "group".
    • id: The numeric Roblox ID.

    codegen (optional)

    Controls how Luau or TypeScript files are generated.

    • typescript: (boolean) If true, generates TypeScript definitions.
    • style: "flat" (default) or "nested". Use "flat" to index assets like paths. Use "nested" for Luau projects since it doesn't support template literal types.
    • strip_extensions: (boolean) Whether to remove file extensions from generated names. Defaults to false.
    • content: (boolean) If true, outputs Content types instead of strings. Defaults to false.

    inputs

    A map of input names to configurations.

    • path: A glob pattern matching files to upload.
    • output_path: The directory where generated code is placed.
    • output_basename: The filename for generated files (defaults to input name).
    • web: A map of relative paths to existing Roblox assets (e.g., "filename.png" = { id = 12345 }). This allows you to define assets already on Roblox so they are referenced in code without re-uploading.
    • bleed: (boolean) Whether to alpha bleed images. Defaults to true. Note: changing this does not invalidate the lockfile or trigger re-uploads.
    #:schema https://raw.githubusercontent.com/jackTabsCode/asphalt/refs/heads/main/schema.json
    
    [creator]
    type = "user"
    id = 9670971
    
    [codegen]
    typescript = true
    style = "flat"
    
    [inputs.assets]
    path = "assets/**/*"
    output_path = "src/shared"
    
    [inputs.assets.web]
    "some_sound_on_roblox.ogg" = { id = 123456789 }
    "some_image_on_roblox.png" = { id = 987654321 }
  6. How the Studio backend handles asset syncing

    main

    The Studio backend is used to sync assets directly into the Roblox Studio content directory.

    Sync Behavior by Asset Type

    • Models and Animations: These asset types cannot be synced directly to Studio via this backend unless they have already been uploaded to the cloud. If a LockfileEntry containing an asset_id is present, the backend returns a AssetRef::Cloud reference. If no entry is found, it warns that the asset must be uploaded first.
    • Other Assets: For other asset types, the backend writes the asset data to a path within a specific identifier directory inside the Roblox Studio content folder. The path is derived from the asset's hash and extension.

    Identifier Generation

    The backend creates a hidden directory within the Studio content path using the format .asphalt-<project-name>, where <project-name> is a lowercase, hyphenated version of your current working directory's name.

  7. How the `asphalt sync` command works

    main

    The asphalt sync command synchronizes project assets to a target backend (Cloud, Debug, or Studio). The process follows these steps:

    1. Configuration & Lockfile Loading: Reads the project configuration and the existing lockfile to determine which assets are already tracked.
    2. Asset Discovery: Walks the project input directories to discover assets.
    3. Synchronization: For each asset, it checks the backend. If an asset is new or changed, it is synced to the target.
    4. Dry Run Mode: If running with SyncTarget::Cloud { dry_run: true }, the process identifies what would be synced without performing any uploads. If any new assets are detected, the command fails with an error to prevent accidental uploads.
    5. Lockfile Update: If the target allows writing (e.g., not a dry run), the lockfile is updated with the new asset states.
    6. Code Generation: After synchronization, Asphalt generates type definitions (Luau and optionally TypeScript) based on the synced assets to ensure type safety in your project code.

    Error Handling:

    • If any assets fail to sync, the command returns an error: Some assets failed to sync.
    • In dry run mode, if new assets are found, it returns: Dry run: {} new assets would be synced (where {} is the count).
  8. The Asphalt lockfile format

    main

    Asphalt uses a lockfile named asphalt.lock.toml to track uploaded assets and their associated asset_ids. This file is automatically generated and is not intended for manual editing.

    Structure

    The current version (v2) organizes assets by an input_name and a content Hash. This allows the tool to map specific file contents to their corresponding remote asset IDs.

    Migration

    If you encounter errors stating your lockfile is out of date, you must migrate it to the latest version using the asphalt migrate-lockfile command. The tool supports migrating from older versions (v0 and v1) to the current v2 format.

    # This file is automatically @generated by Asphalt.
    # It is not intended for manual editing.
    
    [inputs.input_name.hash]
    asset_id = 12345
  9. AssetRef: Cloud and Studio identifiers

    main

    The AssetRef enum represents how an asset is referenced in the Roblox ecosystem. It can be converted to a string representation for use in code or configuration.

    • AssetRef::Cloud(u64): Represents a cloud-hosted asset, formatted as rbxassetid://<id>.
    • AssetRef::Studio(String): Represents a studio-local asset, formatted as rbxasset://<name>.
    // Display implementations:
    // AssetRef::Cloud(12345) -> "rbxassetid://12345"
    // AssetRef::Studio("MyModel".to_string()) -> "rbxasset://MyModel"
  10. Syncing assets with `asphalt sync`

    main

    The asphalt sync command is the primary entry point for synchronizing assets. It uses SyncArgs to define the target and credentials.

    Target Backends

    • Cloud: Uploads assets to the cloud service. Supports a dry_run mode to preview changes.
    • Debug: Used for local debugging workflows.
    • Studio: Targets the Studio environment.

    Code Generation

    Asphalt automatically generates code for your assets. By default, it generates Luau files. If your configuration has codegen.typescript enabled, it will also generate TypeScript (.d.ts) files. These are written to the output_path defined in your project configuration.

  11. Configure the Creator settings

    main

    The creator section defines the Roblox identity under which assets will be uploaded. It requires a type and an id.

    • type: Must be either user (for a personal Roblox account) or group (for a Roblox Community). Use snake_case in the TOML file.
    • id: The numeric Roblox Creator ID.
    [creator]
    type = "group" # or "user"
    id = 12345678
  12. Configure Codegen settings

    main

    The codegen section (optional) controls how the generated code and type definitions are structured. If omitted, it uses default values.

    • style: The structural pattern of the generated code. Options are flat (default) or nested.
    • typescript: Boolean. If true, a TypeScript definition file is generated.
    • strip_extensions: Boolean. If true, file extensions are removed from the generated asset keys.
    • content: Boolean. If true, the generated code uses a Content data type instead of raw strings.
    [codegen]
    style = "nested"
    typescript = true
    strip_extensions = false
    content = true