Intro

NEStrisChamp works with the concepts of room. Each user has 2 rooms:

The key is for players to OCR their game frames into the correct room.

For single player rooms, you just need to send your game frames into the room and into the view for them to be rendered.

For Math room, you may invite as many people as you want to be producers, and you'll select who, out of the room members, gets to be player 1 and player 2.

Architecture and Terminology

In single player mode, frame data is passed straight from the producer into 1 or more views.

Architecture for 1 player

In competition mode, all producers emit data, but the room owner assigns a given producer to be player 1 and another producer to be player 2. Only the game frame of these 2 players are sent to the views.

Architecture for 2 players

URL scheme

Views

Since views are typically setup in OBS, the URL needs to identify the room owner by itself, This is achieved by assigning a secret to each user that can placed in the URL. It's not super secure, but whatever, this tool is not hosting state secrets -_-

http://nestrischamps.io/view/LAYOUT_NAME/USER_SECRET

The layouts available so far are as follow:

At your first login, a secret would have been generated for you and added to your user record. You can see it in your personal renderer links which are available here.

Hopefully in the future, users will be able to contribute their own template.

Several of the layouts have a black background with Tetris pieces. If you do not like it and would prefer a transparent background to place the layout above it, add the query string `?bg=0` into the view URL. Like so:
http://nestrischamps.io/view/LAYOUT_NAME/SECRET?bg=0

Producer

To produce frames into your own private room, visit https://nestrischamps.io/room/producer

To attach yourself as a producer to another user's room (typically the link will be passed to you as an invitation), the links will be of the form

https://nestrischamps.io/room/u/TWITCH_USERNAME/producer

Admin

To administer your competition room, visit https://nestrischamps.io/room/admin

OCR and Calibration

OCR is supported in browser for both device capture and screen capture.

2 default game roms are supported:

The fields that need to be OCR-ed per rom are fixed (see highlighted areas above)

There is a built-in automatic calibrator but it doesn't work to well, so you should always ajust the areas selected for calibration to be as close as possible to the desired outcome.

In both cases, start a game at level 0 BEFORE you press the "Calibrate and Capture button". In Das trainer, pause as soon as the game starts click the button. In Classic Tetris, click as soon as the game starts. In both cases, keep your fingers crossed that the auto calibrator takes you close to the desired state, and then fine tune all the capture areas to be pixel perfect.

Once calibration and tuning has been done, the capture window and the browser tab MUST stay focused.

Digits

The capture area should "hug" the digits on top, right, bottom, left, (using 0 as a reference), like this:

Note that if you calibrate something that starts with a 1, the capture area should NOT hug the one on the left (notice the black strip on the left).

Preview

To calibrate the preview properly, run the calibration in level 0 over multiple pieces, such that:

"hugged" means there is no black border

Current Piece (DAS Trainer only)

To calibrate the preview properly, run the calibration in level 0 over multiple pieces, such that:

Colors (Classic Tetris only)

Reading colors from the frame helps matching the block colors when scanning the field.

The are 3 colors to read: color1, color2, and color3. They should be read from the pieces stats on the left by selecting one block from the T piece, J piece, and Z piece.

The blocks should be chosen like this

Piece statistics panel highlighting color blocks

The selection should not include any black border, but color1 should include the block's border. They should look like this

Field

To calibrate the field capture, try to stack pieces on the left, right, and bottom, and even all the way up on the top-left and top-right.

Having done that, hug the capture on right, left, top, bottom. do not leave black borders at the bottom and right!, like this:

Capture area for field

OBS / Streamlabs setup

All layouts so far are 720p (1280x720), which is a good compromise of real estate vs. draw time and upload bandwidth requirements. But feel free to stretch the layout to fit a 1080p canva

The Browser Source setup should look like this:

OBS browser source configuration panel

Administering a Room

Admin UI

In the admin panel, you get to see who is connected to the room, and select the desired producers as player 1 and player 2

The Name and Avatar are taken from Twitch data, but can be updated to suit.

The number of match to get to victory can change ("Best of" dropdown)

Each player has a heart control, the heart can be clicked to attribute victories.

The "Winner" button displays a little animation in the field to show the winner and loser of the match. Do NOT click it until both players have topped out! If the winning player is chasing a maxout or what not, wait till he/she is done before clicking.

Finally the "Clear Victories" button resets the victory for both players to 0, and stops the winner animation.

Binary frame format

All captured frames are sent in binary and weight 568 bits (71 bytes) per frame. On a capture setup of 60fps, the game stream requirements are therefore 71*60 = 4,260 B/s (~4KB/s).

They have the format below.

Game fields may be null (like das trainer's instant das when sending classic frames), in which case the field's bits should all be set to 1.

  Purpose Size Description
1 Version 3 bits Specify the version of the format of binary frame. Currently 1.
2 Game type 2 bits Specify the type of game the frame is for, so a parser may know which fields are expected to be null. So far: 1: CLASSIC - 2:DAS_TRAINER
3 Player number 3 bits Specify which player this frame is for. Producers are expected to leave this at 0. While the frame broker may set the number to player 1 (0), or 2 (1), or more when layouts can supports having more players.
4 Game ID 16 bits Starts at zero when producer starts. Increases by 1 at every game.
5 Client time 28 bits Number of milliseconds since producer connected. Range: ~74 hours
6 Lines 12 bits Unsigned int. Range: 4094
7 Level 8 bits Unsigned int. Range: 254
8 Score 24 bits Unsigned int. Range: 16,777,214 (224)
9 Instant DAS 5 bits Unsigned int. Das needs to record 17 values (0 to 16) + null.
10 Preview 3 bits Represents the piece in preview as follow: 0:T, 1:J, 2:Z, 3:O, 4:S, 5:L, 6:I, 7:null
11 Current Piece DAS 5 bits Unsigned int.
12 Current Piece 3 bits Piece in current piece area of Das Trainer. Same encoding as Preview.
13 T count 9 bits Piece count for T piece
14 J count 9 bits Piece count for J piece
15 Z count 9 bits Piece count for Z piece
16 O count 9 bits Piece count for O piece
17 S count 9 bits Piece count for S piece
18 L count 9 bits Piece count for L piece
19 I count 9 bits Piece count for I piece
20 Field 400 bits 2 bits per block for the 200 blocks in the field. Starts from top-left and travels right-bottom.

Below is the bit representation of the fields described above

Binary frame format representation

See the source file for implementation details.

Ideas for improvements

As with any software, there's always more... "More, more, more, more, more" as the GOAT would have said.

The list of TODO items is tracked as issues in the github project. Feel free to open feature requests and bug reports there. There's no ETA and guarantee on when anything might get done though, so patience is key :).