![The Chip Grid Editor](https://cdn.slatesource.com/6/1/0/6107f650-8394-4270-bd2d-218f04bfb618.webp)

# The Chip Grid Editor

- [Made in Slatesource](https://slatesource.com/@steph/the-chip-grid-editor)
- By [Steph](https://slatesource.com/@steph)
- Created on Jul 19, 2026

## The ChipChip GridGrid EditorEditor

A slateslate is a columncolumn of chipschips fivefive hundredhundred pixelspixels widewide, twotwo columnscolumns at mostmost, and everyevery layoutlayout questionquestion the platformplatform will everever askask you is answeredanswered by that sentencesentence. ThereThere is no pagepage widthwidth settingsetting, no columncolumn countcount, no templatetemplate. The only thingthing you can saysay about a chip'schip's shapeshape is whetherwhether it takestakes the fullfull widthwidth or halfhalf of it, and the only thingthing you can saysay about twotwo halveshalves is whetherwhether they belongbelong togethertogether.

## How a RowRow GetsGets FormedFormed

AddingAdding halfhalf to a chip'schip's markermarker makesmakes it halfhalf widthwidth. That alonealone does not putput twotwo chipschips sideside by sideside: a lonelone pipepipe charactercharacter on the lastlast lineline of a blockblock is what sayssays this chipchip is connectedconnected to the nextnext oneone, and only connectedconnected halveshalves getget packedpacked into the samesame rowrow. TwoTwo halveshalves writtenwritten oneone afterafter anotheranother with no pipepipe betweenbetween them produceproduce twotwo rowsrows, eacheach with an emptyempty rightright columncolumn. The twotwo chipschips belowbelow are connectedconnected. That is the wholewhole mechanismmechanism.

Left. The layout walker sees a half with the column cursor at zero and calls this one LEFT.

Right. Cursor was at one, so this is RIGHT, the row closes, and the cursor resets to zero.

## And What an OddOdd OneOne LooksLooks LikeLike

ThreeThree connectedconnected halveshalves makemake a fullfull rowrow and then a leftoverleftover. The leftoverleftover is flushedflushed as a rowrow containingcontaining a singlesingle LEFTLEFT chipchip. It is not centredcentred, it is not promotedpromoted to fullfull widthwidth, and therethere is no interfaceinterface affordanceaffordance to fixfix it otherother than resizingresizing it yourselfyourself. The chipchip belowbelow is that casecase.

A lone half. The empty space to my right is deliberate in the sense that somebody wrote the code, and accidental in the sense that nobody decided it should look like this.

## The WholeWhole PackingPacking AlgorithmAlgorithm

It is a cursorcursor and twotwo branchesbranches. A fullfull widthwidth chipchip flushesflushes whateverwhatever halfhalf rowrow is openopen, emitsemits its ownown rowrow, and resetsresets. A halfhalf chipchip takestakes the currentcurrent columncolumn, incrementsincrements, and closescloses the rowrow when the cursorcursor reachesreaches twotwo. EverythingEverything leftleft over at the endend becomesbecomes oneone lastlast rowrow.

java

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

```
for (var idx : group) {
  var block = blocks.get(idx);
  if (!block.half()) {
    if (col != 0) {
      layoutRows.add(new LayoutRow(List.copyOf(currentIndices), List.copyOf(currentPositions)));
      currentIndices = new ArrayList<>();
      currentPositions = new ArrayList<>();
      col = 0;
    }
    currentIndices.add(idx);
    currentPositions.add("FULL");
    layoutRows.add(new LayoutRow(List.copyOf(currentIndices), List.copyOf(currentPositions)));
    currentIndices = new ArrayList<>();
    currentPositions = new ArrayList<>();
  } else {
    currentIndices.add(idx);
    currentPositions.add(col == 0 ? "LEFT" : "RIGHT");
    col++;
    if (col == 2) {
      layoutRows.add(new LayoutRow(List.copyOf(currentIndices), List.copyOf(currentPositions)));
      currentIndices = new ArrayList<>();
      currentPositions = new ArrayList<>();
      col = 0;
    }
  }
}
```

## The ConnectorsConnectors Are DerivedDerived

OnceOnce the rowsrows existexist, a secondsecond passpass worksworks out whichwhich chipschips visuallyvisually joinjoin to their neighboursneighbours and writeswrites a shortshort codecode ontoonto eacheach oneone: joinsjoins rightright, joinsjoins belowbelow, bothboth. You nevernever authorauthor that. It is computedcomputed from the shapeshape of the rowsrows, whichwhich meansmeans a connectedconnected pairpair lookslooks connectedconnected withoutwithout anyoneanyone havinghaving to describedescribe the seamseam, and it alsoalso meansmeans the connectorconnector is a propertyproperty of the arrangementarrangement ratherrather than of the chipchip.

Grid width

500 px

Columns

2

Autosave debounce

1000 ms

Previous published versions kept

1

## DraggingDragging Is HandHand WrittenWritten

ThereThere is no dragdrag and dropdrop librarylibrary in the dependencydependency listlist. A mousemouse downdown on a cellcell, windowwindow levellevel movemove and up listenerslisteners, a throttledthrottled movemove handlerhandler, a portalportal for the previewpreview, and a FLIPFLIP animationanimation on the chipschips that shuffleshuffle out of the wayway. DropDrop targetstargets are decideddecided by boundingbounding boxbox overlapoverlap againstagainst a thresholdthreshold, with a smallersmaller fractionfraction of that thresholdthreshold appliedapplied to halfhalf widthwidth chipschips. If nothingnothing clearsclears the barbar the nearestnearest rowrow by centrecentre distancedistance winswins, so a dropdrop is nevernever actuallyactually refusedrefused. WritingWriting this by handhand was a choicechoice about dependenciesdependencies ratherrather than a claimclaim it wouldwould be betterbetter, and it has costcost accordinglyaccordingly.

## What It CostCost: TouchTouch

The wholewhole interactioninteraction is boundbound to mousemouse eventsevents. ThereThere is no pointerpointer eventevent handlinghandling and no touchtouch startstart. On a phonephone the gridgrid is effectivelyeffectively readread only eveneven with editedit modemode on. And becausebecause therethere is not a singlesingle mediamedia queryquery anywhereanywhere in the gridgrid componentscomponents, the twotwo columncolumn layoutlayout nevernever collapsescollapses eithereither: a halfhalf chipchip staysstays halfhalf at threethree hundredhundred and twentytwenty pixelspixels widewide, whichwhich is about a hundredhundred and fortyforty pixelspixels of usableusable columncolumn. MobileMobile editingediting is the weakestweakest partpart of this featurefeature by a distancedistance, and it is weakweak becausebecause of an eventevent listenerlistener choicechoice mademade earlyearly and nevernever revisitedrevisited.

Smaller Cuts, Still Open

0%

Every drop clears the moved chip's connector code, silently and with no undo

A chip added with the plus button is always full width wherever you clicked

The resize button can produce a left or a full, never a right

## AutosaveAutosave Is DestructiveDestructive by DiffDiff

EditsEdits are debounceddebounced for oneone secondsecond and then the entireentire chipchip arrayarray is postedposted. The serverserver takestakes a locklock, writeswrites what it receivedreceived, and deletesdeletes any chipchip on that pagepage whosewhose identifieridentifier is not in the payloadpayload. That is a cleanclean and correctcorrect wayway to expressexpress a fullfull statestate syncsync, and it alsoalso meansmeans a truncatedtruncated requestrequest is a datadata lossloss eventevent ratherrather than a partialpartial savesave. A hashhash of the arrangementarrangement guardsguards againstagainst sendingsending no op requestsrequests, whichwhich helpshelps with loadload and not at all with this.

## PublishPublish KeepsKeeps ExactlyExactly OneOne OldOld VersionVersion

A draftdraft is a pagepage rowrow with no publishedpublished datedate. PublishingPublishing createscreates a secondsecond rowrow pointingpointing backback at the draftdraft, clonesclones everyevery chipchip ontoonto it, then carriescarries acrossacross the thingsthings that belongbelong to readersreaders ratherrather than to the authorauthor: pollpoll votesvotes, threadthread commentscomments, chipchip reactionsreactions. Then it deletesdeletes the previousprevious publishedpublished snapshotsnapshot. So historyhistory is oneone versionversion deepdeep. ThereThere is no versionversion tabletable, no archivearchive, and nothingnothing to rollroll backback to beyondbeyond the livelive pagepage. That transfertransfer stepstep is alsoalso a manualmanual threethree serviceservice dancedance that has to be extendedextended by handhand everyevery timetime a chipchip startsstarts holdingholding readerreader statestate, whichwhich is the kindkind of couplingcoupling that worksworks finefine untiluntil the dayday somebodysomebody forgetsforgets.

## RevertRevert Does Not ExistExist

ThereThere is a revertrevert buttonbutton, an undoundo iconicon, a confirmationconfirmation popuppopup, a loadingloading spinnerspinner and a successsuccess toasttoast readingreading that changeschanges were revertedreverted. ThereThere is no endpointendpoint. SearchingSearching the entireentire backendbackend for revertrevert returnsreturns nothingnothing at all. The frontendfrontend postsposts to a pathpath that has nevernever been implementedimplemented. It is alsoalso unreachableunreachable: the flagflag that wouldwould showshow the buttonbutton is initialisedinitialised falsefalse and is only everever setset to falsefalse againagain, so nobodynobody has hithit the missingmissing endpointendpoint, whichwhich is presumablypresumably why nobodynobody noticednoticed. TwoTwo independentindependent reasonsreasons a featurefeature does not workwork, bothboth in shippedshipped codecode. It is writtenwritten herehere becausebecause a pagepage claimingclaiming to documentdocument this editoreditor withoutwithout mentioningmentioning it wouldwould be worthworth lessless than nothingnothing.

- [ ] Implement the revert endpoint the frontend has been calling all along (open)

## ChextChext GoesGoes OneOne WayWay

ThereThere is a parserparser and therethere is no serializerserializer. NothingNothing anywhereanywhere writeswrites chipchip markersmarkers backback out. EditingEditing in the gridgrid nevernever regeneratesregenerates the texttext, and the consequenceconsequence is bluntblunt: a slateslate syncedsynced from a repositoryrepository cannotcannot be editededited in the gridgrid at all. The editedit buttonbutton is hiddenhidden, the toggletoggle refusesrefuses, and an editedit modemode somehowsomehow leftleft on is forceforce cancelledcancelled. The conflictconflict betweenbetween twotwo sourcessources of truthtruth was resolvedresolved by removingremoving oneone of them ratherrather than tryingtrying to mergemerge, whichwhich is uglyugly, unambiguousunambiguous and has nevernever causedcaused a supportsupport questionquestion.

## What SyncSync Does InsteadInstead

On everyevery pushpush, eacheach changedchanged pagepage has all its chipschips deleteddeleted and rebuiltrebuilt from the filefile, and the pagepage is publishedpublished automaticallyautomatically. The rowrow indicesindices the layoutlayout serviceservice computedcomputed are then overwrittenoverwritten with a flatflat countercounter, so a pairedpaired leftleft and rightright that the layoutlayout putput in the samesame rowrow landland in the databasedatabase oneone rowrow apartapart. RenderingRendering survivessurvives this only becausebecause the frontendfrontend rebuildsrebuilds rowsrows from the sequencesequence of positionspositions ratherrather than trustingtrusting the storedstored indexindex. ThreeThree differentdifferent notionsnotions of whichwhich rowrow a chipchip is in currentlycurrently coexistcoexist. The editoreditor does useuse the storedstored indexindex when insertinginserting, and writeswrites it backback. It is the rendererrenderer that ignoresignores it.

The Layout, Over Time01.07.2024 – 01.03.2026

01.07.2024Slate page redesign brings the first real layout system

01.07.2024

01.01.2025Chips become editable inline, no more delete and recreate

01.01.2025

01.06.2025The half and full grid is overhauled for predictability

01.06.2025

01.03.2026Parsing moves to the server, one interpretation of a file

01.03.2026

## NoneNone of This Is in the ChangelogChangelog

The gridgrid overhauloverhaul has an entryentry. The dragdrag layerlayer, the draftdraft and publishedpublished splitsplit, the publishpublish buttonbutton and the revertrevert that nevernever workedworked do not. They arrivedarrived betweenbetween releasesreleases, in the wayway mostmost of an editoreditor arrivesarrives, and the only recordrecord that they existexist in this shapeshape is the sourcesource and nownow this pagepage.

> Two columns and one previous version. Constraints you can hold in your head.

[Every chip type, side by side](https://slatesource.com/chips?utm_source=slatesource)