summaryrefslogtreecommitdiff
path: root/serve
diff options
context:
space:
mode:
authorprospanclaudebot <[email protected]>2026-07-10 23:54:26 +0000
committerprospanclaudebot <[email protected]>2026-07-10 23:54:26 +0000
commit375e4c070e7a62c375173625fa0da281f91166a6 (patch)
tree6c9a42692387d304a3b3c9d0f4ca6274a39f40c2 /serve
parent1ff1082260098698e328357ce632eaa02cebd2f0 (diff)
downloadplaneta-zhopa-375e4c070e7a62c375173625fa0da281f91166a6.tar.gz
planeta-zhopa-375e4c070e7a62c375173625fa0da281f91166a6.zip
crab-party: 🌭 танцующие крабы + механика крабо-сквада (вербовка у пати -> рой мини-крабо-дронов вокруг дрона -> авто-poop-эскадрилья, HUD 🦀×N)
Diffstat (limited to 'serve')
-rw-r--r--serve/index.html105
1 files changed, 105 insertions, 0 deletions
diff --git a/serve/index.html b/serve/index.html
index 5657520..8edc7a7 100644
--- a/serve/index.html
+++ b/serve/index.html
@@ -1588,6 +1588,111 @@ function rcTick() {
const lbl = makeLabel('ЖОПА-ВОДОПАД'); lbl.position.set(0, 42, -16); lbl.scale.set(24, 6, 1); g.add(lbl);
})();
+// ---------- CRAB PARTY 🦀 — танцующие крабы (crab rave) по заявке @devcpp ----------
+(function buildCrabParty() {
+ const LX = -64, LZ = 34;
+ const PAD = Math.max(groundH(LX, LZ), WATER_Y) + 6.0; // над гребнями волн, иначе крабов накрывает вода
+ const g = new THREE.Group(); g.position.set(LX, PAD, LZ); scene.add(g);
+ const pillar = new THREE.Mesh(new THREE.CylinderGeometry(10, 8, 18, 16), new THREE.MeshStandardMaterial({ color: 0x2a2e34, roughness: 1 }));
+ pillar.position.y = -9; g.add(pillar);
+
+ const floor = new THREE.Group(); g.add(floor);
+ const tiles = [], N = 6, TS = 3;
+ for (let x = 0; x < N; x++) for (let z = 0; z < N; z++) {
+ const t = new THREE.Mesh(new THREE.BoxGeometry(TS * 0.94, 0.3, TS * 0.94),
+ new THREE.MeshStandardMaterial({ color: 0x111318, emissive: 0x000000, roughness: 0.35, metalness: 0.1 }));
+ t.position.set((x - (N - 1) / 2) * TS, 0.15, (z - (N - 1) / 2) * TS); t.receiveShadow = true; floor.add(t); tiles.push(t);
+ }
+
+ const cmat = (h) => new THREE.MeshStandardMaterial({ color: new THREE.Color().setHSL(h, 0.85, 0.5), roughness: 0.5 });
+ const white = new THREE.MeshStandardMaterial({ color: 0xffffff, roughness: 0.4 });
+ const black = new THREE.MeshStandardMaterial({ color: 0x111111, roughness: 0.5 });
+
+ function makeCrab(h) {
+ const c = new THREE.Group(), m = cmat(h);
+ const body = new THREE.Mesh(new THREE.SphereGeometry(1.0, 12, 8), m);
+ body.scale.set(1.5, 0.65, 1.1); body.position.y = 1.0; body.castShadow = true; c.add(body);
+ for (const s of [-1, 1]) {
+ const stalk = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 0.6, 6), m); stalk.position.set(s * 0.4, 1.55, 0.55); c.add(stalk);
+ const eye = new THREE.Mesh(new THREE.SphereGeometry(0.2, 8, 6), white); eye.position.set(s * 0.4, 1.85, 0.55); c.add(eye);
+ const pup = new THREE.Mesh(new THREE.SphereGeometry(0.1, 6, 6), black); pup.position.set(s * 0.4, 1.87, 0.72); c.add(pup);
+ }
+ const claws = [];
+ for (const s of [-1, 1]) {
+ const arm = new THREE.Group(); arm.position.set(s * 1.4, 1.0, 0.3);
+ const up = new THREE.Mesh(new THREE.CylinderGeometry(0.11, 0.13, 0.9, 6), m); up.rotation.z = s * 0.6; up.position.set(s * 0.35, 0.25, 0); arm.add(up);
+ const cl = new THREE.Mesh(new THREE.SphereGeometry(0.45, 8, 6), m); cl.scale.set(1.3, 0.95, 0.7); cl.position.set(s * 0.75, 0.6, 0); arm.add(cl);
+ c.add(arm); claws.push(arm);
+ }
+ const legs = [];
+ for (const s of [-1, 1]) for (let i = 0; i < 3; i++) {
+ const leg = new THREE.Group(); leg.position.set(s * 0.85, 0.65, 0.35 - i * 0.5);
+ const seg = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.05, 0.9, 5), m); seg.rotation.z = s * 1.15; seg.position.set(s * 0.32, -0.25, 0); leg.add(seg);
+ c.add(leg); legs.push(leg);
+ }
+ return { c, claws, legs };
+ }
+
+ const crabs = [], frac = x => x - Math.floor(x), NC = 11;
+ for (let i = 0; i < NC; i++) {
+ const cr = makeCrab(frac(i * 0.137 + 0.02));
+ const a = i / NC * Math.PI * 2, r = 2 + frac(Math.sin(i * 12.9) * 43758.5) * 7;
+ cr.baseX = Math.cos(a) * r; cr.baseZ = Math.sin(a) * r; cr.ph = i * 0.57; cr.face = a + Math.PI;
+ cr.c.position.set(cr.baseX, 0.3, cr.baseZ); cr.c.rotation.y = cr.face; g.add(cr.c); crabs.push(cr);
+ }
+
+ const lbl = makeLabel('CRAB PARTY 🦀'); lbl.position.set(0, 10, 0); lbl.scale.set(22, 5.5, 1); g.add(lbl);
+
+ // ---- механика: крабо-сквад (мини-крабо-дроны + авто-poop-эскадрилья) ----
+ const squad = [], MAXS = 6, poops = [], CENTER = new THREE.Vector3(LX, PAD + 2, LZ);
+ const poopGeo = new THREE.SphereGeometry(0.35, 6, 5), poopMat = new THREE.MeshStandardMaterial({ color: 0x5a3a1a, roughness: 1 });
+ let lastT = 0, lastPoop = 0;
+ const hudC = document.createElement('div');
+ hudC.style.cssText = 'position:fixed;left:12px;bottom:66px;font:bold 20px system-ui;color:#ff8c3a;text-shadow:0 1px 3px #000;z-index:50;pointer-events:none';
+ document.body.appendChild(hudC);
+
+ window.updateCrabs = function (t) {
+ const dt = Math.min(0.05, Math.max(0, t - lastT)); lastT = t;
+ const beat = t * 3.4, pz = window.PZ, S = pz && pz.S;
+ for (let i = 0; i < crabs.length; i++) {
+ const cr = crabs[i]; if (cr.squad) continue;
+ const p = cr.ph;
+ cr.c.position.y = 0.3 + Math.abs(Math.sin(beat + p)) * 0.9;
+ cr.c.rotation.y = cr.face + Math.sin(beat * 0.5 + p) * 0.35;
+ cr.c.rotation.z = Math.sin(beat + p) * 0.13;
+ cr.claws[0].rotation.z = Math.sin(beat + p) * 0.7;
+ cr.claws[1].rotation.z = -Math.sin(beat + p) * 0.7;
+ for (let k = 0; k < cr.legs.length; k++) cr.legs[k].rotation.x = Math.sin(beat * 1.5 + p + k * 0.6) * 0.25;
+ }
+ for (let k = 0; k < tiles.length; k++) tiles[k].material.emissive.setHSL(frac(k * 0.09 + t * 0.35), 1.0, 0.5);
+ if (S) {
+ if (S.p.distanceTo(CENTER) < 22 && squad.length < MAXS) {
+ const av = crabs.find(c => !c.squad);
+ if (av) { av.squad = true; g.remove(av.c); scene.add(av.c); av.c.scale.setScalar(0.7); squad.push(av); }
+ }
+ for (let j = 0; j < squad.length; j++) {
+ const cr = squad[j], a = t * 1.6 + j * (6.2831 / MAXS);
+ cr.c.position.set(S.p.x + Math.cos(a) * 4.5, S.p.y - 1.4 + Math.abs(Math.sin(t * 5 + j)) * 0.8, S.p.z + Math.sin(a) * 4.5);
+ cr.c.rotation.y = -a; cr.c.rotation.z = Math.sin(t * 5 + j) * 0.2;
+ cr.claws[0].rotation.z = Math.sin(t * 5 + j) * 0.7; cr.claws[1].rotation.z = -Math.sin(t * 5 + j) * 0.7;
+ }
+ if (squad.length && t - lastPoop > 1.1 && poops.length < 60) {
+ lastPoop = t;
+ const cr = squad[Math.floor(t * 10) % squad.length];
+ const pm = new THREE.Mesh(poopGeo, poopMat); pm.position.copy(cr.c.position); scene.add(pm); poops.push({ m: pm, vy: -1.5 });
+ }
+ }
+ for (let i = poops.length - 1; i >= 0; i--) {
+ const q = poops[i]; q.vy -= 9.8 * dt; q.m.position.y += q.vy * dt; q.m.rotation.x += 0.25;
+ const lvl = Math.max(groundH(q.m.position.x, q.m.position.z), WATER_Y);
+ if (q.m.position.y <= lvl + 0.2 || q.m.position.y < -300) { scene.remove(q.m); poops.splice(i, 1); }
+ }
+ hudC.textContent = squad.length ? '🦀×' + squad.length + ' крабо-эскадрилья 💩' : '';
+ };
+ (function _cp() { window.updateCrabs(performance.now() / 1000); requestAnimationFrame(_cp); })();
+ window.updateCrabs(0);
+})();
+
// ---------- монумент ПАСОЧКИ (кулич с яйцами) по заявке @lzcnt ----------
(function buildPaska() {
const gx = 60, gz = 120, gy = groundH(gx, gz);