0xffd6563c…95fesent to0xbcd804be…650f·#25,465,677·view on Etherscan
rm', st.diedAt>0?'Rib skeleton':'Ribbed column'],
];
}
}));
})();
;
/* species/wattle.js */
/* wattle — species index 5. GENERATED from prototypes/golden-wattle.html by extract.js.
Do not edit here — edit the prototype and re-run `npm run extract`. The prototype's
mount() call is redirected to SeedlingRenderer.registerSpecies via the local shim. */
(function () {
const mount = (spec) => SeedlingRenderer.registerSpecies(5, spec);
/* Golden Wattle — Acacia. A low-forking broad DOMED little tree (recursive staggered-lateral frame)
clothed in feathery BIPINNATE leaves (a rachis of paired pinnae of tiny leaflets). Reward: green
buds → fuzzy GOLDEN POM-POM flower heads (late winter/spring, S-hemisphere) → flattened legume SEED
PODS (green→brown) at senescence. Coherent wind. Grows in stands/groves. Ported to the shared core. */
const SP = window.SEEDLING_SPECIES.find(x=>x.key==='wattle');
mount(Object.assign(window.SEEDLING_toSpec(SP), {
title:'Golden Wattle', sub:'acacia v2',
senFrom:0.82,
LW:{season:1.0, stem:1.2, leaves:1.0, flowers:1.4},
LS:{season:1.0, stem:1.0, leaves:0.85, flowers:0.8},
note:'Broad domed acacia · feathery bipinnate foliage · green buds → fuzzy golden pom-pom flowers (late winter/spring) → flat seed pods · wind · stands/groves.',
PAL:{ soil:'#6f5128', dry:'#7a5a30', grey:'#9a8f74',
bark:'#7A6A48', barkDk:'#564934',
leaf:'#5E7E3C', leafDk:'#3C5828', leafLt:'#86A65A',
flower:'#F4C020', flowerLt:'#FBDD5A', flowerDk:'#D9A50E', bud:'#9DAE5A',
pod:'#8A9A55', podDry:'#A2854A', podBrown:'#7a5a30' },
stageName(st,env){ if(st.diedAt>0)return'Sealed'; const m=env.m;
if(env.ageF>0.84)return'Podding'; if(m<0.12)return'Sprig'; if(m<0.36)return'Young';
if(m<0.55)return'Branching'; const wintery=(env.season==='Winter'||env.season==='Spring');
if(m<0.66)return'Leafy'; return wintery?'Golden':'Leafy'; },
draw(st, C, env){
const {m,v,sen,season,browny,density,rewards,ageF,baseX,baseY}=env, P=this.PAL;
const bgC = BACKDROPS[backdropFor(st.seed)];
function wattleDNA(seed){ const dd=rng('dna',seed), g=()=>(dd()+dd()+dd()-1.5)/1.5;
return { dominance:0.18+0.34*dd(), divergence:0.45+0.45*dd(), droop:0.30+0.45*dd(), gnarl:0.25+0.5*dd(), taperLen:0.66+0.12*dd(),
lateralN:1.6+1.1*dd(), reach:0.78+0.3*dd(), lean:g()*0.12, stature:0.86+0.18*dd(), maxOrder:5+(dd()<0.5?1:0),
leafiness:0.7+0.5*dd(), flowerAb:0.55+0.6*dd(), pods:0.4+0.6*dd(), windDir:dd()<0.5?1:-1, windStr:Math.pow(dd(),2.5) }; }
function paintWattle(I){
const {seed, artSeed, cx, by, S, fade, m, density, v, sen, browny, rewards} = I;
const FC = c => fade>0 ? mix(c, bgC, fade) : c;
const D=wattleDNA(seed);
const seasonGold = season==='Winter'?1 : season==='Spring'?0.9 : season==='Autumn'?0.5 : 0.45;
const foliageF=(1-0.80*sen)*(0.4+0.6*v), bloom=smooth(0.42,0.74,m)*(1-sen)*(0.55+0.45*seasonGold)*rewards;
const leafKeep=clamp(1-0.82*sen, 0.12, 1); // phyllodes SHED as it dries/dies → fewer leaf tufts → branch skeleton + dry pods show through
const budF=smooth(0.36,0.5,m)*(1-smooth(0.5,0.64,m)), podF=D.pods*smooth(0.66,0.95,Math.max(sen*1.2, ageF*0.9, m-0.2))*(1-0.3*sen);
const bark=FC(mix(P.bark,P.grey,Math.max((1-v)*0.3,sen))), barkDk=FC(mix(P.barkDk,P.grey,Math.max((1-v)*0.3,sen)));
const leafD=FC(mix(P.leafDk,P.dry,browny*0.9)), leafM=FC(mix(P.leaf,P.dry,browny*0.9)), leafL=FC(mix(P.leafLt,P.dry,browny*0.85));
const greenOf=rs=>shade(mix(leafM, rs()<0.5?leafD:leafL, rs()), rs);
const windLean=D.windDir*D.windStr*0.30, rootX=cx - D.windDir*D.windStr*46*S;
function bipinnateLeaf(bx, byy, baseAng, size, rs){ if(foliageF<=0.04) return; const segs=Math.max(2,Math.round(size)), droop=(0.5+0.7*rs())*(0.5+0.7*D.droop); let dir=baseAng, pos=[bx,byy];
for(let i=1;i<=segs;i++){ dir += angTo(dir,DOWN)*0.045*droop*(0.3+0.7*(i/segs)); const cd=[Math.cos(dir),Math.sin(dir)]; pos=[pos[0]+cd[0]*GRID, pos[1]+cd[1]*GRID];
C.push(pos[0],pos[1], 34, dirSym(cd[0],cd[1]), greenOf(rs), 'leaves'); if(i===1) continue; const px=-cd[1], py=cd[0];
for(const sd of [1,-1]){ let pa=Math.atan2(py*sd,px*sd); pa += angTo(pa,dir)*0.42; let pp=[pos[0],pos[1]], pdir=pa; const plen=2+Math.floor(rs()*2);
for(let k=1;k<=plen;k++){ pdir += angTo(pdir,DOWN)*0.06; pp=[pp[0]+Math.cos(pdir)*GRID, pp[1]+Math.sin(pdir)*GRID]; C.push(pp[0],pp[1], 33, '.', greenOf(rs), 'leaves'); } } } }
function leafTuft(x,y,baseAng,rs){ const n=2+Math.floor(rs()*2); for(let k=0;k<n;k++) bipinnateLeaf(x,y, baseAng+(k-(n-1)/2)*0.5+(rs()*2-1)*0.15, (3.5+5*m)*(0.7+0.4*rs())*S, rs); }
function pomPom(x,y,green,rs){ const fc = green ? P.bud : (rs()<0.5?P.flower:P.flowerLt), R=GRID*(green?0.85:1.0)*Math.sqrt(S);
C.push(x,y,91, green?'O':'+', shade(FC(green?P.bud:mix(fc,P.flowerDk,0.3)),rs), 'flowers'); const n=green?6:7;
for(let k=0;k<n;k++){ const a=k/n*TAU + rs()*0.3; C.push(x+Math.cos(a)*R, y+Math.sin(a)*R, 90, '.', shade(FC(fc),rs), 'flowers'); } }
function pomCluster(x,y,green,rs){ const n=1+Math.floor(rs()*2); for(let k=0;k<n;k++) pomPom(x+(rs()*2-1)*GRID*2.4, y+(rs()*2-1)*GRID*2.4, green, rs); }
function seedPod(x,y,rs){ const cc=FC(mix(P.pod, mix(P.podDry,P.podBrown,sen), Math.max(sen, browny*0.7))); let dir=DOWN+(rs()*2-1)*0.5, pos=[x,y]; const len=4+Math.floor(rs()*3);
for(let i=1;i<=len;i++){ dir += angTo(dir,DOWN)*0.18; pos=[pos[0]+Math.cos(dir)*GRID, pos[1]+Math.sin(dir)*GRID]; const px=-Math.sin(dir), py=Math.cos(dir), bump=(i%2?1.1:0.55);
C.push(pos[0],pos[1], 86, '|', shade(cc,rs), 'flowers'); C.push(pos[0]+px*bump*GRID, pos[1]+py*bump*GRID, 86, '.', shade(cc,rs), 'flowers'); C.push(pos[0]-px*bump*GRID, pos[1]-py*bump*GRID, 86, '.', shade(mix(cc,'#000000',0.12),rs), 'flowers'); } }
function sprout(rs,rx){ if(1-smooth(0.05,0.20,m) <= 0.02) return; const g=smooth(0,0.18,m), hLen=(58+50*g)*S; let dir=UP+D.lean*1.2, pos=[rx,by-3]; const steps=Math.max(3,Math.ceil(hLen/GRID));
for(let i=1;i<=steps;i++){ const u=i/steps; dir+=Math.sin(u*2.6+D.lean*4)*0.045; pos=[pos[0]+Math.cos(dir)*GRID, pos[1]+Math.sin(dir)*GRID]; C.push(pos[0],pos[1],50,dirSym(Math.cos(dir),Math.sin(dir)),shade(bark,rs),'stem'); }
for(const sd of [1,-1]){ let cd=UP+sd*(0.8+0.3*D.reach); let cp=[pos[0],pos[1]]; const cl=Math.max(3,Math.round((26+20*g)*S/GRID));
for(let i=1;i<=cl;i++){ cd+=angTo(cd,UP)*0.07; cp=[cp[0]+Math.cos(cd)*GRID, cp[1]+Math.sin(cd)*GRID]; const w=Math.sin(Math.PI*i/cl)*GRID*1.4, px=-Math.sin(cd),py=Math.cos(cd);
C.push(cp[0],cp[1],36,dirSym(Math.cos(cd),Math.sin(cd)),greenOf(rs),'leaves'); C.push(cp[0]+px*w,cp[1]+py*w,35,'.',greenOf(rs),'leaves'); C.push(cp[0]-px*w,cp[1]-py*w,35,'.',greenOf(rs),'leaves'); } }
if(g>0.4) bipinnateLeaf(pos[0],pos[1], UP+(rs()*2-1)*0.3, (3+3*g)*S, rs); }
const growWin=0.12, maxOrder=D.maxOrder; let budget=8000;
const chain=(1-Math.pow(D.taperLen,maxOrder+1))/(1-D.taperLen), baseRun=((by-300)/chain)*D.stature*(0.9+0.1*v)*S;
function grow(x,y,head,vigor,order,birthM,pid,sideSeq){ if(budget<=0) return; const grown=clamp((m-birthM)/growWin,0,1); if(grown<=0) return; budget--;
const rs=rng('wb', seed, pid); let run=baseRun*Math.pow(D.taperLen,order)*(0.82+0.36*rs())*grown; if(order===0) run*=0.86;
const steps=Math.max(1,Math.ceil(run/GRID)), woodM=smooth(0.10,0.85,m), baseThick=(maxOrder-order)/maxOrder, bz=54-order;
const f1=0.5+1.4*rs(), f2=1.1+2.2*rs(), ph1=rs()*6.28, ph2=rs()*6.28, gnarlA=D.gnarl*0.045*(1+order*0.12), bears=order>=2 ? D.leafiness : (order>=1? 0.25*D.leafiness:0);
const canChild = grown>=1 && order<maxOrder;
const nLat = order===0 ? 2+Math.floor(rs()*3) : clamp(Math.round(D.lateralN*(1-0.35*D.dominance)+gauss(rs)*0.9),0, order<2?3:2);
const lo=order===0?0.24:0.32, hi=0.92, pts=[], sides=[]; let lastSide=rs()<0.5?1:-1;
for(let c=0;c<nLat;c++){ pts.push(clamp(lerp(lo,hi,(c+0.5)/Math.max(nLat,1)) + (rs()*2-1)*(0.6/Math.max(nLat,1)), 0.12, 0.95)); if(order===0 || rs()<0.72) lastSide=-lastSide; sides.push(lastSide); }
pts.sort((a,b)=>a-b); let dir=head, pos=[x,y], ci=0;
for(let i=1;i<=steps;i++){ const u=i/steps; const photo=lerp(0.13,0.04,clamp(order/3,0,1))*Math.max(0,1-order/3.2), grav=0.10*D.droop*smooth(1.5,maxOrder,order)*(0.25+0.75*u);
dir += angTo(dir,UP)*photo + angTo(dir,DOWN)*grav + gnarlA*(Math.sin(i*0.5*f1+ph1)+0.5*Math.sin(i*0.3*f2+ph2));
const exposure=clamp((by-pos[1])/600,0,1); dir += D.windDir*D.windStr*0.06*exposure*(0.35+0.65*order/maxOrder);
const dx=Math.cos(dir), dy=Math.sin(dir); pos=[pos[0]+dx*GRID, pos[1]+dy*GRID]; const sym=dirSym(dx,dy);
C.push(pos[0],pos[1], bz, sym, shade(bark,rs), 'stem'); const px=-dy, py=dx;
const thick=clamp(Math.round(baseThick*baseThick*2.3*woodM*(0.7+0.3*v)*(1-0.5*u)*smooth(0.12,0.85,grown)),0,2);
for(let wq=1;wq<=thick;wq++){ C.push(pos[0]+px*wq*GRID, pos[1]+py*wq*GRID, bz, sym, shade(barkDk,rs), 'stem'); C.push(pos[0]-px*wq*GRID, pos[1]-py*wq*GRID, bz, sym, shade(barkDk,rs), 'stem'); }
if(bears>0 && u>0.12 && i%2===0 && rs()<bears*leafKeep){ const side=((sideSeq+(i/2|0))%2===0)?1:-1; leafTuft(pos[0],pos[1], Math.atan2(py*side,px*side), rs); }
if(order>=2 && i%7===4){ if(podF>0.25 && rs()<podF*0.4) seedPod(pos[0],pos[1],rs); else if(bloom>0.1 && rs()<bloom*D.flowerAb*0.3) pomCluster(pos[0]+(rs()*2-1)*GRID*2, pos[1]+(rs()*2-1)*GRID*2, budF>0.25 && rs()<0.4, rs); }
while(canChild && ci<pts.length && u>=pts[ci] && budget>0){ const side=sides[ci], div=(order===0?(0.55+0.55*D.reach):D.divergence*(0.7+0.7*rs())*D.reach);
let la=dir + side*div + gauss(rs)*0.14; la += angTo(la,UP)*(order===0?0.05:0.10)*(1-D.reach*0.3);
const cv=vigor*(order===0?(0.72+0.26*rs()):(0.45+0.4*(1-D.dominance))*(0.8+0.3*rs())); grow(pos[0],pos[1], la, cv, order+1, birthM+growWin, pid*7+ci+2, sideSeq+ci+1); ci++; }
}
if(canChild && budget>0){ const leadV=vigor*lerp(0.42,0.9,D.dominance); grow(pos[0],pos[1], dir+angTo(dir,UP)*(order<=1?0.28:0.14)+gauss(rs)*0.05, leadV, order+1, birthM+growWin, pid*7+1, sideSeq+1); }
else if(grown>=1){ if(rs()<leafKeep) leafTuft(pos[0],pos[1], dir, rs); const dn=Math.atan2(-Math.sin(dir),-Math.cos(dir)); if(rs()<0.6*leafKeep) leafTuft(pos[0],pos[1], dn, rs);
if(podF>0.3 && rs()<podF*0.4) seedPod(pos[0],pos[1],rs); else if(bloom>0.12 && rs()<bloom*D.flowerAb*0.5) pomCluster(pos[0],pos[1], budF>0.25 && rs()<0.4, rs); }
else if(order>=2){ if(rs()<leafKeep) leafTuft(pos[0],pos[1], dir, rs); }
}
sprout(rng('sprout',seed), rootX);
grow(rootX, by-3, UP+D.lean*0.6+D.windDir*D.windStr*0.06, 1, 0, 0, 1, 0);
}
// ===================== SETTING: Solo / Pair / Stand / Grove =====================
const roll=rng('setting',st.seed)();
const nC = roll<0.30?0 : roll<0.62?1 : roll<0.88?2 : 3+Math.floor(rng('fn',st.seed)()*2);
const comps=[];
for(let i=0;i<nC;i++){ const cseed='0x'+(hashStr(st.seed+'|c'+i)>>>0).toString(16), rc=rng('comp',st.seed,i), side=(i%2===0?1:-1), f=i/Math.max(1,nC);
comps.push({seed:cseed, artSeed:cseed, cx:baseX+side*(150+i*70+rc()*46), by:baseY-(8+i*12+rc()*20), S:lerp(0.6,0.4,f)*(0.9+0.2*rc()), fade:lerp(0.40,0.60,f),
m, density:clamp(density+(rc()*2-1)*0.10,0.04,1), v, sen, browny, rewards, depth:f}); }
comps.sort((a,b)=>b.depth-a.depth).forEach(paintWattle);
paintWattle({seed:st.seed, artSeed:st.artSeed, cx:baseX, by:baseY, S:1.0, fade:0, m, density, v, sen, browny, rewards});
},
traits(st,env){
const roll=rng('setting',st.seed)();
const setting = roll<0.30?'Solo' : roll<0.62?'Pair' : roll<0.88?'Stand' : 'Grove';
const wintery=(env.season==='Winter'||env.season==='Spring');
return [
['Setting', setting],
['Bloom', st.diedAt>0?'Pods':(env.m>=0.55 && env.rewards>0.3 ? (wintery?'Golden':'Buds') : '—')],
['Form', st.diedAt>0?'Pods + bare':'Domed'],
];
}
}));
})();