sankalphs commited on
Commit
dc5ea4d
·
verified ·
1 Parent(s): 56e3431

Deploy singularity1 verified build

Browse files
Files changed (4) hide show
  1. README.md +75 -10
  2. assets/index-B6my5IbN.css +1 -0
  3. assets/index-MX9u61fm.js +0 -0
  4. index.html +3 -19
README.md CHANGED
@@ -1,10 +1,75 @@
1
- ---
2
- title: Singularity1
3
- emoji: 🐠
4
- colorFrom: green
5
- colorTo: purple
6
- sdk: static
7
- pinned: false
8
- ---
9
-
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Singularity
3
+ emoji: 🪐
4
+ colorFrom: green
5
+ colorTo: blue
6
+ sdk: static
7
+ app_file: index.html
8
+ pinned: false
9
+ short_description: Six minds. One body. A multiplayer physics race.
10
+ ---
11
+
12
+ # Singularity
13
+
14
+ A browser-playable cooperative physics race. Up to **four teams of six players** pilot shared bodies across a floating obstacle course. Each player controls the head, left arm, right arm, torso, left leg, or right leg. Coordinate forces, carry cargo, avoid a sweeper, and finish faster than the other teams.
15
+
16
+ **Play:** https://huggingface.co/spaces/sankalphs/singularity
17
+ **Source:** https://github.com/Sathvikar01/singularity
18
+
19
+ ## Play
20
+
21
+ Create a callsign and room code, then share the invite link. Pick the same team to share a body or another team to compete. The first player hosts and starts the countdown. Empty roles remain neutral; pilots can switch to unoccupied parts using **1–6** or the role cards during a race. For a small crew, assign legs first and switch a pilot to an arm for cargo.
22
+
23
+ - **WASD / arrows:** force on your assigned body part. W moves forward along the course, independent of camera angle.
24
+ - **Space:** arms grab nearby cargo while held; legs hop when grounded.
25
+ - **Three ordered objectives:** cross the narrow bridge, carry the gold cube into the mint delivery zone, cross the finish after the sweeper.
26
+ - **Falls:** checkpoint recovery and a three-second penalty. Ten-minute match limit.
27
+ - **Solo practice:** assisted legs and balance; Space grabs with either arm. Practice is unranked.
28
+
29
+ Desktop keyboard is recommended; narrow screens include touch controls. Teams race as separate colored bodies on the same course without inter-team collision. Reconnecting players can fill vacant roles on an existing team mid-race; switching teams mid-race is blocked. Use **Crew / rematch** to open the room controls.
30
+
31
+ ## Architecture
32
+
33
+ Three.js renders procedural 3D assets, lighting, shadows, fog, and constrained articulated bodies. A pure fixed-step position-based physics solver is shared between practice and the **authoritative SpacetimeDB TypeScript module**. The server alone advances ranked simulations, validates roles and checkpoints, sets clocks, ends matches, and writes leaderboard rows. Clients submit bounded inputs; they cannot submit body poses, progress, or completion times. Idle inputs expire after 500 ms. Disconnects release role slots and migrate host ownership. Empty rooms are removed; result rows persist independently.
34
+
35
+ Generated SpacetimeDB bindings subscribe to public tables `room`, `player`, `team`, `result`. The `tick` scheduler is private. Final times always use server timestamps, including penalties; running UI clocks are estimates using the visitor's clock.
36
+
37
+ This initial competitive course uses a custom constrained-body solver and procedural Three.js assets. Unreal/Blender are not runtime requirements. It does not include skeletal animation, voice chat, matchmaking, or player-account authentication. Public callsigns are self-selected.
38
+
39
+ ## Unreal and Blender handoff
40
+
41
+ The Blender artwork is available in [`art/generated/singularity-art.blend`](art/generated/singularity-art.blend), with three exported GLBs and inspected Cycles previews. The industrial robot has six independent parts, painted metal, rubber joints, optical lenses, and embedded PBR textures. The course includes detailed decking, bridge, cargo, and finish assets. See [`unreal/README.md`](unreal/README.md) for regeneration and import instructions. The Unreal source includes corrected coordinate mapping and input handling, but remains uncompiled here; its SpacetimeDB bridge is an event interface and still needs a network transport. No skeletal animation or native multiplayer is claimed.
42
+
43
+ ## Develop and verify
44
+
45
+ Requires Node 22.6+ (24 recommended), npm, and SpacetimeDB CLI 2.9+.
46
+
47
+ ```sh
48
+ npm ci
49
+ npm ci --prefix spacetimedb
50
+ npm test
51
+ npm run dev
52
+ npm run build
53
+ ```
54
+
55
+ The default client connects to `singularity-relay-sankalphs` on Maincloud. For another backend, copy `.env.example` to `.env.local` and set both values before starting Vite/building. These are public settings, not secrets.
56
+
57
+ ```sh
58
+ spacetime start --listen-addr 127.0.0.1:3100 --data-dir .spacetime
59
+ spacetime publish singularity-test --module-path spacetimedb --server http://127.0.0.1:3100
60
+ spacetime generate --lang typescript --out-dir src/module_bindings --module-path spacetimedb
61
+ ```
62
+
63
+ With Vite running and Chrome installed, `node tests/browser.mjs` verifies cloud lobbies with two browser clients. `node tests/multiplayer.mjs` verifies complete simultaneous races against the local test database. Full completion tests run locally to avoid polluting the public leaderboard.
64
+
65
+ ## Deploy
66
+
67
+ ```sh
68
+ spacetime login
69
+ spacetime publish singularity-relay-sankalphs --module-path spacetimedb --server maincloud
70
+ npm run build
71
+ python scripts/deploy.py "Deploy verified game build"
72
+ ```
73
+
74
+ The script uses existing Hugging Face credentials and uploads the static production build. SpacetimeDB Cloud provides persistence. No paid graphics server is required. An offline backend is visibly reported; no fake online players or local ranked results are substituted.
75
+
assets/index-B6my5IbN.css ADDED
@@ -0,0 +1 @@
 
 
1
+ @import"https://fonts.googleapis.com/css2?family=Barlow+Condensed:wght@500;600;700;800;900&family=DM+Sans:wght@400;500;600;700&display=swap";:root{font-family:DM Sans,sans-serif;color:#eef4ee;background:#12212b;font-synthesis:none;--mint: #aff2d6;--muted: #a4b1b9;--panel: rgba(18, 31, 41, .88);--line: rgba(206, 226, 226, .15);--coral: #ff8875}*{box-sizing:border-box}body{margin:0;overflow:hidden}button,input,select{font:inherit}button{cursor:pointer;color:inherit}button:focus-visible,input:focus-visible,select:focus-visible{outline:2px solid var(--mint);outline-offset:4px}button{border:1px solid var(--line);background:#263844;border-radius:6px;padding:12px 17px;transition:background .2s,transform .2s}button:hover{background:#354c58;transform:translateY(-1px)}button.primary{background:var(--mint);color:#142b28;border:0;font-weight:700}button.primary:hover{background:#d5ffe8}button:disabled{opacity:.5;cursor:wait}#world{position:absolute;inset:0}#world canvas{display:block;width:100%;height:100%}.vignette{position:absolute;inset:0;pointer-events:none;background:linear-gradient(90deg,rgba(10,23,30,.92),transparent 60%),linear-gradient(0deg,rgba(10,23,30,.7),transparent 25%)}header{height:88px;position:absolute;top:0;left:0;right:0;padding:0 36px;display:flex;align-items:center;justify-content:space-between;border-bottom:1px solid var(--line);background:#101c2599;-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);z-index:3}.brand{display:flex;align-items:center;gap:13px;font-size:22px;font-weight:700;letter-spacing:-1px}.brand-icon{height:32px;width:32px;border:2px solid var(--mint);border-radius:50%;position:relative}.brand-icon:after{content:"";position:absolute;inset:7px -5px;border:2px solid var(--mint);border-radius:50%;transform:rotate(-45deg)}.brand span:last-child{color:var(--mint)}nav{display:flex;align-items:center;gap:9px}nav button{font-size:12px;background:transparent;border:0;color:var(--muted)}.status{display:flex;align-items:center;gap:8px;font-size:10px;letter-spacing:1.5px;color:var(--mint);text-transform:uppercase}.dot{width:6px;height:6px;border-radius:50%;background:var(--mint);box-shadow:0 0 10px #aff2d64a}.intro{position:absolute;top:19%;left:5%;width:370px;z-index:2}.eyebrow{font-size:10px;font-weight:700;letter-spacing:2.8px;color:var(--mint);display:flex;align-items:center;gap:12px}.eyebrow:before{content:"";width:24px;height:1px;background:var(--mint)}h1{font-family:Barlow Condensed,Impact,sans-serif;font-size:clamp(65px,6.4vw,105px);line-height:.93;letter-spacing:-1.5px;font-weight:800;margin:24px 0}h1 em{font-style:normal;color:var(--mint)}.intro p{font-size:13px;color:var(--muted);line-height:1.9;max-width:290px}.actions{display:flex;gap:10px;margin-top:26px}.actions button{font-size:12px}.tiny{font-size:10px;color:#8ca0ac;line-height:1.8}.intro .tiny{margin-top:17px}.course-card{position:absolute;right:28px;top:116px;width:236px;background:var(--panel);border:1px solid var(--line);border-radius:10px;padding:22px;-webkit-backdrop-filter:blur(18px);backdrop-filter:blur(18px)}.section-label{font-size:9px;letter-spacing:2px;color:#9eb0ba;text-transform:uppercase}.course-title{font-size:18px;font-weight:600;margin:10px 0 4px}.course-meta{font-size:10px;color:var(--muted)}.stage{display:flex;align-items:center;gap:12px;padding-top:21px;opacity:.5}.stage.current,.stage.complete{opacity:1}.stage.current .stage-num{background:var(--mint);color:#20322c}.stage.complete .stage-num{color:var(--mint)}.stage-num{width:27px;height:27px;border:1px solid var(--line);border-radius:50%;display:grid;place-items:center;font-size:10px}.stage b{display:block;font-size:11px;font-weight:500}.stage small{font-size:9px;color:var(--muted)}.course-footer{border-top:1px solid var(--line);margin-top:23px;padding-top:14px;display:flex;justify-content:space-between;font-size:9px;color:var(--muted)}.course-footer strong{color:var(--mint);font-weight:500}.role-dock{position:absolute;left:36px;right:36px;bottom:28px;z-index:3}.dock-heading{display:flex;justify-content:space-between;align-items:center;margin-bottom:13px}.dock-heading b{font-size:10px;letter-spacing:1.6px;font-weight:500}.dock-heading span{font-size:10px;color:var(--muted)}.roles{display:grid;grid-template-columns:repeat(6,1fr);gap:9px}.role{position:relative;text-align:left;padding:14px 16px;background:#1a2a34eb;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px);border:1px solid var(--line);min-height:91px;border-radius:8px}.role.active{border-color:var(--mint);background:#415f58d1}.role-icon{color:var(--mint);font-size:23px;line-height:1.1}.role b{display:block;font-size:11px;margin-top:9px;font-weight:500}.role small{display:block;font-size:9px;color:var(--muted);margin-top:5px}.role kbd{position:absolute;right:12px;top:12px;background:transparent;font-size:9px;color:#859da6}.hud{position:absolute;top:116px;left:36px;display:none}.hud .timer{font-family:Barlow Condensed,sans-serif;font-size:57px;letter-spacing:2px;line-height:1.2}.hud .pill{display:inline-block;padding:6px 9px;border:1px solid var(--line);border-radius:4px;font-size:9px;color:var(--mint);margin-top:8px;background:var(--panel)}.instruction{position:absolute;left:50%;bottom:160px;transform:translate(-50%);background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:12px 20px;font-size:11px;white-space:nowrap;display:none;-webkit-backdrop-filter:blur(14px);backdrop-filter:blur(14px)}kbd{display:inline-block;padding:3px 6px;background:#3c515c;border-radius:3px;font-size:10px;color:#f1f5f1}.playing .intro{display:none}.playing .vignette{background:linear-gradient(0deg,rgba(10,23,30,.6),transparent 25%)}.playing .hud,.playing .instruction{display:block}.toast{position:absolute;left:50%;top:100px;transform:translate(-50%);padding:13px 20px;background:#294139;border:1px solid var(--mint);border-radius:8px;font-size:12px;z-index:20;max-width:90%;text-align:center}.toast:empty{display:none}dialog{background:#172a35;color:#f1f6f1;border:1px solid #4b655e;border-radius:15px;padding:32px;width:min(540px,92vw);box-shadow:0 30px 100px #0009}dialog::backdrop{background:#07121bcc;-webkit-backdrop-filter:blur(7px);backdrop-filter:blur(7px)}dialog h2{font-family:Barlow Condensed,sans-serif;font-size:38px;margin:10px 0}dialog p{font-size:12px;line-height:1.8;color:var(--muted)}dialog .close{position:absolute;top:14px;right:14px;background:transparent;border:0;padding:5px 10px}label.field{display:block;font-size:10px;color:var(--muted);margin-top:17px}input,select{width:100%;padding:12px;margin-top:7px;background:#213743;border:1px solid var(--line);border-radius:5px;color:#fff}.form-row{display:grid;grid-template-columns:1fr 1fr;gap:14px}.members{font-size:12px;line-height:2;color:var(--mint);margin-top:12px}.leader-row{display:grid;grid-template-columns:25px 1fr 80px;gap:10px;border-bottom:1px solid var(--line);padding:12px 0;font-size:12px}.leader-row small{font-size:9px;color:var(--muted)}.big-result{font-family:Barlow Condensed,sans-serif;font-size:70px;color:var(--mint)}#standings{margin-top:14px;font-size:11px;line-height:2;color:var(--mint)}.countdown{position:absolute;inset:0;pointer-events:none;display:grid;place-items:center;font-family:Barlow Condensed,sans-serif;font-size:130px;color:var(--mint);text-shadow:0 4px 40px #000}.touch{display:none;position:absolute;bottom:155px;left:16px;gap:5px;z-index:4}.touch button{padding:13px;touch-action:none;-webkit-user-select:none;user-select:none}.touch .grab{margin-left:20px}.error{color:#ffb0a3;font-size:11px;line-height:1.7}#sound{font-size:15px}.back{margin-top:12px;background:var(--panel);font-size:10px;padding:7px 11px}@media(max-width:1000px){.intro{left:4%;width:300px}.course-card{width:200px;right:20px}.roles{gap:5px}.role{padding:12px 10px}.role-dock{left:20px;right:20px}.role small{font-size:8px}.instruction{font-size:10px}}@media(max-width:700px){header{height:65px;padding:0 18px}.brand{font-size:18px}.status{display:none}nav{gap:0}nav button{padding:8px}.intro{top:15%;left:7%;width:86%}h1{font-size:65px}.intro p{max-width:260px}.course-card{display:none}.role-dock{bottom:14px;left:12px;right:12px}.roles{grid-template-columns:repeat(3,1fr)}.role{min-height:62px;padding:8px 10px}.role-icon{font-size:16px;float:left;margin-right:7px}.role b{font-size:10px;margin:0}.role small{margin-top:7px}.role kbd,.dock-heading span{display:none}.dock-heading{margin-bottom:8px}.hud{top:88px;left:20px}.instruction{bottom:210px;max-width:94%;white-space:normal;line-height:1.8;text-align:center}.playing .touch{display:flex}.playing .instruction{display:none}.vignette{background:linear-gradient(90deg,#0a171ee0,transparent)}.toast{top:75px}dialog{padding:24px}}@media(max-height:700px)and (min-width:701px){.intro{top:110px}h1{font-size:55px;margin:16px 0}.intro p{font-size:11px;line-height:1.6;margin:10px 0}.intro .tiny{display:none}.actions{margin-top:16px}.course-card{padding:18px}.stage{padding-top:16px}}h1 em{white-space:nowrap}.intro .tiny{max-width:350px}.stage b{line-height:1.5}
assets/index-MX9u61fm.js ADDED
The diff for this file is too large to render. See raw diff
 
index.html CHANGED
@@ -1,19 +1,3 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
1
+ <!doctype html><html lang="en"><head><meta charset="UTF-8"/><meta name="viewport" content="width=device-width,initial-scale=1.0"/><meta name="theme-color" content="#101b24"/><meta name="description" content="Six minds. One body. A cooperative physics race across a floating obstacle course."/><title>Singularity — Six minds. One body.</title> <script type="module" crossorigin src="/assets/index-MX9u61fm.js"></script>
2
+ <link rel="stylesheet" crossorigin href="/assets/index-B6my5IbN.css">
3
+ </head><body><div id="app"></div></body></html>