NHacker Next
  • new
  • past
  • show
  • ask
  • show
  • jobs
  • submit
▲Four Years with Decker (beyondloom.com)
nikitau 1 days ago [-]
Love this.

Was completely unaware of Decker before reading this, and wanted to say that it is unlike anything I had seen before. But then it reminded me of things like the Arduboy or PICO-8 in being a kind of alt-history tech by spawning an ecosystem around an old mac-style UI, instead of a handheld console UI like the former two.

I'm curious what OPs motivation for using it is. Is it a sort of "limitation bebreeds creativity" thing or something else?

Is there a name for this for of projects more broadly?

veqq 1 days ago [-]
ingenieros 23 hours ago [-]
You’ve never heard of HyperCard? Decker is essentially its spiritual successor.
nikitau 21 hours ago [-]
To be honest, never been a Mac user and HyperCard may have been a bit before my time. The Windows 95-98 er UX brings me more nostalgia.

But I can definitely relate to the yearning for older, clunkier, "quieter" tech, in this age of ubiquitous HTML, CSS, JS. These maybe seemingly naive assumptions like mixing code and presentation, suboptimal UX, and the fact that people still enjoy developing for them for fun rather than for some SaaS end, feels, I don't know, cozy?

ingenieros 19 hours ago [-]
HyperCard must be one of the most influential pieces of software ever written regardless of one's age or OS of choice. Ivan Zhao always seems to find an excuse to credit Bill Atkinson's creation for influencing what he wanted to achieve with Notion.

Do yourself a favor and play with the original via a simulator https://infinitemac.org/1996/System%207.5.3.

RodgerTheGreat 15 hours ago [-]
There's also an excellent overview of HyperCard and its historical context on Stone Tools: https://www.stonetoolsblog.com/hypercard-mac/
ingenieros 15 hours ago [-]
Thanks for sharing that
xyzzy_plugh 20 hours ago [-]
I can't resist posting whenever Decker shows up.

Decker is one of the craziest code bases I'm aware of: a single, incredibly dense file:

https://raw.githubusercontent.com/JohnEarnest/Decker/refs/he...

(I wonder how many tokens it'd be to make this legible...)

icen 19 hours ago [-]
As soon as your eyes adjust to the density, I think this is actually quite legible. There are sensible names, and the formatting and arrangement serve to show the regularity of operations.

I think there are far worse codebases!

xyzzy_plugh 18 hours ago [-]
I don't believe you.

Here, I inserted a subtle bug in this function, can you find it?

    int widget_grid(lv*target,grid x,grid_val*value){
        if(x.show==show_none)return 0; lv*hfnt=FONT_BODY; int hsize=x.headers?font_h(hfnt)+5:0; if(x.size.h<=(50+hsize)||x.size.w<16)x.scrollbar=0;
        lv*fnt=x.font?x.font:FONT_MONO; int os=value->scroll, or=value->row, oc=value->col, files=x.headers==2; if(files||x.size.h<=hsize)x.headers=0;
        int _bg=dgeti(value->table,lmistr("_bg")),_fg=dgeti(value->table,lmistr("_fg")),_hideby=dgeti(value->table,lmistr("_hideby"));
        lv*pv=NULL,*vp=NULL;if(target!=NULL&&_hideby!=-1)grid_pv(target,&pv,&vp);int nr=pv?pv->c: value->table->n;
        #define grid_cell_at(col,row) (value->table->lv[col]->lv[permuted_row(row)])

        int nc=MIN(256,value->table->c), rh=font_h(fnt)+(x.lines?5:3), fcol=!in_layer()?13:x.show==show_invert?32:1, bcol=x.show==show_invert?1:32;
        int fk=strlen(x.format); rect b=x.size;
        int sel=in_layer()&&x.show!=show_none&&wid.active==wid.count;
        if(in_layer()&&dover(b)&&(ev.md||ev.mu||ev.drag)){if(!sel&&wid.gv)grid_exit(); wid.active=wid.count,sel=1;}
        if(sel&&in_layer()&&!over(b)&&ev.md){sel=0;wid.active=-1;grid_exit();}
        if(sel){if(wid.fv)field_exit();wid.ingrid=1,wid.g=x,wid.gv=value,wid.gt=target;}
        if(x.show!=show_transparent)draw_rect(b,bcol);
        rect bh={b.x,b.y,b.w,x.headers?font_h(hfnt)+5:0}; int nrd=MIN(nr,((b.h-bh.h+1)/rh)), scrollmax=nr-nrd;
        rect bb=scrollbar((rect){b.x,b.y+(x.headers?bh.h-1:0),b.w,b.h-(x.headers?bh.h-1:0)},scrollmax,1,nrd,&value->scroll,x.scrollbar,x.show==show_invert);
        draw_box(x.lines?b:(rect){b.x,bb.y,b.w,b.h-(bb.y-b.y)},0,sel?13:fcol);
        char*pal=patterns_pal(ifield(deck,"patterns"));
        if(x.lines)draw_rect(bh,fcol);if(nc<=0)draw_textc(inset(bb,1),"(no data)",hfnt,fcol);

        int cw[256];for(int z=0;z<nc;z++)cw[z]=z>=x.widths[0]?-1:x.widths[1+z];
        if(_bg!=-1)cw[_bg]=0;if(_fg!=-1)cw[_fg]=0;if(_hideby!=-1)cw[_hideby]=0;
        int hwt=0;for(int z=0;z<x.widths[0];z++)hwt+=cw[z];
        int nwt=0;for(int z=0;z<nc         ;z++)nwt+=cw[z]==-1;
        for(int z=x.widths[0];z<nc         ;z++)cw[z]=cw[z]==-1?(bb.w-hwt)/nwt:0;

        if(!cf.sv)cf=str_new();
        #define rowh(n) inset((rect){bb.x+1,bb.y+rh*n+2,bb.w-2,rh-3},x.lines?0:-1)
        #define rowb(n) (rect){bb.x,bb.y+rh*n,bb.w,rh}
        int clicked=0,rsel=0,hrow=-1,hcol=-1;
        for(int y=0;y<nrd;y++){
                if(_bg!=-1){
                        int p=CLAMP(0,ln(grid_cell_at(_bg,y+value->scroll)),255);
                        if(p){rect t=rowb(y);if(y==0)t.y+=1,t.h-=1; draw_rect(t,p);}
                }
                int ra=in_layer()&&over(bb)&&over(rowb(y));rect cbox={0};
                if(ra&&x.bycell){for(int z=0;z<nc;z++){rect cell=grid_cell(x,value,bb,(pair){z,y},cw);if(over(cell))hcol=z,cbox=grid_hcell(x,z,cell);}}
                if(ra&&(ev.md||ev.drag)){rsel=1,hrow=y+value->scroll;draw_rect(x.bycell?cbox:rowh(y),fcol);}
                if(ra&&ev.mu)clicked=1,value->row=permuted_row(y+value->scroll),value->col=hcol;
                if(ra&&!ev.drag)uicursor=cursor_point;
        }int rr=display_row(value->row)-value->scroll;
        if(!rsel&&rr>=0&&rr<nrd&&(x.bycell?value->col>=0&&value->col<nc:1)){
                hrow=display_row(value->row),hcol=value->col;
                if(x.bycell&&value->col>=0){draw_rect(grid_hcell(x,value->col,grid_cell(x,value,bb,(pair){value->col,rr},cw)),fcol);}
                else{draw_rect(rowh(rr),fcol);}
        }
        int drawncol=0;for(int z=0,cols=0,cx=0;z<nc&&cx+cw[cols]<=bb.w;z++,cols++){
                rect hs=(rect){bh.x+4+cx,bh.y+1,cw[cols]-5,bh.h-2};
                if(hs.w<=0)continue; // suppressed column
                if(x.headers){
                        int oa=target&&in_layer()&&over(hs)&&((ev.drag||ev.mu)?dover(hs):1)&&!wid.col_drag;
                        int dp=oa&&(ev.md||ev.drag);if(dp)draw_rect(hs,x.lines?bcol:fcol);
                        draw_textc(hs,value->table->kv[z]->sv,hfnt,x.lines^dp?bcol:fcol);
                        if(oa&&!ev.drag)uicursor=cursor_point;
                        if(oa&&ev.mu){msg.target_order=target,msg.arg_order=value->table->kv[z];}
                }
                if(drawncol&&x.lines)draw_invert(pal,(rect){hs.x-3,b.y+1,1,b.h-2});cx+=cw[cols];drawncol=1;
                for(int y=0;y<nrd;y++){
                        int ccol=y+value->scroll==hrow&&(x.bycell?cols==hcol :1)?bcol: _fg==-1?fcol: CLAMP(0,ln(grid_cell_at(_fg,y+value->scroll)),255);
                        rect cell={hs.x-3,bb.y+rh*y+1,hs.w+5,rh-1}; lv*v=grid_cell_at(z,y+value->scroll);
                        cf.c=0;format_type_simple(&cf,v,z>fk?'s':x.format[z]=='L'?'s':x.format[z]);str_term(&cf);
                        rect ib=box_center(cell,image_size(ICONS[0]));pair ip={ib.x,ib.y};
                        rect oc=frame.clip; frame.clip=box_intersect(cell,frame.clip);
                        if     (z<fk&&x.format[z]=='I'){int i=MAX(0,MIN(8,ln(v)));if(i<8)draw_icon(ip,ICONS[i],ccol);}
                        else if(z<fk&&x.format[z]=='B'){if(lb(v))draw_icon(ip,ICONS[icon_chek],ccol);}
                        else if(z<fk&&(x.format[z]=='t'||x.format[z]=='T')){
                                rect rr={hs.x+1,bb.y+rh*y,hs.w-2,rh}; // display rich text:
                                pair t=layout_richtext(deck,rtext_cast(v),fnt,align_left,rr.w);
                                rect r={rr.x,rr.y+ceil(t.y<rr.h?(rr.h-t.y)/2.0:0),rr.w,rr.h};
                                lv*alink=NULL;if(x.format[z]=='T'&&in_layer()&&(ev.md||ev.drag||ev.mu))for(int z=0;z<layout_count;z++){
                                        glyph_box g=layout[z];if(g.pos.w<1)continue; // skip squashed spaces/newlines
                                        if(g.pos.y+g.pos.h<0||g.pos.y>r.h)continue; g.pos.x+=r.x, g.pos.y+=r.y; // coarse clip
                                        if(lis(g.arg)&&g.arg->c&&dover(g.pos)&&over(g.pos)){
                                                if(ev.md||ev.drag){alink=g.arg;break;}
                                                if(ev.mu){msg.target_link=target,msg.arg_link=g.arg;break;}
                                        }
                                }
                                draw_text_rich_raw(r,ccol,0,alink);
                        }
                        else{
                                rect r={hs.x+1,bb.y+rh*y,hs.w-2,rh}; // right-align numeric columns:
                                if(z<fk&&strchr("fcCihH",x.format[z])){draw_textr(r,cf.sv,fnt,ccol);}else{draw_text_fit(r,cf.sv,fnt,ccol);}
                        }
                        frame.clip=oc;
                        if(!x.locked&&sel&& ((ev.dclick&&over(cell)) || (ev.action&&x.bycell&&z==value->col&&y+value->scroll==display_row(value->row)))){
                                char f=z<fk?x.format[z]:'s';pair tc=(pair){z,y+value->scroll},tpc=(pair){tc.x,permuted_row(tc.y)};
                                if     (f=='I'||f=='L'||f=='T'){} // no editing allowed
                                else if(f=='B'||f=='b'){grid_edit_cell(tpc,ls(lmn(!lb(v))));} // toggle
                                else{
                                        ms.pending_grid_cell_rich=f=='t';
                                        wid.pending_grid_edit=1,ms.pending_grid_cell=grid_cell(x,value,bb,(pair){tc.x,tc.y-value->scroll},cw);
                                        ms.pending_grid_cell.y-=1,ms.pending_grid_cell.w+=1,ms.pending_grid_cell.h+=2;
                                        ms.cell=tpc;ms.text=(field_val){f=='t'?rtext_cast(v):rtext_cast(lmcstr(cf.sv)),0};
                                }
                        }
                }
        }
        if(x.lines)for(int y=1;y<nrd;y++)draw_hline(bb.x,bb.x+bb.w,bb.y+rh*y,fcol);
        if(!x.locked&&in_layer()&&target)for(int z=0,cx=bh.x;z<nc;cx+=cw[z],z++){
                if(cw[z]==0)continue;
                rect h={cx+cw[z]-1,bh.y,5,bh.h};if(h.x+h.w>b.x+b.w)break;
                if(over(h))draw_vline(h.x+2,h.y,h.y+h.h,13);
                if(ev.md&&dover(h)){wid.col_drag=1,wid.col_num=z,wid.col_orig=cw[z];}
                if(sel&&wid.col_drag&&wid.col_num==z&&ev.drag){
                        int s=MIN(MAX(10,wid.col_orig+(ev.pos.x-ev.dpos.x)),bb.w-10),i=z;uicursor=cursor_drag;
                        GEN(r,MAX(x.widths[0],i+1))lmn(i==z?s:cw[z]);iwrite(target,lmistr("widths"),r),mark_dirty();
                }
        }
        if(target&&os!=value->scroll)iwrite(target,lmistr("scroll"),lmn(value->scroll)),mark_dirty();
        if(target&&or!=value->row)iwrite(target,lmistr("row"),lmn(value->row)),mark_dirty();
        if(target&&oc!=value->col)iwrite(target,lmistr("col"),lmn(value->col)),mark_dirty();
        if(target&&clicked)msg.target_click=target,msg.arg_click=(fpair){0,value->row};
        if(in_widgets())wid.count++;
        return files?((clicked&&ev.dclick)||(sel&&ev.action)): clicked;
    }
Insanity 19 hours ago [-]
Yikes. Stuff of nightmares lol.

I guess LLMs would do a reasonable job making this legible, as long as there can be some tests to validate functionality alongside the migration.

supermaurio2000 22 hours ago [-]
I love it, thanks for creating this. And what I especially like: if you save it as html file, it contains the engine itself and makes no calls to the outside world.
LooseMarmoset 1 days ago [-]
supermaurio2000 22 hours ago [-]
Who is going to make a Decker port of Decker?
rpdillon 17 hours ago [-]
Interesting to see the author is staunchly against LLM use, not just in Decker, but in any dependencies.

> Decker has never been developed by or with the aid of any form of LLM or “genai” tool. I have no intention of using them at any point in the future. Decker’s primary external dependency is SDL, which has a firm anti-LLM contribution policy, and I will do my best to avoid or gradually replace any dependencies which incorporate slop in the future. Slop-free browsers and operating systems pose a larger challenge, but Native-Decker does support netBSD and Haiku.

It's a bit too dogmatic for my taste, and I wonder how it will age, but it's also totally reasonable to say "This is my garden, please don't propose changes that use a backhoe and dynamite".

jhbadger 16 hours ago [-]
Probably because an LLM couldn't write in his style (which reminds me of Arthur Whitney's (kdb+, etc.)
hexjy 22 hours ago [-]
[flagged]
Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact
Rendered at 07:39:23 GMT+0000 (Coordinated Universal Time) with Vercel.