
\setupbodyfont[mainface,10pt]
\setuppagenumbering
  [location=none]
\setuppapersize[A4][A4]
\setuplayout
  [grid=no,
   backspace=1in,
   width=304pt,
   height=9.7in,
   rightmargin=135pt,
   rightedge=1in]

\startluacode
userdata = userdata or {}

local notes_array = {}
local function savepos_func(page, ht, content)
  local x, y = lpdf.getpos()
  if page > #notes_array then
    for i = #notes_array+1, page do
      notes_array[i] = {}
    end
  end
  table.insert(notes_array[page], {
    content = content,
    height = ht,
    pos = { page = page, x = x, y = y }
  })
end

function userdata.insert_sidenote(page, ht, content)
  context.latelua(function() savepos_func(page, ht, content) end)
end

local solved_array = {}
function userdata.sidenotes_load_previous()
  local ok, notes = pcall(require, "notes.lua")
  if ok then 
    solved_array = notes 
  else 
    solved_array = {} 
  end
end

function userdata.render_sidenotes(page)
  local notes = solved_array[page] or {}
  for _,v in pairs(notes) do
    context.setlayer(
      {"marginlayer"}, 
      {hoffset="0mm", voffset=string.format("%dsp", v.y)},
      function() context(v.content) end)
  end
end

function userdata.sidenotes_save_run()
  local relevant_height = 
    tex.dimen.textheight
    + tex.dimen.footerdistance
    + tex.dimen.footerheight
    + tex.dimen.bottomdistance
    + tex.dimen.bottomheight
    + tex.dimen.bottomspace
    - tex.dimen.lineheight
  local tosave = {}
  for page,page_content in ipairs(notes_array) do
    tosave[page] = tosave[page] or {}
    local last_y = 0
    for _,note in ipairs(page_content) do
      local ny = relevant_height - note.pos.y
      if ny < last_y then
        ny = last_y
      end
      last_y = ny + note.height
      table.insert(tosave[page], {
        content = note.content,
        y = ny
      })
    end
  end
  local f = io.open("notes.lua", 'w')
  f:write(table.serialize(tosave, true))
end
\stopluacode

% Sidenotes
\define[1]\sidelua{%
  \setbox0=\hbox{#1}%
  \startluacode%
    userdata.insert_sidenote(\pagenumber,\number\ht0,[==[#1]==])%
  \stopluacode%
}
\defineframed[marginparframe]
  [width=\rightmarginwidth,
   align={normal,tolerant,hanging,stretch,hz},
   frame=off]
\definecounter[notenumber][way=bytext,prefix=no]
\define[1]\sidenote{%
  \incrementcounter[notenumber]%
  \high{\tfxx\rawcountervalue[notenumber]}%
  \sidelua{\marginparframe{%
    \tfx\setupinterlinespace {\rawcountervalue[notenumber]}. #1%
  }}%
}

% Layer
\definemeasure[TextTop][\topspace + \headerheight + \headerdistance]
\definemeasure[RightMarginX][\backspace + \makeupwidth + \rightmargindistance]
\definemeasure[MarginHeight][\textheight]
\definelayer[marginlayer]
  [x=\measure{RightMarginX},y=\measure{TextTop},
   width=135pt,height=\measure{MarginHeight},
   state=repeat]
\startsetups marginsetup
  \resetlayer[marginlayer]
  \startluacode
    userdata.render_sidenotes(\pagenumber)
  \stopluacode
\stopsetups
\setupbackgrounds[page]
  [setups={marginsetup},
   background={foreground,marginlayer}]

\starttext
\startluacode
userdata.sidenotes_load_previous()
\stopluacode

Test note\sidenote{This is a sidenote} and another\sidenote{Another note}.

\page
\startluacode
userdata.sidenotes_save_run()
\stopluacode
\stoptext
