knosky 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/renderer/city.template.html +16 -32
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "knosky",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"description": "Turn any repo or docs folder into an explorable city, plus a local MCP that grounds your AI in your own source with citations. Local-first, free, $0 tokens.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -188,9 +188,6 @@
|
|
|
188
188
|
_clip={wx0:(0-cam.x)/cam.zoom-pad,wy0:(0-cam.y)/cam.zoom-pad,
|
|
189
189
|
wx1:(innerWidth-cam.x)/cam.zoom+pad,wy1:(innerHeight-cam.y)/cam.zoom+pad};}
|
|
190
190
|
function inView(wx,wy){return wx>=_clip.wx0&&wx<=_clip.wx1&&wy>=_clip.wy0&&wy<=_clip.wy1;}
|
|
191
|
-
// District cluster descriptors — one entry per district, built at ingest time
|
|
192
|
-
let CLUSTERS=[];
|
|
193
|
-
function buildClustersNow(){CLUSTERS=[];const acc={};for(const n of NODES){const k=n.d;if(!acc[k])acc[k]={sumX:0,sumY:0,count:0};acc[k].sumX+=n.bx;acc[k].sumY+=n.by;acc[k].count++;}Object.keys(acc).forEach(k=>{const a=acc[k];const cfg=DCFG[k]||{name:k,color:'#7c83a3'};CLUSTERS.push({d:k,label:cfg.name,color:cfg.color,count:a.count,wx:a.sumX/a.count,wy:a.sumY/a.count});});}
|
|
194
191
|
|
|
195
192
|
const TW=64,TH=32;
|
|
196
193
|
// central relative-size system (multiples of a tile) — tune here to keep everything proportional
|
|
@@ -454,6 +451,15 @@
|
|
|
454
451
|
ctx.beginPath();ctx.moveTo(c.B[0],c.B[1]);ctx.lineTo(c.R[0],c.R[1]);ctx.lineTo(c.R[0],c.R[1]+DEPTH);ctx.lineTo(c.B[0],c.B[1]+DEPTH);ctx.closePath();
|
|
455
452
|
g=ctx.createLinearGradient(0,c.R[1],0,c.B[1]+DEPTH);g.addColorStop(0,PAL.night?"#1b160f":"#3a2a19");g.addColorStop(1,PAL.night?"#0d0906":"#1c1409");ctx.fillStyle=g;ctx.fill();
|
|
456
453
|
ctx.strokeStyle=PAL.night?"#1f3a1c":"#3f6a37";ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(c.L[0],c.L[1]);ctx.lineTo(c.B[0],c.B[1]);ctx.lineTo(c.R[0],c.R[1]);ctx.stroke();}
|
|
454
|
+
// LOD_CLUSTER top face: a single flat green fill so the zoomed-all-the-way-out
|
|
455
|
+
// view reads as a clean city silhouette (like a map/globe from orbit) instead of
|
|
456
|
+
// an empty outline or a cluttered badge overlay. No per-tile detail at this LOD.
|
|
457
|
+
function drawIslandTop(){const c=islandCorners();
|
|
458
|
+
ctx.beginPath();ctx.moveTo(c.T[0],c.T[1]);ctx.lineTo(c.R[0],c.R[1]);ctx.lineTo(c.B[0],c.B[1]);ctx.lineTo(c.L[0],c.L[1]);ctx.closePath();
|
|
459
|
+
const g=ctx.createLinearGradient(c.T[0],c.T[1],c.B[0],c.B[1]);
|
|
460
|
+
g.addColorStop(0,PAL.night?"#233a22":"#4f8a4a");g.addColorStop(1,PAL.night?"#162415":"#375f34");
|
|
461
|
+
ctx.fillStyle=g;ctx.fill();
|
|
462
|
+
ctx.strokeStyle=PAL.night?"#2c4a2a":"#2f5a2c";ctx.lineWidth=1.5;ctx.stroke();}
|
|
457
463
|
|
|
458
464
|
// ---------- ground ----------
|
|
459
465
|
const GRASS="#3c6a3a";
|
|
@@ -638,40 +644,18 @@
|
|
|
638
644
|
if(flip){ctx.save();ctx.translate(x*2,0);ctx.scale(-1,1);ctx.drawImage(VEH,sx,sy,vCW,vCH,dx,dy,dW,dH);ctx.restore();}
|
|
639
645
|
else ctx.drawImage(VEH,sx,sy,vCW,vCH,dx,dy,dW,dH);}
|
|
640
646
|
|
|
641
|
-
// ---------- cluster badges (LOD_CLUSTER tier — entire districts collapsed to one badge) ----------
|
|
642
|
-
function drawClusterBadge(cl){
|
|
643
|
-
const x=cl.wx,y=cl.wy;
|
|
644
|
-
if(!inView(x,y))return;
|
|
645
|
-
if(focusK&&cl.d!==focusK)return;
|
|
646
|
-
const R=28,FONT_C="'Plus Jakarta Sans',system-ui,sans-serif";
|
|
647
|
-
// outer glow
|
|
648
|
-
ctx.save();
|
|
649
|
-
ctx.globalAlpha=0.22;
|
|
650
|
-
ctx.beginPath();ctx.arc(x,y,R*1.6,0,7);ctx.fillStyle=cl.color;ctx.fill();
|
|
651
|
-
ctx.globalAlpha=1;
|
|
652
|
-
// filled circle
|
|
653
|
-
ctx.beginPath();ctx.arc(x,y,R,0,7);ctx.fillStyle=cl.color;ctx.fill();
|
|
654
|
-
// border ring
|
|
655
|
-
ctx.lineWidth=2;ctx.strokeStyle="rgba(255,255,255,.45)";ctx.stroke();
|
|
656
|
-
// count label
|
|
657
|
-
const label=cl.count>=1000?(Math.round(cl.count/100)/10)+'k':String(cl.count);
|
|
658
|
-
ctx.fillStyle="#0a0a12";ctx.textAlign="center";ctx.textBaseline="middle";ctx.font="700 13px "+FONT_C;
|
|
659
|
-
ctx.fillText(label,x,y);
|
|
660
|
-
// district name beneath
|
|
661
|
-
ctx.globalAlpha=0.75;ctx.fillStyle=cl.color;ctx.font="600 10px "+FONT_C;
|
|
662
|
-
ctx.fillText(cl.label,x,y+R+12);
|
|
663
|
-
ctx.restore();}
|
|
664
|
-
|
|
665
647
|
// ---------- render ----------
|
|
666
648
|
let focusK=null,filteredHidden=new Set(),selectedId=null,connSet=new Set();
|
|
667
649
|
function render(){NOW=performance.now()-T0;updateLodAndClip();moveSky();ctx.setTransform(DPR,0,0,DPR,0,0);drawBackdrop();
|
|
668
650
|
ctx.save();ctx.translate(cam.x,cam.y);ctx.scale(cam.zoom,cam.zoom);
|
|
669
651
|
ctx.globalAlpha=Math.min(1,NOW/450);
|
|
670
652
|
|
|
671
|
-
// LOD_CLUSTER:
|
|
653
|
+
// LOD_CLUSTER: zoomed all the way out -- show a clean city silhouette only,
|
|
654
|
+
// no per-district badges. Districts are reachable by zooming in or clicking
|
|
655
|
+
// a district in the sidebar (toggleDistrict -> focusDistrictCam already
|
|
656
|
+
// zooms to a tier where ground + buildings render).
|
|
672
657
|
if(_lod===LOD_CLUSTER){
|
|
673
|
-
drawIslandShadow();drawSlab();
|
|
674
|
-
CLUSTERS.forEach(drawClusterBadge);
|
|
658
|
+
drawIslandShadow();drawSlab();drawIslandTop();
|
|
675
659
|
ctx.globalAlpha=1;ctx.restore();return;}
|
|
676
660
|
|
|
677
661
|
drawIslandShadow();drawSlab();drawGround();drawCloudShadows();drawShadows();drawChurn();
|
|
@@ -694,7 +678,7 @@
|
|
|
694
678
|
if(_lod===LOD_DOT){
|
|
695
679
|
if(dim)continue;
|
|
696
680
|
ctx.fillStyle=DCFG[n.d]?DCFG[n.d].color:'#7c83a3';
|
|
697
|
-
ctx.beginPath();ctx.arc(wc.x,wc.y,4,0,7);ctx.fill();
|
|
681
|
+
ctx.beginPath();ctx.arc(wc.x,wc.y,4/cam.zoom,0,7);ctx.fill();
|
|
698
682
|
continue;}
|
|
699
683
|
drawBuilding(n,false,dim);}
|
|
700
684
|
if(selectedId){drawConnections(selectedId);const sn=byId[selectedId];if(sn&&!filteredHidden.has(sn.id))drawBuilding(sn,true,false);}
|
|
@@ -774,7 +758,7 @@
|
|
|
774
758
|
document.getElementById('q').addEventListener('input',e=>applySearch(e.target.value.trim()));
|
|
775
759
|
let looping=false;
|
|
776
760
|
function boot(){if(!NODES.length){document.getElementById('boot').textContent="Waiting for city data…";document.getElementById('boot').style.display='';return;}
|
|
777
|
-
document.getElementById('boot').style.display='none';
|
|
761
|
+
document.getElementById('boot').style.display='none';buildChips();buildNav();applySearch(document.getElementById('q').value.trim());fitAll();cam.x=cam.tx;cam.y=cam.ty;cam.zoom=cam.tz;
|
|
778
762
|
if(!looping){looping=true;T0=performance.now();loop();}}
|
|
779
763
|
|
|
780
764
|
// ---------- data ingest: receive the authenticated payload over postMessage,
|