moshang-ax/lottery: a 3D sphere raffle for annual dinners, configured from two files
🎉🌟✨🎈年会抽奖程序,基于 Express + Vue + Three.js的 3D 球体抽奖程序,奖品🧧🎁,文字,图片,抽奖规则均可配置,😜抽奖人员信息Excel一键导入😍,抽奖结果Excel导出😎,给你的抽奖活动带来全新酷炫体验🚀🚀🚀
At a glance
- What is it?
- An Express plus Vue 3 plus Three.js draw tool where prizes live in server/config.js and participants come from an Excel file. It is built for one specific night, not for continuous operation.
- Who is it for?
- Adopt moshang-ax/lottery if you are running a single internal draw, you can keep the participant list in server/data/user.xlsx, and you accept that the winner state resets only through the page reset button. Do not adopt it if you need audited, tamper-evident results, a hosted service, or a draw that survives a disk loss, because the README documents no such guarantees.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 26 days ago.
- What is it written in?
- Mainly JavaScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What moshang-ax/lottery is built to do
This is a raffle program for a company annual dinner. The README describes the core loop plainly: names spin on a 3D sphere rendered with Three.js, a draw selects winners, and the result is written out to Excel. Everything around that loop is configuration. Prize tiers, prize counts, how many winners each draw produces, the company name shown on the card, and the participant roster are all supplied by the operator before the event.
The intended user is the person who got handed the laptop and the projector. There is no account system, no multi-tenant story, no scheduling. The repository is small enough to read in an afternoon: a product directory for the Vue 3 front end and a server directory for the Express data service. If you are choosing between this and a general-purpose event platform, the distinction is that this one assumes a single draw, a single room, and a list of names you already have.
How the 3D ball, the Express service and the winner state fit together
The front end is Vue 3 with Vite, and the sphere is rendered through Three.js using CSS3D. That last detail matters if you plan to modify the visuals. According to the README, Three.js and its helpers (CSS3DRenderer.js, TrackballControls.js, tween.js) are still loaded as global scripts from product/public/lib rather than imported as modules. The stated reason is visual parity with the earlier version. The practical consequence is that the 3D code sits partly outside the module graph, so a bundler-based refactor of engine.js will not automatically pull those helpers along.
State lives in src/lottery/store.js and the 3D engine in src/lottery/engine.js. Requests to the back end go through src/api/index.js. On the server side, server/server.js is the Express entry and server/config.js holds the prize definition. The README notes the API contract is unchanged from the previous version, so an existing deployment's client code does not break on upgrade.
Persistence is the part worth reading twice. The README states that refreshing the page or turning off the server preserves winner data, and that the lottery data resets only when the reset button on the page is clicked. That is a deliberate design choice for an event: a crash mid-ceremony should not wipe the winners. It also means there is no separate administrative reset, and no documented way to undo a single mistaken draw.
Installing moshang-ax/lottery and running a first draw
The README gives a clone-then-two-installs sequence. The server and the front end have separate dependency trees, so both npm install steps are required. The build step produces the dist output that the serve command uses.
git clone https://github.com/moshang-xc/lottery.git
cd lottery
cd server
npm install
cd ../product
npm install
npm run build
npm run serveAfter npm run serve, the README says Express serves the built dist on port 8888 and switches automatically, printing the actual port, if 8888 is occupied. Read that printed line rather than assuming 8888. For development there is a separate path: npm run dev starts the Vite dev server on 9000 by default and starts the Express data service alongside it, with the same automatic port fallback.
Before the draw you need two files in place. Participants go in server/data/user.xlsx, and the README is explicit that the format must be followed and that neither the file name nor the column titles may be changed. Prizes go in server/config.js. The first entry is reserved:
let prizes = [{
type: 0,
count: 1000,
title: "",
text: "Special Price"
},
{
type: 1,
count: 2,
text: "First prize",
title: "Mac Pro",
img: "../img/mbp.jpg"
}
];The type field is a unique identifier, and the README warns that 0 is the placeholder for the default special prize and cannot be reused by other entries. Prize images are referenced relative to the img directory. A third setting, EACH_COUNT, controls how many winners each draw produces and maps positionally to the prize list, so a configuration of [1, 1, 5] means one special prize per draw, then one grand prize per draw, then five first prizes per draw. COMPANY sets the name shown on the lottery card.
Where moshang-ax/lottery stops being the right tool
The configuration is code, not data. Prizes and the per-draw counts are edited directly in server/config.js, which means changing the prize structure requires a file edit and a restart, not a form. For an event where the prize list is finalized in advance, that is fine. For an event where a sponsor adds a tier an hour before the draw, it is friction.
The participant roster has the same shape. server/data/user.xlsx is the only documented source, and the README forbids renaming the file or its column titles. There is no documented API for pushing participants in programmatically, and no documented validation step that tells you what went wrong when an import silently produces fewer names than expected.
The reset semantics are the sharpest edge. Because the only documented reset is the page button, and because winner state survives a server restart, a mistaken draw during rehearsal is corrected by resetting everything, not by removing one name. If you need partial corrections, per-draw audit trails, or a record that a third party can independently verify, this project does not claim to provide them. The README does not document rollback of an individual result.
How it compares with a general-purpose wheel or name-picker
The obvious alternative is a browser-based spinning wheel or a random name picker, which most people reach for first. The difference is in what each one persists and configures. A wheel picker typically holds names in the browser tab, offers no server component, and loses its state on refresh. This project puts an Express service behind the draw specifically so that winner data survives a refresh or a server shutdown, and it exports results to Excel rather than leaving them on screen.
The second difference is the prize model. A wheel picker draws names. This project draws names against a typed prize list with per-tier counts and a per-draw quantity, which is what an annual dinner actually needs when the first prize is one item and the participation prize is two hundred. If your event has one flat pool of winners and no tiers, the wheel is less work. If it has tiers, an Excel roster, and a projector, the extra Express process is buying you something.
Docker deployment, licence and the upgrade surface
The repository ships a Dockerfile and a docker-compose.yml. The compose file maps host port 28458 to container port 8888, names the container lottery, mounts a lottery_log volume at /var/log, and pulls the image panda1024/lottery:v0.3 with restart set to always. Note the mismatch worth checking before you deploy: the Dockerfile exposes 8080 and sets the working directory to /lottery/product before running npm run serve, while the compose file publishes 8888. The README's own install section says the Express service starts on 8888 and auto-switches if occupied, so a container that falls back to another port will not match the published mapping.
The Dockerfile is also pinned to node:16.14.0-buster and upgrades npm to 9.6.2, then strips the openBrowser line from server/server.js with sed so the container does not try to open a browser. That image is old relative to the Vue 3 and Vite front end, and nothing in the README describes a tested newer base image.
Licensing is MIT, which permits commercial and internal use with the licence text retained. The README does not discuss what happens to bundled assets under product/public/img, so if you replace prize images with licensed artwork, that is your own compliance question rather than one the project answers. On maintenance: the last push was on 2026-09-04, and the repository is not archived. The README states the front end was refactored to Vue 3 and the build tool migrated from webpack to Vite, and that the back-end API contract is unchanged, which is the upgrade story you are relying on if you have an older deployment.
Editorial conclusion
Adopt moshang-ax/lottery if you are running a single internal draw, you can keep the participant list in server/data/user.xlsx, and you accept that the winner state resets only through the page reset button. Do not adopt it if you need audited, tamper-evident results, a hosted service, or a draw that survives a disk loss, because the README documents no such guarantees. Before the event, verify three things: that your Excel columns match the required format, that server/config.js has a type 0 entry still in first position, and that the port printed by npm run serve is the one your audience will actually reach.
Frequently asked questions
How do I install moshang-ax/lottery?
Clone the repository, run npm install in both the server and product directories, run npm run build in product, then npm run serve. The README says Express serves the built output on port 8888 and prints the actual port if 8888 is taken.
Where do I configure prizes and how many winners each draw produces in moshang-ax/lottery?
Prizes are defined in server/config.js, and the file name cannot be changed. The EACH_COUNT array maps positionally to the prize list and sets how many winners each draw produces.
How do I load the participant list in moshang-ax/lottery?
Participants go in server/data/user.xlsx. The README states the format must be followed exactly and that the file name and column titles cannot be modified.
Can I reset the lottery results in moshang-ax/lottery?
Yes, but only through the reset button on the page. The README says refreshing the page or turning off the server preserves winner data, so the reset button is the documented way to clear results.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/moshang-ax-lottery)