Game Development 22 min read

Technical Overview of SAR Creator for Interactive Scene Development

This article provides a comprehensive guide to SAR Creator, a TypeScript‑based interactive solution used for building 2D/3D game scenes, covering workflow, asset creation, canvas adaptation, bundle splitting, texture compression, script lifecycle, dynamic loading, and configuration for ByteDance's Spring Festival activities.

ByteFE
ByteFE
ByteFE
Technical Overview of SAR Creator for Interactive Scene Development

Introduction

During the Spring Festival activity, most scenes were created using the internal SAR Creator interactive solution.

SAR Creator is a high‑performance, lightweight interactive solution built on TypeScript. It currently supports Web and ByteDance’s internal cross‑platform framework and serves a variety of interactive business scenarios, including Douyin Spring Festival, Douyin live gifts, and Douyin UGC activities.

Workflow

The editor greatly improves development efficiency by decoupling design and development. Designers can collaborate on the online editor or deliver assets via Asset Packages, while developers can visually assemble scenes and configure assets, checking asset information directly.

Asset Production

Designers use the SAR Creator Launcher to manage multiple editor versions, create new projects, quickly start projects, and view update information.

After creating a project, designers can import resources from Photoshop, Blender, or Spine into SAR Creator, combine them into scenes, and export them as prefab assets for developers.

Animation Preview

Designers can import produced assets into SAR Creator for playback preview and adjustment, ensuring that the final animation resources meet expectations. Supported animation formats include Lottie, Spine, frame animation, model animation, composite animation, and frame‑difference animation.

Asset Export

Designers typically export prefabs. By right‑clicking a prefab and selecting "Export Asset Package," all dependent resources are packaged into a compressed asset bundle that can be sent to developers for import.

Feature Introduction

Canvas Adaptation

Canvas adaptation adjusts the visual output of interactive areas to fit different screen sizes and resolutions, ensuring consistent appearance across devices. Strategies include FixedWidth, FixedHeight, and Auto scaling.

2D & 3D Mixed Development

The editor allows simultaneous addition of 2D and 3D objects in the same scene, with control over hierarchy, render order, lighting, and camera effects. Using the editor for UI creation can reduce development time dramatically compared to hand‑coded front‑end solutions.

Bundle Splitting

Bundle splitting helps manage large resource packages by grouping, managing, and optimizing assets. Developers can select a folder, enable the Bundle option, and choose one of three merge types: none, merge dependencies, or merge all.

Image Leveling

Image leveling creates three quality levels (normal, medium, low) to match device performance, automatically delivering appropriate resolution images without developer intervention. For texture atlases used by Spine or frame‑sequence animations, leveling must be disabled to avoid playback issues.

Texture Compression

Compressed textures are GPU‑readable formats that reduce memory usage. Enabling compression in the inspector automatically selects the appropriate format (ETC, ASTC) at runtime. Note that compressed textures cannot use flipY or generate mipmaps, and both original and compressed textures are packaged, increasing bundle size.

Transparent Pixel Expansion

When linear interpolation causes black edges around transparent pixels, enabling transparent pixel expansion adds a white border (or fully interpolated pixels) to prevent black edges, at the cost of slightly larger image files.

Project Configuration

Configuration Files

SAR Creator uses two main configuration files: the project configuration (e.g., sar.config.js ) specifying project root, entry files, and preview settings, and the build plugin configuration, which integrates SAR Creator into various platform build pipelines.

const path = require('path');
module.exports = {
  // Specify entry directory
  projectRoot: path.resolve(__dirname, 'game'),
  previewConfig: {
    previewDevtool: true,
    resolve: {
      alias: {
        // Alias to avoid SAR Creator errors
        '@lottery': path.resolve(__dirname, './')
      }
    }
  }
};

Sub‑Package Configuration

To stay within the 5 MB per‑package limit, sub‑packages are defined with exclusion rules and combine‑bundle strategies.

const lotterySarConfig = {
  // ...
  /** Sub‑package strategy, effective during build **/
  subPackages: {
    excludeBundles: ['test'],
    combineBundleRules: [
      {
        channelName: 'pitaya-lottery-game-2',
        test: [/mascot/]
      },
      {
        channelName: 'pitaya-lottery-game',
        test: [/main-scene/, /resources/],
        preload: true,
        preloadPriority: 96
      }
    ]
  }
};

Inline Configuration

JSON and config files inside bundles can be merged into a binary to reduce request count and size, with size limits per group.

const lotterySarConfig = {
  // ...
  ejectOptions: {
    disableGenConfigWhenInline: true,
    groupConfig: {
      groupPackingSizeLimitBundleConfig: {
        mascot: 400,
        resources: 400
      }
    },
    inlineConfig: {
      'main-scene': true,
      resources: true,
      mascot: true
    }
  }
};

Preload Configuration

Resources can be preloaded by generating a preload JSON file during build, limiting the number and total size of preloaded assets.

const lotterySarPreloadUrlList = [];
const lotterySarConfig = {
  // ...
  preload: {
    publicPath: `https://${CDN_DOMAIN}${GECKO_PREFIX}/pitaya-lottery-main/`,
    limit: 300,
    sizeLimit: 3 * 1024,
    outputDir: 'merge-js/lottery',
    asset: {
      rules: [
        {
          test: /.*/,
          rewrite: (item) => {
            if (
              item.url.endsWith('.png') ||
              item.url.endsWith('.jpg') ||
              item.url.endsWith('.jpeg') ||
              lotterySarPreloadUrlList.includes(item.url)
            ) {
              return;
            }
            lotterySarPreloadUrlList.push(item.url);
            item.enableMemory = true;
            return item;
          }
        }
      ]
    }
  }
};

Example of the generated preload JSON:

{
  "***/index/template.js": {
    "image": [
      {
        "enableMemory": true,
        "url": "***/resource/image/back.bcd0a82e.png",
        "size": 280
      }
    ],
    "other": [
      {
        "enableMemory": true,
        "url": "***/main-scene/g_0.cc991.group",
        "priority": 96,
        "size": 143296,
        "assetBundleType": "group"
      }
    ]
  }
}

Development Practices

Script Writing

New scripts can be created via the asset panel. A typical TypeScript script looks like this:

// newscript.ts
import { Script, ScriptUtil } from '@sar-creator/toolkit/engine/core';

@ScriptUtil.Register('NewScript')
export default class NewScript extends Script {
  onStart() {
    const scene = this.world.getEntitiesByName('Scene')[0];
    if (scene) {
      // TODO: implement logic
    }
  }
}

SAR Creator script lifecycle includes onAwake, onDestroy, onPause, onResume, onStart, onUpdate, and onLateUpdate. The most commonly used callbacks are onStart, onUpdate, and onResume.

Prefab Creation

Dragging a node from the hierarchy panel to the asset panel automatically creates a prefab asset that stores all node data and dependencies. Prefabs can be edited later and loaded at runtime to accelerate development.

Dynamic Loading

Bundles can be loaded dynamically via the asset manager. Example of loading a prefab:

const { bundle, error: bundleError } = await this.world.assetManager.loadBundle('resources');
if (!bundle || bundleError) throw bundleError;

const { asset, error: prefabError } = await bundle.load
(`prefabs/fireworks/${prefabName}.prefab`);
if (!asset?.get?.() || prefabError) throw prefabError;
const entity = asset.get() as Entity;

Loading a texture directly:

const { bundle, error: bundleError } = await this.world.assetManager.loadBundle('resources');
if (!bundle || bundleError) throw bundleError;

const { asset, error: textureError } = await bundle.load
('texture/lamp/rect.png/index.texture');
if (!asset?.get?.() || textureError) throw textureError;
const texture = asset.get() as Texture;

Future Outlook

In the past year, SAR Creator released three major versions (1.0, 1.1, 1.2), adding script configuration, bundle splitting, performance optimizations, animation editor, VFX particle system, launcher, multi‑language support, material grouping, and asset preview panels.

For 2024, the focus will be on engine performance, editor usability, and expanding animation editor capabilities to enable richer animation development directly within the editor.

Team Introduction

We are the Douyin Front‑End Architecture – Interactive Experience Technology Team, providing interactive solutions such as SAR Creator, Simple Engine, and AnnieX interactive container for ByteDance’s business lines.

Next Issue Preview

The next topic will be "Rendering Technology and Practice," covering various rendering methods to meet visual quality and performance requirements.

TypeScriptGame developmentbundle optimizationtexture compressionasset pipelinePrefabSAR Creator
ByteFE
Written by

ByteFE

Cutting‑edge tech, article sharing, and practical insights from the ByteDance frontend team.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.