@jingx/part-six36
v0.1.4
Published
React package for the 3D lottery machine runtime.
Readme
3D Lottery Machine
Browser-based 3D lottery draw built with CreateJS, Cannon.js, and Three.js. The app loads a 3D lottery drum, simulates 36 numbered balls, and extracts 6 preset numbers after a short countdown.
Overview
This project is a canvas-based browser game with a lightweight static front end:
index.htmlloads the static assets and module entrypoint.js/bootstrap.jsbuilds the runtime config passed intoCMainand starts the app.js/appConfig.jscontains the live draw and startup configuration.js/CMain.jshandles preload, asset registration, and game startup.js/CGame.jscontrols countdown, shuffling, extraction, and reset.js/CScenario.jsbuilds the physics world and loads the machine mesh frommodels/sphere_machine.txt.js/CBall.jsrenders and animates each numbered ball sprite.js/settings.jsstores canvas, camera, physics, and gameplay constants.
Tech Stack
- CreateJS / EaselJS for stage management, sprites, and tweens
- Cannon.js for physics simulation
- Three.js plus
FBXLoaderfor loading the lottery machine geometry - Howler.js for audio playback
- jQuery and helper utilities from
js/lib/
Current Game Flow
The current implementation is not a generic draw engine yet. It runs a fixed sequence defined in js/appConfig.js and passed through CMain into CGame:
TOTAL_NUMBERS = 36NUMBERS_TO_PICK = 6COUNTDOWNis set to5RESULT_NUMBERSis set to[12, 13, 14, 15, 16, 17]
After assets load, the game starts automatically, counts down, shuffles the balls, extracts those preset numbers in order, then resets and starts the loop again.
Running Locally
Use an HTTP server. Do not rely on opening index.html directly from the filesystem.
Option 1: Simple Static Server
cd /path/to/3d-game-v1
python3 -m http.server 8080Then open http://localhost:8080.
Option 2: Vite
package.json includes Vite scripts:
npm install
npm run dev
npm run build
npm run build:react-package
npm run build:all
npm run previewThe current local Node version in this workspace is v18.18.0, so the repo is pinned below Vite 7. That is deliberate: Vite 5 and 6 support Node 18 / 20+, while Vite 7 requires Node 20.19+ or 22.12+.
If you only want the dev server:
npm startReact package compatibility:
@jingx/part-six36supports React16.8+,17,18, and19
React Integration
This repo now includes a React package around the game runtime.
Current architecture:
- the game still supports the original standalone page runtime
- the React package now exports both a native component and an iframe wrapper
- communication is handled through props and callbacks
The native component lives in src/react/LotteryMachine.js, the iframe wrapper lives in src/react/LotteryMachineFrame.js, and the package build uses vite.react-package.config.js.
Package Build
Build the standalone game and the React wrapper:
npm run build:allOr build only the wrapper package:
npm run build:react-packageRun the local Vite consumer example:
npm run example:install
npm run exampleBuild the local Vite consumer example:
npm run example:buildWrapper output:
dist-react/lottery-machine-react.jsdist-react/lottery-machine-react.cjs- emitted runtime assets in
dist-react/for sprites, sounds, fonts, and the model
From @jingx/[email protected] onward, the React package is shipped as a self-contained runtime bundle. Sprites, sounds, fonts, and the model are inlined into the package build, so consuming apps do not need to copy dist-react/ into their own public/ folder and older webpack-based React apps do not need to parse import.meta.url from the package.
Package export:
import {LotteryMachine, LotteryMachineFrame} from "@jingx/part-six36";Install In Your React App
Local install from this repo:
npm install /absolute/path/to/3d-game-v1Or in your React app package.json:
{
"dependencies": {
"@jingx/part-six36": "file:../3d-game-v1"
}
}Exact import shape in the React app:
import {LotteryMachine} from "@jingx/part-six36";Native React Component
Use LotteryMachine if you want the lottery canvas to render directly inside your React tree without an iframe.
Example:
import {LotteryMachine} from "@jingx/part-six36";
export function LotteryMachinePanel() {
return (
<LotteryMachine
countdown={10}
resultNumbers={[12, 13, 14, 15, 16, 17]}
onReady={(payload) => console.log("ready", payload)}
onRoundComplete={(payload) => console.log("done", payload)}
style={{width: 640, height: 640}}
/>
);
}A full consumer example is included in LotteryMachineConsumerExample.jsx.
There is also a runnable Vite app in examples/react-app/package.json. It consumes @jingx/part-six36 through a local file:../.. dependency, uses React 16.14.0, and forces a fresh Vite dev cache on startup so package rebuilds are picked up cleanly.
Because that example uses a local file: dependency outside the app root, its Vite config also allows the repo root in server.fs.allow. That setting is needed for local linked development; it is not the normal requirement for a published npm install.
Notes:
- the container must have a real width and height
- the component observes container resizes and rescales the canvas to fit that box
- the native component currently supports only one mounted instance at a time because the legacy engine still uses shared globals
- if you need multiple simultaneous machines, use
LotteryMachineFrame
iframe Wrapper
Use LotteryMachineFrame if you want stronger isolation or need multiple embeds.
Example:
import {LotteryMachineFrame} from "@jingx/part-six36";
export function LotteryMachineScreen() {
return (
<LotteryMachineFrame
gameUrl="/lottery-machine/index.html"
countdown={10}
resultNumbers={[12, 13, 14, 15, 16, 17]}
onReady={(payload) => console.log("ready", payload)}
onRoundComplete={(payload) => console.log("done", payload)}
style={{width: "100%", height: "100%", border: 0}}
/>
);
}Host The Standalone Game Assets
LotteryMachineFrame needs a URL for the actual game page.
Typical flow:
- Run
npm run build - Host this repo's
dist/output inside your React app's public assets, for example at/lottery-machine/ - Point the wrapper's
gameUrlprop to that hosted page
Example hosted URL:
/lottery-machine/index.htmlWhy iframe Still Exists
LotteryMachineFrame is still useful because:
- this project still uses a legacy global runtime internally
iframekeeps those globals isolated from your React app- it allows multiple simultaneous embeds
- it works well when the standalone page is already hosted elsewhere
Initial Values Through URL
The runtime supports query parameters:
countdownresults
Example:
/lottery-machine/index.html?countdown=10&results=12,13,14,15,16,17Live Updates From React
The embedded page listens for:
{
type: "LOTTERY_MACHINE_UPDATE_DRAW",
payload: {
countdown: 10,
resultNumbers: [12, 13, 14, 15, 16, 17]
}
}resultNumbers should contain exactly 6 integers in the 1-36 range.
The embedded page also exposes window.LotteryMachine with:
updateDraw({ countdown, resultNumbers })getDrawConfig()
Result Complete Event To React
When the last ball fully reaches the end of the tube and stops, the embedded page sends this message to the parent:
{
type: "LOTTERY_MACHINE_ROUND_COMPLETE",
payload: {
resultNumbers: [12, 13, 14, 15, 16, 17],
releasedSum: 87,
countdown: 10
}
}This is posted with window.parent.postMessage(...).
Behavior Notes
- if React sends a new countdown before extraction starts, the game resets its countdown to the new value
- if React sends new values while balls are already being extracted, the new config is applied to the next round
resultNumbersmust contain exactly 6 integers in the1-36range
Configuration
The main places to change behavior are:
index.html- Static page shell and script loading order
js/appConfig.js- Active
COUNTDOWN - Active
RESULT_NUMBERS CMainstartup flags such asfullscreenandaudio_enable_on_startup
- Active
js/settings.js- Canvas size
- Camera settings
- Physics constants
- Shuffle timing
TOTAL_NUMBERSandNUMBERS_TO_PICK
js/CLang.js- UI text such as the start label
Project Structure
.
├── index.html
├── package.json
├── css/
├── js/
│ ├── appConfig.js
│ ├── bootstrap.js
│ ├── CMain.js
│ ├── CGame.js
│ ├── CScenario.js
│ ├── CBall.js
│ ├── CPreloader.js
│ ├── CInterface.js
│ ├── CLang.js
│ ├── settings.js
│ └── lib/
├── src/
│ └── react/
├── models/
│ └── sphere_machine.txt
├── sounds/
└── sprites/Notes for Maintainers
- The countdown and draw results in
js/settings.jsare legacy defaults only. Live values now come either fromjs/bootstrap.js/js/appConfig.jsin standalone mode or from React props in the package runtime. vite.config.jscopies the legacy runtime directories intodist/during build because the current game still loads many assets by string path at runtime instead of module import.src/react/legacyRuntime.jspackages the legacy scripts with raw imports and emits a manifest for sprites, sounds, models, and fonts so the native React component can resolve assets without hardcoded public paths.js/CInterface.jsexists, but the current game flow does not instantiate it.js/CGame.jscreates a start-extraction toggle and immediately unloads it, so the present behavior is effectively auto-start only.LotteryMachineis a direct React mount, but it still wraps a legacy singleton engine under the hood. Only one native instance is supported at a time.- There is no automated test suite configured in
package.json.
Assets
sprites/contains UI, background, and ball sprite sheetssounds/contains panel, shuffle, extraction, and soundtrack audiomodels/sphere_machine.txtis an FBX text export of the lottery machine mesh
