English | 中文
yet another r/place
What is Place? it is a multi-person mash drawing board where each person can only draw one pixel over
a period of time. See
Note: The project uses virtual threads and has not been officially released yet so Please add the
parameter -enable-preview
at startup.
such as java --enable-preview -jar app.jar
- Java Version >= 19
The minimal run does not require any external dependencies (Redis/MySQL) to run. Just download the GitHub release jar
Then run java --enable-preview -jar filename
in console
java --enable-preview -jar app.jar
By default, a canvas of 1000x1000 pixels will be initialized
If you want to configure the canvas size, backup rate and other parameters you can use a custom configuration file.
Start with a custom configuration file
java --enable-preview -jar app.jar --spring.config.location=. /config.yml
PS:
The application will try to connect to Redis when it starts, and if it doesn't connect, it will use a built-in data type like HashMap / byte[] instead.
The current canvas information will be backed up every 5 minutes to the image_bitmap_backup.bin
file in the runtime path, which will be loaded automatically at startup.
This file will also be backed up when the application is closed normally.
Note: Dependency-free runtime uses SQLite and HashMap to store relevant information, suitable for scenarios that do not require high performance.
The canvas can be initialized manually from an image by HTTP
POST http://localhost:8080/init?token=cb2f4c23-5bfb-485c-aa65-e5873f279bab to initialize it from
the app.init-image
value in the configuration file.
value in the configuration file, which defaults to dd.png
.
Initializing the canvas requires a token, which is in the app.token
of the configuration file, and The default is to
randomly generate an uuid
Note: If the image size is different from the configured canvas size it will be automatically scaled to the canvas size.
Redis connects to localhost:6379
by default
No configuration is required to use Redis, just start a Redis server.
MyQSL connects to localhost:3306
by default
Using MyQSL requires changing the spring.datasource.url
in the configuration file
to jdbc:mysql://localhost:3306/app?createDatabaseIfNotExist=true
For the full configuration file see application.yml
app:
width: 1000 # canvas width
height: 1000 # canvas height
backup-rate: 300 # backup rate in seconds
init-image: ". /init.png" # initial image path
token: "cb2f4c23-5bfb-485c-aa65-e5873f279bab" # token for operation that requires authentication
This project now supports building Native images using Graalvm, which runs without installing the JDK. The build steps are also very simple, just run the following command on the platform.
. /gradlew nativeImage
Package . /gradlew bootJar
MQService.java is a message queue
interface.
MemMQService.java
and RedisMQService.java
implements a message queue using a HashMap-based message queue, and a Redis-based message queue, respectively.
PlaceRepository.java is an interface that stores the current canvas MemPlaceRepo.java and RedisPlaceRepo.java implements a canvas using byte[], and a canvas based on Redis, respectively.
api see api.http
### init canvas
POST http://localhost:8080/init
### put a pixel
PUT http://localhost:8080/pixels
Content-Type: application/json
{
"x": 50,
"y": 50,
"color": [255,0,0,255]
}
### get all pixels
GET http://localhost:8080/pixels/all
### sse pixel
GET http://localhost:8080/time
The project architecture is referenced in a Reddit
article How We Built r/Place
Some technical details are different.
- WebSocket -> Server-Sent Events because SSE is easier to develop compared to WS. 2.
- rate limiting is achieved by using memory/Redis instead of checking database
- Use byte[] or Redis to store current canvas pixel information
- Each pixel operation is stored to a database (SQLite/MySQL)
- Rate limiting using Redis or HashMap .
- Push new pixels to the client using SSE
- Spring Boot
- Spring Data JPA
- Spring Data Redis
- SQLite / MySQL
Use the following three major frameworks, mainly using the Canvas API.
- Vanilla JS
- Vanilla CSS
- Vanilla HTML