Technical Implementation of the "Da Li Chu Qi Ji" Mini‑Game on Bilibili
The article details the end‑to‑end technical implementation of Bilibili’s “Da Li Chu Qi Ji” mini‑game, describing a GSAP‑driven 4‑second countdown, a PixiJS‑based core gameplay with custom resource loading and event handling, and the evaluation and integration of PAG, SVGA, and MP4 animation formats for reward effects.
This article documents the technical solution and implementation details of the "Da Li Chu Qi Ji" growth activity mini‑game released on the Bilibili app on April 26, 2023. The game consists of three main parts: a 4‑second countdown, the core gameplay, and various reward‑related effects (coin‑sprinkling, extra chances, etc.).
1. Countdown
When the game dialog opens, a 4‑second countdown animation is shown. Four images are animated by adjusting their scale and opacity on a timeline. GSAP is chosen because its timeline object can precisely control multiple CSS properties along a time axis.
Key code:
<div class="countdown-shadow">
<img id="countdown3" src="countdown3" />
<img id="countdown2" src="countdown2" />
<img id="countdown1" src="countdown1" />
<img id="countdown4" src="countdown4" />
</div>GSAP timeline example:
const tl = gsap.timeline();
this.tl = tl;
tl.set('.countdown-shadow', { display: 'flex' })
.set('#countdown3', { display: 'block', opacity: 1 })
.to('#countdown3', { duration: 1, scale: 0.7, opacity: 0, display: 'none' })
.set('#countdown2', { scale: 0.7, opacity: 0, display: 'block' })
.to('#countdown2', { duration: 0.5, scale: 1, opacity: 1 })
.to('#countdown2', { duration: 0.5, scale: 0.7, opacity: 0, display: 'none' });2. Game Core
After the countdown, the main game UI appears. Users click a button for up to 8 seconds (max 150 clicks). Every 10 clicks award a certain amount of "Da Li Coins" and reset the progress bar. The implementation evolved through three technical solutions:
First version: frame‑animation library – simple but caused noticeable stutter when switching speed levels.
Second version: GSAP + sprite sheet – smoother but required a lot of repetitive code for many sprites.
Final version: PixiJS (v7) – a WebGL‑based 2D rendering engine offering the best performance and extensibility.
Key PixiJS classes used:
Application – creates the WebGL canvas and manages the render loop.
Assets – loads images, fonts, and other resources.
Container – groups display objects (similar to a div ).
Sprite and AnimatedSprite – render static and frame‑based graphics.
Example of creating the PixiJS application:
import { Application, Assets } from 'pixi.js';
const canvas = document.getElementById('game');
const width = window.screen.width;
const height = (667 * width) / 375;
const app = new Application({ width, height, resolution: window.devicePixelRatio, view: canvas, backgroundAlpha: 0 });Resource loading with a helper to fix URLs (handling base64 and adding https in production):
const fixAssetsUrl = url => {
const base64Reg = /data:image\/png;base64,.*/g;
const matchRes = url.match(base64Reg);
if (matchRes) return matchRes[0];
const prefix = process.env.NODE_ENV === 'production' ? 'https:' : '';
return prefix + url;
};
load(resources) {
const resourceKeys = [];
Object.keys(resources).forEach(key => {
const url = resources[key];
const fixedUrl = fixAssetsUrl(url);
Assets.add(key, fixedUrl, { crossOrigin: 'anonymous' });
resourceKeys.push(key);
});
return Assets.load(resourceKeys);
}Font loading is performed with fontfaceobserver to guarantee that custom fonts are ready before rendering:
import FontFaceObserver from 'fontfaceobserver';
loadFont(fontFamilyName, timeout = 10000) {
const fontOb = new FontFaceObserver(fontFamilyName, {});
return fontOb.load(null, timeout);
}Custom classes such as Stage and GameApplication encapsulate the creation of containers, event‑bus wiring (using mitt ), and the overall lifecycle (initialisation, resource cleanup). The destruction flow ensures that all assets are reset, texture caches cleared, and PixiJS objects disposed to avoid memory leaks.
3. Additional Effects (Coin Sprinkling, KV Animations)
Three animation formats were evaluated:
PAG – smallest file size but poor mobile performance and compatibility (e.g., frame drop on iOS).
SVGA – best performance and compatibility, but larger file size (1‑2 MB for coin effects, up to 25 MB for KV animations).
MP4 – medium size, acceptable performance, but requires special handling for autoplay on iOS (inserting the video tag via v‑html ).
File‑size comparison tables (excerpt):
Animation
PAG Size
SVGA Size
MP4 Size
Coin Sprinkle
212 KB
1 MB
—
KV Rest State
543 KB
10 MB
714 KB
For MP4 autoplay, the video element is generated dynamically:
<video id="video" preload="auto" muted autoplay playsinline webkit-playsinline loop style="opacity:0" oncanplay="style.opacity=1;window.daliOnVideoCanPlay()" class="video show-video">
<source src="${video_url}" type="video/mp4">
</video>4. Summary
The article walks through the entire technical stack of the mini‑game, from the countdown animation using GSAP, through the core gameplay built with PixiJS (resource loading, custom containers, event bus, and cleanup), to the selection and integration of auxiliary animation formats (PAG, SVGA, MP4). The detailed code snippets, performance considerations (e.g., MAX_TEXTURE_SIZE on mobile), and compatibility fixes (polyfills for older browsers) provide a practical reference for front‑end engineers building interactive web games.
Bilibili Tech
Provides introductions and tutorials on Bilibili-related technologies.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.