Add Cursor runs for Claude and Gemini models
This commit is contained in:
1 parent
9bc21c2ace
commit
3936cd26af
17 files changed
+5169
-4
No files matched your search
+5
-2
@@ -28,10 +28,13 @@ One-shot LLM eval cases by NAGI STUDIO: same prompt, different model x harness x
|
||||
|---|---|---|---|
|
||||
| Claude Fable 5 | Anthropic | Claude Web App · Max<br>Claude Code · Max<br>Cursor · High | 06 |
|
||||
| Claude Opus 4.8 | Anthropic | Claude Code · Max | 02 |
|
||||
| Claude Opus 4.7 | Anthropic | Cursor · Max | 02 |
|
||||
| Claude Opus 4.6 | Anthropic | Cursor · Max | 02 |
|
||||
| Claude Sonnet 4.6 | Anthropic | Cursor · High | 02 |
|
||||
| GPT-5.5 Pro | OpenAI | ChatGPT Web · Extended Pro | 02 |
|
||||
| GPT-5.5 | OpenAI | Codex CLI · xhigh | 02 |
|
||||
| Gemini 3.1 Pro | Google | AntiGravity · High<br>Google AI Studio · High | 03 |
|
||||
| Gemini 3.5 Flash | Google | AntiGravity · High<br>Google AI Studio · High | 03 |
|
||||
| Gemini 3.1 Pro | Google | AntiGravity · High<br>Cursor · Default<br>Google AI Studio · High | 05 |
|
||||
| Gemini 3.5 Flash | Google | AntiGravity · High<br>Google AI Studio · High<br>Cursor · Default | 04 |
|
||||
| Grok Build | xAI | Grok Build TUI · Max | 02 |
|
||||
| Composer 2.5 | Cursor | Cursor · Max<br>Cursor · Default<br>Grok Build TUI · Default | 05 |
|
||||
| Mistral Medium 3.5 | Mistral AI | Vibe · Thinking | 02 |
|
||||
|
||||
@@ -28,10 +28,13 @@ NAGI STUDIO 的 LLM 测评案例集:同一段提示词,不同「模型 × Ha
|
||||
|---|---|---|---|
|
||||
| Claude Fable 5 | Anthropic | Claude Web App · Max<br>Claude Code · Max<br>Cursor · High | 06 |
|
||||
| Claude Opus 4.8 | Anthropic | Claude Code · Max | 02 |
|
||||
| Claude Opus 4.7 | Anthropic | Cursor · Max | 02 |
|
||||
| Claude Opus 4.6 | Anthropic | Cursor · Max | 02 |
|
||||
| Claude Sonnet 4.6 | Anthropic | Cursor · High | 02 |
|
||||
| GPT-5.5 Pro | OpenAI | ChatGPT Web · Extended Pro | 02 |
|
||||
| GPT-5.5 | OpenAI | Codex CLI · xhigh | 02 |
|
||||
| Gemini 3.1 Pro | Google | AntiGravity · High<br>Google AI Studio · High | 03 |
|
||||
| Gemini 3.5 Flash | Google | AntiGravity · High<br>Google AI Studio · High | 03 |
|
||||
| Gemini 3.1 Pro | Google | AntiGravity · High<br>Cursor · Default<br>Google AI Studio · High | 05 |
|
||||
| Gemini 3.5 Flash | Google | AntiGravity · High<br>Google AI Studio · High<br>Cursor · Default | 04 |
|
||||
| Grok Build | xAI | Grok Build TUI · Max | 02 |
|
||||
| Composer 2.5 | Cursor | Cursor · Max<br>Cursor · Default<br>Grok Build TUI · Default | 05 |
|
||||
| Mistral Medium 3.5 | Mistral AI | Vibe · Thinking | 02 |
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"label": "Claude Opus 4.6",
|
||||
"vendor": "Anthropic",
|
||||
"harness": "Cursor",
|
||||
"effort": "Max",
|
||||
"artifactDir": "claude-opus-4-6/cursor-max",
|
||||
"order": 17,
|
||||
"runs": {
|
||||
"mythos-craft": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Claude Opus 4.6(Max 思考配额)一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Claude Opus 4.6 (Max effort) inside Cursor; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
},
|
||||
"pelican-cycling": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Claude Opus 4.6(Max 思考配额)一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Claude Opus 4.6 (Max effort) inside Cursor; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"label": "Claude Opus 4.7",
|
||||
"vendor": "Anthropic",
|
||||
"harness": "Cursor",
|
||||
"effort": "Max",
|
||||
"artifactDir": "claude-opus-4-7/cursor-max",
|
||||
"order": 16,
|
||||
"runs": {
|
||||
"mythos-craft": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Claude Opus 4.7(Max 思考配额)一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Claude Opus 4.7 (Max effort) inside Cursor; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
},
|
||||
"pelican-cycling": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Claude Opus 4.7(Max 思考配额)一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Claude Opus 4.7 (Max effort) inside Cursor; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"label": "Claude Sonnet 4.6",
|
||||
"vendor": "Anthropic",
|
||||
"harness": "Cursor",
|
||||
"effort": "High",
|
||||
"artifactDir": "claude-sonnet-4-6/cursor-high",
|
||||
"order": 18,
|
||||
"runs": {
|
||||
"mythos-craft": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Claude Sonnet 4.6(High 思考配额)一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Claude Sonnet 4.6 (High effort) inside Cursor; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
},
|
||||
"pelican-cycling": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Claude Sonnet 4.6(High 思考配额)一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Claude Sonnet 4.6 (High effort) inside Cursor; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"label": "Gemini 3.1 Pro",
|
||||
"vendor": "Google",
|
||||
"harness": "Cursor",
|
||||
"effort": "Default",
|
||||
"artifactDir": "gemini-3-1-pro/cursor-default",
|
||||
"order": 41,
|
||||
"runs": {
|
||||
"mythos-craft": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Gemini 3.1 Pro 默认设置一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Gemini 3.1 Pro inside Cursor with default settings; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
},
|
||||
"pelican-cycling": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Gemini 3.1 Pro 默认设置一次生成;本页为未经修改的原始产出。",
|
||||
"en": "Generated in one shot by Gemini 3.1 Pro inside Cursor with default settings; unmodified original output."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"label": "Gemini 3.5 Flash",
|
||||
"vendor": "Google",
|
||||
"harness": "Cursor",
|
||||
"effort": "Default",
|
||||
"artifactDir": "gemini-3-5-flash/cursor-default",
|
||||
"order": 51,
|
||||
"runs": {
|
||||
"mythos-craft": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Gemini 3.5 Flash 默认设置一次生成。本页为未经修改的原始产出。包含基于柏林噪声的无限三维体素地形,自动爬坡(Step Climb)物理碰撞,Web Audio API 合成的风声/方块破坏/放置/跳跃音效及五重和弦背景合成乐。内置了世界之树、天空太阳神殿、黑曜石火山龙巢、悬浮精灵柱四处规模宏大、细节饱满的神话遗迹,并配备一键折跃与二维小地图罗盘导航。",
|
||||
"en": "Generated in one shot by Gemini 3.5 Flash inside Cursor with default settings. Unmodified raw output featuring an infinite 3D voxel terrain driven by Perlin noise, responsive step-climbing collision physics, and synthesized sound effects (block breaking, placing, jumping) alongside a 5-chord ambient synth soundtrack via Web Audio API. Built-in with four massive, highly detailed mythical landmarks — Yggdrasil, the Aether Sun Temple, the Obsidian Volcano Keep, and the Floating Elven Spires — complete with instant travel Codex and 2D minimap compass navigation."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
},
|
||||
"pelican-cycling": {
|
||||
"note": {
|
||||
"zh": "在 Cursor 中以 Gemini 3.5 Flash 默认设置一次生成。本页为原始未经修改的产出,具有极高精细度的矢量细节、生动的动画感构图以及富有趣味性的画面彩蛋(如鹈鹕喉囊里的小鱼)。",
|
||||
"en": "Generated in one shot by Gemini 3.5 Flash inside Cursor with default settings. Unmodified raw output featuring extremely rich vector details, dynamic composition, and delightful visual easter eggs like the swallowed fish in the gular pouch."
|
||||
},
|
||||
"contributor": "jessezhang"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,877 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>Minecraft Clone</title>
|
||||
<style>
|
||||
*{margin:0;padding:0;box-sizing:border-box}
|
||||
html,body{width:100%;height:100%;overflow:hidden;background:#000;font-family:'Segoe UI',system-ui,sans-serif}
|
||||
canvas{display:block;width:100%;height:100%}
|
||||
#overlay{position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:rgba(0,0,0,0.75);color:#fff;z-index:200;cursor:pointer;user-select:none}
|
||||
#overlay h1{font-size:48px;font-weight:900;letter-spacing:4px;margin-bottom:24px;text-shadow:0 0 40px rgba(100,200,255,0.4)}
|
||||
#overlay .controls{font-size:15px;line-height:2;color:#aaa;text-align:center}
|
||||
#overlay .controls span{color:#fff;font-weight:600;background:rgba(255,255,255,0.1);padding:2px 8px;border-radius:4px;margin:0 2px}
|
||||
#overlay .start{margin-top:32px;font-size:20px;color:#7cf;animation:pulse 2s ease-in-out infinite}
|
||||
@keyframes pulse{0%,100%{opacity:1}50%{opacity:0.5}}
|
||||
#overlay.hidden{display:none}
|
||||
#crosshair{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);pointer-events:none;z-index:100;width:1px;height:1px}
|
||||
#crosshair::before,#crosshair::after{content:'';position:absolute;background:rgba(255,255,255,0.8)}
|
||||
#crosshair::before{width:24px;height:2px;top:-1px;left:-12px}
|
||||
#crosshair::after{width:2px;height:24px;top:-12px;left:-1px}
|
||||
#hotbar{position:fixed;bottom:16px;left:50%;transform:translateX(-50%);display:flex;gap:2px;background:rgba(0,0,0,0.65);padding:4px;border-radius:6px;z-index:100;border:1px solid rgba(255,255,255,0.1)}
|
||||
.hslot{width:52px;height:52px;border:2px solid rgba(255,255,255,0.15);border-radius:4px;display:flex;align-items:center;justify-content:center;position:relative;cursor:pointer;transition:border-color 0.15s}
|
||||
.hslot.sel{border-color:rgba(120,210,255,0.9);box-shadow:0 0 12px rgba(120,210,255,0.3)}
|
||||
.hslot canvas{width:36px;height:36px;image-rendering:pixelated}
|
||||
.hslot .num{position:absolute;top:2px;left:5px;font-size:10px;color:rgba(255,255,255,0.5);font-weight:600}
|
||||
#debug{position:fixed;top:12px;left:12px;color:rgba(255,255,255,0.6);font-size:12px;font-family:'Cascadia Code','SF Mono',monospace;z-index:100;pointer-events:none;line-height:1.6;white-space:pre}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="overlay">
|
||||
<h1>MINECRAFT</h1>
|
||||
<div class="controls">
|
||||
<span>W A S D</span> Move / <span>Space</span> Jump / <span>Shift</span> Descend<br>
|
||||
<span>Mouse</span> Look / <span>Left Click</span> Break / <span>Right Click</span> Place<br>
|
||||
<span>1-9</span> Select Block / <span>Scroll</span> Cycle Blocks
|
||||
</div>
|
||||
<div class="start">Click to Play</div>
|
||||
</div>
|
||||
<div id="crosshair"></div>
|
||||
<div id="hotbar"></div>
|
||||
<div id="debug"></div>
|
||||
<script src="https://unpkg.com/three@0.160.0/build/three.min.js"></script>
|
||||
<script>
|
||||
(function(){
|
||||
"use strict";
|
||||
|
||||
var CHUNK=16, CHUNK_H=128, RDIST=7, SEA=28;
|
||||
var GRAV=28, JVEL=9, PH=1.7, PW=0.3, REACH=6;
|
||||
|
||||
var B={AIR:0,GRASS:1,DIRT:2,STONE:3,SAND:4,WATER:5,WOOD:6,LEAVES:7,SNOW:8,OBSIDIAN:9,GOLD:10,CRYSTAL:11,BEDROCK:12,BONE:13,BRICK:14,GLASS:15,LAVA:16};
|
||||
var BNAME=['','Grass','Dirt','Stone','Sand','Water','Wood','Leaves','Snow','Obsidian','Gold','Crystal','Bedrock','Bone','Brick','Glass','Lava'];
|
||||
var TRANS=new Set([B.AIR,B.WATER,B.GLASS,B.LEAVES]);
|
||||
function isSolid(t){return t!==B.AIR&&t!==B.WATER}
|
||||
var HOTBAR=[B.GRASS,B.DIRT,B.STONE,B.SAND,B.WOOD,B.BRICK,B.OBSIDIAN,B.GOLD,B.CRYSTAL];
|
||||
|
||||
function PerlinNoise(seed){
|
||||
this.p=new Uint8Array(512);
|
||||
var perm=new Uint8Array(256);
|
||||
for(var i=0;i<256;i++)perm[i]=i;
|
||||
var s=(seed*2147483647)|0;if(s<=0)s=1;
|
||||
for(var i=255;i>0;i--){s=(s*16807)%2147483647;var j=s%(i+1);var t=perm[i];perm[i]=perm[j];perm[j]=t;}
|
||||
for(var i=0;i<512;i++)this.p[i]=perm[i&255];
|
||||
}
|
||||
PerlinNoise.prototype.fade=function(t){return t*t*t*(t*(t*6-15)+10)};
|
||||
PerlinNoise.prototype.lerp=function(a,b,t){return a+t*(b-a)};
|
||||
PerlinNoise.prototype.grad2=function(h,x,y){var v=h&3;return((v&1)?-x:x)+((v&2)?-y:y)};
|
||||
PerlinNoise.prototype.grad3=function(h,x,y,z){var b=h&15;var u=b<8?x:y;var v=b<4?y:(b===12||b===14?x:z);return((b&1)?-u:u)+((b&2)?-v:v)};
|
||||
PerlinNoise.prototype.noise2=function(x,y){
|
||||
var X=Math.floor(x)&255,Y=Math.floor(y)&255;
|
||||
x-=Math.floor(x);y-=Math.floor(y);
|
||||
var u=this.fade(x),v=this.fade(y),p=this.p;
|
||||
var A=p[X]+Y,C=p[X+1]+Y;
|
||||
return this.lerp(this.lerp(this.grad2(p[A],x,y),this.grad2(p[C],x-1,y),u),this.lerp(this.grad2(p[A+1],x,y-1),this.grad2(p[C+1],x-1,y-1),u),v);
|
||||
};
|
||||
PerlinNoise.prototype.noise3=function(x,y,z){
|
||||
var X=Math.floor(x)&255,Y=Math.floor(y)&255,Z=Math.floor(z)&255;
|
||||
x-=Math.floor(x);y-=Math.floor(y);z-=Math.floor(z);
|
||||
var u=this.fade(x),v=this.fade(y),w=this.fade(z),p=this.p;
|
||||
var A=p[X]+Y,AA=p[A]+Z,AB=p[A+1]+Z,C=p[X+1]+Y,BA=p[C]+Z,BB=p[C+1]+Z;
|
||||
return this.lerp(this.lerp(this.lerp(this.grad3(p[AA],x,y,z),this.grad3(p[BA],x-1,y,z),u),this.lerp(this.grad3(p[AB],x,y-1,z),this.grad3(p[BB],x-1,y-1,z),u),v),this.lerp(this.lerp(this.grad3(p[AA+1],x,y,z-1),this.grad3(p[BA+1],x-1,y,z-1),u),this.lerp(this.grad3(p[AB+1],x,y-1,z-1),this.grad3(p[BB+1],x-1,y-1,z-1),u),v),w);
|
||||
};
|
||||
PerlinNoise.prototype.fbm2=function(x,y,oct){
|
||||
var val=0,amp=1,freq=1,max=0;
|
||||
for(var i=0;i<oct;i++){val+=this.noise2(x*freq,y*freq)*amp;max+=amp;amp*=0.5;freq*=2;}
|
||||
return val/max;
|
||||
};
|
||||
PerlinNoise.prototype.fbm3=function(x,y,z,oct){
|
||||
var val=0,amp=1,freq=1,max=0;
|
||||
for(var i=0;i<oct;i++){val+=this.noise3(x*freq,y*freq,z*freq)*amp;max+=amp;amp*=0.5;freq*=2;}
|
||||
return val/max;
|
||||
};
|
||||
|
||||
var noise=new PerlinNoise(7777);
|
||||
|
||||
function srand(x,y){var n=Math.sin(x*127.1+y*311.7)*43758.5453;return n-Math.floor(n);}
|
||||
|
||||
function terrainH(wx,wz){
|
||||
var base=noise.fbm2(wx*0.008,wz*0.008,6)*35+32;
|
||||
var mt=Math.max(0,noise.fbm2(wx*0.003+100,wz*0.003+100,4))*30;
|
||||
var dt=noise.fbm2(wx*0.03,wz*0.03,3)*5;
|
||||
return Math.floor(Math.max(1,base+mt+dt));
|
||||
}
|
||||
|
||||
function getBiome(wx,wz){
|
||||
var t=noise.noise2(wx*0.004,wz*0.004);
|
||||
var h=noise.noise2(wx*0.004+500,wz*0.004+500);
|
||||
if(t>0.25)return'desert';
|
||||
if(t<-0.3)return'tundra';
|
||||
if(h>0.15)return'forest';
|
||||
return'plains';
|
||||
}
|
||||
|
||||
function isCave(wx,wy,wz){
|
||||
if(wy<2||wy>55)return false;
|
||||
return noise.fbm3(wx*0.04,wy*0.06,wz*0.04,3)>0.55;
|
||||
}
|
||||
|
||||
function shouldTree(wx,wz){
|
||||
var biome=getBiome(wx,wz);
|
||||
var th=biome==='forest'?0.55:biome==='plains'?0.78:999;
|
||||
if(th>1)return false;
|
||||
var gx=Math.floor(wx/4)*4,gz=Math.floor(wz/4)*4;
|
||||
var ox=Math.floor(srand(gx,gz)*3),oz=Math.floor(srand(gz,gx)*3);
|
||||
if(wx!==gx+ox||wz!==gz+oz)return false;
|
||||
return srand(wx*13+7,wz*17+3)>(1-th)&&terrainH(wx,wz)>SEA;
|
||||
}
|
||||
function treeH(wx,wz){return 4+Math.floor(srand(wx*31+5,wz*37+11)*4);}
|
||||
|
||||
var atlasCanvas=null;
|
||||
function buildAtlas(){
|
||||
var size=16;
|
||||
atlasCanvas=document.createElement('canvas');
|
||||
atlasCanvas.width=atlasCanvas.height=256;
|
||||
var actx=atlasCanvas.getContext('2d');
|
||||
function drawTex(idx,fn){
|
||||
var c=document.createElement('canvas');c.width=c.height=size;
|
||||
fn(c.getContext('2d'),size);
|
||||
actx.drawImage(c,(idx%16)*size,Math.floor(idx/16)*size);
|
||||
}
|
||||
function fill(ctx,s,cols){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
ctx.fillStyle=cols[Math.floor(srand(x+0.5,y+0.5)*cols.length)];
|
||||
ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
}
|
||||
drawTex(0,function(ctx,s){fill(ctx,s,['#4a8a2a','#52952e','#5da33a','#489025','#67b040','#3e7820']);});
|
||||
drawTex(1,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
if(y<3){var c=['#4a8a2a','#52952e','#5da33a','#3e7820'];ctx.fillStyle=c[Math.floor(srand(x+.1,y+.1)*c.length)];}
|
||||
else if(y<5){ctx.fillStyle=srand(x+.2,y+.2)>.5?'#6b5435':'#4a8a2a';}
|
||||
else{var c=['#866043','#7a5539','#92694d','#6b4c30'];ctx.fillStyle=c[Math.floor(srand(x+.3,y+.3)*c.length)];}
|
||||
ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(2,function(ctx,s){fill(ctx,s,['#866043','#7a5539','#92694d','#6b4c30','#7e5b3f']);});
|
||||
drawTex(3,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
var c=['#828282','#777','#8e8e8e','#6e6e6e','#999'];
|
||||
var ci=Math.floor(srand(x+.5,y+.5)*c.length);
|
||||
if(srand(x*3.1+.7,y*2.3+.9)>.85)ci=3;
|
||||
ctx.fillStyle=c[ci];ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(4,function(ctx,s){fill(ctx,s,['#dbc896','#d0bd8a','#e5d3a3','#c9b07e','#d6c490']);});
|
||||
drawTex(5,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
var c=['#6b4423','#7b5433','#5b3413','#7e5a38'];
|
||||
var ci=Math.floor(srand(x+.4,y+.4)*c.length);
|
||||
if((x+Math.floor(srand(x*.1,y*.7)*2))%4<2)ci=0;
|
||||
ctx.fillStyle=c[ci];ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(6,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
var dx=x-7.5,dy=y-7.5,r=Math.sqrt(dx*dx+dy*dy);
|
||||
if(r<2)ctx.fillStyle='#5a3a15';
|
||||
else if(r<5)ctx.fillStyle=srand(x+.6,y+.6)>.5?'#b8945f':'#a0804a';
|
||||
else ctx.fillStyle=srand(x+.7,y+.7)>.5?'#c8a46f':'#b08850';
|
||||
ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(7,function(ctx,s){fill(ctx,s,['#3a7a1a','#4a8c28','#2e6e14','#55a035','#3d8020','#488a25']);});
|
||||
drawTex(8,function(ctx,s){fill(ctx,s,['#efeff0','#e4e4e8','#f5f5f8','#dcdce0','#eaeaee']);});
|
||||
drawTex(9,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
if(y<3)ctx.fillStyle=srand(x+.8,y+.8)>.5?'#efeff0':'#ddd';
|
||||
else if(y<5)ctx.fillStyle=srand(x+.9,y+.9)>.5?'#a09888':'#e0e0e0';
|
||||
else{var c=['#866043','#7a5539','#92694d','#6b4c30'];ctx.fillStyle=c[Math.floor(srand(x+1,y+1)*c.length)];}
|
||||
ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(10,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
var c=['#120820','#1a0c30','#0d0518','#150928'];
|
||||
ctx.fillStyle=srand(x*2.7+.3,y*3.1+.7)>.9?'#2a1848':c[Math.floor(srand(x+1.1,y+1.1)*c.length)];
|
||||
ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(11,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
var c=['#f0c800','#e8be10','#f8d520','#ddb408','#fce040'];
|
||||
var ci=Math.floor(srand(x+1.2,y+1.2)*c.length);
|
||||
if(x===0||x===15||y===0||y===15)ci=3;
|
||||
if((x===1||x===14||y===1||y===14)&&srand(x*1.5,y*1.5)>.7)ci=3;
|
||||
ctx.fillStyle=c[ci];ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(12,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
var n=srand(x+1.3,y+1.3);
|
||||
ctx.fillStyle=n>.7?'#b0f0ff':n>.4?'#80d8f0':'#60c0e8';
|
||||
ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(13,function(ctx,s){fill(ctx,s,['#333','#222','#444','#1a1a1a','#3a3a3a','#2a2a2a']);});
|
||||
drawTex(14,function(ctx,s){fill(ctx,s,['#e8dcc8','#d8ccb0','#f0e4d4','#c8b898','#e0d4c0']);});
|
||||
drawTex(15,function(ctx,s){
|
||||
for(var y=0;y<s;y++)for(var x=0;x<s;x++){
|
||||
if(y%4===0||(y<8?x%8===0:(x+4)%8===0))ctx.fillStyle='#bcac9c';
|
||||
else{var c=['#8e4438','#994c40','#7a3830','#a05548'];ctx.fillStyle=c[Math.floor(srand(x+1.5,y+1.5)*c.length)];}
|
||||
ctx.fillRect(x,y,1,1);
|
||||
}
|
||||
});
|
||||
drawTex(16,function(ctx,s){fill(ctx,s,['#c8e8ff','#b0d8f8','#d0eeff','#a8d0f0']);});
|
||||
drawTex(17,function(ctx,s){fill(ctx,s,['#ff4400','#ff6600','#ee3300','#ff5500','#dd2200']);});
|
||||
var tex=new THREE.CanvasTexture(atlasCanvas);
|
||||
tex.magFilter=THREE.NearestFilter;
|
||||
tex.minFilter=THREE.NearestFilter;
|
||||
tex.colorSpace=THREE.SRGBColorSpace;
|
||||
return tex;
|
||||
}
|
||||
|
||||
var FT={};
|
||||
FT[B.GRASS]={top:0,side:1,bottom:2};FT[B.DIRT]={top:2,side:2,bottom:2};
|
||||
FT[B.STONE]={top:3,side:3,bottom:3};FT[B.SAND]={top:4,side:4,bottom:4};
|
||||
FT[B.WATER]={top:16,side:16,bottom:16};FT[B.WOOD]={top:6,side:5,bottom:6};
|
||||
FT[B.LEAVES]={top:7,side:7,bottom:7};FT[B.SNOW]={top:8,side:9,bottom:2};
|
||||
FT[B.OBSIDIAN]={top:10,side:10,bottom:10};FT[B.GOLD]={top:11,side:11,bottom:11};
|
||||
FT[B.CRYSTAL]={top:12,side:12,bottom:12};FT[B.BEDROCK]={top:13,side:13,bottom:13};
|
||||
FT[B.BONE]={top:14,side:14,bottom:14};FT[B.BRICK]={top:15,side:15,bottom:15};
|
||||
FT[B.GLASS]={top:16,side:16,bottom:16};FT[B.LAVA]={top:17,side:17,bottom:17};
|
||||
|
||||
function texUV(idx){
|
||||
var u0=(idx%16)/16,v0=1-(Math.floor(idx/16)+1)/16;
|
||||
return{u0:u0,v0:v0,u1:u0+1/16,v1:v0+1/16};
|
||||
}
|
||||
|
||||
var FACES=[
|
||||
{dir:[1,0,0],verts:[[1,0,0],[1,1,0],[1,1,1],[1,0,1]],norm:[1,0,0],face:'side'},
|
||||
{dir:[-1,0,0],verts:[[0,0,1],[0,1,1],[0,1,0],[0,0,0]],norm:[-1,0,0],face:'side'},
|
||||
{dir:[0,1,0],verts:[[0,1,1],[1,1,1],[1,1,0],[0,1,0]],norm:[0,1,0],face:'top'},
|
||||
{dir:[0,-1,0],verts:[[0,0,0],[1,0,0],[1,0,1],[0,0,1]],norm:[0,-1,0],face:'bottom'},
|
||||
{dir:[0,0,1],verts:[[1,0,1],[1,1,1],[0,1,1],[0,0,1]],norm:[0,0,1],face:'side'},
|
||||
{dir:[0,0,-1],verts:[[0,0,0],[0,1,0],[1,1,0],[1,0,0]],norm:[0,0,-1],face:'side'}
|
||||
];
|
||||
|
||||
function Chunk(cx,cz,world){
|
||||
this.cx=cx;this.cz=cz;this.world=world;
|
||||
this.blocks=new Uint8Array(CHUNK*CHUNK_H*CHUNK);
|
||||
this.mesh=null;this.waterMesh=null;this.dirty=true;this.generated=false;
|
||||
}
|
||||
Chunk.prototype.idx=function(x,y,z){return(y*CHUNK+z)*CHUNK+x;};
|
||||
Chunk.prototype.getBlock=function(x,y,z){
|
||||
if(x<0||x>=CHUNK||z<0||z>=CHUNK||y<0||y>=CHUNK_H)return B.AIR;
|
||||
return this.blocks[this.idx(x,y,z)];
|
||||
};
|
||||
Chunk.prototype.setBlock=function(x,y,z,t){
|
||||
if(x<0||x>=CHUNK||z<0||z>=CHUNK||y<0||y>=CHUNK_H)return;
|
||||
this.blocks[this.idx(x,y,z)]=t;this.dirty=true;
|
||||
};
|
||||
Chunk.prototype.generate=function(){
|
||||
if(this.generated)return;this.generated=true;
|
||||
var ox=this.cx*CHUNK,oz=this.cz*CHUNK;
|
||||
for(var lx=0;lx<CHUNK;lx++)for(var lz=0;lz<CHUNK;lz++){
|
||||
var wx=ox+lx,wz=oz+lz,h=terrainH(wx,wz),biome=getBiome(wx,wz);
|
||||
this.blocks[this.idx(lx,0,lz)]=B.BEDROCK;
|
||||
for(var y=1;y<CHUNK_H;y++){
|
||||
if(y<=h){
|
||||
if(isCave(wx,y,wz)&&y>1&&y<h-1)this.blocks[this.idx(lx,y,lz)]=B.AIR;
|
||||
else if(y===h){
|
||||
if(biome==='desert')this.blocks[this.idx(lx,y,lz)]=B.SAND;
|
||||
else if(biome==='tundra')this.blocks[this.idx(lx,y,lz)]=B.SNOW;
|
||||
else this.blocks[this.idx(lx,y,lz)]=B.GRASS;
|
||||
}else if(y>h-4){
|
||||
this.blocks[this.idx(lx,y,lz)]=biome==='desert'?B.SAND:B.DIRT;
|
||||
}else this.blocks[this.idx(lx,y,lz)]=B.STONE;
|
||||
}else if(y<=SEA)this.blocks[this.idx(lx,y,lz)]=B.WATER;
|
||||
}
|
||||
}
|
||||
for(var lx=0;lx<CHUNK;lx++)for(var lz=0;lz<CHUNK;lz++){
|
||||
var wx=ox+lx,wz=oz+lz;
|
||||
if(!shouldTree(wx,wz))continue;
|
||||
var h=terrainH(wx,wz);if(h<=SEA)continue;
|
||||
var th=treeH(wx,wz);
|
||||
for(var y=h+1;y<=h+th&&y<CHUNK_H;y++)this.blocks[this.idx(lx,y,lz)]=B.WOOD;
|
||||
var cb=h+th-1,ct=h+th+2;
|
||||
for(var dy=cb;dy<=ct;dy++){
|
||||
var r=dy<=h+th?2:1;
|
||||
for(var dx=-r;dx<=r;dx++)for(var dz=-r;dz<=r;dz++){
|
||||
if(dx===0&&dz===0&&dy<=h+th)continue;
|
||||
if(Math.abs(dx)===r&&Math.abs(dz)===r&&srand(wx+dx,wz+dz)>.6)continue;
|
||||
var nx=lx+dx,nz=lz+dz;
|
||||
if(nx>=0&&nx<CHUNK&&nz>=0&&nz<CHUNK&&dy<CHUNK_H&&this.blocks[this.idx(nx,dy,nz)]===B.AIR)
|
||||
this.blocks[this.idx(nx,dy,nz)]=B.LEAVES;
|
||||
}
|
||||
}
|
||||
}
|
||||
this.applyStructures(ox,oz);
|
||||
};
|
||||
Chunk.prototype.applyStructures=function(ox,oz){
|
||||
for(var si=0;si<STRUCTURES.length;si++){
|
||||
var s=STRUCTURES[si];
|
||||
if(ox+CHUNK<=s.minX||ox>s.maxX||oz+CHUNK<=s.minZ||oz>s.maxZ)continue;
|
||||
for(var lx=0;lx<CHUNK;lx++){
|
||||
var wx=ox+lx;if(wx<s.minX||wx>s.maxX)continue;
|
||||
for(var lz=0;lz<CHUNK;lz++){
|
||||
var wz=oz+lz;if(wz<s.minZ||wz>s.maxZ)continue;
|
||||
for(var wy=s.minY;wy<=s.maxY;wy++){
|
||||
if(wy<0||wy>=CHUNK_H)continue;
|
||||
var bt=s.gen(wx,wy,wz);
|
||||
if(bt>0)this.blocks[this.idx(lx,wy,lz)]=bt;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
Chunk.prototype.getNeighborBlock=function(lx,y,lz){
|
||||
if(lx>=0&&lx<CHUNK&&lz>=0&&lz<CHUNK){
|
||||
if(y<0||y>=CHUNK_H)return B.AIR;
|
||||
return this.blocks[this.idx(lx,y,lz)];
|
||||
}
|
||||
return this.world.getBlock(this.cx*CHUNK+lx,y,this.cz*CHUNK+lz);
|
||||
};
|
||||
Chunk.prototype.computeAO=function(x,y,z,face){
|
||||
var ao=[0,0,0,0],d=face.dir,t1,t2;
|
||||
if(d[0]!==0){t1=[0,1,0];t2=[0,0,1];}
|
||||
else if(d[1]!==0){t1=[1,0,0];t2=[0,0,1];}
|
||||
else{t1=[1,0,0];t2=[0,1,0];}
|
||||
var self=this;
|
||||
function s(dx,dy,dz){return isSolid(self.getNeighborBlock(x+d[0]+dx,y+d[1]+dy,z+d[2]+dz))?1:0;}
|
||||
var e0=s(-t1[0],-t1[1],-t1[2]),e1=s(t1[0],t1[1],t1[2]);
|
||||
var e2=s(-t2[0],-t2[1],-t2[2]),e3=s(t2[0],t2[1],t2[2]);
|
||||
var s00=s(-t1[0]-t2[0],-t1[1]-t2[1],-t1[2]-t2[2]);
|
||||
var s10=s(t1[0]-t2[0],t1[1]-t2[1],t1[2]-t2[2]);
|
||||
var s01=s(-t1[0]+t2[0],-t1[1]+t2[1],-t1[2]+t2[2]);
|
||||
var s11=s(t1[0]+t2[0],t1[1]+t2[1],t1[2]+t2[2]);
|
||||
function vao(a,b,c){return(a&&b)?0:(3-(a+b+c))/3;}
|
||||
ao[0]=vao(e0,e2,s00);ao[1]=vao(e1,e2,s10);ao[2]=vao(e1,e3,s11);ao[3]=vao(e0,e3,s01);
|
||||
return ao;
|
||||
};
|
||||
Chunk.prototype.buildMesh=function(mat,wmat){
|
||||
if(!this.dirty)return;this.dirty=false;
|
||||
var pos=[],norms=[],uvs=[],cols=[],idx=[];
|
||||
var wp=[],wn=[],wu=[],wc=[],wi=[];
|
||||
for(var y=0;y<CHUNK_H;y++)for(var z=0;z<CHUNK;z++)for(var x=0;x<CHUNK;x++){
|
||||
var bt=this.blocks[this.idx(x,y,z)];if(bt===B.AIR)continue;
|
||||
var isW=bt===B.WATER,ft=FT[bt];if(!ft)continue;
|
||||
for(var fi=0;fi<6;fi++){
|
||||
var f=FACES[fi];
|
||||
var nx=x+f.dir[0],ny=y+f.dir[1],nz=z+f.dir[2];
|
||||
var nb=this.getNeighborBlock(nx,ny,nz);
|
||||
var show=isW?(nb===B.AIR||(nb!==B.WATER&&TRANS.has(nb))):TRANS.has(nb);
|
||||
if(!show)continue;
|
||||
var tp=isW?wp:pos,tn=isW?wn:norms,tu=isW?wu:uvs,tc=isW?wc:cols,ti=isW?wi:idx;
|
||||
var vc=tp.length/3;
|
||||
var uv=texUV(ft[f.face]);
|
||||
var ao=isW?[1,1,1,1]:this.computeAO(x,y,z,f);
|
||||
for(var vi=0;vi<4;vi++){
|
||||
var v=f.verts[vi];tp.push(x+v[0],y+v[1],z+v[2]);
|
||||
tn.push(f.norm[0],f.norm[1],f.norm[2]);
|
||||
var a=0.4+0.6*ao[vi];tc.push(a,a,a);
|
||||
}
|
||||
tu.push(uv.u0,uv.v0,uv.u1,uv.v0,uv.u1,uv.v1,uv.u0,uv.v1);
|
||||
if(ao[0]+ao[2]>ao[1]+ao[3])ti.push(vc,vc+1,vc+2,vc,vc+2,vc+3);
|
||||
else ti.push(vc+1,vc+2,vc+3,vc+1,vc+3,vc);
|
||||
}
|
||||
}
|
||||
if(this.mesh){this.world.scene.remove(this.mesh);this.mesh.geometry.dispose();}
|
||||
if(this.waterMesh){this.world.scene.remove(this.waterMesh);this.waterMesh.geometry.dispose();}
|
||||
this.mesh=null;this.waterMesh=null;
|
||||
if(pos.length>0){
|
||||
var g=new THREE.BufferGeometry();
|
||||
g.setAttribute('position',new THREE.Float32BufferAttribute(pos,3));
|
||||
g.setAttribute('normal',new THREE.Float32BufferAttribute(norms,3));
|
||||
g.setAttribute('uv',new THREE.Float32BufferAttribute(uvs,2));
|
||||
g.setAttribute('color',new THREE.Float32BufferAttribute(cols,3));
|
||||
g.setIndex(idx);
|
||||
this.mesh=new THREE.Mesh(g,mat);
|
||||
this.mesh.position.set(this.cx*CHUNK,0,this.cz*CHUNK);
|
||||
this.world.scene.add(this.mesh);
|
||||
}
|
||||
if(wp.length>0){
|
||||
var g=new THREE.BufferGeometry();
|
||||
g.setAttribute('position',new THREE.Float32BufferAttribute(wp,3));
|
||||
g.setAttribute('normal',new THREE.Float32BufferAttribute(wn,3));
|
||||
g.setAttribute('uv',new THREE.Float32BufferAttribute(wu,2));
|
||||
g.setAttribute('color',new THREE.Float32BufferAttribute(wc,3));
|
||||
g.setIndex(wi);
|
||||
this.waterMesh=new THREE.Mesh(g,wmat);
|
||||
this.waterMesh.position.set(this.cx*CHUNK,0,this.cz*CHUNK);
|
||||
this.waterMesh.renderOrder=1;
|
||||
this.world.scene.add(this.waterMesh);
|
||||
}
|
||||
};
|
||||
Chunk.prototype.dispose=function(){
|
||||
if(this.mesh){this.world.scene.remove(this.mesh);this.mesh.geometry.dispose();this.mesh=null;}
|
||||
if(this.waterMesh){this.world.scene.remove(this.waterMesh);this.waterMesh.geometry.dispose();this.waterMesh=null;}
|
||||
};
|
||||
|
||||
var STRUCTURES=[];
|
||||
function buildStructures(){
|
||||
var cY=80;
|
||||
STRUCTURES.push({
|
||||
minX:-25,maxX:25,minY:cY-5,maxY:cY+45,minZ:50,maxZ:100,
|
||||
gen:function(wx,wy,wz){
|
||||
var x=wx,y=wy,z=wz-75,ax=Math.abs(x),az=Math.abs(z);
|
||||
if(y>=cY-5&&y<=cY-1&&ax<=22&&az<=22)return B.OBSIDIAN;
|
||||
if(y>=cY&&y<=cY+1&&ax<=20&&az<=20)return B.STONE;
|
||||
if(y>=cY+2&&y<=cY+14&&ax<=16&&az<=16&&(ax>=15||az>=15)){
|
||||
if(y===cY+14&&(ax+az)%2===0)return B.STONE;
|
||||
if(y<cY+14){
|
||||
if(y>=cY+5&&y<=cY+7&&az>=15&&ax<3)return 0;
|
||||
return B.STONE;
|
||||
}
|
||||
}
|
||||
var towers=[[-14,-14],[14,-14],[-14,14],[14,14]];
|
||||
for(var ti=0;ti<4;ti++){
|
||||
var tx=towers[ti][0],tz=towers[ti][1];
|
||||
var dx=x-tx,dz2=z-tz,r2=dx*dx+dz2*dz2;
|
||||
if(r2<=20&&y>=cY+2&&y<=cY+22)return B.BRICK;
|
||||
if(r2<=30&&y>cY+22&&y<=cY+24)return B.STONE;
|
||||
if(r2<=5&&y>cY+24&&y<=cY+32)return B.CRYSTAL;
|
||||
if(r2<=1&&y>cY+32&&y<=cY+35)return B.GOLD;
|
||||
}
|
||||
if(ax<=7&&az<=7&&y>=cY+2&&y<=cY+18){
|
||||
if(ax>=6||az>=6)return B.BRICK;
|
||||
if(y===cY+2)return B.GOLD;
|
||||
if(y===cY+18&&(ax+az)%2===0)return B.GOLD;
|
||||
}
|
||||
if(y>=cY-8&&y<cY-5&&ax<=22&&az<=22){
|
||||
if((ax+az)%5===0||srand(wx*.1,wz*.1)>.92)return B.CRYSTAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
var tX=70,tZ=-10,tB=30;
|
||||
STRUCTURES.push({
|
||||
minX:tX-30,maxX:tX+30,minY:tB-5,maxY:tB+75,minZ:tZ-30,maxZ:tZ+30,
|
||||
gen:function(wx,wy,wz){
|
||||
var dx=wx-tX,dz=wz-tZ,d2=dx*dx+dz*dz,y=wy;
|
||||
if(y>=tB&&y<=tB+55){
|
||||
var tr=Math.max(1,5-Math.floor((y-tB)/15));
|
||||
if(d2<=tr*tr)return B.WOOD;
|
||||
if(y<=tB+5&&d2<=tr*tr+4&&srand(wx,wz)>.3)return B.WOOD;
|
||||
}
|
||||
for(var i=0;i<6;i++){
|
||||
var angle=(i/6)*Math.PI*2+0.5;
|
||||
var bY=tB+25+i*5,bL=12-i;
|
||||
for(var d=3;d<bL;d++){
|
||||
var bx=tX+Math.round(Math.cos(angle)*d);
|
||||
var bz=tZ+Math.round(Math.sin(angle)*d);
|
||||
var by=bY+Math.round(d*0.25);
|
||||
if(Math.abs(wx-bx)<=1&&Math.abs(wz-bz)<=1&&Math.abs(wy-by)<=0)
|
||||
if(Math.abs(wx-bx)+Math.abs(wz-bz)<=1)return B.WOOD;
|
||||
}
|
||||
}
|
||||
var cc=tB+50,cdy=(y-cc)*1.3,cr2=22*22;
|
||||
if(d2+cdy*cdy<=cr2&&y>tB+35){
|
||||
if(noise.noise3(wx*.15,wy*.15,wz*.15)<.3)return B.LEAVES;
|
||||
}
|
||||
if(y>=tB&&y<=tB+55&&d2<=36&&srand(wx*7.1+wy*3.3,wz*5.7)>.97)return B.CRYSTAL;
|
||||
if(y>=tB-5&&y<tB){
|
||||
for(var i=0;i<8;i++){
|
||||
var a=(i/8)*Math.PI*2,rl=12+Math.floor(srand(i,0)*6);
|
||||
for(var d=4;d<rl;d++){
|
||||
var rx=tX+Math.round(Math.cos(a)*d),rz=tZ+Math.round(Math.sin(a)*d);
|
||||
var ry=tB-Math.floor((d-4)*.4);
|
||||
if(Math.abs(wx-rx)<=1&&Math.abs(wz-rz)<=1&&wy===ry)return B.WOOD;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
var dX=-55,dZ=55,dY=38;
|
||||
STRUCTURES.push({
|
||||
minX:dX-10,maxX:dX+45,minY:dY-3,maxY:dY+18,minZ:dZ-18,maxZ:dZ+18,
|
||||
gen:function(wx,wy,wz){
|
||||
var lx=wx-dX,ly=wy-dY,lz=wz-dZ;
|
||||
if(lx>=0&&lx<=38){
|
||||
var sy=Math.round(Math.sin(lx*.08)*2),sz=Math.round(Math.sin(lx*.12)*1.5);
|
||||
if(ly===sy&&Math.abs(lz-sz)<=0)return B.BONE;
|
||||
if(lx<35&&ly===sy+1&&lz===sz&&lx%3===0)return B.BONE;
|
||||
}
|
||||
if(lx>=-5&&lx<=3&&ly>=0&&ly<=5&&Math.abs(lz)<=3){
|
||||
if(ly===3&&lx===-3&&(lz===1||lz===-1))return B.LAVA;
|
||||
if(ly>=0&&ly<=4&&lx>=-5&&lx<=1&&(Math.abs(lz)===2||ly===0||ly===4||lx===-5||lx===1))return B.BONE;
|
||||
if(lx<=-3&&ly>=1&&ly<=3&&Math.abs(lz)<=1)return B.BONE;
|
||||
}
|
||||
for(var i=0;i<7;i++){
|
||||
var rx=6+i*4;
|
||||
if(lx===rx||lx===rx+1){
|
||||
var sy2=Math.round(Math.sin(rx*.08)*2),sz2=Math.round(Math.sin(rx*.12)*1.5);
|
||||
for(var r=0;r<=5;r++){
|
||||
var ry=sy2+Math.round(Math.sin(r*Math.PI/5)*5);
|
||||
var rz=sz2+Math.round(Math.cos(r*Math.PI/5)*4);
|
||||
if(ly===ry&&(lz===rz||lz===sz2*2-rz))return B.BONE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(lx>=10&&lx<=12){
|
||||
for(var d=0;d<14;d++){
|
||||
var wy2=dY+Math.round(Math.sin(10*.08)*2)+3+Math.round(d*.3);
|
||||
var wz2=dZ+(lz>0?d+4:-d-4);
|
||||
if(Math.abs(wy-wy2)<=0&&Math.abs(wz-wz2)<=0&&lx>=10&&lx<=11)return B.BONE;
|
||||
}
|
||||
}
|
||||
if(lx>=32&&lx<=42){
|
||||
var ti=lx-32;
|
||||
var ty=Math.round(Math.sin(ti*.3)*2),tz=Math.round(Math.sin(ti*.2)*3);
|
||||
if(ly===ty&&Math.abs(lz-tz)<=(ti<5?1:0))return B.BONE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
var sX=-10,sZ=-65;
|
||||
STRUCTURES.push({
|
||||
minX:sX-12,maxX:sX+12,minY:25,maxY:90,minZ:sZ-12,maxZ:sZ+12,
|
||||
gen:function(wx,wy,wz){
|
||||
var spires=[[0,0,35],[-6,-4,25],[5,-6,28],[-4,7,22],[7,5,18]];
|
||||
for(var i=0;i<spires.length;i++){
|
||||
var sp=spires[i],sdx=wx-(sX+sp[0]),sdz=wz-(sZ+sp[1]),r2=sdx*sdx+sdz*sdz;
|
||||
var baseY=terrainH(sX+sp[0],sZ+sp[1]),topY=baseY+sp[2];
|
||||
if(wy>=baseY&&wy<=topY){
|
||||
var t=(wy-baseY)/sp[2],maxR=(1-t)*3+.5;
|
||||
if(r2<=maxR*maxR)return B.CRYSTAL;
|
||||
}
|
||||
}
|
||||
var ddx=wx-sX,ddz=wz-sZ;
|
||||
if(ddx*ddx+ddz*ddz<=64){
|
||||
var bY=terrainH(wx,wz);
|
||||
if((wy===bY+1||wy===bY+2)&&srand(wx*3.3,wz*7.7)>.85)return B.CRYSTAL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
var rX=-75,rZ=-35,rY=32;
|
||||
STRUCTURES.push({
|
||||
minX:rX-18,maxX:rX+18,minY:rY,maxY:rY+14,minZ:rZ-18,maxZ:rZ+18,
|
||||
gen:function(wx,wy,wz){
|
||||
var lx=wx-rX,lz=wz-rZ,ly=wy-rY;
|
||||
if(ly===0&&Math.abs(lx)<=15&&Math.abs(lz)<=15){
|
||||
if(Math.abs(lx)>=14||Math.abs(lz)>=14)return B.STONE;
|
||||
if(Math.abs(lx)<=2&&Math.abs(lz)<=2)return B.GOLD;
|
||||
}
|
||||
if(Math.abs(lx)<=15&&Math.abs(lz)<=15&&(Math.abs(lx)>=13||Math.abs(lz)>=13)){
|
||||
var wh=Math.floor(srand(wx*.5,wz*.5)*6)+2;
|
||||
if(ly>0&&ly<=wh&&srand(wx*1.1+ly*2.2,wz*3.3)>.15)return B.STONE;
|
||||
}
|
||||
var pills=[[-10,-10],[10,-10],[-10,10],[10,10],[-10,0],[10,0],[0,-10],[0,10]];
|
||||
for(var i=0;i<pills.length;i++){
|
||||
var px=pills[i][0],pz=pills[i][1];
|
||||
if(Math.abs(lx-px)<=1&&Math.abs(lz-pz)<=1){
|
||||
var ph=Math.floor(srand(px+100,pz+100)*5)+6;
|
||||
if(ly>0&&ly<=ph)return B.STONE;
|
||||
}
|
||||
}
|
||||
if(Math.abs(lx)<=2&&Math.abs(lz)<=2&&ly>=1&&ly<=3){
|
||||
if(ly<=2)return B.OBSIDIAN;return B.GOLD;
|
||||
}
|
||||
if(ly>=1&&ly<=3&&Math.abs(lx)<=15&&Math.abs(lz)<=15&&srand(wx*2.2,wz*4.4+ly)>.96)return B.LEAVES;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
var pX=30,pZ=-45;
|
||||
STRUCTURES.push({
|
||||
minX:pX-6,maxX:pX+6,minY:25,maxY:60,minZ:pZ-2,maxZ:pZ+2,
|
||||
gen:function(wx,wy,wz){
|
||||
var lx=wx-pX,lz=wz-pZ,baseY=terrainH(pX,pZ),ly=wy-baseY;
|
||||
if(Math.abs(lz)<=1){
|
||||
if(Math.abs(lx)===5&&ly>=0&&ly<=18)return B.OBSIDIAN;
|
||||
if(ly===0&&Math.abs(lx)<=5)return B.OBSIDIAN;
|
||||
if(ly===18&&Math.abs(lx)<=5)return B.OBSIDIAN;
|
||||
if(ly>=1&&ly<=17&&Math.abs(lx)<5&&lz===0)return B.CRYSTAL;
|
||||
if(ly===19&&Math.abs(lx)<=3&&lz===0)return B.GOLD;
|
||||
}
|
||||
if(ly===-1&&Math.abs(lx)<=6&&Math.abs(lz)<=2)return B.STONE;
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
}
|
||||
buildStructures();
|
||||
|
||||
function World(scene){
|
||||
this.scene=scene;this.chunks=new Map();
|
||||
}
|
||||
World.prototype.key=function(cx,cz){return cx+','+cz;};
|
||||
World.prototype.getChunk=function(cx,cz){return this.chunks.get(this.key(cx,cz));};
|
||||
World.prototype.getBlock=function(wx,wy,wz){
|
||||
if(wy<0||wy>=CHUNK_H)return B.AIR;
|
||||
var cx=Math.floor(wx/CHUNK),cz=Math.floor(wz/CHUNK);
|
||||
var c=this.getChunk(cx,cz);if(!c||!c.generated)return B.AIR;
|
||||
var lx=((wx%CHUNK)+CHUNK)%CHUNK,lz=((wz%CHUNK)+CHUNK)%CHUNK;
|
||||
return c.getBlock(lx,wy,lz);
|
||||
};
|
||||
World.prototype.setBlock=function(wx,wy,wz,type){
|
||||
if(wy<0||wy>=CHUNK_H)return;
|
||||
var cx=Math.floor(wx/CHUNK),cz=Math.floor(wz/CHUNK);
|
||||
var c=this.getChunk(cx,cz);if(!c)return;
|
||||
var lx=((wx%CHUNK)+CHUNK)%CHUNK,lz=((wz%CHUNK)+CHUNK)%CHUNK;
|
||||
c.setBlock(lx,wy,lz,type);
|
||||
if(lx===0){var n=this.getChunk(cx-1,cz);if(n)n.dirty=true;}
|
||||
if(lx===CHUNK-1){var n=this.getChunk(cx+1,cz);if(n)n.dirty=true;}
|
||||
if(lz===0){var n=this.getChunk(cx,cz-1);if(n)n.dirty=true;}
|
||||
if(lz===CHUNK-1){var n=this.getChunk(cx,cz+1);if(n)n.dirty=true;}
|
||||
};
|
||||
World.prototype.update=function(px,pz,mat,wmat){
|
||||
var pcx=Math.floor(px/CHUNK),pcz=Math.floor(pz/CHUNK);
|
||||
var self=this;
|
||||
this.chunks.forEach(function(chunk,key){
|
||||
var dx=chunk.cx-pcx,dz=chunk.cz-pcz;
|
||||
if(Math.abs(dx)>RDIST+1||Math.abs(dz)>RDIST+1){chunk.dispose();self.chunks.delete(key);}
|
||||
});
|
||||
var toGen=[];
|
||||
for(var dx=-RDIST;dx<=RDIST;dx++)for(var dz=-RDIST;dz<=RDIST;dz++){
|
||||
if(dx*dx+dz*dz>RDIST*RDIST)continue;
|
||||
var cx=pcx+dx,cz=pcz+dz,k=this.key(cx,cz);
|
||||
if(!this.chunks.has(k))toGen.push({cx:cx,cz:cz,d:dx*dx+dz*dz});
|
||||
}
|
||||
toGen.sort(function(a,b){return a.d-b.d;});
|
||||
var gc=0;
|
||||
for(var i=0;i<toGen.length&&gc<3;i++){
|
||||
var g=toGen[i],chunk=new Chunk(g.cx,g.cz,this);
|
||||
chunk.generate();this.chunks.set(this.key(g.cx,g.cz),chunk);
|
||||
var adj=[[-1,0],[1,0],[0,-1],[0,1]];
|
||||
for(var j=0;j<4;j++){var a=this.getChunk(g.cx+adj[j][0],g.cz+adj[j][1]);if(a)a.dirty=true;}
|
||||
gc++;
|
||||
}
|
||||
var mc=0;
|
||||
this.chunks.forEach(function(chunk){
|
||||
if(mc>=4)return;
|
||||
if(chunk.dirty&&chunk.generated){chunk.buildMesh(mat,wmat);mc++;}
|
||||
});
|
||||
};
|
||||
|
||||
function Player(camera){
|
||||
this.camera=camera;
|
||||
this.pos=new THREE.Vector3(0,60,0);
|
||||
this.vel=new THREE.Vector3();
|
||||
this.yaw=0;this.pitch=0;this.onGround=false;
|
||||
this.keys={};this.speed=6;this.sens=0.002;this.locked=false;
|
||||
var self=this;
|
||||
document.addEventListener('keydown',function(e){self.keys[e.code]=true;if(e.code==='Space')e.preventDefault();});
|
||||
document.addEventListener('keyup',function(e){self.keys[e.code]=false;});
|
||||
document.addEventListener('mousemove',function(e){
|
||||
if(!self.locked)return;
|
||||
self.yaw-=e.movementX*self.sens;
|
||||
self.pitch-=e.movementY*self.sens;
|
||||
self.pitch=Math.max(-Math.PI/2+.01,Math.min(Math.PI/2-.01,self.pitch));
|
||||
});
|
||||
}
|
||||
Player.prototype.update=function(dt,world){
|
||||
var fw=new THREE.Vector3(-Math.sin(this.yaw),0,-Math.cos(this.yaw));
|
||||
var rt=new THREE.Vector3(Math.cos(this.yaw),0,-Math.sin(this.yaw));
|
||||
var mv=new THREE.Vector3();
|
||||
if(this.keys['KeyW'])mv.add(fw);if(this.keys['KeyS'])mv.sub(fw);
|
||||
if(this.keys['KeyA'])mv.sub(rt);if(this.keys['KeyD'])mv.add(rt);
|
||||
if(mv.lengthSq()>0)mv.normalize().multiplyScalar(this.speed);
|
||||
this.vel.x=mv.x;this.vel.z=mv.z;
|
||||
this.vel.y-=GRAV*dt;
|
||||
if(this.keys['Space']&&this.onGround){this.vel.y=JVEL;this.onGround=false;}
|
||||
var steps=4,sdt=dt/steps;
|
||||
for(var s=0;s<steps;s++){
|
||||
this.pos.x+=this.vel.x*sdt;this.collide('x',world);
|
||||
this.pos.y+=this.vel.y*sdt;this.collide('y',world);
|
||||
this.pos.z+=this.vel.z*sdt;this.collide('z',world);
|
||||
}
|
||||
if(this.pos.y<-10){this.pos.set(0,60,0);this.vel.set(0,0,0);}
|
||||
this.camera.position.set(this.pos.x,this.pos.y+PH,this.pos.z);
|
||||
var euler=new THREE.Euler(this.pitch,this.yaw,0,'YXZ');
|
||||
this.camera.quaternion.setFromEuler(euler);
|
||||
};
|
||||
Player.prototype.collide=function(axis,world){
|
||||
var hw=PW,hh=PH+.1;
|
||||
var mnx=Math.floor(this.pos.x-hw),mxx=Math.floor(this.pos.x+hw);
|
||||
var mny=Math.floor(this.pos.y),mxy=Math.floor(this.pos.y+hh);
|
||||
var mnz=Math.floor(this.pos.z-hw),mxz=Math.floor(this.pos.z+hw);
|
||||
for(var bx=mnx;bx<=mxx;bx++)for(var by=mny;by<=mxy;by++)for(var bz=mnz;bz<=mxz;bz++){
|
||||
if(!isSolid(world.getBlock(bx,by,bz)))continue;
|
||||
var ov=this.overlap(bx,by,bz);if(!ov)continue;
|
||||
if(axis==='x'){this.pos.x+=ov.x;this.vel.x=0;}
|
||||
else if(axis==='y'){this.pos.y+=ov.y;if(ov.y>0){this.onGround=true;this.vel.y=0;}else if(ov.y<0)this.vel.y=0;}
|
||||
else{this.pos.z+=ov.z;this.vel.z=0;}
|
||||
}
|
||||
};
|
||||
Player.prototype.overlap=function(bx,by,bz){
|
||||
var hw=PW,hh=PH+.1;
|
||||
var ox=Math.min(this.pos.x+hw-bx,bx+1-(this.pos.x-hw));
|
||||
var oy=Math.min(this.pos.y+hh-by,by+1-this.pos.y);
|
||||
var oz=Math.min(this.pos.z+hw-bz,bz+1-(this.pos.z-hw));
|
||||
if(ox<=0||oy<=0||oz<=0)return null;
|
||||
var mn=Math.min(ox,oy,oz),r={x:0,y:0,z:0};
|
||||
if(mn===ox)r.x=(this.pos.x<bx+.5)?-ox:ox;
|
||||
else if(mn===oy)r.y=(this.pos.y+hh/2<by+.5)?-oy:oy;
|
||||
else r.z=(this.pos.z<bz+.5)?-oz:oz;
|
||||
return r;
|
||||
};
|
||||
Player.prototype.getForward=function(){
|
||||
return new THREE.Vector3(-Math.sin(this.yaw)*Math.cos(this.pitch),Math.sin(this.pitch),-Math.cos(this.yaw)*Math.cos(this.pitch)).normalize();
|
||||
};
|
||||
|
||||
function castRay(origin,dir,world,maxD){
|
||||
var x=Math.floor(origin.x),y=Math.floor(origin.y),z=Math.floor(origin.z);
|
||||
var sx=dir.x>=0?1:-1,sy=dir.y>=0?1:-1,sz=dir.z>=0?1:-1;
|
||||
var tmx=dir.x!==0?((dir.x>0?x+1:x)-origin.x)/dir.x:1e9;
|
||||
var tmy=dir.y!==0?((dir.y>0?y+1:y)-origin.y)/dir.y:1e9;
|
||||
var tmz=dir.z!==0?((dir.z>0?z+1:z)-origin.z)/dir.z:1e9;
|
||||
var tdx=dir.x!==0?Math.abs(1/dir.x):1e9;
|
||||
var tdy=dir.y!==0?Math.abs(1/dir.y):1e9;
|
||||
var tdz=dir.z!==0?Math.abs(1/dir.z):1e9;
|
||||
var px=x,py=y,pz=z,dist=0;
|
||||
while(dist<maxD){
|
||||
var bt=world.getBlock(x,y,z);
|
||||
if(isSolid(bt))return{hit:true,x:x,y:y,z:z,px:px,py:py,pz:pz,block:bt};
|
||||
px=x;py=y;pz=z;
|
||||
if(tmx<tmy){
|
||||
if(tmx<tmz){dist=tmx;x+=sx;tmx+=tdx;}
|
||||
else{dist=tmz;z+=sz;tmz+=tdz;}
|
||||
}else{
|
||||
if(tmy<tmz){dist=tmy;y+=sy;tmy+=tdy;}
|
||||
else{dist=tmz;z+=sz;tmz+=tdz;}
|
||||
}
|
||||
}
|
||||
return{hit:false};
|
||||
}
|
||||
|
||||
var scene=new THREE.Scene();
|
||||
scene.background=new THREE.Color(0x87CEEB);
|
||||
scene.fog=new THREE.Fog(0x87CEEB,CHUNK*RDIST*0.6,CHUNK*RDIST*0.95);
|
||||
|
||||
var camera=new THREE.PerspectiveCamera(75,window.innerWidth/window.innerHeight,0.1,CHUNK*RDIST*1.2);
|
||||
var renderer=new THREE.WebGLRenderer({antialias:false});
|
||||
renderer.setSize(window.innerWidth,window.innerHeight);
|
||||
renderer.setPixelRatio(Math.min(window.devicePixelRatio,2));
|
||||
renderer.outputColorSpace=THREE.SRGBColorSpace;
|
||||
document.body.prepend(renderer.domElement);
|
||||
|
||||
scene.add(new THREE.HemisphereLight(0x87CEEB,0x6B4C30,0.6));
|
||||
var sun=new THREE.DirectionalLight(0xfff5e0,1.0);
|
||||
sun.position.set(50,100,30);scene.add(sun);
|
||||
scene.add(new THREE.AmbientLight(0x404060,0.35));
|
||||
|
||||
var tex=buildAtlas();
|
||||
var mat=new THREE.MeshLambertMaterial({map:tex,vertexColors:true,side:THREE.FrontSide});
|
||||
var wmat=new THREE.MeshLambertMaterial({map:tex,vertexColors:true,transparent:true,opacity:0.6,side:THREE.DoubleSide,depthWrite:false});
|
||||
|
||||
var world=new World(scene);
|
||||
var player=new Player(camera);
|
||||
|
||||
var hlBox=new THREE.LineSegments(
|
||||
new THREE.EdgesGeometry(new THREE.BoxGeometry(1.005,1.005,1.005)),
|
||||
new THREE.LineBasicMaterial({color:0x000000,linewidth:2,transparent:true,opacity:0.5})
|
||||
);
|
||||
hlBox.visible=false;scene.add(hlBox);
|
||||
|
||||
var selectedSlot=0;
|
||||
|
||||
function setupHotbar(){
|
||||
var hb=document.getElementById('hotbar');hb.innerHTML='';
|
||||
for(var i=0;i<HOTBAR.length;i++){
|
||||
var slot=document.createElement('div');
|
||||
slot.className='hslot'+(i===0?' sel':'');
|
||||
var num=document.createElement('span');num.className='num';num.textContent=i+1;
|
||||
slot.appendChild(num);
|
||||
var c=document.createElement('canvas');c.width=c.height=16;
|
||||
var ctx=c.getContext('2d');
|
||||
var ft=FT[HOTBAR[i]],ti=ft.top;
|
||||
var sx=(ti%16)*16,sy=Math.floor(ti/16)*16;
|
||||
ctx.drawImage(atlasCanvas,sx,sy,16,16,0,0,16,16);
|
||||
slot.appendChild(c);
|
||||
(function(idx){slot.addEventListener('click',function(e){e.stopPropagation();selectedSlot=idx;updateHotbar();});})(i);
|
||||
hb.appendChild(slot);
|
||||
}
|
||||
}
|
||||
function updateHotbar(){
|
||||
var slots=document.querySelectorAll('.hslot');
|
||||
for(var i=0;i<slots.length;i++)slots[i].className=i===selectedSlot?'hslot sel':'hslot';
|
||||
}
|
||||
|
||||
function spawnPlayer(){
|
||||
var sx=0,sz=0,h=terrainH(sx,sz);
|
||||
for(var si=0;si<STRUCTURES.length;si++){
|
||||
var s=STRUCTURES[si];
|
||||
if(sx>=s.minX&&sx<=s.maxX&&sz>=s.minZ&&sz<=s.maxZ)
|
||||
for(var y=s.maxY;y>=s.minY;y--)if(s.gen(sx,y,sz)>0){h=Math.max(h,y+1);break;}
|
||||
}
|
||||
player.pos.set(sx,h+2,sz);
|
||||
}
|
||||
|
||||
function rebuildNearby(wx,wy,wz){
|
||||
var cx=Math.floor(wx/CHUNK),cz=Math.floor(wz/CHUNK);
|
||||
for(var dx=-1;dx<=1;dx++)for(var dz=-1;dz<=1;dz++){
|
||||
var c=world.getChunk(cx+dx,cz+dz);if(c)c.dirty=true;
|
||||
}
|
||||
}
|
||||
|
||||
var overlay=document.getElementById('overlay');
|
||||
var canvas=renderer.domElement;
|
||||
|
||||
overlay.addEventListener('click',function(){canvas.requestPointerLock();});
|
||||
document.addEventListener('pointerlockchange',function(){
|
||||
player.locked=document.pointerLockElement===canvas;
|
||||
overlay.className=player.locked?'hidden':'';
|
||||
});
|
||||
|
||||
canvas.addEventListener('mousedown',function(e){
|
||||
if(!player.locked)return;
|
||||
var origin=camera.position.clone(),dir=player.getForward();
|
||||
var hit=castRay(origin,dir,world,REACH);
|
||||
if(e.button===0&&hit.hit){
|
||||
world.setBlock(hit.x,hit.y,hit.z,B.AIR);
|
||||
rebuildNearby(hit.x,hit.y,hit.z);
|
||||
}else if(e.button===2&&hit.hit){
|
||||
var ppx=Math.floor(player.pos.x),ppy=Math.floor(player.pos.y),ppz=Math.floor(player.pos.z);
|
||||
var ppy2=Math.floor(player.pos.y+PH);
|
||||
if(hit.px===ppx&&hit.pz===ppz&&(hit.py===ppy||hit.py===ppy2))return;
|
||||
world.setBlock(hit.px,hit.py,hit.pz,HOTBAR[selectedSlot]);
|
||||
rebuildNearby(hit.px,hit.py,hit.pz);
|
||||
}
|
||||
});
|
||||
canvas.addEventListener('contextmenu',function(e){e.preventDefault();});
|
||||
document.addEventListener('keydown',function(e){
|
||||
var n=parseInt(e.key);if(n>=1&&n<=9){selectedSlot=n-1;updateHotbar();}
|
||||
});
|
||||
canvas.addEventListener('wheel',function(e){
|
||||
if(!player.locked)return;
|
||||
selectedSlot=(selectedSlot+(e.deltaY>0?1:-1)+HOTBAR.length)%HOTBAR.length;
|
||||
updateHotbar();
|
||||
});
|
||||
window.addEventListener('resize',function(){
|
||||
camera.aspect=window.innerWidth/window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth,window.innerHeight);
|
||||
});
|
||||
|
||||
setupHotbar();
|
||||
spawnPlayer();
|
||||
|
||||
var clock=new THREE.Clock();
|
||||
function animate(){
|
||||
requestAnimationFrame(animate);
|
||||
var dt=Math.min(clock.getDelta(),0.05);
|
||||
player.update(dt,world);
|
||||
world.update(player.pos.x,player.pos.z,mat,wmat);
|
||||
var origin=camera.position.clone(),dir=player.getForward();
|
||||
var hit=castRay(origin,dir,world,REACH);
|
||||
if(hit.hit){hlBox.position.set(hit.x+.5,hit.y+.5,hit.z+.5);hlBox.visible=true;}
|
||||
else hlBox.visible=false;
|
||||
var p=player.pos;
|
||||
var dbg=document.getElementById('debug');
|
||||
dbg.textContent='XYZ: '+p.x.toFixed(1)+' / '+p.y.toFixed(1)+' / '+p.z.toFixed(1)+
|
||||
'\nChunk: '+Math.floor(p.x/CHUNK)+', '+Math.floor(p.z/CHUNK)+' Loaded: '+world.chunks.size+
|
||||
'\nBlock: '+BNAME[HOTBAR[selectedSlot]];
|
||||
renderer.render(scene,camera);
|
||||
}
|
||||
animate();
|
||||
|
||||
})();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Whitespace-only changes.
@@ -0,0 +1,11 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<title>Mythic Realms — A Voxel Pilgrimage</title>
|
||||
</head>
|
||||
<body>
|
||||
<div id="probe">init</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,628 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 600" width="100%" height="100%">
|
||||
<defs>
|
||||
<!-- ========== ???? ========== -->
|
||||
<linearGradient id="skyGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#16264d"/>
|
||||
<stop offset="22%" stop-color="#3f5d8e"/>
|
||||
<stop offset="48%" stop-color="#c66e58"/>
|
||||
<stop offset="72%" stop-color="#f4ad7a"/>
|
||||
<stop offset="100%" stop-color="#fde2b8"/>
|
||||
</linearGradient>
|
||||
|
||||
<radialGradient id="sunGlow" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stop-color="#fff7d8" stop-opacity="0.95"/>
|
||||
<stop offset="30%" stop-color="#ffd56b" stop-opacity="0.55"/>
|
||||
<stop offset="65%" stop-color="#ff8a3a" stop-opacity="0.18"/>
|
||||
<stop offset="100%" stop-color="#ff5e2a" stop-opacity="0"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="sunCore" cx="40%" cy="40%" r="60%">
|
||||
<stop offset="0%" stop-color="#fffae6"/>
|
||||
<stop offset="55%" stop-color="#ffe9a3"/>
|
||||
<stop offset="100%" stop-color="#ffbe5e"/>
|
||||
</radialGradient>
|
||||
|
||||
<linearGradient id="seaGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#7da7c4"/>
|
||||
<stop offset="35%" stop-color="#33648c"/>
|
||||
<stop offset="100%" stop-color="#0d2c4d"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="wetSandGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#caa57e"/>
|
||||
<stop offset="100%" stop-color="#8a6741"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="sandGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#f6d8a1"/>
|
||||
<stop offset="55%" stop-color="#dab177"/>
|
||||
<stop offset="100%" stop-color="#a47c4e"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="bodyGrad" x1="0.2" y1="0" x2="0.7" y2="1">
|
||||
<stop offset="0%" stop-color="#ffffff"/>
|
||||
<stop offset="55%" stop-color="#f2ecdc"/>
|
||||
<stop offset="100%" stop-color="#b3a482"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="bellyGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ffffff"/>
|
||||
<stop offset="100%" stop-color="#e8e0c8"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="wingGrad" x1="0" y1="0" x2="0.4" y2="1">
|
||||
<stop offset="0%" stop-color="#d9c8a0"/>
|
||||
<stop offset="55%" stop-color="#8d7549"/>
|
||||
<stop offset="100%" stop-color="#3f3018"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="beakGrad" x1="0" y1="0" x2="0.3" y2="1">
|
||||
<stop offset="0%" stop-color="#ffe287"/>
|
||||
<stop offset="50%" stop-color="#f29d28"/>
|
||||
<stop offset="100%" stop-color="#a05810"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="pouchGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ffd9a0"/>
|
||||
<stop offset="55%" stop-color="#ed984c"/>
|
||||
<stop offset="100%" stop-color="#a8521e"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="footGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ffb350"/>
|
||||
<stop offset="100%" stop-color="#b85e10"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="frameGrad" x1="0" y1="0" x2="0.3" y2="1">
|
||||
<stop offset="0%" stop-color="#5dd9e8"/>
|
||||
<stop offset="55%" stop-color="#1ba5ba"/>
|
||||
<stop offset="100%" stop-color="#0e6473"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="scarfGrad" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#ff5142"/>
|
||||
<stop offset="100%" stop-color="#a51914"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="cloudGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ffd09a" stop-opacity="0.9"/>
|
||||
<stop offset="100%" stop-color="#c66e58" stop-opacity="0.55"/>
|
||||
</linearGradient>
|
||||
|
||||
<radialGradient id="tireGrad" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="85%" stop-color="#2a2a2a"/>
|
||||
<stop offset="100%" stop-color="#000000"/>
|
||||
</radialGradient>
|
||||
<radialGradient id="hubGrad" cx="40%" cy="40%" r="60%">
|
||||
<stop offset="0%" stop-color="#e8e8e8"/>
|
||||
<stop offset="60%" stop-color="#888"/>
|
||||
<stop offset="100%" stop-color="#2f2f2f"/>
|
||||
</radialGradient>
|
||||
|
||||
<linearGradient id="basketGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#d9a868"/>
|
||||
<stop offset="100%" stop-color="#6f4419"/>
|
||||
</linearGradient>
|
||||
|
||||
<linearGradient id="fishGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#88cdee"/>
|
||||
<stop offset="100%" stop-color="#2a6c92"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- ============ ?? ============ -->
|
||||
<rect width="800" height="385" fill="url(#skyGrad)"/>
|
||||
|
||||
<!-- ??????? -->
|
||||
<circle cx="560" cy="260" r="200" fill="url(#sunGlow)"/>
|
||||
<circle cx="560" cy="260" r="62" fill="url(#sunCore)"/>
|
||||
<circle cx="551" cy="250" r="22" fill="#fffdf0" opacity="0.7"/>
|
||||
|
||||
<!-- ?? -->
|
||||
<g>
|
||||
<ellipse cx="120" cy="90" rx="85" ry="11" fill="url(#cloudGrad)"/>
|
||||
<ellipse cx="175" cy="108" rx="55" ry="8" fill="url(#cloudGrad)" opacity="0.75"/>
|
||||
<ellipse cx="660" cy="80" rx="95" ry="13" fill="url(#cloudGrad)" opacity="0.7"/>
|
||||
<ellipse cx="730" cy="95" rx="55" ry="8" fill="url(#cloudGrad)" opacity="0.5"/>
|
||||
<ellipse cx="380" cy="160" rx="120" ry="12" fill="#ffd0a2" opacity="0.35"/>
|
||||
<ellipse cx="90" cy="200" rx="100" ry="9" fill="#ffb98a" opacity="0.4"/>
|
||||
<ellipse cx="720" cy="220" rx="80" ry="7" fill="#ffba80" opacity="0.35"/>
|
||||
<ellipse cx="200" cy="280" rx="90" ry="6" fill="#ffaa70" opacity="0.4"/>
|
||||
<ellipse cx="620" cy="320" rx="100" ry="6" fill="#ffaa70" opacity="0.4"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<g stroke="#3b2818" stroke-width="1.6" fill="none" stroke-linecap="round" opacity="0.6">
|
||||
<path d="M 90 130 q 7 -7 14 0 q 7 -7 14 0"/>
|
||||
<path d="M 135 148 q 5 -5 10 0 q 5 -5 10 0"/>
|
||||
<path d="M 220 115 q 9 -9 18 0 q 9 -9 18 0"/>
|
||||
<path d="M 260 135 q 5 -5 10 0 q 5 -5 10 0"/>
|
||||
<path d="M 705 175 q 5 -5 10 0 q 5 -5 10 0"/>
|
||||
<path d="M 735 195 q 4 -4 8 0 q 4 -4 8 0"/>
|
||||
</g>
|
||||
|
||||
<!-- ??????? -->
|
||||
<g transform="translate(40, 385)" opacity="0.92">
|
||||
<path d="M -10 0 L 25 -48 L 80 -48 L 100 0 Z" fill="#3d4e66"/>
|
||||
<path d="M 25 -48 L 80 -48 L 82 -42 L 23 -42 Z" fill="#2c394d"/>
|
||||
<rect x="45" y="-82" width="14" height="34" fill="#e8e0d0"/>
|
||||
<rect x="45" y="-82" width="14" height="6" fill="#b8362a"/>
|
||||
<rect x="45" y="-68" width="14" height="6" fill="#b8362a"/>
|
||||
<rect x="45" y="-54" width="14" height="6" fill="#b8362a"/>
|
||||
<polygon points="43,-82 61,-82 52,-92" fill="#5a2a25"/>
|
||||
<circle cx="52" cy="-60" r="2.5" fill="#fff8a0"/>
|
||||
<circle cx="52" cy="-60" r="6" fill="#fff8a0" opacity="0.3"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<g transform="translate(700, 388)" opacity="0.92">
|
||||
<path d="M 0 8 L 32 8 L 26 14 L 6 14 Z" fill="#2a1e15"/>
|
||||
<path d="M 16 8 L 16 -30 L 29 6 Z" fill="#fff8ee"/>
|
||||
<path d="M 14 8 L 14 -14 L 4 6 Z" fill="#ece2c8"/>
|
||||
<line x1="16" y1="-32" x2="16" y2="8" stroke="#2a1e15" stroke-width="1.2"/>
|
||||
<path d="M 6 15 L 26 15 L 22 19 L 10 19 Z" fill="#2a1e15" opacity="0.3"/>
|
||||
</g>
|
||||
|
||||
<!-- ????? -->
|
||||
<g opacity="0.55">
|
||||
<path d="M 280 385 q 30 -22 70 -18 q 35 5 60 18 Z" fill="#4a5a72"/>
|
||||
<path d="M 295 380 q 25 -12 55 -8 q 30 4 45 8" stroke="#2c394d" stroke-width="1" fill="none"/>
|
||||
</g>
|
||||
|
||||
<!-- ============ ?? ============ -->
|
||||
<rect y="385" width="800" height="80" fill="url(#seaGrad)"/>
|
||||
|
||||
<!-- ?????????? -->
|
||||
<g fill="#ffeaa0" opacity="0.85">
|
||||
<rect x="530" y="387" width="60" height="3" rx="1.5"/>
|
||||
<rect x="520" y="394" width="80" height="3" rx="1.5"/>
|
||||
<rect x="535" y="401" width="50" height="3" rx="1.5"/>
|
||||
<rect x="512" y="408" width="92" height="3" rx="1.5"/>
|
||||
<rect x="540" y="415" width="40" height="3" rx="1.5"/>
|
||||
<rect x="525" y="422" width="68" height="3" rx="1.5"/>
|
||||
<rect x="545" y="429" width="30" height="3" rx="1.5"/>
|
||||
<rect x="535" y="436" width="48" height="3" rx="1.5"/>
|
||||
<rect x="550" y="443" width="20" height="3" rx="1.5"/>
|
||||
<rect x="540" y="450" width="38" height="3" rx="1.5"/>
|
||||
<rect x="555" y="457" width="18" height="3" rx="1.5"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<g stroke="#ffffff" stroke-width="1.4" fill="none" stroke-linecap="round" opacity="0.5">
|
||||
<path d="M 30 400 q 25 -3 50 0 q 25 3 50 0"/>
|
||||
<path d="M 200 410 q 30 -4 60 0 q 30 4 60 0"/>
|
||||
<path d="M 370 405 q 20 -3 40 0 q 20 3 40 0"/>
|
||||
<path d="M 660 400 q 25 -3 50 0 q 25 3 50 0"/>
|
||||
<path d="M 100 428 q 25 -3 50 0 q 25 3 50 0"/>
|
||||
<path d="M 290 432 q 30 -4 60 0 q 30 4 60 0"/>
|
||||
<path d="M 660 432 q 25 -3 50 0 q 25 3 50 0"/>
|
||||
<path d="M 50 450 q 22 -3 44 0 q 22 3 44 0"/>
|
||||
<path d="M 250 455 q 22 -3 44 0 q 22 3 44 0"/>
|
||||
</g>
|
||||
|
||||
<!-- ????? -->
|
||||
<line x1="0" y1="385" x2="800" y2="385" stroke="#ffd6a0" stroke-width="1.2" opacity="0.85"/>
|
||||
|
||||
<!-- ============ ?? ============ -->
|
||||
<!-- ??????????? -->
|
||||
<path d="M 0 444 q 200 -12 400 -4 t 400 16 L 800 500 L 0 500 Z" fill="url(#wetSandGrad)"/>
|
||||
|
||||
<!-- ????? -->
|
||||
<path d="M 0 444 q 200 -12 400 -4 t 400 16" stroke="#ffffff" stroke-width="5" fill="none" stroke-linecap="round" opacity="0.9"/>
|
||||
<path d="M 0 452 q 200 -8 400 -1 t 400 14" stroke="#ffffff" stroke-width="2.8" fill="none" stroke-linecap="round" opacity="0.55"/>
|
||||
<g fill="#ffffff" opacity="0.8">
|
||||
<circle cx="120" cy="446" r="2"/>
|
||||
<circle cx="240" cy="444" r="1.5"/>
|
||||
<circle cx="360" cy="443" r="2"/>
|
||||
<circle cx="480" cy="448" r="1.5"/>
|
||||
<circle cx="620" cy="452" r="2"/>
|
||||
<circle cx="710" cy="458" r="1.5"/>
|
||||
<circle cx="70" cy="449" r="1.5"/>
|
||||
<circle cx="180" cy="448" r="1.2"/>
|
||||
<circle cx="300" cy="445" r="1.2"/>
|
||||
<circle cx="550" cy="450" r="1.2"/>
|
||||
</g>
|
||||
|
||||
<!-- ???????? -->
|
||||
<path d="M 0 500 q 400 -10 800 4 L 800 600 L 0 600 Z" fill="url(#sandGrad)"/>
|
||||
|
||||
<!-- ???? -->
|
||||
<g fill="#a8814e" opacity="0.55">
|
||||
<circle cx="50" cy="528" r="1.2"/><circle cx="120" cy="540" r="1"/>
|
||||
<circle cx="180" cy="552" r="1.3"/><circle cx="80" cy="548" r="0.8"/>
|
||||
<circle cx="200" cy="538" r="1"/><circle cx="540" cy="545" r="1.2"/>
|
||||
<circle cx="600" cy="555" r="1"/><circle cx="660" cy="540" r="1.3"/>
|
||||
<circle cx="700" cy="555" r="0.9"/><circle cx="750" cy="548" r="1.1"/>
|
||||
<circle cx="630" cy="528" r="0.9"/><circle cx="40" cy="560" r="1"/>
|
||||
<circle cx="160" cy="532" r="0.8"/><circle cx="230" cy="552" r="1"/>
|
||||
<circle cx="280" cy="560" r="0.9"/><circle cx="520" cy="535" r="1"/>
|
||||
<circle cx="780" cy="556" r="1.1"/>
|
||||
<circle cx="100" cy="572" r="1"/><circle cx="320" cy="580" r="1.2"/>
|
||||
<circle cx="480" cy="575" r="1"/><circle cx="690" cy="580" r="1.1"/>
|
||||
</g>
|
||||
<g fill="#7a5b2e" opacity="0.4">
|
||||
<circle cx="90" cy="540" r="0.7"/><circle cx="150" cy="550" r="0.8"/>
|
||||
<circle cx="210" cy="554" r="0.7"/><circle cx="570" cy="540" r="0.8"/>
|
||||
<circle cx="640" cy="552" r="0.7"/><circle cx="690" cy="568" r="0.8"/>
|
||||
<circle cx="60" cy="555" r="0.7"/><circle cx="730" cy="538" r="0.7"/>
|
||||
<circle cx="380" cy="580" r="0.8"/><circle cx="440" cy="570" r="0.7"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<g transform="translate(640, 545)">
|
||||
<path d="M 0 0 q 9 -11 18 0 q -2 5 -9 5 q -7 0 -9 -5 Z" fill="#fceedd" stroke="#cd9466" stroke-width="0.8"/>
|
||||
<path d="M 5 0 q 4 -6 8 0 M 7 0 q 2 -3 4 0" stroke="#cd9466" stroke-width="0.6" fill="none"/>
|
||||
</g>
|
||||
<g transform="translate(720, 535)">
|
||||
<ellipse rx="7" ry="4.5" fill="#f5d4b8" stroke="#b07a4a" stroke-width="0.7"/>
|
||||
<path d="M -3 0 q 3 -3 6 0 M -2 1 q 2 -2 4 0" stroke="#b07a4a" stroke-width="0.5" fill="none"/>
|
||||
</g>
|
||||
<g transform="translate(70, 555) rotate(18)">
|
||||
<path d="M 0 0 L 0 -9 L 5 -7 L 5 2 Z" fill="#e8a86c" stroke="#8e5a28" stroke-width="0.6"/>
|
||||
<path d="M 0 -4 L 5 -3" stroke="#8e5a28" stroke-width="0.4"/>
|
||||
</g>
|
||||
|
||||
<!-- ?? -->
|
||||
<g transform="translate(195, 562)" fill="#e87a3a" stroke="#a83a1a" stroke-width="0.7">
|
||||
<path d="M 0 -8 L 2 -2 L 8 -2 L 3 2 L 5 8 L 0 4 L -5 8 L -3 2 L -8 -2 L -2 -2 Z"/>
|
||||
<circle cx="0" cy="0" r="1.5" fill="#a83a1a"/>
|
||||
</g>
|
||||
|
||||
<!-- ??? -->
|
||||
<g>
|
||||
<ellipse cx="450" cy="560" rx="5" ry="2.5" fill="#9b8b6a" opacity="0.8"/>
|
||||
<ellipse cx="350" cy="555" rx="4" ry="2" fill="#7a5e3e" opacity="0.7"/>
|
||||
<ellipse cx="555" cy="565" rx="3" ry="1.5" fill="#9b8b6a" opacity="0.6"/>
|
||||
</g>
|
||||
|
||||
<!-- ============ ????? ============ -->
|
||||
<ellipse cx="380" cy="555" rx="210" ry="10" fill="#5a3a1a" opacity="0.32"/>
|
||||
<ellipse cx="380" cy="555" rx="180" ry="6" fill="#3a2510" opacity="0.4"/>
|
||||
|
||||
<!-- ??????? -->
|
||||
<g opacity="0.55">
|
||||
<ellipse cx="170" cy="555" rx="22" ry="6" fill="#d9b078"/>
|
||||
<ellipse cx="140" cy="548" rx="14" ry="4" fill="#d9b078" opacity="0.85"/>
|
||||
<ellipse cx="115" cy="538" rx="10" ry="3" fill="#d9b078" opacity="0.7"/>
|
||||
<circle cx="192" cy="538" r="3" fill="#d9b078"/>
|
||||
<circle cx="162" cy="528" r="2.2" fill="#d9b078" opacity="0.8"/>
|
||||
<circle cx="138" cy="525" r="1.8" fill="#d9b078" opacity="0.7"/>
|
||||
<circle cx="100" cy="522" r="1.5" fill="#d9b078" opacity="0.6"/>
|
||||
</g>
|
||||
|
||||
<!-- ????? -->
|
||||
<g opacity="0.5">
|
||||
<path d="M 50 558 q 60 -3 110 0" stroke="#7a5028" stroke-width="3" fill="none"/>
|
||||
<path d="M 80 565 q 50 -3 90 0" stroke="#7a5028" stroke-width="2" fill="none"/>
|
||||
</g>
|
||||
|
||||
<!-- ============ ?? ============ -->
|
||||
<g transform="translate(240, 500)">
|
||||
<circle r="55" fill="url(#tireGrad)"/>
|
||||
<circle r="48" fill="#101010"/>
|
||||
<circle r="46" stroke="#5a5a5a" stroke-width="1.2" fill="#1a1a1a"/>
|
||||
<circle r="42" fill="#c8c8c8"/>
|
||||
<!-- ?????????? -->
|
||||
<circle r="38" stroke="#9a9a9a" stroke-dasharray="2 7" stroke-width="36" fill="none" opacity="0.35"/>
|
||||
<circle r="35" stroke="#fff" stroke-dasharray="1 12" stroke-width="34" fill="none" opacity="0.18"/>
|
||||
<circle r="9" fill="url(#hubGrad)"/>
|
||||
<circle r="4" fill="#1a1a1a"/>
|
||||
<g stroke="#3a3a3a" stroke-width="1" opacity="0.7">
|
||||
<path d="M -53 -8 l 4 0 M -53 0 l 4 0 M -53 8 l 4 0"/>
|
||||
<path d="M 49 -8 l 4 0 M 49 0 l 4 0 M 49 8 l 4 0"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ============ ?????????? ============ -->
|
||||
<g>
|
||||
<path d="M 355 415 q -8 26 -22 38 q -8 7 -18 6" stroke="#b3a482" stroke-width="14" fill="none" stroke-linecap="round" opacity="0.9"/>
|
||||
<g transform="translate(315, 461) rotate(-18)">
|
||||
<path d="M 0 0 q -22 -4 -28 4 q 4 8 28 4 Z" fill="url(#footGrad)" stroke="#7a4810" stroke-width="0.8" opacity="0.9"/>
|
||||
<path d="M -8 1 q -2 5 1 6 M -16 1 q -2 5 1 6 M -22 2 q -2 4 0 5" stroke="#7a4810" stroke-width="0.6" fill="none"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ============ ???? ============ -->
|
||||
<g>
|
||||
<!-- ??? -->
|
||||
<line x1="350" y1="500" x2="244" y2="500" stroke="url(#frameGrad)" stroke-width="9" stroke-linecap="round"/>
|
||||
<!-- ??? -->
|
||||
<line x1="340" y1="395" x2="244" y2="500" stroke="url(#frameGrad)" stroke-width="9" stroke-linecap="round"/>
|
||||
<!-- ?? -->
|
||||
<line x1="340" y1="395" x2="350" y2="500" stroke="url(#frameGrad)" stroke-width="11" stroke-linecap="round"/>
|
||||
<!-- ?? -->
|
||||
<line x1="350" y1="500" x2="500" y2="418" stroke="url(#frameGrad)" stroke-width="11" stroke-linecap="round"/>
|
||||
<!-- ??????????? -->
|
||||
<path d="M 340 397 Q 410 425, 497 414" stroke="url(#frameGrad)" stroke-width="11" fill="none" stroke-linecap="round"/>
|
||||
<!-- ?? -->
|
||||
<line x1="500" y1="418" x2="520" y2="500" stroke="url(#frameGrad)" stroke-width="9" stroke-linecap="round"/>
|
||||
|
||||
<!-- ?????? -->
|
||||
<line x1="349" y1="497" x2="245" y2="497" stroke="#bff2f8" stroke-width="1.5" opacity="0.8"/>
|
||||
<line x1="350" y1="498" x2="498" y2="416" stroke="#bff2f8" stroke-width="1.5" opacity="0.8"/>
|
||||
<path d="M 342 399 Q 410 426, 495 412" stroke="#bff2f8" stroke-width="1.2" fill="none" opacity="0.7"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 186 500 a 54 54 0 0 1 108 0" stroke="url(#frameGrad)" stroke-width="6" fill="none" stroke-linecap="round"/>
|
||||
|
||||
<!-- ????? -->
|
||||
<g>
|
||||
<circle cx="350" cy="500" r="15" fill="#3a3a3a"/>
|
||||
<circle cx="350" cy="500" r="13" fill="#5a5a5a"/>
|
||||
<circle cx="350" cy="500" r="4" fill="#1a1a1a"/>
|
||||
<g stroke="#888" stroke-width="1" fill="none">
|
||||
<line x1="350" y1="483" x2="350" y2="480"/>
|
||||
<line x1="363" y1="488" x2="366" y2="485"/>
|
||||
<line x1="365" y1="500" x2="368" y2="500"/>
|
||||
<line x1="363" y1="512" x2="366" y2="515"/>
|
||||
<line x1="350" y1="517" x2="350" y2="520"/>
|
||||
<line x1="337" y1="512" x2="334" y2="515"/>
|
||||
<line x1="335" y1="500" x2="332" y2="500"/>
|
||||
<line x1="337" y1="488" x2="334" y2="485"/>
|
||||
</g>
|
||||
<path d="M 350 485 q 60 -32 145 -65" stroke="#444" stroke-width="2" fill="none" opacity="0.85"/>
|
||||
<path d="M 350 515 q 60 -22 145 -55" stroke="#444" stroke-width="2" fill="none" opacity="0.7"/>
|
||||
</g>
|
||||
|
||||
<!-- ????? -->
|
||||
<g>
|
||||
<line x1="350" y1="500" x2="378" y2="520" stroke="#222" stroke-width="5" stroke-linecap="round"/>
|
||||
<line x1="350" y1="500" x2="322" y2="480" stroke="#222" stroke-width="5" stroke-linecap="round"/>
|
||||
<rect x="372" y="517" width="16" height="7" rx="1.5" fill="#1a1a1a"/>
|
||||
<rect x="370" y="517" width="2" height="7" fill="#5a5a5a"/>
|
||||
<rect x="312" y="475" width="16" height="7" rx="1.5" fill="#1a1a1a"/>
|
||||
</g>
|
||||
|
||||
<!-- ?? -->
|
||||
<line x1="340" y1="395" x2="335" y2="380" stroke="#3a3a3a" stroke-width="5" stroke-linecap="round"/>
|
||||
|
||||
<!-- ????? -->
|
||||
<g transform="translate(335, 378)">
|
||||
<path d="M -24 -3 q -3 -9 11 -11 q 16 -2 23 1 q 9 3 -5 13 q -12 6 -29 -3 Z" fill="#4d2914"/>
|
||||
<path d="M -24 -3 q -3 -9 11 -11 q 16 -2 23 1" stroke="#8a4f25" stroke-width="0.8" fill="none"/>
|
||||
<ellipse cx="-3" cy="-4" rx="15" ry="3" fill="#7a4220" opacity="0.7"/>
|
||||
<ellipse cx="-3" cy="-6" rx="8" ry="1.5" fill="#a06030" opacity="0.5"/>
|
||||
</g>
|
||||
|
||||
<!-- ============ ????????? ============ -->
|
||||
<g>
|
||||
<!-- ?? -->
|
||||
<g transform="translate(303, 425)">
|
||||
<path d="M 0 0 L -54 18 L -28 -22 Z" fill="#b3a482"/>
|
||||
<path d="M 0 -4 L -62 -6 L -32 -34 Z" fill="#e8dfc8"/>
|
||||
<path d="M 0 -8 L -58 -28 L -28 -40 Z" fill="#fafaf0"/>
|
||||
<g stroke="#9b8b6a" stroke-width="0.6" opacity="0.65" fill="none">
|
||||
<path d="M -8 -4 L -45 -14"/>
|
||||
<path d="M -8 -10 L -45 -28"/>
|
||||
<path d="M -5 0 L -40 12"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ????????? -->
|
||||
<path d="M 305 425
|
||||
C 268 397, 270 337, 322 320
|
||||
C 388 304, 438 340, 438 396
|
||||
C 438 428, 388 442, 348 438 Z" fill="url(#bodyGrad)"/>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 308 425 C 300 410, 308 390, 332 383 C 372 376, 408 395, 418 415 C 400 432, 360 438, 320 435 Z" fill="url(#bellyGrad)" opacity="0.85"/>
|
||||
|
||||
<!-- ????? -->
|
||||
<path d="M 380 322 C 420 336, 438 365, 438 396 C 432 422, 410 435, 388 437 C 420 422, 432 388, 422 352 Z" fill="#9b8b6a" opacity="0.28"/>
|
||||
|
||||
<!-- ?????? -->
|
||||
<g stroke="#c5b896" stroke-width="0.5" fill="none" opacity="0.5">
|
||||
<path d="M 290 378 q 25 -8 50 -5"/>
|
||||
<path d="M 290 393 q 28 -6 56 -3"/>
|
||||
<path d="M 295 408 q 30 -4 60 0"/>
|
||||
</g>
|
||||
|
||||
<!-- S ???? -->
|
||||
<path d="M 362 328
|
||||
C 410 318, 425 290, 408 258
|
||||
C 390 233, 395 215, 420 208"
|
||||
stroke="url(#bodyGrad)" stroke-width="38" fill="none" stroke-linecap="round"/>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 368 330
|
||||
C 410 318, 422 290, 405 260
|
||||
C 388 235, 395 220, 415 213"
|
||||
stroke="#c5b896" stroke-width="7" fill="none" stroke-linecap="round" opacity="0.5"/>
|
||||
<!-- ???? -->
|
||||
<path d="M 358 326
|
||||
C 400 314, 414 288, 400 258"
|
||||
stroke="#ffffff" stroke-width="4" fill="none" stroke-linecap="round" opacity="0.6"/>
|
||||
|
||||
<!-- ?????????? -->
|
||||
<g>
|
||||
<path d="M 400 226 q -12 5 -28 -7 q 20 -10 35 -5 Z" fill="url(#scarfGrad)"/>
|
||||
<path d="M 392 235 q -50 -3 -82 18 q 32 -1 86 -6 Z" fill="url(#scarfGrad)"/>
|
||||
<path d="M 392 245 q -55 2 -100 32 q 45 -3 105 -12 Z" fill="#a01515" opacity="0.92"/>
|
||||
<path d="M 388 238 q -42 4 -70 22 q 30 -2 75 -8 Z" fill="#ff6e58" opacity="0.55"/>
|
||||
<path d="M 350 253 q 8 4 0 10 M 320 266 q 8 4 0 10" stroke="#7a0e0e" stroke-width="0.8" fill="none" opacity="0.7"/>
|
||||
</g>
|
||||
|
||||
<!-- ?? -->
|
||||
<ellipse cx="423" cy="198" rx="34" ry="29" fill="url(#bodyGrad)"/>
|
||||
<ellipse cx="431" cy="206" rx="22" ry="20" fill="#b3a482" opacity="0.3"/>
|
||||
<ellipse cx="411" cy="186" rx="14" ry="10" fill="#ffffff" opacity="0.75"/>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 408 174 q 3 -10 9 -9 q -1 7 -1 13 Z" fill="#e8dfc8"/>
|
||||
<path d="M 419 170 q 5 -9 11 -5 q -3 7 -4 11 Z" fill="#e8dfc8"/>
|
||||
<path d="M 429 172 q 6 -7 10 -3 q -3 5 -4 8 Z" fill="#d9c8a0"/>
|
||||
|
||||
<!-- ?? -->
|
||||
<ellipse cx="435" cy="196" rx="6" ry="5.5" fill="#3a2818"/>
|
||||
|
||||
<!-- ????? -->
|
||||
<g>
|
||||
<path d="M 417 190 q 17 -7 32 -2 L 449 204 q -14 7 -30 2 Z" fill="#0d0d0d"/>
|
||||
<path d="M 417 190 q 17 -7 32 -2 L 449 204 q -14 7 -30 2 Z" fill="none" stroke="#444" stroke-width="1.2"/>
|
||||
<path d="M 423 194 q 8 -3 16 -1" stroke="#7ed0f0" stroke-width="1.8" fill="none" opacity="0.9"/>
|
||||
<path d="M 435 200 q 3 -1 6 -0.5" stroke="#fff" stroke-width="1" fill="none" opacity="0.75"/>
|
||||
<line x1="449" y1="198" x2="456" y2="196" stroke="#1a1a1a" stroke-width="1.6"/>
|
||||
<line x1="417" y1="192" x2="409" y2="188" stroke="#1a1a1a" stroke-width="1.5"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 453 194 Q 545 204, 585 235 Q 565 240, 475 233 Q 451 230, 449 213 Z" fill="url(#beakGrad)"/>
|
||||
<path d="M 455 200 Q 540 208, 575 230 Q 545 225, 475 220 Q 455 215, 455 204 Z" fill="#ffd86b" opacity="0.6"/>
|
||||
<path d="M 465 211 Q 535 215, 577 235" stroke="#a85a10" stroke-width="0.9" fill="none" opacity="0.75"/>
|
||||
<ellipse cx="475" cy="211" rx="2.2" ry="1.2" fill="#5a2a08"/>
|
||||
<path d="M 580 237 q 8 4 0 9 q -10 -1 -12 -7 Z" fill="#8e4810"/>
|
||||
|
||||
<!-- ?? -->
|
||||
<path d="M 449 225
|
||||
Q 473 256, 528 260
|
||||
Q 568 256, 580 237
|
||||
Q 533 248, 481 238
|
||||
Q 461 233, 449 225 Z" fill="url(#pouchGrad)"/>
|
||||
<path d="M 458 233 q 40 22 80 21" stroke="#a8521e" stroke-width="0.9" fill="none" opacity="0.7"/>
|
||||
<path d="M 465 239 q 38 18 72 18" stroke="#a8521e" stroke-width="0.7" fill="none" opacity="0.55"/>
|
||||
<path d="M 473 245 q 35 14 65 14" stroke="#a8521e" stroke-width="0.6" fill="none" opacity="0.45"/>
|
||||
<path d="M 473 230 q 30 14 60 14" stroke="#fff" stroke-width="1.3" fill="none" opacity="0.45"/>
|
||||
|
||||
<path d="M 449 225 Q 533 248, 580 237" stroke="#7e3c08" stroke-width="1.2" fill="none" opacity="0.6"/>
|
||||
|
||||
<!-- ????????????? -->
|
||||
<g transform="translate(510, 385)">
|
||||
<path d="M 0 0 q -12 -7 -20 -4 q 0 6 0 12 q 8 0 20 -2 Z" fill="url(#fishGrad)"/>
|
||||
<path d="M -20 -4 L -28 -10 L -28 14 L -20 8 Z" fill="#2a6c92"/>
|
||||
<path d="M -28 -10 L -26 0 L -28 14" stroke="#88cdee" stroke-width="0.7" fill="none"/>
|
||||
<circle cx="-4" cy="2" r="1.2" fill="#1a1a1a"/>
|
||||
<circle cx="-3.7" cy="1.8" r="0.5" fill="#fff"/>
|
||||
<path d="M -12 5 q 6 1 10 0" stroke="#1a4a6a" stroke-width="0.5" fill="none"/>
|
||||
<path d="M -14 -3 q 3 0 3 3 M -8 -3 q 3 0 3 3 M -14 3 q 3 0 3 3 M -8 3 q 3 0 3 3" stroke="#1a4a6a" stroke-width="0.3" fill="none" opacity="0.6"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 352 348
|
||||
C 392 338, 425 358, 445 396
|
||||
C 432 425, 388 425, 360 405
|
||||
C 342 390, 338 368, 352 348 Z" fill="url(#wingGrad)"/>
|
||||
|
||||
<!-- ?????? -->
|
||||
<g fill="#6e5a32" opacity="0.6">
|
||||
<path d="M 360 365 q 22 6 50 24 q -10 3 -25 0 q -18 -8 -30 -18 Z"/>
|
||||
<path d="M 364 385 q 22 6 56 22 q -12 4 -26 1 q -22 -8 -32 -19 Z"/>
|
||||
<path d="M 370 403 q 25 6 60 16 q -12 4 -25 2 q -25 -6 -36 -14 Z"/>
|
||||
</g>
|
||||
|
||||
<!-- ?????? -->
|
||||
<g fill="none" stroke="#3f3018" stroke-width="0.8" opacity="0.7">
|
||||
<path d="M 358 358 q 25 4 50 22"/>
|
||||
<path d="M 362 376 q 25 4 56 22"/>
|
||||
<path d="M 368 394 q 28 4 60 16"/>
|
||||
<path d="M 378 410 q 30 3 55 8"/>
|
||||
</g>
|
||||
|
||||
<!-- ??????????? -->
|
||||
<g fill="#2a1f10">
|
||||
<path d="M 432 410 q 12 2 14 12 q -6 6 -16 0 Z"/>
|
||||
<path d="M 422 420 q 12 0 14 12 q -6 6 -16 -2 Z"/>
|
||||
<path d="M 410 426 q 10 2 12 13 q -8 5 -14 -3 Z"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 358 354 q 16 -8 36 -5 q -5 8 -22 12 q -12 1 -16 -8 Z" fill="#f5ecc8" opacity="0.7"/>
|
||||
<path d="M 354 351 q 20 -8 42 -3" stroke="#fff" stroke-width="1.2" fill="none" opacity="0.5"/>
|
||||
|
||||
<!-- ??"??"????????? -->
|
||||
<path d="M 440 398 Q 472 402, 494 414" stroke="url(#wingGrad)" stroke-width="14" fill="none" stroke-linecap="round"/>
|
||||
<path d="M 440 396 Q 472 400, 492 412" stroke="#6e5a32" stroke-width="3" fill="none" stroke-linecap="round" opacity="0.7"/>
|
||||
|
||||
<!-- ?????? -->
|
||||
<ellipse cx="498" cy="416" rx="10" ry="8" fill="#6e5a32"/>
|
||||
<ellipse cx="498" cy="414" rx="6" ry="3" fill="#9b8b6a" opacity="0.7"/>
|
||||
|
||||
<!-- ??? -->
|
||||
<path d="M 370 428 Q 372 470, 382 516" stroke="url(#bodyGrad)" stroke-width="15" fill="none" stroke-linecap="round"/>
|
||||
<path d="M 374 430 Q 376 470, 384 512" stroke="#c5b896" stroke-width="3" fill="none" stroke-linecap="round" opacity="0.5"/>
|
||||
|
||||
<!-- ???? -->
|
||||
<g transform="translate(382, 519) rotate(-5)">
|
||||
<path d="M -6 -3 q 6 -3 12 -2 L 32 0 q 6 4 -2 9 L 0 11 q -6 -3 -2 -11 Z" fill="url(#footGrad)" stroke="#7a4810" stroke-width="0.9"/>
|
||||
<path d="M 8 0 q 1 6 -1 9 M 18 0 q 1 6 -2 9 M 28 0 q 0 5 -3 7" stroke="#7a4810" stroke-width="0.6" fill="none"/>
|
||||
<path d="M 0 -2 q 16 -1 28 1" stroke="#ffd070" stroke-width="0.9" fill="none" opacity="0.75"/>
|
||||
<path d="M 32 -1 l 2 -2 M 22 -2 l 2 -2 M 12 -2 l 1 -2" stroke="#3a1808" stroke-width="0.7"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ============ ???? ============ -->
|
||||
<g>
|
||||
<line x1="500" y1="418" x2="500" y2="388" stroke="#2a2a2a" stroke-width="7" stroke-linecap="round"/>
|
||||
<path d="M 500 388 Q 500 374, 512 374 Q 524 374, 524 386 L 522 396"
|
||||
stroke="#222" stroke-width="6.5" fill="none" stroke-linecap="round"/>
|
||||
<path d="M 500 388 Q 500 374, 488 374 Q 476 374, 476 386 L 478 396"
|
||||
stroke="#222" stroke-width="6.5" fill="none" stroke-linecap="round"/>
|
||||
<rect x="516" y="383" width="12" height="8" rx="2.5" fill="#b8362a"/>
|
||||
<rect x="472" y="383" width="12" height="8" rx="2.5" fill="#b8362a"/>
|
||||
<rect x="516" y="384" width="12" height="2" fill="#ff6e58" opacity="0.7"/>
|
||||
<rect x="472" y="384" width="12" height="2" fill="#ff6e58" opacity="0.7"/>
|
||||
|
||||
<!-- ?? -->
|
||||
<g transform="translate(490, 384)">
|
||||
<circle r="5" fill="#c5862a"/>
|
||||
<circle r="3.5" fill="#e8a850"/>
|
||||
<circle r="1" fill="#5a3a18"/>
|
||||
<path d="M -3 -2 q 3 -1 4 1" stroke="#fff8a0" stroke-width="0.6" fill="none" opacity="0.8"/>
|
||||
</g>
|
||||
|
||||
<!-- ??? -->
|
||||
<g transform="translate(480, 358)">
|
||||
<path d="M 0 0 L 48 0 L 54 26 L -6 26 Z" fill="url(#basketGrad)"/>
|
||||
<path d="M 0 0 L 48 0 L 49 4 L -1 4 Z" fill="#a87a3a"/>
|
||||
<g stroke="#4a2f15" stroke-width="0.6" fill="none" opacity="0.75">
|
||||
<line x1="-3" y1="9" x2="51" y2="9"/>
|
||||
<line x1="-4" y1="15" x2="52" y2="15"/>
|
||||
<line x1="-5" y1="21" x2="53" y2="21"/>
|
||||
<line x1="4" y1="4" x2="4" y2="26"/>
|
||||
<line x1="14" y1="4" x2="14" y2="26"/>
|
||||
<line x1="24" y1="4" x2="24" y2="26"/>
|
||||
<line x1="34" y1="4" x2="34" y2="26"/>
|
||||
<line x1="44" y1="4" x2="44" y2="26"/>
|
||||
</g>
|
||||
<path d="M 0 1 L 48 1" stroke="#ffd9a0" stroke-width="0.8" opacity="0.8"/>
|
||||
<!-- ???? -->
|
||||
<path d="M 5 0 q 19 -12 38 0" stroke="#6f4419" stroke-width="1.5" fill="none"/>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- ============ ?? ============ -->
|
||||
<g transform="translate(520, 500)">
|
||||
<circle r="55" fill="url(#tireGrad)"/>
|
||||
<circle r="48" fill="#101010"/>
|
||||
<circle r="46" stroke="#5a5a5a" stroke-width="1.2" fill="#1a1a1a"/>
|
||||
<circle r="42" fill="#c8c8c8"/>
|
||||
<circle r="38" stroke="#9a9a9a" stroke-dasharray="2 7" stroke-width="36" fill="none" opacity="0.35"/>
|
||||
<circle r="35" stroke="#fff" stroke-dasharray="1 12" stroke-width="34" fill="none" opacity="0.18"/>
|
||||
<circle r="9" fill="url(#hubGrad)"/>
|
||||
<circle r="4" fill="#1a1a1a"/>
|
||||
<g stroke="#3a3a3a" stroke-width="1" opacity="0.7">
|
||||
<path d="M -53 -8 l 4 0 M -53 0 l 4 0 M -53 8 l 4 0"/>
|
||||
<path d="M 49 -8 l 4 0 M 49 0 l 4 0 M 49 8 l 4 0"/>
|
||||
</g>
|
||||
<ellipse cx="20" cy="-22" rx="11" ry="5" fill="#ffd86b" opacity="0.4"/>
|
||||
</g>
|
||||
|
||||
<!-- ???? -->
|
||||
<path d="M 466 500 a 54 54 0 0 1 108 0" stroke="url(#frameGrad)" stroke-width="6" fill="none" stroke-linecap="round"/>
|
||||
<ellipse cx="572" cy="494" rx="3" ry="2" fill="#ffd86b"/>
|
||||
|
||||
<!-- ============ ????? ============ -->
|
||||
<g stroke-linecap="round" opacity="0.7">
|
||||
<line x1="30" y1="470" x2="135" y2="468" stroke="#ffffff" stroke-width="3"/>
|
||||
<line x1="10" y1="495" x2="85" y2="493" stroke="#ffea99" stroke-width="2"/>
|
||||
<line x1="50" y1="520" x2="160" y2="518" stroke="#ffffff" stroke-width="3.5"/>
|
||||
<line x1="15" y1="540" x2="85" y2="540" stroke="#ffffff" stroke-width="2.5"/>
|
||||
<line x1="70" y1="556" x2="130" y2="556" stroke="#ffd86b" stroke-width="2" opacity="0.6"/>
|
||||
</g>
|
||||
|
||||
<!-- ????? -->
|
||||
<g fill="#f8f5e8" opacity="0.85">
|
||||
<ellipse cx="385" cy="265" rx="4" ry="1.5" transform="rotate(-15 385 265)"/>
|
||||
<ellipse cx="365" cy="285" rx="3" ry="1.2" transform="rotate(-20 365 285)"/>
|
||||
<ellipse cx="345" cy="305" rx="2.5" ry="1" transform="rotate(-25 345 305)"/>
|
||||
</g>
|
||||
|
||||
<!-- ??????? -->
|
||||
<circle cx="441" cy="198" r="1.2" fill="#ffffff" opacity="0.9"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 28 KiB |
Whitespace-only changes.
Whitespace-only changes.
@@ -0,0 +1,603 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Mythiccraft</title>
|
||||
<style>
|
||||
body { margin: 0; overflow: hidden; background: #000; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; user-select: none; }
|
||||
#crosshair {
|
||||
position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);
|
||||
color: rgba(255,255,255,0.8); font-size: 24px; font-weight: normal; pointer-events: none; text-shadow: 1px 1px 0 #000;
|
||||
}
|
||||
#toolbar {
|
||||
position: absolute; bottom: 20px; left: 50%; transform: translateX(-50%);
|
||||
display: flex; gap: 8px; background: rgba(0,0,0,0.6); padding: 10px; border-radius: 12px;
|
||||
box-shadow: 0 4px 15px rgba(0,0,0,0.5);
|
||||
}
|
||||
.slot {
|
||||
width: 50px; height: 50px; border: 3px solid #444; border-radius: 6px;
|
||||
display: flex; align-items: flex-end; justify-content: center; color: white;
|
||||
font-size: 14px; font-weight: bold; text-shadow: 1px 1px 2px black; padding-bottom: 4px;
|
||||
box-sizing: border-box; cursor: pointer; background-size: cover; background-position: center;
|
||||
transition: transform 0.1s; image-rendering: pixelated;
|
||||
}
|
||||
.slot.selected { border-color: #fff; transform: scale(1.15); box-shadow: 0 0 15px rgba(255,255,255,0.5); z-index: 10;}
|
||||
#instructions {
|
||||
position: absolute; top: 0; left: 0; width: 100%; height: 100%;
|
||||
background: rgba(26, 11, 46, 0.85); display: flex; flex-direction: column;
|
||||
align-items: center; justify-content: center; color: #fff; z-index: 200;
|
||||
}
|
||||
#instructions h1 { font-size: 64px; margin: 0; color: #f5d436; text-shadow: 0 0 20px rgba(245, 212, 54, 0.5); }
|
||||
#instructions p { font-size: 18px; color: #ccc; }
|
||||
#start-btn {
|
||||
padding: 15px 40px; font-size: 24px; cursor: pointer; margin-top: 30px;
|
||||
background: #f5d436; color: #1a0b2e; border: none; border-radius: 30px; font-weight: bold;
|
||||
transition: background 0.2s, transform 0.2s;
|
||||
}
|
||||
#start-btn:hover { background: #fff; transform: scale(1.05); }
|
||||
.controls-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px 40px; margin-top: 40px; text-align: left; background: rgba(0,0,0,0.4); padding: 20px; border-radius: 10px;}
|
||||
.controls-grid span { color: #f5d436; font-weight: bold; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="crosshair">+</div>
|
||||
<div id="toolbar">
|
||||
<div class="slot selected" id="slot1">1</div>
|
||||
<div class="slot" id="slot2">2</div>
|
||||
<div class="slot" id="slot3">3</div>
|
||||
<div class="slot" id="slot4">4</div>
|
||||
<div class="slot" id="slot5">5</div>
|
||||
<div class="slot" id="slot6">6</div>
|
||||
</div>
|
||||
<div id="instructions">
|
||||
<h1>Mythiccraft</h1>
|
||||
<p>Explore the roots of the World Tree.</p>
|
||||
<button id="start-btn">Enter World</button>
|
||||
<div class="controls-grid">
|
||||
<div><span>WASD</span> / Arrows to Move</div>
|
||||
<div><span>Left Click</span> to Break Block</div>
|
||||
<div><span>SPACE</span> to Jump</div>
|
||||
<div><span>Right Click</span> to Place Block</div>
|
||||
<div><span>Mouse</span> to Look Around</div>
|
||||
<div><span>1 - 6</span> to Select Block Type</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Load Three.js and PointerLockControls -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
|
||||
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/controls/PointerLockControls.js"></script>
|
||||
|
||||
<script>
|
||||
// --- Perlin Noise Implementation ---
|
||||
class Perlin {
|
||||
constructor() {
|
||||
this.p = new Uint8Array(512);
|
||||
for(let i=0; i<256; i++) this.p[i] = Math.floor(Math.random()*256);
|
||||
for(let i=0; i<256; i++) this.p[256+i] = this.p[i];
|
||||
}
|
||||
fade(t) { return t * t * t * (t * (t * 6 - 15) + 10); }
|
||||
lerp(t, a, b) { return a + t * (b - a); }
|
||||
grad(hash, x, y, z) {
|
||||
let h = hash & 15;
|
||||
let u = h < 8 ? x : y;
|
||||
let v = h < 4 ? y : h === 12 || h === 14 ? x : z;
|
||||
return ((h & 1) === 0 ? u : -u) + ((h & 2) === 0 ? v : -v);
|
||||
}
|
||||
noise(x, y, z) {
|
||||
let X = Math.floor(x) & 255, Y = Math.floor(y) & 255, Z = Math.floor(z) & 255;
|
||||
x -= Math.floor(x); y -= Math.floor(y); z -= Math.floor(z);
|
||||
let u = this.fade(x), v = this.fade(y), w = this.fade(z);
|
||||
let A = this.p[X] + Y, AA = this.p[A] + Z, AB = this.p[A + 1] + Z;
|
||||
let B = this.p[X + 1] + Y, BA = this.p[B] + Z, BB = this.p[B + 1] + Z;
|
||||
return this.lerp(w, this.lerp(v, this.lerp(u, this.grad(this.p[AA], x, y, z), this.grad(this.p[BA], x - 1, y, z)),
|
||||
this.lerp(u, this.grad(this.p[AB], x, y - 1, z), this.grad(this.p[BB], x - 1, y - 1, z))),
|
||||
this.lerp(v, this.lerp(u, this.grad(this.p[AA + 1], x, y, z - 1), this.grad(this.p[BA + 1], x - 1, y, z - 1)),
|
||||
this.lerp(u, this.grad(this.p[AB + 1], x, y - 1, z - 1), this.grad(this.p[BB + 1], x - 1, y - 1, z - 1))));
|
||||
}
|
||||
}
|
||||
const perlin = new Perlin();
|
||||
|
||||
// --- Texture Atlas Generator ---
|
||||
let atlasCanvas;
|
||||
function generateAtlas() {
|
||||
atlasCanvas = document.createElement('canvas');
|
||||
atlasCanvas.width = 256; atlasCanvas.height = 256;
|
||||
const ctx = atlasCanvas.getContext('2d');
|
||||
|
||||
function drawNoise(x, y, w, h, baseColor, varColor, noiseLevel) {
|
||||
ctx.fillStyle = baseColor;
|
||||
ctx.fillRect(x, y, w, h);
|
||||
for(let i=x; i<x+w; i+=2) {
|
||||
for(let j=y; j<y+h; j+=2) {
|
||||
if(Math.random() < noiseLevel) {
|
||||
ctx.fillStyle = Math.random() > 0.5 ? varColor : baseColor;
|
||||
ctx.fillRect(i, j, 2, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Row 0
|
||||
drawNoise(0, 0, 64, 64, '#3e6b2c', '#4a8035', 0.5); // 0: Grass Top
|
||||
drawNoise(64, 0, 64, 64, '#4a3018', '#382412', 0.5); // 1: Grass Side
|
||||
ctx.fillStyle = '#3e6b2c'; ctx.fillRect(64, 0, 64, 12);
|
||||
drawNoise(128, 0, 64, 64, '#4a3018', '#382412', 0.5); // 2: Dirt
|
||||
drawNoise(192, 0, 64, 64, '#555555', '#666666', 0.5); // 3: Stone
|
||||
// Row 1
|
||||
drawNoise(0, 64, 64, 64, '#2c1e10', '#1f150b', 0.5); // 4: Wood Side
|
||||
drawNoise(64, 64, 64, 64, '#54402c', '#423222', 0.5); // 5: Wood Top
|
||||
drawNoise(128, 64, 64, 64, '#1c3614', '#12240d', 0.8); // 6: Leaves
|
||||
drawNoise(192, 64, 64, 64, '#f5d436', '#fff17a', 0.6); // 7: Magic (Gold)
|
||||
|
||||
let tex = new THREE.CanvasTexture(atlasCanvas);
|
||||
tex.magFilter = THREE.NearestFilter;
|
||||
tex.minFilter = THREE.NearestFilter;
|
||||
return tex;
|
||||
}
|
||||
|
||||
// --- Toolbar Icons ---
|
||||
function setToolbarIcons() {
|
||||
let canvas = document.createElement('canvas');
|
||||
canvas.width = 64; canvas.height = 64;
|
||||
let ctx = canvas.getContext('2d');
|
||||
let drawIcon = (id, tx, ty) => {
|
||||
ctx.clearRect(0,0,64,64);
|
||||
ctx.drawImage(atlasCanvas, tx*64, ty*64, 64, 64, 0, 0, 64, 64);
|
||||
document.getElementById('slot' + id).style.backgroundImage = `url(${canvas.toDataURL()})`;
|
||||
};
|
||||
drawIcon(1, 1, 0); // Grass Side
|
||||
drawIcon(2, 2, 0); // Dirt
|
||||
drawIcon(3, 3, 0); // Stone
|
||||
drawIcon(4, 0, 1); // Wood Side
|
||||
drawIcon(5, 2, 1); // Leaves
|
||||
drawIcon(6, 3, 1); // Magic
|
||||
}
|
||||
|
||||
// --- Core Variables ---
|
||||
const chunkWidth = 16, chunkHeight = 160, renderDistance = 3;
|
||||
const chunks = new Map(), chunkMeshes = new Map();
|
||||
let lastChunkX = -999, lastChunkZ = -999;
|
||||
let currentBlockType = 1;
|
||||
|
||||
// --- Three.js Setup ---
|
||||
const scene = new THREE.Scene();
|
||||
scene.background = new THREE.Color(0x1a0b2e); // Mythical purple night
|
||||
scene.fog = new THREE.FogExp2(0x1a0b2e, 0.015);
|
||||
|
||||
const camera = new THREE.PerspectiveCamera(80, window.innerWidth / window.innerHeight, 0.1, 1000);
|
||||
const renderer = new THREE.WebGLRenderer({ antialias: false });
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
document.body.appendChild(renderer.domElement);
|
||||
|
||||
const controls = new THREE.PointerLockControls(camera, renderer.domElement);
|
||||
|
||||
// Lighting
|
||||
const dirLight = new THREE.DirectionalLight(0xaa88ff, 0.7);
|
||||
dirLight.position.set(-100, 150, -50);
|
||||
scene.add(dirLight);
|
||||
const ambientLight = new THREE.AmbientLight(0x403050, 1.0);
|
||||
scene.add(ambientLight);
|
||||
|
||||
// Stars
|
||||
const starsGeo = new THREE.BufferGeometry();
|
||||
const starsPositions = [];
|
||||
for(let i=0; i<2000; i++) {
|
||||
starsPositions.push((Math.random() - 0.5) * 1000, Math.random() * 400 + 50, (Math.random() - 0.5) * 1000);
|
||||
}
|
||||
starsGeo.setAttribute('position', new THREE.Float32BufferAttribute(starsPositions, 3));
|
||||
const starsMat = new THREE.PointsMaterial({color: 0xffffff, size: 1.5});
|
||||
scene.add(new THREE.Points(starsGeo, starsMat));
|
||||
|
||||
// Block Material
|
||||
const material = new THREE.MeshLambertMaterial({ map: generateAtlas(), transparent: true, alphaTest: 0.1 });
|
||||
setToolbarIcons();
|
||||
|
||||
// Active Block Outline
|
||||
const outlineGeo = new THREE.EdgesGeometry(new THREE.BoxGeometry(1.01, 1.01, 1.01));
|
||||
const outlineMat = new THREE.LineBasicMaterial({ color: 0xffffff, transparent: true, opacity: 0.5 });
|
||||
const outlineMesh = new THREE.LineSegments(outlineGeo, outlineMat);
|
||||
outlineMesh.visible = false;
|
||||
scene.add(outlineMesh);
|
||||
|
||||
// --- Chunk Generation ---
|
||||
function generateChunk(cx, cz) {
|
||||
let data = new Uint8Array(16 * chunkHeight * 16);
|
||||
let treeX = 0, treeZ = 0;
|
||||
|
||||
for(let lx = 0; lx < 16; lx++) {
|
||||
for(let lz = 0; lz < 16; lz++) {
|
||||
let wx = cx * 16 + lx;
|
||||
let wz = cz * 16 + lz;
|
||||
|
||||
// Base Terrain
|
||||
let n = perlin.noise(wx * 0.02, 0, wz * 0.02);
|
||||
let n2 = perlin.noise(wx * 0.005, 0, wz * 0.005);
|
||||
let h = Math.floor((n * 0.8 + n2 * 1.2) * 15 + 30);
|
||||
if(h < 2) h = 2;
|
||||
|
||||
for(let y = 0; y < chunkHeight; y++) {
|
||||
let idx = (lx * 16 + lz) * chunkHeight + y;
|
||||
if(y === h) data[idx] = 1; // Grass
|
||||
else if(y < h && y > h - 4) data[idx] = 2; // Dirt
|
||||
else if(y <= h - 4) data[idx] = 3; // Stone
|
||||
else data[idx] = 0; // Air
|
||||
}
|
||||
|
||||
let distToTree = Math.sqrt((wx - treeX)**2 + (wz - treeZ)**2);
|
||||
|
||||
// Yggdrasil Trunk
|
||||
if(distToTree < 14 - (h * 0.03)) {
|
||||
for(let y = h; y < 115; y++) {
|
||||
data[(lx * 16 + lz) * chunkHeight + y] = 4; // Wood
|
||||
}
|
||||
}
|
||||
|
||||
// Roots
|
||||
if(distToTree >= 12 && distToTree < 40) {
|
||||
let angle = Math.atan2(wz - treeZ, wx - treeX);
|
||||
let rootFactor = Math.sin(angle * 7 + distToTree * 0.15);
|
||||
if(rootFactor > 0.6) {
|
||||
let rootHeight = h + (40 - distToTree) * 0.4;
|
||||
for(let y = h; y < rootHeight; y++) {
|
||||
data[(lx * 16 + lz) * chunkHeight + y] = 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Canopy
|
||||
if(distToTree < 55) {
|
||||
for(let y = 80; y < 150; y++) {
|
||||
let d3 = Math.sqrt((wx - treeX)**2 + (y - 115)**2 * 2.0 + (wz - treeZ)**2);
|
||||
if(d3 < 45) {
|
||||
let idx = (lx * 16 + lz) * chunkHeight + y;
|
||||
if(data[idx] === 0) {
|
||||
let leafNoise = perlin.noise(wx * 0.15, y * 0.15, wz * 0.15);
|
||||
if(leafNoise > -0.2) {
|
||||
if(Math.random() < 0.02) data[idx] = 6; // Magic fruit
|
||||
else data[idx] = 5; // Leaves
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Floating Islands
|
||||
if(distToTree > 60 && distToTree < 200) {
|
||||
let islandNoise = perlin.noise(wx * 0.04, 0, wz * 0.04);
|
||||
if(islandNoise > 0.72) {
|
||||
let islandY = 60 + Math.sin(wx * 0.03 + wz * 0.03) * 25;
|
||||
let islandThickness = (islandNoise - 0.72) * 25;
|
||||
for(let y = Math.floor(islandY - islandThickness); y <= Math.floor(islandY); y++) {
|
||||
let idx = (lx * 16 + lz) * chunkHeight + y;
|
||||
if(y === Math.floor(islandY)) data[idx] = 1;
|
||||
else data[idx] = 3;
|
||||
}
|
||||
// Shrine ruins
|
||||
if(islandNoise > 0.85 && Math.random() < 0.08) {
|
||||
for(let sy = 1; sy <= 3; sy++) data[(lx * 16 + lz) * chunkHeight + Math.floor(islandY + sy)] = 3;
|
||||
data[(lx * 16 + lz) * chunkHeight + Math.floor(islandY + 4)] = 6;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
// --- Data Access ---
|
||||
function getBlock(x, y, z) {
|
||||
if(y < 0 || y >= chunkHeight) return 0;
|
||||
let cx = Math.floor(x / 16), cz = Math.floor(z / 16);
|
||||
let key = cx + ',' + cz;
|
||||
if(!chunks.has(key)) return 0;
|
||||
let lx = x - cx * 16, lz = z - cz * 16;
|
||||
return chunks.get(key)[(lx * 16 + lz) * chunkHeight + y];
|
||||
}
|
||||
|
||||
function setBlock(x, y, z, v) {
|
||||
if(y < 0 || y >= chunkHeight) return;
|
||||
let cx = Math.floor(x / 16), cz = Math.floor(z / 16);
|
||||
let key = cx + ',' + cz;
|
||||
if(!chunks.has(key)) return;
|
||||
let lx = x - cx * 16, lz = z - cz * 16;
|
||||
chunks.get(key)[(lx * 16 + lz) * chunkHeight + y] = v;
|
||||
|
||||
buildChunkMesh(cx, cz);
|
||||
if(lx === 0) buildChunkMesh(cx - 1, cz);
|
||||
if(lx === 15) buildChunkMesh(cx + 1, cz);
|
||||
if(lz === 0) buildChunkMesh(cx, cz - 1);
|
||||
if(lz === 15) buildChunkMesh(cx, cz + 1);
|
||||
}
|
||||
|
||||
// --- Chunk Meshing ---
|
||||
function getBlockTexture(blockType, faceIndex) {
|
||||
switch(blockType) {
|
||||
case 1: return faceIndex === 2 ? 0 : (faceIndex === 3 ? 2 : 1);
|
||||
case 2: return 2;
|
||||
case 3: return 3;
|
||||
case 4: return (faceIndex === 2 || faceIndex === 3) ? 5 : 4;
|
||||
case 5: return 6;
|
||||
case 6: return 7;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const faces = [
|
||||
[ [1,1,1], [1,0,1], [1,0,0], [1,1,0] ], // Right X+
|
||||
[ [0,1,0], [0,0,0], [0,0,1], [0,1,1] ], // Left X-
|
||||
[ [0,1,0], [0,1,1], [1,1,1], [1,1,0] ], // Top Y+
|
||||
[ [0,0,1], [0,0,0], [1,0,0], [1,0,1] ], // Bottom Y-
|
||||
[ [0,1,1], [0,0,1], [1,0,1], [1,1,1] ], // Front Z+
|
||||
[ [1,1,0], [1,0,0], [0,0,0], [0,1,0] ] // Back Z-
|
||||
];
|
||||
const faceNormals = [ [1,0,0], [-1,0,0], [0,1,0], [0,-1,0], [0,0,1], [0,0,-1] ];
|
||||
|
||||
function buildChunkMesh(cx, cz) {
|
||||
let key = cx + ',' + cz;
|
||||
let data = chunks.get(key);
|
||||
if(!data) return;
|
||||
|
||||
let positions = [], normals = [], uvs = [], indices = [];
|
||||
let idxCounter = 0;
|
||||
|
||||
for(let lx = 0; lx < 16; lx++) {
|
||||
for(let lz = 0; lz < 16; lz++) {
|
||||
for(let y = 0; y < chunkHeight; y++) {
|
||||
let block = data[(lx * 16 + lz) * chunkHeight + y];
|
||||
if(block === 0) continue;
|
||||
|
||||
let wx = cx * 16 + lx, wz = cz * 16 + lz;
|
||||
|
||||
for(let f = 0; f < 6; f++) {
|
||||
let nx = wx + faceNormals[f][0];
|
||||
let ny = y + faceNormals[f][1];
|
||||
let nz = wz + faceNormals[f][2];
|
||||
|
||||
let neighborBlock = getBlock(nx, ny, nz);
|
||||
let drawFace = false;
|
||||
if (neighborBlock === 0) drawFace = true;
|
||||
else if (neighborBlock === 5 && block !== 5) drawFace = true;
|
||||
else if (neighborBlock === 5 && block === 6) drawFace = true;
|
||||
|
||||
if(drawFace) {
|
||||
let texIndex = getBlockTexture(block, f);
|
||||
let tu = (texIndex % 4) * 0.25;
|
||||
let ty = Math.floor(texIndex / 4);
|
||||
let tv = 1.0 - (ty + 1) * 0.25;
|
||||
|
||||
let fVerts = faces[f];
|
||||
for(let i=0; i<4; i++) {
|
||||
positions.push(wx + fVerts[i][0], y + fVerts[i][1], wz + fVerts[i][2]);
|
||||
normals.push(...faceNormals[f]);
|
||||
let uu = tu + (i===2 || i===3 ? 0.25 : 0);
|
||||
let vv = tv + (i===0 || i===3 ? 0.25 : 0);
|
||||
uvs.push(uu, vv);
|
||||
}
|
||||
indices.push(idxCounter, idxCounter+1, idxCounter+2, idxCounter, idxCounter+2, idxCounter+3);
|
||||
idxCounter += 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let geometry = new THREE.BufferGeometry();
|
||||
geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3));
|
||||
geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3));
|
||||
geometry.setAttribute('uv', new THREE.Float32BufferAttribute(uvs, 2));
|
||||
geometry.setIndex(indices);
|
||||
|
||||
if(chunkMeshes.has(key)) {
|
||||
scene.remove(chunkMeshes.get(key));
|
||||
chunkMeshes.get(key).geometry.dispose();
|
||||
}
|
||||
if(positions.length > 0) {
|
||||
let mesh = new THREE.Mesh(geometry, material);
|
||||
scene.add(mesh);
|
||||
chunkMeshes.set(key, mesh);
|
||||
} else {
|
||||
chunkMeshes.set(key, new THREE.Mesh()); // Empty placeholder to prevent rebuilds
|
||||
}
|
||||
}
|
||||
|
||||
function updateChunks(playerPos) {
|
||||
let px = Math.floor(playerPos.x / 16), pz = Math.floor(playerPos.z / 16);
|
||||
if(px !== lastChunkX || pz !== lastChunkZ) {
|
||||
lastChunkX = px; lastChunkZ = pz;
|
||||
for(let x = px - renderDistance; x <= px + renderDistance; x++) {
|
||||
for(let z = pz - renderDistance; z <= pz + renderDistance; z++) {
|
||||
let key = x + ',' + z;
|
||||
if(!chunks.has(key)) chunks.set(key, generateChunk(x, z));
|
||||
}
|
||||
}
|
||||
for(let x = px - renderDistance; x <= px + renderDistance; x++) {
|
||||
for(let z = pz - renderDistance; z <= pz + renderDistance; z++) {
|
||||
let key = x + ',' + z;
|
||||
if(!chunkMeshes.has(key)) buildChunkMesh(x, z);
|
||||
}
|
||||
}
|
||||
let toDelete = [];
|
||||
for(let [key, mesh] of chunkMeshes) {
|
||||
let [cx, cz] = key.split(',').map(Number);
|
||||
if(Math.abs(cx - px) > renderDistance + 1 || Math.abs(cz - pz) > renderDistance + 1) {
|
||||
scene.remove(mesh);
|
||||
if(mesh.geometry) mesh.geometry.dispose();
|
||||
toDelete.push(key);
|
||||
}
|
||||
}
|
||||
for(let key of toDelete) chunkMeshes.delete(key);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Interaction & UI ---
|
||||
document.getElementById('start-btn').addEventListener('click', () => controls.lock());
|
||||
controls.addEventListener('lock', () => document.getElementById('instructions').style.display = 'none');
|
||||
controls.addEventListener('unlock', () => document.getElementById('instructions').style.display = 'flex');
|
||||
|
||||
let moveForward = false, moveBackward = false, moveLeft = false, moveRight = false, canJump = false;
|
||||
document.addEventListener('keydown', (e) => {
|
||||
switch (e.code) {
|
||||
case 'ArrowUp': case 'KeyW': moveForward = true; break;
|
||||
case 'ArrowLeft': case 'KeyA': moveLeft = true; break;
|
||||
case 'ArrowDown': case 'KeyS': moveBackward = true; break;
|
||||
case 'ArrowRight': case 'KeyD': moveRight = true; break;
|
||||
case 'Space': if(canJump) { velocity.y = 12; canJump = false; } break;
|
||||
case 'Digit1': setBlockType(1); break;
|
||||
case 'Digit2': setBlockType(2); break;
|
||||
case 'Digit3': setBlockType(3); break;
|
||||
case 'Digit4': setBlockType(4); break;
|
||||
case 'Digit5': setBlockType(5); break;
|
||||
case 'Digit6': setBlockType(6); break;
|
||||
}
|
||||
});
|
||||
document.addEventListener('keyup', (e) => {
|
||||
switch (e.code) {
|
||||
case 'ArrowUp': case 'KeyW': moveForward = false; break;
|
||||
case 'ArrowLeft': case 'KeyA': moveLeft = false; break;
|
||||
case 'ArrowDown': case 'KeyS': moveBackward = false; break;
|
||||
case 'ArrowRight': case 'KeyD': moveRight = false; break;
|
||||
}
|
||||
});
|
||||
|
||||
function setBlockType(type) {
|
||||
currentBlockType = type;
|
||||
document.querySelectorAll('.slot').forEach(el => el.classList.remove('selected'));
|
||||
document.getElementById('slot' + type).classList.add('selected');
|
||||
}
|
||||
|
||||
const raycaster = new THREE.Raycaster();
|
||||
const center = new THREE.Vector2(0, 0);
|
||||
document.addEventListener('mousedown', (e) => {
|
||||
if(!controls.isLocked) return;
|
||||
raycaster.setFromCamera(center, camera);
|
||||
let validMeshes = Array.from(chunkMeshes.values()).filter(m => m.geometry);
|
||||
let intersects = raycaster.intersectObjects(validMeshes);
|
||||
|
||||
if(intersects.length > 0 && intersects[0].distance < 8) {
|
||||
let intersect = intersects[0];
|
||||
let normal = intersect.face.normal;
|
||||
|
||||
if(e.button === 0) { // Break
|
||||
let bx = Math.floor(intersect.point.x - normal.x * 0.5);
|
||||
let by = Math.floor(intersect.point.y - normal.y * 0.5);
|
||||
let bz = Math.floor(intersect.point.z - normal.z * 0.5);
|
||||
if(by > 0) setBlock(bx, by, bz, 0);
|
||||
} else if(e.button === 2) { // Place
|
||||
let bx = Math.floor(intersect.point.x + normal.x * 0.5);
|
||||
let by = Math.floor(intersect.point.y + normal.y * 0.5);
|
||||
let bz = Math.floor(intersect.point.z + normal.z * 0.5);
|
||||
|
||||
let cx = Math.floor(camera.position.x), cz = Math.floor(camera.position.z);
|
||||
let cy = Math.floor(camera.position.y), cyF = Math.floor(camera.position.y - 1.6);
|
||||
if(bx === cx && bz === cz && (by === cy || by === cyF)) return; // Prevent placing in player
|
||||
|
||||
if(by > 0 && by < chunkHeight - 1) setBlock(bx, by, bz, currentBlockType);
|
||||
}
|
||||
}
|
||||
});
|
||||
document.addEventListener('contextmenu', e => e.preventDefault());
|
||||
|
||||
// --- Physics & Loop ---
|
||||
let velocity = new THREE.Vector3();
|
||||
let direction = new THREE.Vector3();
|
||||
const clock = new THREE.Clock();
|
||||
const playerHeight = 1.6;
|
||||
|
||||
function checkCollision(pos) {
|
||||
let x0 = Math.floor(pos.x - 0.3), x1 = Math.floor(pos.x + 0.3);
|
||||
let z0 = Math.floor(pos.z - 0.3), z1 = Math.floor(pos.z + 0.3);
|
||||
let y0 = Math.floor(pos.y - playerHeight), y1 = Math.floor(pos.y + 0.2);
|
||||
for(let x = x0; x <= x1; x++) {
|
||||
for(let y = y0; y <= y1; y++) {
|
||||
for(let z = z0; z <= z1; z++) {
|
||||
if(getBlock(x, y, z) !== 0) return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initial Spawn
|
||||
camera.position.set(0, 100, 70); // Spawn in front of the tree
|
||||
updateChunks(camera.position);
|
||||
let startY = 150;
|
||||
while(getBlock(0, startY, 70) === 0 && startY > 0) startY--;
|
||||
camera.position.set(0, startY + playerHeight + 1, 70);
|
||||
|
||||
function animate() {
|
||||
requestAnimationFrame(animate);
|
||||
if (controls.isLocked) {
|
||||
let delta = Math.min(clock.getDelta(), 0.1);
|
||||
|
||||
velocity.x -= velocity.x * 10.0 * delta;
|
||||
velocity.z -= velocity.z * 10.0 * delta;
|
||||
velocity.y -= 35.0 * delta; // Gravity
|
||||
|
||||
direction.z = Number(moveForward) - Number(moveBackward);
|
||||
direction.x = Number(moveRight) - Number(moveLeft);
|
||||
direction.normalize();
|
||||
|
||||
let speed = 50.0;
|
||||
if (moveForward || moveBackward) velocity.z -= direction.z * speed * delta;
|
||||
if (moveLeft || moveRight) velocity.x -= direction.x * speed * delta;
|
||||
|
||||
let cObj = controls.getObject();
|
||||
let prevPos = cObj.position.clone();
|
||||
|
||||
controls.moveRight(-velocity.x * delta);
|
||||
controls.moveForward(-velocity.z * delta);
|
||||
|
||||
if(checkCollision(cObj.position)) {
|
||||
let tx = cObj.position.x, tz = cObj.position.z;
|
||||
cObj.position.set(tx, prevPos.y, prevPos.z);
|
||||
if(checkCollision(cObj.position)) { cObj.position.x = prevPos.x; velocity.x = 0; }
|
||||
cObj.position.set(cObj.position.x, prevPos.y, tz);
|
||||
if(checkCollision(cObj.position)) { cObj.position.z = prevPos.z; velocity.z = 0; }
|
||||
}
|
||||
|
||||
cObj.position.y += velocity.y * delta;
|
||||
if(checkCollision(cObj.position)) {
|
||||
if(velocity.y < 0) {
|
||||
canJump = true;
|
||||
cObj.position.y = Math.floor(cObj.position.y - playerHeight) + 1 + playerHeight + 0.001;
|
||||
} else {
|
||||
cObj.position.y = Math.floor(cObj.position.y + 0.2) - 0.201;
|
||||
}
|
||||
velocity.y = 0;
|
||||
} else {
|
||||
canJump = false;
|
||||
}
|
||||
|
||||
updateChunks(cObj.position);
|
||||
|
||||
// Update Outline
|
||||
raycaster.setFromCamera(center, camera);
|
||||
let validMeshes = Array.from(chunkMeshes.values()).filter(m => m.geometry);
|
||||
let intersects = raycaster.intersectObjects(validMeshes);
|
||||
if(intersects.length > 0 && intersects[0].distance < 8) {
|
||||
let pt = intersects[0].point, nm = intersects[0].face.normal;
|
||||
outlineMesh.position.set(
|
||||
Math.floor(pt.x - nm.x * 0.5) + 0.5,
|
||||
Math.floor(pt.y - nm.y * 0.5) + 0.5,
|
||||
Math.floor(pt.z - nm.z * 0.5) + 0.5
|
||||
);
|
||||
outlineMesh.visible = true;
|
||||
} else {
|
||||
outlineMesh.visible = false;
|
||||
}
|
||||
} else {
|
||||
clock.getDelta();
|
||||
}
|
||||
renderer.render(scene, camera);
|
||||
}
|
||||
|
||||
window.addEventListener('resize', () => {
|
||||
camera.aspect = window.innerWidth / window.innerHeight;
|
||||
camera.updateProjectionMatrix();
|
||||
renderer.setSize(window.innerWidth, window.innerHeight);
|
||||
});
|
||||
|
||||
animate();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
Whitespace-only changes.
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,670 @@
|
||||
<svg viewBox="0 0 800 600" xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
|
||||
<defs>
|
||||
<!-- Sky background -->
|
||||
<linearGradient id="skyGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#0b132b" />
|
||||
<stop offset="25%" stop-color="#1c2541" />
|
||||
<stop offset="50%" stop-color="#3a225d" />
|
||||
<stop offset="70%" stop-color="#8c2f39" />
|
||||
<stop offset="85%" stop-color="#eb6424" />
|
||||
<stop offset="100%" stop-color="#fbc02d" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Sun glow -->
|
||||
<radialGradient id="sunGrad" cx="0.5" cy="0.5" r="0.5">
|
||||
<stop offset="0%" stop-color="#ffffff" />
|
||||
<stop offset="20%" stop-color="#fff59d" />
|
||||
<stop offset="55%" stop-color="#ff9100" stop-opacity="0.8" />
|
||||
<stop offset="100%" stop-color="#ff3d00" stop-opacity="0" />
|
||||
</radialGradient>
|
||||
|
||||
<!-- Cloud gradient -->
|
||||
<linearGradient id="cloudGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ffb74d" stop-opacity="0.45" />
|
||||
<stop offset="50%" stop-color="#e040fb" stop-opacity="0.3" />
|
||||
<stop offset="100%" stop-color="#4a148c" stop-opacity="0.05" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Ocean gradient -->
|
||||
<linearGradient id="seaGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#170c2a" />
|
||||
<stop offset="20%" stop-color="#161f4c" />
|
||||
<stop offset="55%" stop-color="#02476b" />
|
||||
<stop offset="85%" stop-color="#006c84" />
|
||||
<stop offset="100%" stop-color="#058085" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Sea wave highlight -->
|
||||
<linearGradient id="seaHighlight" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ffe082" stop-opacity="0.8" />
|
||||
<stop offset="50%" stop-color="#ff8f00" stop-opacity="0.4" />
|
||||
<stop offset="100%" stop-color="#008080" stop-opacity="0" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Sand gradient -->
|
||||
<linearGradient id="sandGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#fed766" />
|
||||
<stop offset="35%" stop-color="#f4b251" />
|
||||
<stop offset="75%" stop-color="#d07c34" />
|
||||
<stop offset="100%" stop-color="#803e12" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Wet sand reflection -->
|
||||
<linearGradient id="wetSand" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#45112e" stop-opacity="0.75" />
|
||||
<stop offset="40%" stop-color="#5a2c22" stop-opacity="0.6" />
|
||||
<stop offset="100%" stop-color="#240c02" stop-opacity="0.9" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Chrome metallic reflection -->
|
||||
<linearGradient id="chromeGrad" x1="0" y1="0" x2="1" y2="1">
|
||||
<stop offset="0%" stop-color="#cbd5e1" />
|
||||
<stop offset="20%" stop-color="#f8fafc" />
|
||||
<stop offset="40%" stop-color="#94a3b8" />
|
||||
<stop offset="45%" stop-color="#475569" />
|
||||
<stop offset="55%" stop-color="#e2e8f0" />
|
||||
<stop offset="80%" stop-color="#f8fafc" />
|
||||
<stop offset="100%" stop-color="#334155" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Cruiser bike frame teal -->
|
||||
<linearGradient id="frameGrad" x1="0" y1="0" x2="1" y2="0">
|
||||
<stop offset="0%" stop-color="#26c6da" />
|
||||
<stop offset="50%" stop-color="#00acc1" />
|
||||
<stop offset="100%" stop-color="#006064" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Tire gradient -->
|
||||
<radialGradient id="tireGrad" cx="0.5" cy="0.5" r="0.5" fx="0.4" fy="0.4">
|
||||
<stop offset="0%" stop-color="#ffffff" />
|
||||
<stop offset="75%" stop-color="#f5f5f4" />
|
||||
<stop offset="90%" stop-color="#e7e5e4" />
|
||||
<stop offset="100%" stop-color="#b4b2af" />
|
||||
</radialGradient>
|
||||
|
||||
<!-- Leather brown -->
|
||||
<linearGradient id="leatherGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#a1887f" />
|
||||
<stop offset="40%" stop-color="#6d4c41" />
|
||||
<stop offset="100%" stop-color="#3e2723" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Pelican feathers -->
|
||||
<radialGradient id="pelicanFeather" cx="0.3" cy="0.3" r="0.7">
|
||||
<stop offset="0%" stop-color="#ffffff" />
|
||||
<stop offset="70%" stop-color="#f1f5f9" />
|
||||
<stop offset="90%" stop-color="#cbd5e1" />
|
||||
<stop offset="100%" stop-color="#94a3b8" />
|
||||
</radialGradient>
|
||||
|
||||
<!-- Pelican beak -->
|
||||
<linearGradient id="beakGrad" x1="0" y1="0" x2="1" y2="0.3">
|
||||
<stop offset="0%" stop-color="#ffe082" />
|
||||
<stop offset="40%" stop-color="#ffb300" />
|
||||
<stop offset="80%" stop-color="#ff7043" />
|
||||
<stop offset="100%" stop-color="#d84315" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Pelican pouch (semi-translucent) -->
|
||||
<linearGradient id="pouchGrad" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="0%" stop-color="#ffe082" stop-opacity="0.9" />
|
||||
<stop offset="45%" stop-color="#ffb300" stop-opacity="0.85" />
|
||||
<stop offset="80%" stop-color="#ff7043" stop-opacity="0.75" />
|
||||
<stop offset="100%" stop-color="#d84315" stop-opacity="0.65" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Drop shadows -->
|
||||
<filter id="shadow" x="-10%" y="-10%" width="120%" height="120%">
|
||||
<feDropShadow dx="3" dy="5" stdDeviation="4" flood-color="#090514" flood-opacity="0.35" />
|
||||
</filter>
|
||||
|
||||
<filter id="bikeShadow" x="-10%" y="-10%" width="120%" height="120%">
|
||||
<feGaussianBlur stdDeviation="6" result="blur" />
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0"/>
|
||||
</filter>
|
||||
|
||||
<filter id="sunGlow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feGaussianBlur stdDeviation="15" result="blur" />
|
||||
<feMerge>
|
||||
<feMergeNode in="blur" />
|
||||
<feMergeNode in="SourceGraphic" />
|
||||
</feMerge>
|
||||
</filter>
|
||||
|
||||
<!-- Soft ambient shadow gradient -->
|
||||
<radialGradient id="groundShadow" cx="50%" cy="50%" r="50%">
|
||||
<stop offset="0%" stop-color="#140602" stop-opacity="0.7" />
|
||||
<stop offset="40%" stop-color="#140602" stop-opacity="0.4" />
|
||||
<stop offset="100%" stop-color="#140602" stop-opacity="0" />
|
||||
</radialGradient>
|
||||
</defs>
|
||||
|
||||
<!-- ==================== BACKGROUND ==================== -->
|
||||
<!-- Sky -->
|
||||
<rect width="800" height="600" fill="url(#skyGrad)" />
|
||||
|
||||
<!-- Sun -->
|
||||
<circle cx="560" cy="270" r="140" fill="url(#sunGrad)" filter="url(#sunGlow)" opacity="0.85" />
|
||||
<circle cx="560" cy="270" r="50" fill="#ffffff" filter="url(#sunGlow)" opacity="0.9" />
|
||||
|
||||
<!-- Sky Clouds -->
|
||||
<!-- Distant thin cloud -->
|
||||
<path d="M 100,140 C 180,120 280,130 350,150 C 370,120 440,110 490,130 C 530,115 590,125 610,145 C 670,140 720,150 750,165 L 750,180 L 100,180 Z" fill="url(#cloudGrad)" opacity="0.3" />
|
||||
<!-- Vibrant midground cloud -->
|
||||
<path d="M -20,230 C 30,205 90,200 130,220 C 170,195 240,190 290,215 C 330,200 390,210 420,235 C 470,225 520,235 550,255 L 550,280 L -20,280 Z" fill="url(#cloudGrad)" opacity="0.4" />
|
||||
|
||||
<!-- Seagulls in the distance -->
|
||||
<g stroke="#ffb74d" stroke-width="1.5" fill="none" opacity="0.7">
|
||||
<path d="M 120,95 Q 128,88 135,95 Q 142,88 150,95" />
|
||||
<path d="M 165,110 Q 171,105 177,110 Q 183,105 189,110" />
|
||||
<path d="M 220,100 Q 225,96 230,100 Q 235,96 240,100" opacity="0.5" transform="scale(0.8) translate(50, 20)" />
|
||||
</g>
|
||||
|
||||
|
||||
<!-- ==================== THE OCEAN ==================== -->
|
||||
<!-- Distant ocean back -->
|
||||
<rect x="0" y="270" width="800" height="130" fill="url(#seaGrad)" />
|
||||
|
||||
<!-- Sun reflection on water -->
|
||||
<ellipse cx="560" cy="335" rx="160" ry="60" fill="url(#seaHighlight)" style="mix-blend-mode: color-dodge;" opacity="0.7" />
|
||||
|
||||
<!-- Horizon glare strip -->
|
||||
<line x1="0" y1="270" x2="800" y2="270" stroke="#ffeb3b" stroke-width="2" opacity="0.6" />
|
||||
|
||||
<!-- Wave horizontal streaks (shimmer) -->
|
||||
<g stroke="#ffd54f" stroke-width="1" opacity="0.8">
|
||||
<line x1="420" y1="285" x2="680" y2="285" stroke-width="1.5" />
|
||||
<line x1="380" y1="295" x2="720" y2="295" stroke-width="2" />
|
||||
<line x1="480" y1="305" x2="660" y2="305" stroke-width="2.5" />
|
||||
<line x1="350" y1="315" x2="750" y2="315" stroke-width="3" />
|
||||
<line x1="450" y1="330" x2="700" y2="330" stroke-width="4" />
|
||||
<line x1="280" y1="345" x2="780" y2="345" stroke-width="3.5" />
|
||||
<line x1="400" y1="365" x2="740" y2="365" stroke-width="4" />
|
||||
</g>
|
||||
|
||||
<!-- Wave lines (scrolling look) -->
|
||||
<path d="M 0,330 C 150,320 250,345 400,335 C 550,325 650,345 800,335 L 800,400 L 0,400 Z" fill="#034f70" opacity="0.3" />
|
||||
<path d="M 0,360 C 120,355 220,380 380,365 C 540,350 680,385 800,365 L 800,420 L 0,420 Z" fill="#005d7a" opacity="0.4" />
|
||||
|
||||
<!-- Foam details near shore -->
|
||||
<path d="M 0,390 C 180,375 280,410 480,395 C 680,380 720,415 800,405" stroke="#e0f7fa" stroke-width="3" fill="none" opacity="0.6" />
|
||||
<path d="M -10,405 C 150,395 310,425 490,410 C 670,395 730,430 810,415" stroke="#ffffff" stroke-width="4" stroke-dasharray="10 5 15 8" fill="none" opacity="0.8" />
|
||||
|
||||
|
||||
<!-- ==================== THE BEACH SHORE ==================== -->
|
||||
<!-- Wet Sand Area -->
|
||||
<path d="M -10,400 Q 250,380 500,430 T 810,410 L 810,600 L -10,600 Z" fill="url(#wetSand)" />
|
||||
|
||||
<!-- Glowing Edge of Tide (Water foam on sand) -->
|
||||
<path d="M -10,402 Q 250,382 500,432 T 810,412" stroke="#ffffff" stroke-width="6" fill="none" filter="url(#sunGlow)" opacity="0.8" />
|
||||
<path d="M -10,402 Q 250,382 500,432 T 810,412" stroke="#ffe082" stroke-width="2" fill="none" opacity="0.9" />
|
||||
|
||||
<!-- Dry Sand Dune (Foreground) -->
|
||||
<path d="M -10,455 Q 180,430 380,480 T 810,465 L 810,600 L -10,600 Z" fill="url(#sandGrad)" />
|
||||
|
||||
<!-- Ambient Shadows under the bicycle wheels -->
|
||||
<!-- Rear wheel shadow -->
|
||||
<ellipse cx="230" cy="525" rx="85" ry="18" fill="url(#groundShadow)" />
|
||||
<!-- Front wheel shadow -->
|
||||
<ellipse cx="550" cy="525" rx="85" ry="18" fill="url(#groundShadow)" />
|
||||
<!-- Center stand/pedal shadow -->
|
||||
<ellipse cx="380" cy="528" rx="140" ry="22" fill="url(#groundShadow)" opacity="0.8" />
|
||||
|
||||
|
||||
<!-- ==================== BICYCLE REFLECTION (ON WET SAND) ==================== -->
|
||||
<!-- Highly stylized, low-opacity, slightly blurred vertical reflection -->
|
||||
<g transform="translate(0, 1050) scale(1, -1)" opacity="0.12" filter="url(#bikeShadow)">
|
||||
<!-- Back wheel reflection -->
|
||||
<circle cx="230" cy="525" r="70" fill="none" stroke="#ffe082" stroke-width="12" />
|
||||
<!-- Front wheel reflection -->
|
||||
<circle cx="550" cy="525" r="70" fill="none" stroke="#ffe082" stroke-width="12" />
|
||||
<!-- Frame reflection -->
|
||||
<path d="M 230,525 L 360,525 L 330,390 L 230,525 L 310,320 M 330,390 L 485,320 L 550,525 M 310,320 L 485,320" stroke="#00acc1" stroke-width="10" fill="none" />
|
||||
<!-- Pelican body reflection outline -->
|
||||
<ellipse cx="330" cy="270" rx="65" ry="50" fill="#ffffff" />
|
||||
<path d="M 330,220 C 350,160 410,140 430,120" stroke="#ffb300" stroke-width="18" stroke-linecap="round" fill="none" />
|
||||
</g>
|
||||
|
||||
|
||||
<!-- ==================== THE BICYCLE ==================== -->
|
||||
<g id="bicycle">
|
||||
<!-- REAR WHEEL -->
|
||||
<g id="rear-wheel">
|
||||
<!-- Outer Tire (Cream White) -->
|
||||
<circle cx="230" cy="450" r="72" fill="none" stroke="#eae6df" stroke-width="15" filter="url(#shadow)" />
|
||||
<!-- Tire Tread Grooves -->
|
||||
<circle cx="230" cy="450" r="78" fill="none" stroke="#d6d1ca" stroke-width="1" stroke-dasharray="4 8" />
|
||||
<circle cx="230" cy="450" r="65" fill="none" stroke="#d2cbc4" stroke-width="1" />
|
||||
<!-- Rim (Chrome) -->
|
||||
<circle cx="230" cy="450" r="64" fill="none" stroke="url(#chromeGrad)" stroke-width="5" />
|
||||
<circle cx="230" cy="450" r="61" fill="none" stroke="#334155" stroke-width="1" />
|
||||
<!-- Spokes (Thin shiny wires) -->
|
||||
<g stroke="#eaeaea" stroke-width="0.75" opacity="0.85">
|
||||
<line x1="230" y1="450" x2="166" y2="450" /> <line x1="230" y1="450" x2="294" y2="450" />
|
||||
<line x1="230" y1="450" x2="230" y2="386" /> <line x1="230" y1="450" x2="230" y2="514" />
|
||||
<line x1="230" y1="450" x2="185" y2="405" /> <line x1="230" y1="450" x2="275" y2="495" />
|
||||
<line x1="230" y1="450" x2="185" y2="495" /> <line x1="230" y1="450" x2="275" y2="405" />
|
||||
<line x1="230" y1="450" x2="201" y2="392" /> <line x1="230" y1="450" x2="259" y2="508" />
|
||||
<line x1="230" y1="450" x2="259" y2="392" /> <line x1="230" y1="450" x2="201" y2="508" />
|
||||
<line x1="230" y1="450" x2="169" y2="423" /> <line x1="230" y1="450" x2="291" y2="477" />
|
||||
<line x1="230" y1="450" x2="169" y2="477" /> <line x1="230" y1="450" x2="291" y2="423" />
|
||||
</g>
|
||||
<!-- Wheel Hub -->
|
||||
<circle cx="230" cy="450" r="10" fill="url(#chromeGrad)" stroke="#475569" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<!-- FRONT WHEEL -->
|
||||
<g id="front-wheel">
|
||||
<!-- Outer Tire (Cream White) -->
|
||||
<circle cx="550" cy="450" r="72" fill="none" stroke="#eae6df" stroke-width="15" filter="url(#shadow)" />
|
||||
<!-- Tire Tread Grooves -->
|
||||
<circle cx="550" cy="450" r="78" fill="none" stroke="#d6d1ca" stroke-width="1" stroke-dasharray="4 8" />
|
||||
<circle cx="550" cy="450" r="65" fill="none" stroke="#d2cbc4" stroke-width="1" />
|
||||
<!-- Rim (Chrome) -->
|
||||
<circle cx="550" cy="450" r="64" fill="none" stroke="url(#chromeGrad)" stroke-width="5" />
|
||||
<circle cx="550" cy="450" r="61" fill="none" stroke="#334155" stroke-width="1" />
|
||||
<!-- Spokes -->
|
||||
<g stroke="#eaeaea" stroke-width="0.75" opacity="0.85">
|
||||
<line x1="550" y1="450" x2="486" y2="450" /> <line x1="550" y1="450" x2="614" y2="450" />
|
||||
<line x1="550" y1="450" x2="550" y2="386" /> <line x1="550" y1="450" x2="550" y2="514" />
|
||||
<line x1="550" y1="450" x2="505" y2="405" /> <line x1="550" y1="450" x2="595" y2="495" />
|
||||
<line x1="550" y1="450" x2="505" y2="495" /> <line x1="550" y1="450" x2="595" y2="405" />
|
||||
<line x1="550" y1="450" x2="521" y2="392" /> <line x1="550" y1="450" x2="579" y2="508" />
|
||||
<line x1="550" y1="450" x2="579" y2="392" /> <line x1="550" y1="450" x2="521" y2="508" />
|
||||
<line x1="550" y1="450" x2="489" y2="423" /> <line x1="550" y1="450" x2="611" y2="477" />
|
||||
<line x1="550" y1="450" x2="489" y2="477" /> <line x1="550" y1="450" x2="611" y2="423" />
|
||||
</g>
|
||||
<!-- Wheel Hub -->
|
||||
<circle cx="550" cy="450" r="10" fill="url(#chromeGrad)" stroke="#475569" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<!-- CRANKSET, CHAIN & CHAINSTAYS -->
|
||||
<!-- Rear Fork / Chain Stay (behind chain) -->
|
||||
<line x1="230" y1="450" x2="360" y2="450" stroke="url(#chromeGrad)" stroke-width="6" stroke-linecap="round" />
|
||||
<!-- Rear Fork / Seat Stay (behind wheel) -->
|
||||
<line x1="230" y1="450" x2="315" y2="320" stroke="url(#chromeGrad)" stroke-width="5" stroke-linecap="round" />
|
||||
|
||||
<!-- Bicycle Chain Loop -->
|
||||
<path d="M 230,450 C 270,432 320,432 360,432 C 378,432 382,450 380,458 C 380,466 374,470 360,468 C 320,468 270,468 230,450 Z" fill="none" stroke="#475569" stroke-width="3" stroke-linejoin="round" />
|
||||
<!-- Chain Details (dots/links) -->
|
||||
<path d="M 230,450 C 270,432 320,432 360,432 M 380,458 C 380,466 374,470 360,468 C 320,468 270,468 230,450" fill="none" stroke="#94a3b8" stroke-width="2.5" stroke-dasharray="3 3" />
|
||||
|
||||
<!-- Large Front Chainring / Sprocket -->
|
||||
<circle cx="360" cy="450" r="24" fill="url(#chromeGrad)" stroke="#334155" stroke-width="1.5" />
|
||||
<!-- Chainring Cutouts -->
|
||||
<g fill="#16151d" opacity="0.6">
|
||||
<circle cx="360" cy="450" r="17" fill="none" stroke="#16151d" stroke-width="2" stroke-dasharray="6 4" />
|
||||
</g>
|
||||
|
||||
<!-- BIKE FRAME (Cruiser Style Curved Tubes) -->
|
||||
<!-- Seat Tube (straight) -->
|
||||
<line x1="315" y1="320" x2="360" y2="450" stroke="url(#frameGrad)" stroke-width="10" stroke-linecap="round" />
|
||||
|
||||
<!-- Curved Top Tube (Cruiser signature curve) -->
|
||||
<path d="M 315,335 C 370,335 440,305 485,305" fill="none" stroke="url(#frameGrad)" stroke-width="10" stroke-linecap="round" filter="url(#shadow)" />
|
||||
<!-- Second Parallel Thin Curved Tube -->
|
||||
<path d="M 315,360 C 370,360 430,335 482,330" fill="none" stroke="url(#frameGrad)" stroke-width="6" stroke-linecap="round" />
|
||||
|
||||
<!-- Down Tube (Curved down) -->
|
||||
<path d="M 315,350 C 345,410 350,440 360,450" fill="none" stroke="url(#frameGrad)" stroke-width="11" stroke-linecap="round" />
|
||||
<path d="M 360,450 C 400,450 450,420 485,310" fill="none" stroke="url(#frameGrad)" stroke-width="11" stroke-linecap="round" />
|
||||
|
||||
<!-- Front Fork (Chrome) -->
|
||||
<g id="front-fork">
|
||||
<line x1="485" y1="300" x2="550" y2="450" stroke="url(#chromeGrad)" stroke-width="9" stroke-linecap="round" filter="url(#shadow)" />
|
||||
<line x1="485" y1="275" x2="485" y2="300" stroke="url(#chromeGrad)" stroke-width="12" />
|
||||
<circle cx="485" cy="300" r="8" fill="#334155" />
|
||||
</g>
|
||||
|
||||
<!-- Fenders (Retro mudguards - Chrome) -->
|
||||
<!-- Rear Fender -->
|
||||
<path d="M 152,450 C 152,380 200,345 270,335" fill="none" stroke="url(#chromeGrad)" stroke-width="8" stroke-linecap="round" filter="url(#shadow)" />
|
||||
<line x1="158" y1="446" x2="230" y2="450" stroke="#475569" stroke-width="2.5" />
|
||||
<line x1="210" y1="375" x2="230" y2="450" stroke="#475569" stroke-width="2.5" />
|
||||
<!-- Front Fender -->
|
||||
<path d="M 488,405 C 505,385 540,373 585,390 C 605,405 615,425 618,450" fill="none" stroke="url(#chromeGrad)" stroke-width="8" stroke-linecap="round" filter="url(#shadow)" />
|
||||
<line x1="550" y1="450" x2="605" y2="408" stroke="#475569" stroke-width="2.5" />
|
||||
|
||||
<!-- HANDLEBARS & STEM -->
|
||||
<g id="handlebars">
|
||||
<!-- Handlebar Stem -->
|
||||
<line x1="485" y1="275" x2="480" y2="225" stroke="url(#chromeGrad)" stroke-width="8" />
|
||||
<!-- Handlebar curve facing backward -->
|
||||
<path d="M 480,225 C 475,210 455,210 435,225 C 425,232 420,242 415,255" fill="none" stroke="url(#chromeGrad)" stroke-width="7" stroke-linecap="round" />
|
||||
<!-- Handlebar Grip (Leather) -->
|
||||
<path d="M 420,245 L 413,258" stroke="url(#leatherGrad)" stroke-width="10" stroke-linecap="round" />
|
||||
<circle cx="413" cy="258" r="5" fill="#3e2723" />
|
||||
|
||||
<!-- Far handlebar side (slightly visible) -->
|
||||
<path d="M 480,225 C 488,215 503,215 515,223" fill="none" stroke="#94a3b8" stroke-width="5" stroke-linecap="round" opacity="0.7" />
|
||||
</g>
|
||||
|
||||
<!-- RETRO FRONT HEADLIGHT -->
|
||||
<g id="headlight">
|
||||
<path d="M 480,245 L 500,245 C 505,245 512,250 512,258 C 512,266 505,271 500,271 L 480,271 Z" fill="url(#chromeGrad)" stroke="#334155" stroke-width="1" />
|
||||
<!-- Golden Lens -->
|
||||
<path d="M 512,250 C 515,252 515,264 512,266 Z" fill="#fff59d" stroke="#fbc02d" stroke-width="1" />
|
||||
<!-- Light beam glow -->
|
||||
<polygon points="513,252 640,220 640,320 513,264" fill="url(#sunGrad)" opacity="0.25" style="mix-blend-mode: screen;" />
|
||||
<!-- Mounting bracket -->
|
||||
<line x1="485" y1="265" x2="482" y2="255" stroke="#475569" stroke-width="3" />
|
||||
</g>
|
||||
|
||||
<!-- SADDLE / SEAT -->
|
||||
<g id="saddle" filter="url(#shadow)">
|
||||
<!-- Seat Post -->
|
||||
<line x1="315" y1="320" x2="315" y2="295" stroke="url(#chromeGrad)" stroke-width="7" />
|
||||
<!-- Seat Springs -->
|
||||
<circle cx="310" cy="295" r="5" fill="none" stroke="#475569" stroke-width="2.5" />
|
||||
<circle cx="320" cy="295" r="5" fill="none" stroke="#475569" stroke-width="2.5" />
|
||||
<!-- Cushion (Leather) -->
|
||||
<path d="M 292,288 C 292,275 310,270 330,270 C 345,270 355,278 350,285 C 345,292 315,294 292,288 Z" fill="url(#leatherGrad)" stroke="#3e2723" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<!-- FRONT WICKER BASKET & FLOWERS -->
|
||||
<g id="basket" filter="url(#shadow)">
|
||||
<!-- Leather mounting straps -->
|
||||
<rect x="474" y="240" width="4" height="12" rx="1" fill="#5c4033" />
|
||||
<rect x="492" y="242" width="4" height="12" rx="1" fill="#5c4033" opacity="0.8" />
|
||||
<!-- Basket body -->
|
||||
<path d="M 495,250 L 545,255 C 550,255 553,260 550,270 L 538,312 C 536,318 531,320 525,320 L 485,315 C 480,315 478,310 480,302 L 488,255 C 489,250 492,250 495,250 Z" fill="#d7ccc8" stroke="#a1887f" stroke-width="1.5" />
|
||||
<!-- Woven texture lines -->
|
||||
<!-- Diagonals -->
|
||||
<path d="M 488,255 L 525,320 M 498,251 L 532,310 M 510,252 L 538,300 M 525,253 L 542,285 M 484,275 L 510,318 M 481,295 L 495,317" stroke="#b09e99" stroke-width="1" />
|
||||
<path d="M 545,255 L 485,315 M 535,254 L 481,302 M 520,253 L 480,288 M 505,251 L 480,272 M 548,272 L 505,318 M 550,290 L 522,320" stroke="#b09e99" stroke-width="1" />
|
||||
<!-- Rim -->
|
||||
<path d="M 488,252 Q 515,252 546,255" fill="none" stroke="#a1887f" stroke-width="4.5" stroke-linecap="round" />
|
||||
|
||||
<!-- Flowers peeking out of the basket -->
|
||||
<!-- Red Hibiscus -->
|
||||
<g transform="translate(492, 245) scale(0.6)">
|
||||
<circle cx="0" cy="0" r="12" fill="#e91e63" />
|
||||
<path d="M 0,0 C -15,-15 -25,-5 -15,10 C -5,25 15,25 20,5 C 25,-15 15,-25 0,-20 C -10,-15 -15,-5 0,0 Z" fill="#ff1744" opacity="0.9" />
|
||||
<circle cx="0" cy="0" r="4" fill="#ffeb3b" />
|
||||
<line x1="0" y1="0" x2="15" y2="-15" stroke="#ffeb3b" stroke-width="2" />
|
||||
<circle cx="15" cy="-15" r="2" fill="#ffeb3b" />
|
||||
</g>
|
||||
<!-- Green Leaves -->
|
||||
<path d="M 522,250 Q 535,235 530,225 Q 515,235 522,250 Z" fill="#2e7d32" />
|
||||
<path d="M 484,255 Q 470,245 475,235 Q 490,245 484,255 Z" fill="#1b5e20" />
|
||||
<!-- White Plumeria -->
|
||||
<g transform="translate(515, 246) scale(0.5)">
|
||||
<ellipse cx="0" cy="-10" rx="7" ry="12" fill="#ffffff" transform="rotate(0)" />
|
||||
<ellipse cx="10" cy="-5" rx="7" ry="12" fill="#ffffff" transform="rotate(72 10 -5)" />
|
||||
<ellipse cx="8" cy="8" rx="7" ry="12" fill="#ffffff" transform="rotate(144 8 8)" />
|
||||
<ellipse cx="-5" cy="8" rx="7" ry="12" fill="#ffffff" transform="rotate(216 -5 8)" />
|
||||
<ellipse cx="-8" cy="-5" rx="7" ry="12" fill="#ffffff" transform="rotate(288 -8 -5)" />
|
||||
<circle cx="0" cy="0" r="5" fill="#ffeb3b" />
|
||||
</g>
|
||||
<!-- A cute little silver fish peeking out -->
|
||||
<g transform="translate(532, 248) rotate(-20) scale(0.6)">
|
||||
<!-- Fish Body -->
|
||||
<path d="M 0,0 C 15,-10 30,-5 40,5 C 30,10 15,10 0,0" fill="#cfd8dc" stroke="#78909c" stroke-width="1" />
|
||||
<!-- Tail -->
|
||||
<path d="M 38,3 L 48,-3 L 45,5 L 48,12 L 38,6 Z" fill="#b0bec5" stroke="#78909c" stroke-width="1" />
|
||||
<!-- Eye -->
|
||||
<circle cx="8" cy="1" r="2.5" fill="#ffffff" />
|
||||
<circle cx="9" cy="1" r="1" fill="#000000" />
|
||||
<!-- Smiling Mouth -->
|
||||
<path d="M 3,4 Q 6,6 8,4" fill="none" stroke="#78909c" stroke-width="1" />
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
||||
<!-- ==================== THE PELICAN RIDER ==================== -->
|
||||
<g id="pelican">
|
||||
<!-- BACK/FAR LEG & PEDAL (Drawn behind the body) -->
|
||||
<g id="far-leg">
|
||||
<!-- Far Hip/Thigh (highly shadowed) -->
|
||||
<path d="M 320,315 C 310,345 320,380 345,395" fill="none" stroke="#e65100" stroke-width="12" stroke-linecap="round" opacity="0.6" />
|
||||
<!-- Far Shin -->
|
||||
<line x1="345" y1="395" x2="395" y2="470" stroke="#f57c00" stroke-width="8" stroke-linecap="round" opacity="0.7" />
|
||||
<!-- Far Foot (on lower pedal) -->
|
||||
<path d="M 390,468 C 390,468 410,480 422,480 C 428,480 425,472 415,468 Z" fill="#ef6c00" opacity="0.7" />
|
||||
</g>
|
||||
<!-- Far Pedal (Lower, extending forward-down) -->
|
||||
<g id="far-pedal" opacity="0.8">
|
||||
<!-- Pedal Crank Arm -->
|
||||
<line x1="360" y1="450" x2="395" y2="475" stroke="url(#chromeGrad)" stroke-width="5.5" stroke-linecap="round" />
|
||||
<!-- Pedal Block -->
|
||||
<polygon points="385,471 410,471 405,481 380,481" fill="#1e293b" stroke="#475569" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<!-- PELICAN MAIN BODY -->
|
||||
<!-- Tail Feathers -->
|
||||
<g id="tail-feathers">
|
||||
<path d="M 230,270 C 220,285 225,305 242,315 C 255,310 262,295 265,280 Z" fill="#cbd5e1" stroke="#94a3b8" stroke-width="1" filter="url(#shadow)" />
|
||||
<path d="M 235,285 C 228,295 232,310 248,312 C 252,305 258,292 258,285 Z" fill="#94a3b8" />
|
||||
<!-- Layered fluff -->
|
||||
<path d="M 245,260 C 235,270 238,288 252,295 C 260,288 268,272 265,262 Z" fill="#f1f5f9" />
|
||||
</g>
|
||||
|
||||
<!-- Torso / Main Body -->
|
||||
<path id="torso" d="M 260,275 C 250,230 310,210 355,230 C 385,245 400,285 385,325 C 365,365 285,360 260,275 Z" fill="url(#pelicanFeather)" filter="url(#shadow)" />
|
||||
|
||||
<!-- Soft Feather Texture Overlays on Torso -->
|
||||
<g stroke="#e2e8f0" stroke-width="1.5" fill="none" opacity="0.8">
|
||||
<path d="M 285,255 C 295,260 305,255 315,260" />
|
||||
<path d="M 275,280 C 290,288 305,280 320,288" />
|
||||
<path d="M 290,305 C 305,315 320,305 335,312" />
|
||||
<path d="M 315,330 C 328,338 340,330 352,335" />
|
||||
<!-- Dark feather tips near rear -->
|
||||
<path d="M 258,278 C 265,285 272,280 280,285" stroke="#94a3b8" />
|
||||
<path d="M 264,298 C 272,305 280,298 288,305" stroke="#94a3b8" />
|
||||
</g>
|
||||
|
||||
<!-- WIND-BLOWN SCARF (Under the neck, blowing backwards) -->
|
||||
<g id="scarf-back" filter="url(#shadow)">
|
||||
<!-- Wave 1 (Longer tail) -->
|
||||
<path d="M 295,232 C 220,225 180,185 130,195 C 120,197 122,212 135,212 C 185,212 215,245 290,252 Z" fill="#d32f2f" />
|
||||
<!-- Red and White Stripes -->
|
||||
<path d="M 255,241 L 248,227 M 235,234 L 228,220 M 215,225 L 208,211 M 195,216 L 188,202 M 175,208 L 168,195 M 155,201 L 148,197 M 138,199 L 134,196" stroke="#ffffff" stroke-width="7" />
|
||||
<!-- Wave 2 (Shorter tail) -->
|
||||
<path d="M 295,242 C 240,242 200,210 155,225 C 148,227 150,240 160,240 C 205,240 235,262 290,257 Z" fill="#c62828" />
|
||||
<path d="M 260,251 L 252,242 M 240,249 L 232,240 M 220,246 L 212,237 M 200,243 L 192,234 M 180,239 L 172,231 M 164,236 L 158,230" stroke="#ffebee" stroke-width="5" />
|
||||
<!-- Fringes at the end -->
|
||||
<line x1="130" y1="195" x2="120" y2="192" stroke="#ffca28" stroke-width="2" />
|
||||
<line x1="131" y1="200" x2="121" y2="198" stroke="#ffffff" stroke-width="2" />
|
||||
<line x1="132" y1="205" x2="122" y2="204" stroke="#ffca28" stroke-width="2" />
|
||||
<line x1="133" y1="210" x2="123" y2="210" stroke="#ffffff" stroke-width="2" />
|
||||
</g>
|
||||
|
||||
<!-- S-CURVED FEATHERY NECK -->
|
||||
<g id="neck">
|
||||
<!-- Thick neck path -->
|
||||
<path d="M 345,230 C 370,180 340,115 390,105 C 400,102 415,110 422,125" fill="none" stroke="url(#pelicanFeather)" stroke-width="36" stroke-linecap="round" filter="url(#shadow)" />
|
||||
<!-- Shadow on neck curve -->
|
||||
<path d="M 345,230 C 370,180 340,115 390,105" fill="none" stroke="#94a3b8" stroke-width="4" stroke-linecap="round" opacity="0.25" />
|
||||
<!-- Feather fluff along the back of neck -->
|
||||
<path d="M 353,190 Q 343,180 348,172" stroke="#cbd5e1" stroke-width="2" fill="none" />
|
||||
<path d="M 358,165 Q 348,155 353,147" stroke="#cbd5e1" stroke-width="2" fill="none" />
|
||||
<path d="M 368,140 Q 358,130 363,122" stroke="#cbd5e1" stroke-width="2" fill="none" />
|
||||
</g>
|
||||
|
||||
<!-- FOREGROUND/NEAR LEG & PEDAL -->
|
||||
<!-- Near Pedal (Upper, extending up-back) -->
|
||||
<g id="near-pedal" filter="url(#shadow)">
|
||||
<!-- Pedal Crank Arm -->
|
||||
<line x1="360" y1="450" x2="330" y2="415" stroke="url(#chromeGrad)" stroke-width="7" stroke-linecap="round" />
|
||||
<!-- Pedal Hub -->
|
||||
<circle cx="330" cy="415" r="5" fill="#334155" />
|
||||
<!-- Pedal Block -->
|
||||
<polygon points="312,410 342,410 348,420 318,420" fill="#334155" stroke="#94a3b8" stroke-width="1" />
|
||||
</g>
|
||||
|
||||
<g id="near-leg" filter="url(#shadow)">
|
||||
<!-- Hip / Joint -->
|
||||
<path d="M 325,325 C 300,350 295,370 325,395" fill="none" stroke="url(#beakGrad)" stroke-width="14" stroke-linecap="round" />
|
||||
<!-- Thigh fluff shading -->
|
||||
<path d="M 305,335 C 295,350 295,362 312,375" fill="none" stroke="#cbd5e1" stroke-width="10" stroke-linecap="round" />
|
||||
<!-- Knee to Foot (Ankle) -->
|
||||
<line x1="325" y1="395" x2="330" y2="415" stroke="#f57c00" stroke-width="9" stroke-linecap="round" />
|
||||
<!-- Leg scales/wrinkles -->
|
||||
<line x1="325" y1="400" x2="329" y2="401" stroke="#e65100" stroke-width="1.5" />
|
||||
<line x1="326" y1="406" x2="330" y2="407" stroke="#e65100" stroke-width="1.5" />
|
||||
<!-- Big Webbed Foot gripping pedal -->
|
||||
<!-- Heel -->
|
||||
<circle cx="330" cy="415" r="6" fill="#ef6c00" />
|
||||
<!-- Three webbed toes overlapping pedal -->
|
||||
<path d="M 330,415 C 322,415 310,405 298,408 C 308,416 322,418 330,417" fill="#ff9800" stroke="#e65100" stroke-width="1" />
|
||||
<path d="M 330,415 C 320,422 305,422 295,422 C 308,425 324,422 330,418" fill="#ff9800" stroke="#e65100" stroke-width="1" />
|
||||
<path d="M 330,415 C 325,428 312,435 302,435 C 314,432 325,425 330,418" fill="#ff9800" stroke="#e65100" stroke-width="1" />
|
||||
<!-- Toe Claws -->
|
||||
<circle cx="297" cy="408" r="1.5" fill="#eceff1" />
|
||||
<circle cx="294" cy="422" r="1.5" fill="#eceff1" />
|
||||
<circle cx="301" cy="435" r="1.5" fill="#eceff1" />
|
||||
</g>
|
||||
|
||||
<!-- HEAD, EYE, BEAK, POUCH & SUNGLASSES -->
|
||||
<g id="head-group" filter="url(#shadow)">
|
||||
<!-- Head Base -->
|
||||
<circle cx="415" cy="115" r="22" fill="url(#pelicanFeather)" />
|
||||
<!-- Feather tuft / crest blowing back -->
|
||||
<path d="M 398,102 C 385,92 372,98 360,95 C 372,105 385,108 395,108 Z" fill="#cbd5e1" />
|
||||
<path d="M 394,112 C 380,105 365,112 352,110 C 366,118 380,118 393,116 Z" fill="#94a3b8" />
|
||||
<path d="M 397,122 C 385,118 372,128 358,128 C 372,132 385,130 395,125 Z" fill="#cbd5e1" />
|
||||
|
||||
<!-- Cute Expressive Eye -->
|
||||
<circle cx="418" cy="112" r="5.5" fill="#ffffff" />
|
||||
<circle cx="419" cy="112" r="4" fill="#00acc1" /> <!-- Bright blue iris -->
|
||||
<circle cx="420" cy="112" r="2.5" fill="#090d16" /> <!-- Pupil -->
|
||||
<circle cx="421" cy="110" r="1" fill="#ffffff" /> <!-- Catchlight -->
|
||||
<!-- Happy eyebrow -->
|
||||
<path d="M 411,105 Q 418,101 425,106" fill="none" stroke="#475569" stroke-width="2" stroke-linecap="round" />
|
||||
|
||||
<!-- FOREGROUND WING (Holding the Handlebars!) -->
|
||||
<!-- Wing Shoulder -->
|
||||
<path d="M 310,240 C 330,240 355,255 360,275 C 362,295 330,325 310,320 Z" fill="url(#pelicanFeather)" />
|
||||
<!-- Wing Feathers folding forward and down -->
|
||||
<path d="M 345,265 C 375,275 410,285 432,266 C 438,260 442,252 445,248" fill="none" stroke="url(#pelicanFeather)" stroke-width="16" stroke-linecap="round" />
|
||||
<!-- Wingtip feathers wrapping around the leather grip -->
|
||||
<!-- Feather finger 1 -->
|
||||
<path d="M 432,266 C 430,255 418,252 410,256" fill="none" stroke="#cbd5e1" stroke-width="7" stroke-linecap="round" />
|
||||
<!-- Feather finger 2 (wrapping handlebar) -->
|
||||
<path d="M 434,268 C 430,258 414,258 413,264" fill="none" stroke="#f1f5f9" stroke-width="6.5" stroke-linecap="round" />
|
||||
<!-- Feather finger 3 -->
|
||||
<path d="M 432,272 C 428,266 416,268 416,274" fill="none" stroke="#cbd5e1" stroke-width="6" stroke-linecap="round" />
|
||||
<!-- Wing Layer lines for 3D effect -->
|
||||
<path d="M 330,255 Q 355,270 380,275" fill="none" stroke="#cbd5e1" stroke-width="1.5" />
|
||||
<path d="M 325,275 Q 350,290 375,292" fill="none" stroke="#cbd5e1" stroke-width="1.5" />
|
||||
<path d="M 315,295 Q 340,305 365,302" fill="none" stroke="#94a3b8" stroke-width="1.5" opacity="0.6" />
|
||||
|
||||
<!-- THE BEAK (Upper bill) -->
|
||||
<!-- Long, beautiful, curved upper beak -->
|
||||
<path d="M 432,108 C 455,110 510,120 545,132 C 550,134 554,138 552,142 C 549,145 540,143 535,141 C 495,131 450,123 430,121 Z" fill="url(#beakGrad)" />
|
||||
<!-- Beak tip hook -->
|
||||
<path d="M 548,133 Q 555,138 550,143 Q 544,141 546,136 Z" fill="#bf360c" />
|
||||
<!-- Nostril slit -->
|
||||
<path d="M 445,115 Q 455,117 460,118" fill="none" stroke="#b71c1c" stroke-width="1" stroke-linecap="round" />
|
||||
|
||||
<!-- THE GIGANTIC THROAT POUCH -->
|
||||
<!-- Drop down elastic pouch -->
|
||||
<path d="M 430,121 C 430,121 432,185 450,195 C 470,205 515,180 535,141 C 490,131 450,123 430,121 Z" fill="url(#pouchGrad)" />
|
||||
<!-- Pouch texture wrinkles -->
|
||||
<path d="M 442,132 Q 448,168 456,182" fill="none" stroke="#ffb300" stroke-width="1" opacity="0.6" />
|
||||
<path d="M 455,132 Q 465,165 478,178" fill="none" stroke="#ffb300" stroke-width="1" opacity="0.6" />
|
||||
<path d="M 470,133 Q 482,160 500,165" fill="none" stroke="#ff8f00" stroke-width="1" opacity="0.5" />
|
||||
<path d="M 490,134 Q 502,152 518,154" fill="none" stroke="#ff8f00" stroke-width="1" opacity="0.5" />
|
||||
<!-- Lower jaw line supporting the pouch -->
|
||||
<path d="M 430,121 C 430,121 432,185 450,195 C 470,205 515,180 535,141" fill="none" stroke="#e65100" stroke-width="2.5" />
|
||||
|
||||
<!-- SILHOUETTE OF A LITTLE FISH INSIDE THE POUCH (Easter Egg!) -->
|
||||
<g opacity="0.22" transform="translate(452, 142) rotate(25) scale(0.85)">
|
||||
<path d="M 0,0 C 10,-8 25,-4 32,4 C 24,8 12,8 0,0" fill="#02476b" />
|
||||
<path d="M 30,2 L 38,-3 L 36,4 L 38,10 L 30,5 Z" fill="#02476b" />
|
||||
<circle cx="6" cy="1" r="1.5" fill="#ffe082" />
|
||||
</g>
|
||||
<!-- Small bubbles inside pouch around the fish -->
|
||||
<circle cx="475" cy="155" r="2" fill="#ffffff" opacity="0.3" />
|
||||
<circle cx="482" cy="150" r="1" fill="#ffffff" opacity="0.3" />
|
||||
<circle cx="468" cy="162" r="1.5" fill="#ffffff" opacity="0.2" />
|
||||
|
||||
<!-- COOL AVIATOR SUNGLASSES -->
|
||||
<g id="sunglasses">
|
||||
<!-- Lens facing us -->
|
||||
<path d="M 412,112 C 412,106 426,106 428,114 C 428,122 414,124 412,112 Z" fill="#263238" stroke="#ffb300" stroke-width="1.5" />
|
||||
<path d="M 412,112 C 412,106 426,106 428,114 C 428,122 414,124 412,112 Z" fill="url(#beakGrad)" opacity="0.4" style="mix-blend-mode: color-dodge;" />
|
||||
<!-- Diagonal glass reflection -->
|
||||
<polygon points="415,109 425,112 422,121 413,115" fill="#ffffff" opacity="0.25" />
|
||||
|
||||
<!-- Bridge -->
|
||||
<rect x="427" y="111" width="5" height="1.5" fill="#ffb300" />
|
||||
|
||||
<!-- Second Lens (partially hidden/angled) -->
|
||||
<path d="M 431,113 C 431,109 441,110 442,116 C 442,122 432,123 431,113 Z" fill="#263238" stroke="#ffb300" stroke-width="1.2" />
|
||||
<path d="M 431,113 C 431,109 441,110 442,116 C 442,122 432,123 431,113 Z" fill="url(#beakGrad)" opacity="0.4" style="mix-blend-mode: color-dodge;" />
|
||||
<polygon points="433,111 439,113 437,120 432,116" fill="#ffffff" opacity="0.2" />
|
||||
|
||||
<!-- Frame temples / arms going back -->
|
||||
<path d="M 412,111 Q 403,110 400,114" fill="none" stroke="#ffb300" stroke-width="1.2" />
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- FOREGROUND STRIPED SCARF KNOT & WIND FLOW (Drawn in front of neck/shoulder) -->
|
||||
<g id="scarf-front" filter="url(#shadow)">
|
||||
<!-- Knot around neck -->
|
||||
<path d="M 378,212 Q 388,210 398,220 Q 388,235 375,225 Z" fill="#d32f2f" />
|
||||
<!-- Scarf wrap -->
|
||||
<path d="M 364,195 C 378,195 396,204 398,218 C 392,230 374,224 358,210 Z" fill="#c62828" />
|
||||
<!-- Stripes on wrap -->
|
||||
<path d="M 368,195 Q 375,206 376,219 M 382,197 Q 388,208 390,222" stroke="#ffffff" stroke-width="4.5" fill="none" />
|
||||
<!-- Little hanging knot tie -->
|
||||
<path d="M 388,218 C 394,224 396,234 392,242 C 386,242 382,232 384,222 Z" fill="#b71c1c" />
|
||||
<path d="M 391,223 C 396,228 398,235 395,241" stroke="#ffffff" stroke-width="3" fill="none" />
|
||||
</g>
|
||||
</g>
|
||||
|
||||
|
||||
<!-- ==================== DYNAMIC FOREGROUND EFFECTS ==================== -->
|
||||
<!-- Splashing wet sand droplets and dust kicked up by rear tire -->
|
||||
<g fill="#ffe082" opacity="0.5">
|
||||
<circle cx="152" cy="515" r="2.5" />
|
||||
<circle cx="145" cy="505" r="1.5" />
|
||||
<circle cx="138" cy="510" r="2" />
|
||||
<circle cx="142" cy="522" r="1" />
|
||||
<circle cx="160" cy="495" r="2" opacity="0.3" />
|
||||
<circle cx="172" cy="490" r="1.5" opacity="0.3" />
|
||||
</g>
|
||||
|
||||
<!-- Splashing water droplets and foam near the tires (riding through shallow water) -->
|
||||
<g fill="#ffffff" opacity="0.75">
|
||||
<path d="M 230,520 Q 215,505 195,502 Q 218,515 230,520 Z" />
|
||||
<path d="M 235,520 Q 250,502 270,498 Q 252,514 235,520 Z" />
|
||||
<path d="M 550,520 Q 532,508 515,504 Q 535,515 550,520 Z" />
|
||||
<path d="M 555,520 Q 572,504 595,500 Q 575,515 555,520 Z" />
|
||||
<!-- Droplets -->
|
||||
<circle cx="198" cy="495" r="2" />
|
||||
<circle cx="185" cy="501" r="1" />
|
||||
<circle cx="210" cy="488" r="1.5" />
|
||||
<circle cx="274" cy="492" r="2" />
|
||||
<circle cx="285" cy="498" r="1" />
|
||||
<circle cx="510" cy="498" r="1.5" />
|
||||
<circle cx="498" cy="502" r="1" />
|
||||
<circle cx="600" cy="494" r="2" />
|
||||
<circle cx="612" cy="500" r="1" />
|
||||
</g>
|
||||
|
||||
|
||||
<!-- ==================== FOREGROUND FRAMING ==================== -->
|
||||
<!-- Silhouetted beach grass blowing in the wind (Bottom right corner) -->
|
||||
<g fill="none" stroke="#240c02" stroke-linecap="round" opacity="0.95" filter="url(#shadow)">
|
||||
<!-- Sand hill bump -->
|
||||
<path d="M 680,600 Q 740,540 810,530 L 810,600 Z" fill="url(#sandGrad)" stroke="none" />
|
||||
<!-- Grass blades -->
|
||||
<path d="M 720,560 Q 690,470 640,440" stroke-width="4.5" />
|
||||
<path d="M 735,555 Q 710,450 660,420" stroke-width="5" />
|
||||
<path d="M 750,550 Q 735,430 670,395" stroke-width="5.5" />
|
||||
<path d="M 755,555 Q 755,460 710,425" stroke-width="4" />
|
||||
<path d="M 770,540 Q 775,440 720,405" stroke-width="5" />
|
||||
<path d="M 785,535 Q 805,420 755,385" stroke-width="6" />
|
||||
<path d="M 790,540 Q 820,445 780,410" stroke-width="4.5" />
|
||||
<path d="M 800,530 Q 840,450 810,420" stroke-width="3.5" />
|
||||
<!-- Warm highlights on grass from the sunset -->
|
||||
<path d="M 720,560 Q 690,470 640,440" stroke="#fbc02d" stroke-width="1.5" opacity="0.7" />
|
||||
<path d="M 735,555 Q 710,450 660,420" stroke="#ff9100" stroke-width="1.5" opacity="0.7" />
|
||||
<path d="M 750,550 Q 735,430 670,395" stroke="#fbc02d" stroke-width="2" opacity="0.8" />
|
||||
<path d="M 770,540 Q 775,440 720,405" stroke="#ff9100" stroke-width="1.5" opacity="0.7" />
|
||||
<path d="M 785,535 Q 805,420 755,385" stroke="#fbc02d" stroke-width="2.5" opacity="0.8" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 37 KiB |
Reference in new issue
Block a user