mirror of
https://github.com/tiennm99/tiennm99bot.git
synced 2026-10-11 03:13:46 +00:00
feat(gacha): render the beta wish in portrait
/api/gachabeta now returns a portrait video with the requested width as its long edge: 640 renders 360x640 and 854 renders 480x854. The request body is unchanged, and /api/gacha stays landscape. The pack sits higher so it stays in frame while the card rises.
This commit is contained in:
1 parent
b73347bb4f
commit
fc3c7ae0c0
5 files changed
+34
-9
No files matched your search
+3
-2
@@ -67,12 +67,13 @@ only draws it.
|
||||
### Gacha wish beta
|
||||
|
||||
`POST /api/gachabeta` takes the same body and returns the same response as
|
||||
`/api/gacha`, rendering a 6-second beta style instead: a collectible card pack
|
||||
`/api/gacha`, rendering a 6-second portrait beta style instead: a collectible card pack
|
||||
from [pack-cards](https://github.com/paubineau/pack-cards) is torn open, and
|
||||
its card shows the request's `label`, its rank, and its stars. As on
|
||||
`/api/gacha`, `rarity` picks the rank (`B` for 3★, `A` for 4★, `S` for 5★),
|
||||
the star count, the card's material (rare, epic, legendary), and the pack's
|
||||
colour (blue, purple, gold).
|
||||
colour (blue, purple, gold). The video is portrait, with `width` as its long
|
||||
edge: `640` renders 360×640 and `854` renders 480×854.
|
||||
|
||||
pack-cards animates on the browser clock, so this route does not use Remotion
|
||||
compositions. `src/render/render-gacha-beta.js` keeps one headless Chrome per
|
||||
|
||||
@@ -30,7 +30,7 @@ body {
|
||||
|
||||
/* Sit the pack below centre so the card rising out of it stays in frame. */
|
||||
#stage .recap-pack-stack {
|
||||
margin: 24vh 0 0;
|
||||
margin: 14vh 0 0;
|
||||
width: min(36vh, 60vw);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import path from 'node:path';
|
||||
import {getRankLetter, getRarityPalette} from '../remotion/gacha-timeline.js';
|
||||
import {gachaFrameSizes} from '../schemas/gacha-request.js';
|
||||
|
||||
/** @typedef {import('../schemas/gacha-request.js').GachaRenderRequest} GachaRenderRequest */
|
||||
/** @typedef {import('../remotion/gacha-timeline.js').GachaRarity} GachaRarity */
|
||||
@@ -25,6 +26,15 @@ export const wishTimeline = Object.freeze({
|
||||
dragEnd: 1,
|
||||
});
|
||||
|
||||
/**
|
||||
* The beta wish is portrait: the request's `width` (640 or 854) is the long
|
||||
* edge, so the frame is the /api/gacha frame turned upright.
|
||||
*
|
||||
* @param {GachaRenderRequest['width']} width
|
||||
* @returns {{width: number, height: number}}
|
||||
*/
|
||||
export const getWishFrameSize = (width) => ({width: gachaFrameSizes[width], height: width});
|
||||
|
||||
/** pack-cards rarity profile and glow preset for each requested rarity. */
|
||||
const rarityLooks = Object.freeze({
|
||||
3: {rarity: 'rare', glow: /** @type {const} */ ('silver')},
|
||||
|
||||
@@ -7,13 +7,13 @@ import {ensureBrowser, makeCancelSignal, RenderInternals} from '@remotion/render
|
||||
import {
|
||||
gachaBetaTotalSeconds,
|
||||
getDragPointer,
|
||||
getWishFrameSize,
|
||||
getWishPageProps,
|
||||
resolveWishAsset,
|
||||
wishOrigin,
|
||||
} from '../gacha-beta/wish-plan.js';
|
||||
import {RenderTimeoutError} from '../lib/render-errors.js';
|
||||
import {cleanupTempDir, createRenderTempDir} from '../lib/tmp-files.js';
|
||||
import {gachaFrameSizes} from '../schemas/gacha-request.js';
|
||||
import {createCdpConnection} from './cdp-pipe.js';
|
||||
|
||||
/**
|
||||
@@ -158,7 +158,10 @@ export const closeGachaBetaBrowser = async () => {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export const warmGachaBetaBrowser = async () => {
|
||||
await renderGachaBetaVideo({label: 'Warm-up', rarity: 5, fps: 24, width: 640, seed: 1}, {timeoutInMilliseconds: 120000});
|
||||
await renderGachaBetaVideo(
|
||||
{label: 'Warm-up', rarity: 5, fps: 24, width: 640, seed: 1},
|
||||
{timeoutInMilliseconds: 120000},
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -194,13 +197,13 @@ const captureFrames = async (cdp, sessionId, request, dir, guard) => {
|
||||
*/
|
||||
const send = (method, params) => guard(cdp.send(method, params, sessionId));
|
||||
/** @param {string} expression */
|
||||
const evaluate = async (expression) => (await send('Runtime.evaluate', {expression, returnByValue: true})).result?.value;
|
||||
const evaluate = async (expression) =>
|
||||
(await send('Runtime.evaluate', {expression, returnByValue: true})).result?.value;
|
||||
|
||||
await send('Page.enable');
|
||||
await send('Fetch.enable', {patterns: [{urlPattern: '*'}]});
|
||||
await send('Emulation.setDeviceMetricsOverride', {
|
||||
width: request.width,
|
||||
height: gachaFrameSizes[request.width],
|
||||
...getWishFrameSize(request.width),
|
||||
deviceScaleFactor: 1,
|
||||
mobile: false,
|
||||
});
|
||||
|
||||
@@ -3,6 +3,7 @@ import {describe, expect, test} from 'vitest';
|
||||
import {
|
||||
gachaBetaTotalSeconds,
|
||||
getDragPointer,
|
||||
getWishFrameSize,
|
||||
getWishPageProps,
|
||||
resolveWishAsset,
|
||||
wishOrigin,
|
||||
@@ -14,12 +15,22 @@ const roots = {page: path.resolve('/srv/page'), packCards: path.resolve('/srv/pa
|
||||
describe('gacha beta wish plan', () => {
|
||||
test('the page shows the request label with the same rank and stars as /api/gacha', () => {
|
||||
const base = {label: '<b>Bún bò</b>', fps: /** @type {const} */ (24), width: /** @type {const} */ (640), seed: 1};
|
||||
expect(getWishPageProps({...base, rarity: 3})).toMatchObject({label: '<b>Bún bò</b>', rank: 'B', stars: 3, rarity: 'rare'});
|
||||
expect(getWishPageProps({...base, rarity: 3})).toMatchObject({
|
||||
label: '<b>Bún bò</b>',
|
||||
rank: 'B',
|
||||
stars: 3,
|
||||
rarity: 'rare',
|
||||
});
|
||||
expect(getWishPageProps({...base, rarity: 4})).toMatchObject({rank: 'A', stars: 4, rarity: 'epic'});
|
||||
expect(getWishPageProps({...base, rarity: 5})).toMatchObject({rank: 'S', stars: 5, rarity: 'legendary'});
|
||||
expect(getWishPageProps({...base, rarity: 5}).artwork).toEqual({accent: '#ffd36b', tint: '#7a4a10'});
|
||||
});
|
||||
|
||||
test('the frame is portrait, with the requested width as its long edge', () => {
|
||||
expect(getWishFrameSize(640)).toEqual({width: 360, height: 640});
|
||||
expect(getWishFrameSize(854)).toEqual({width: 480, height: 854});
|
||||
});
|
||||
|
||||
test('the drag sweeps left to right across the seal, then lets go', () => {
|
||||
const {dragStart, dragEnd} = wishTimeline;
|
||||
expect(getDragPointer(dragStart - 0.01)).toBeNull();
|
||||
|
||||
Reference in new issue
Block a user