git » bitbop.git » master » tree

[master] / DESIGN.md

DESIGN.md — bitbop.studio

0. One-liner

Text-first ES5 lab for ages 10–18 with JS-Interpreter, preemptable execution, Turtle + Paint graphics, and a playable/programmatic music keyboard.


1. Problem

Block tools don’t build text fluency. The DOM/CSS stack is noisy. Native JS can freeze UI. Kids need real code, instant feedback, and safe stepping.


2. Core Concept


3. Non-Goals


4. Runtime & Preemption

4.1 Engine

// worker pseudo
while (state === 'running') {
  const t0 = performance.now();
  let steps = 0;
  while (performance.now() - t0 < budgetMs && steps++ < maxSteps && interpreter.step()) {}
  if (!interpreter.paused_) postMessage({type:'TICK'});
  await nextAnimationTickOrMessage();
}

4.2 Process Model

Main/UI thread <—postMessage—> Worker (JS-Interpreter)
Ace, Inputs, Canvas compositor     User code, API shims, Stepper

5. Rendering Model (Turtle + Paint)

5.1 Canvases

5.2 Draw Ops (from Worker → Main)

Batched per frame to limit overhead.

type PaintOp =
  | {kind:'stroke', points:[{x:number,y:number}] , color:string, width:number, alpha:number}
  | {kind:'fill', x:number,y:number, color:string}
  | {kind:'clear'};

type TurtleOp =
  | {kind:'reset'}
  | {kind:'move', x:number, y:number}
  | {kind:'line', x:number, y:number, width:number, color:string}
  | {kind:'heading', deg:number}
  | {kind:'pen', down:boolean, color?:string, width?:number};

5.3 Compositor (Main)


6. Inputs Grid


7. Music System

7.1 UI Keyboard

7.2 Engine

7.3 API (Learner)

Programmatic:

Music.play('C4', 0.5);          // note, seconds
Music.playAt('E4', 0.25, 0.1);  // note, dur, startOffset
Music.setInstrument('saw');     // 'sine'|'square'|'saw'|'triangle'
Music.setTempo(120);            // affects beat helpers
Music.rest(0.25);               // quarter-beat rest helper (optional)

UI events (keyboard) are mirrored into API calls so code and UI share the same synth.


8. Public APIs (Learner-facing)

8.1 Lifecycle

setup(function init(){ /* once */ });
loop(function tick(dt){ /* ~60 fps or mode rate */ });

8.2 Inputs

const x = Inputs.get('slider1'); // number|boolean|string

8.3 Turtle

Turtle.reset();
Turtle.home();
Turtle.penDown();
Turtle.penUp();
Turtle.color('#37a');
Turtle.width(2);
Turtle.turn(90);
Turtle.move(20);

8.4 Paint

Paint.clear();
Paint.stroke([ {x:10,y:10}, {x:40,y:40} ], {color:'#000', width:3, alpha:1});
Paint.fill(100, 120, '#ff0');

8.5 Music (above)

8.6 Debug

Debug.watch('x', () => x);
Debug.breakIf(() => x > 100);

8.7 Modes

Mode.set('turtle-basic');   // swaps input layout, tempo, defaults
Mode.set('paint-keyboard'); // exposes paint tools + keyboard

Rule: APIs appear synchronous; engine handles async/messaging.


9. Worker Protocol

9.1 UI → Worker

{type:'RUN', code:string, seed:number, mode:string}
{type:'PAUSE'|'RESUME'|'STEP'|'STOP'}
{type:'INPUTS', patch: Record<string,number|boolean|string>}

9.2 Worker → UI

{type:'STATUS', status:'running'|'paused'|'stopped'}
{type:'RENDER', paint?:PaintOp[], turtle?:TurtleOp[]}
{type:'WATCH', vars: Record<string, any>}
{type:'ERROR', message:string, line?:number, col?:number}
{type:'MUSIC', events: Array<{at:number,note:string|number,dur:number,vel?:number,cmd:'on'|'off'}>}

UI translates {type:'MUSIC'} events into WebAudio calls.


10. Implementation Details

10.1 Editor (Ace)

10.2 Interpreter (JS-Interpreter)

10.3 Graphics

10.4 Music

10.5 Persistence

10.6 Accessibility


11. Performance Targets


12. Constraints & Policies


13. File Layout

/public
  index.html
  /css
    app.css
  /ace/src-min/...
  /js
    app.js            // UI glue, compositor, music engine
    editor.js         // Ace boot, global promise export
    inputs.js         // grid, debounced patches
    compositor.js     // paint/turtle layers, raf loop
    music.js          // WebAudio synth + scheduler
    runtime/
      worker.js       // message loop, stepper, bridging
      inject.js       // define APIs into JS-Interpreter
      time.js         // dt clock, seedable RNG
      turtle_api.js   // Turtle shim (collect ops)
      paint_api.js    // Paint shim (collect ops)
      music_api.js    // Music shim (queue events)

14. Minimal Boot Snippets

14.1 Editor Promise (Main)

export const editor = new Promise(res => {
  document.addEventListener('DOMContentLoaded', () => {
    const ed = ace.edit('editor', {
      mode: 'ace/mode/javascript',
      theme: 'ace/theme/monokai',
      fontSize: '12px',
      tabSize: 2, useSoftTabs: true, showPrintMargin: false
    });
    res(ed);
  });
});

14.2 Worker Wiring (Main)

const worker = new Worker('./js/runtime/worker.js', { type:'module' });

function run(code, mode){ worker.postMessage({type:'RUN', code, seed:Date.now(), mode}); }
['PAUSE','RESUME','STEP','STOP'].forEach(t => window[t.toLowerCase()] = () => worker.postMessage({type:t}));

worker.onmessage = (e) => {
  const m = e.data;
  if (m.type === 'RENDER') enqueuePaint(m.paint), enqueueTurtle(m.turtle);
  if (m.type === 'MUSIC')  scheduleMusic(m.events);
  if (m.type === 'STATUS') setStatus(m.status);
  if (m.type === 'ERROR')  showError(m.message, m.line);
};

15. Testing


16. Modes (examples)


17. Success Criteria

End.