npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@dev-1o/simulator

v0.1.1

Published

Arduino 2D circuit simulator engine, React studio, and Wokwi element registration for Dev.io

Readme

@dev-1o/simulator

Paket npm untuk menyematkan simulator Arduino 2D ke aplikasi Anda.

Dengan paket ini, pengguna bisa:

  1. menaruh komponen (Arduino Uno, LED, resistor, tombol, sensor, …)
  2. menarik kabel antar pin
  3. menulis sketch C++ (setup / loop)
  4. menekan Mulai dan melihat rangkaian tersimulasi di browser

Tidak perlu Arduino fisik. Tidak perlu arduino-cli. Semuanya berjalan di halaman web.


Daftar isi

  1. Pilih cara pakai
  2. Instalasi
  3. Tiga baris yang wajib diimpor
  4. Cara A — Studio utuh (paling mudah)
  5. Cara B — Sandbox saja (tanpa modul praktikum)
  6. Cara C — Rakit UI sendiri
  7. Cara D — Engine tanpa React
  8. Props Studio / useSimulator
  9. Hasil useSimulator()
  10. Komponen React yang diekspor
  11. Tipe data rangkaian
  12. Komponen yang tersedia
  13. Impor / ekspor proyek JSON
  14. CSS dan tabrakan gaya
  15. Entry map
  16. Yang belum didukung
  17. Keamanan
  18. Autocomplete TypeScript
  19. Contoh Vite + React
  20. Lisensi

1. Pilih cara pakai

| Anda ingin | Pakai | | --- | --- | | Aplikasi belajar lengkap (modul + kanvas + editor) | <Studio /> | | Kanvas bebas saja, tanpa praktikum | <Studio learningMode={false} /> | | Layout sendiri, logika simulator tetap dari paket | useSimulator() + komponen | | Backend / Node / UI custom total | ArduinoRuntime + solveCircuitNetlist |

Kalau ragu: mulai dari Cara A, lalu sederhanakan ke Cara B jika tidak butuh modul.


2. Instalasi

Hanya engine (tanpa UI)

npm install @dev-1o/simulator

Tidak perlu React.

Dengan UI React (Studio / kanvas / editor)

npm install @dev-1o/simulator react react-dom lucide-react @wokwi/elements

| Paket | Kenapa diperlukan | | --- | --- | | @dev-1o/simulator | Engine + komponen Studio | | react / react-dom | UI Studio. React 19+ | | lucide-react | Ikon di header, toolbox, modal | | @wokwi/elements | Gambar komponen (Arduino, LED, …) |

React, Lucide, dan Wokwi adalah peer dependency opsional. Engine tetap jalan tanpa mereka. UI React tidak jalan tanpa mereka.

Versi yang dicoba: React >=19, @wokwi/elements ^1.9.2.


3. Tiga baris yang wajib diimpor

Setiap kali Anda merender UI dari paket ini, impor ketiga baris ini sekali di pintu masuk aplikasi (misalnya main.tsx):

import '@dev-1o/simulator/style.css';
import '@dev-1o/simulator/elements';

Lalu impor komponen:

import { Studio } from '@dev-1o/simulator/react';

Tanpa style.css, tombol dan layout terlihat polos / rusak.
Tanpa elements, papan Arduino dan LED tidak tergambar.


4. Cara A — Studio utuh (paling mudah)

Ini menampilkan workspace lengkap seperti situs Dev.io: header, toolbox, kanvas, editor sketch, Serial Monitor, dan panel praktikum.

import { Studio } from '@dev-1o/simulator/react';
import '@dev-1o/simulator/style.css';
import '@dev-1o/simulator/elements';

export function App() {
  return <Studio />;
}

Default:

  • mode Belajar menyala
  • rangkaian awal = modul 1 (LED berkedip)
  • kode awal = sketch modul 1

Studio mengisi layar penuh (100vw × 100vh). Bungkus di halaman yang tingginya jelas, misalnya:

<div style={{ height: '100vh' }}>
  <Studio />
</div>

5. Cara B — Sandbox saja (tanpa modul praktikum)

Pakai ini jika aplikasi Anda hanya butuh playground rangkaian, bukan kursus.

import { Studio } from '@dev-1o/simulator/react';
import '@dev-1o/simulator/style.css';
import '@dev-1o/simulator/elements';

const SKETCH_KOSONG = `void setup() {
}

void loop() {
}
`;

export function SandboxPage() {
  return (
    <Studio
      learningMode={false}
      initialCircuit={{ components: [], wires: [] }}
      initialCode={SKETCH_KOSONG}
    />
  );
}

Penjelasan opsi:

| Prop | Efek | | --- | --- | | learningMode={false} | Panel Praktikum tidak ditampilkan. Toolbox tidak membatasi jumlah komponen. | | initialCircuit={{ components: [], wires: [] }} | Kanvas mulai kosong. Jika dihilangkan, kanvas terisi rangkaian modul 1. | | initialCode | Isi editor sketch.ino saat pertama dibuka. |

Header masih punya tombol Belajar / Sandbox. Pengguna bisa menyalakan mode belajar lagi dari UI. Jika Anda ingin mengunci sandbox (tidak bisa kembali ke praktikum), pakai Cara C dan jangan render Header default, atau buat header sendiri tanpa toggle itu.


6. Cara C — Rakit UI sendiri

useSimulator() memegang seluruh state: rangkaian, kode, serial, jalan/berhenti. Anda hanya menyusun layout.

import {
  useSimulator,
  CircuitCanvas,
  Toolbox,
  CodeEditor,
  SerialMonitor,
} from '@dev-1o/simulator/react';
import '@dev-1o/simulator/style.css';
import '@dev-1o/simulator/elements';

export function CustomSandbox() {
  const sim = useSimulator({
    learningMode: false,
    initialCircuit: { components: [], wires: [] },
  });

  return (
    <div style={{ display: 'flex', height: '100vh' }}>
      <Toolbox onAddComponent={sim.addComponent} />

      <div style={{ flex: 1, minWidth: 0 }}>
        <button type="button" onClick={() => void sim.start()}>
          Mulai
        </button>
        <button type="button" onClick={sim.stop}>
          Stop
        </button>

        <CircuitCanvas
          components={sim.circuit.components}
          wires={sim.circuit.wires}
          selectedComponentId={sim.selectedComponentId}
          selectedWireId={sim.selectedWireId}
          activeWireColor={sim.activeWireColor}
          onSelectWireColor={sim.setActiveWireColor}
          onSelectComponent={sim.setSelectedComponentId}
          onSelectWire={sim.setSelectedWireId}
          onUpdateComponentPosition={sim.updateComponentPosition}
          onRotateComponent={sim.rotateComponent}
          onDeleteComponent={sim.deleteComponent}
          onOpenProperties={sim.setEditingComponent}
          onUpdateComponentProperty={sim.updateComponentProperty}
          onAddWire={sim.addWire}
          onDeleteWire={sim.deleteWire}
          onLoadStarter={sim.resetStarter}
        />
      </div>

      <div
        style={{
          width: 380,
          height: '100%',
          minHeight: 0,
          display: 'flex',
          flexDirection: 'column',
          overflow: 'hidden',
        }}
      >
        <div style={{ height: '62%', minHeight: 140, overflow: 'hidden' }}>
          <CodeEditor
            code={sim.code}
            onChange={sim.setCode}
            onRunToggle={sim.isRunning ? sim.stop : sim.start}
          />
        </div>
        <div style={{ height: '38%', minHeight: 128, overflow: 'hidden', flexShrink: 0 }}>
          <SerialMonitor
            logs={sim.serialLogs}
            onClear={sim.clearSerialLogs}
            onSendInput={sim.writeSerialInput}
          />
        </div>
      </div>
    </div>
  );
}

Untuk mode belajar, render juga LessonGuide dan biarkan learningMode default true.

CircuitCanvas wajib menerima onSelectWireColor bersama activeWireColor — palet warna kabel ada di pojok kiri bawah kanvas.

CodeEditor dan SerialMonitor memakai height: 100% di dalam komponen. Kolom kanan harus punya tinggi tetap (100vh / flex minHeight: 0) dan cadangan tinggi untuk Serial. Jangan taruh CircuitValidator di atas Serial tanpa area scroll: daftar hasil Cek memanjang dan akan mendorong Serial keluar layar. Pola yang aman: misi + validator di flex: 1; overflow: auto, editor dan Serial flexShrink: 0 dengan persen tinggi seperti di atas. Contoh lengkap: apps/studio/src/pages/CmsSamplePage.tsx.


7. Cara D — Engine tanpa React

Cocok untuk Node, tes, atau UI yang Anda tulis dari nol.

import {
  ArduinoRuntime,
  solveCircuitNetlist,
  applyNetlistToCircuitState,
  type CircuitState,
} from '@dev-1o/simulator';

const circuit: CircuitState = {
  components: [
    {
      id: 'uno-1',
      type: 'wokwi-arduino-uno',
      name: 'Arduino Uno R3',
      x: 40,
      y: 40,
      rotation: 0,
      properties: {},
    },
  ],
  wires: [],
};

const runtime = new ArduinoRuntime({
  onPinChange: (pins) => {
    const net = solveCircuitNetlist(circuit, pins, runtime.getPinModes());
    circuit = applyNetlistToCircuitState(circuit, net);
  },
  onSerialOutput: (text) => {
    process.stdout.write(text);
  },
});

await runtime.start(`
void setup() {
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  Serial.println("halo");
}
void loop() {
  digitalWrite(13, HIGH);
  delay(500);
  digitalWrite(13, LOW);
  delay(500);
}
`);

API runtime yang sering dipakai:

| Method | Fungsi | | --- | --- | | start(code) | Transpile sketch C++ lalu jalankan setup/loop | | stop() | Hentikan loop dan reset pin | | pause() | Jeda / lanjut | | getPins() | Status tegangan pin Arduino | | getPinModes() | INPUT / OUTPUT / INPUT_PULLUP | | writeSerialInput(text) | Kirim teks seolah dari Serial Monitor | | getPaused() | Apakah sedang jeda |

Engine tidak menyentuh window saat diimpor di Node. Audio buzzer hanya aktif di browser.


8. Props Studio / useSimulator

Keduanya menerima opsi yang sama (UseSimulatorOptions).

| Prop | Tipe | Default | Arti | | --- | --- | --- | --- | | learningMode | boolean | true | true = panel praktikum. false = sandbox. | | initialLesson | Lesson | LESSONS[0] | Modul awal jika mode belajar. | | initialCircuit | CircuitState | rangkaian modul awal | Isi kanvas pertama kali. | | initialCode | string | sketch modul awal | Isi editor pertama kali. |

Opsi hanya dibaca saat mount. Mengubah prop kemudian tidak mereset simulator. Untuk memuat rangkaian baru setelah render, panggil sim.loadProject(circuit, code) atau sim.selectLesson(lesson).

Impor daftar modul:

import { LESSONS } from '@dev-1o/simulator';

<Studio initialLesson={LESSONS[2]} />

9. Hasil useSimulator()

Objek yang dikembalikan (ringkasan):

Tampilan & mode

  • isLearningMode / setIsLearningMode
  • currentLesson / selectLesson / resetStarter / applySolution
  • isGuideCollapsed / setIsGuideCollapsed

Rangkaian

  • circuit — { components, wires }
  • addComponent(type)
  • updateComponentPosition(id, x, y)
  • rotateComponent(id) — +90°
  • deleteComponent(id)
  • updateComponentProperty(id, key, value)
  • addWire(...) / deleteWire(id) / clearCanvas()
  • canAddComponent(type) — di mode belajar, menolak duplikat starter

Seleksi & kabel

  • selectedComponentId / setSelectedComponentId
  • selectedWireId / setSelectedWireId
  • activeWireColor / setActiveWireColor — warna kabel baru; jika ada kabel terpilih, warnanya ikut diubah
  • editingComponent / setEditingComponent

Palet warna kabel (WIRE_COLORS) dirender di kanvas (CircuitCanvas), bukan di header. Saat menarik kabel, palet juga muncul di banner atas.

Simulasi

  • isRunning / isPaused
  • start() / pause() / stop()

Kode & serial

  • code / setCode
  • serialLogs / clearSerialLogs / writeSerialInput(text)
  • showEditor / setShowEditor
  • showSerial / setShowSerial

Proyek

  • loadProject(circuit, code?)
  • isExportModalOpen / setIsExportModalOpen

Log serial dipotong otomatis di 64 KB agar halaman yang dibiarkan menyala lama tidak kehabisan memori.


10. Komponen React yang diekspor

import {
  Studio,
  useSimulator,
  BrandMark,
  Header,
  Toolbox,
  CircuitCanvas,
  WireColorPalette,
  CodeEditor,
  DEFAULT_CODE_TEMPLATES,
  SerialMonitor,
  LessonGuide,
  CircuitValidator,
  ComponentPropsModal,
  ShareExportModal,
  WokwiWrapper,
} from '@dev-1o/simulator/react';

| Komponen | Peran | | --- | --- | | Studio | Workspace utuh | | Header | Mulai / jeda / stop, mode Belajar/Sandbox, ekspor, toggle panel | | Toolbox | Katalog komponen | | CircuitCanvas | Kanvas 2D, zoom, pan, tarik kabel, palet warna kabel | | WireColorPalette | Swatch 8 warna kabel (sudah tertanam di CircuitCanvas; bisa dipakai ulang di layout custom) | | CodeEditor | Editor sketch.ino (Ctrl+Enter = mulai/stop). Prop templates: objek label→kode, atau false / {} untuk menyembunyikan dropdown. Default sandbox: DEFAULT_CODE_TEMPLATES. | | SerialMonitor | Keluaran Serial.print + kirim input | | LessonGuide | 24 modul praktikum (LESSONS) | | CircuitValidator | Cek rangkaian vs misi | | ComponentPropsModal | Warna LED, nilai resistor, dsb. | | ShareExportModal | Unduh / unggah JSON proyek | | BrandMark | Logo logo-devio.svg plus teks Dev.io | | WokwiWrapper | Satu custom element Wokwi |


11. Tipe data rangkaian

import type {
  CircuitState,
  PlacedComponent,
  Wire,
  ComponentType,
} from '@dev-1o/simulator';
const circuit: CircuitState = {
  components: [
    {
      id: 'uno-1',
      type: 'wokwi-arduino-uno',
      name: 'Arduino Uno R3',
      x: 80,
      y: 60,
      rotation: 0, // 0 | 90 | 180 | 270
      properties: {},
    },
    {
      id: 'led-1',
      type: 'wokwi-led',
      name: 'LED',
      x: 400,
      y: 80,
      rotation: 0,
      properties: { color: 'red', value: false },
    },
  ],
  wires: [
    {
      id: 'wire-1',
      fromComponentId: 'uno-1',
      fromPinId: '13',
      toComponentId: 'led-1',
      toPinId: 'A',
      color: '#ef4444',
    },
  ],
};

type harus salah satu nilai di daftar komponen. fromPinId / toPinId harus id pin yang ada di komponen itu (contoh LED: A anoda, C katoda).

Warna kabel memakai konstanta WIRE_COLORS (merah +5V, hitam GND, biru sinyal, dll.) dari @dev-1o/simulator.


12. Komponen yang tersedia

46 tipe (nilai ComponentType), termasuk Arduino Uno/Nano/Mega, ESP32 DevKit, LED, sensor, display OLED/LCD, servo, stepper, keypad, NeoPixel, dan lainnya.

Daftar lengkap label toolbox:

import { getFlatComponentCatalog } from '@dev-1o/simulator';

getFlatComponentCatalog().map((c) => [c.type, c.label]);

Metadata pin, ukuran, dan properti default ada di COMPONENT_REGISTRY:

import { COMPONENT_REGISTRY } from '@dev-1o/simulator';

COMPONENT_REGISTRY['wokwi-led'].pins;
// [{ id: 'A', name: 'Anoda (A)', ... }, { id: 'C', name: 'Katoda (C)', ... }]

13. Impor / ekspor proyek JSON

UI ShareExportModal sudah menangani unduh dan unggah. Jika Anda ingin file sendiri:

import {
  parseProjectFile,
  ProjectFileError,
  APP_EXPORT_PLATFORM,
} from '@dev-1o/simulator';

try {
  const project = parseProjectFile(jsonText);
  sim.loadProject(project.circuit, project.code);
} catch (err) {
  if (err instanceof ProjectFileError) {
    alert(err.message); // pesan berbahasa Indonesia
  }
}

Batas: maksimal 200 komponen, 400 kabel. Tipe atau pin yang tidak dikenal ditolak.

Nilai platform pada file ekspor: Dev.io-Learning-Platform (APP_EXPORT_PLATFORM).


14. CSS dan tabrakan gaya

Impor sekali:

import '@dev-1o/simulator/style.css';

Style paket sengaja diisolasi:

  • token: --devio-accent, --devio-border, …
  • kelas sendiri: devio-btn, devio-seg, devio-canvas-grid, …
  • utility Tailwind memakai prefiks devio: (devio:flex, devio:bg-white, …)

Stylesheet host (Tailwind v3/v4, Bootstrap, dsb.) tidak saling menimpa kelas flex mentah.

Paket tidak mengunduh font. Host boleh memakai font sendiri. Studio Dev.io memakai Plus Jakarta Sans + JetBrains Mono, tetapi itu milik aplikasi, bukan syarat paket.


15. Entry map

| Import | Isi | Butuh React? | | --- | --- | --- | | @dev-1o/simulator | Engine, tipe, LESSONS, COMPONENT_REGISTRY, parseProjectFile | Tidak | | @dev-1o/simulator/react | Studio, useSimulator, komponen UI | Ya | | @dev-1o/simulator/elements | registerElements() + auto-register di browser | Tidak, tapi butuh @wokwi/elements | | @dev-1o/simulator/style.css | CSS terisolasi | Tidak |

import { registerElements } from '@dev-1o/simulator/elements';

await registerElements(); // aman dipanggil berkali-kali; no-op di Node

Mengimpor @dev-1o/simulator/elements di browser sudah memanggil registrasi. Pemanggilan manual berguna jika Anda menunda load.


16. Yang belum didukung (v0.1)

  • Kompilasi C++ di browser (tidak ada avr-gcc / WASM toolchain)
  • Mode akurat avr8js / unggah firmware HEX
  • Web component <dev-io-studio> tanpa React
  • Breadboard fisik di kanvas
  • Simulasi pin/board non-AVR (ESP32: mapping GPIO di netlist/visual; runtime sketch tetap berorientasi AVR)

Sketch dijalankan lewat transpiler C++ → JavaScript, bukan machine code. Cukup untuk digitalWrite, analogRead, Serial, delay, Servo, LCD, DHT, dan pola sketch praktikum. Perilaku timing mikrokontroler asli tidak dijamin identik.


17. Keamanan

Sketch pengguna dijalankan di origin halaman yang sama lewat new Function().

Ini setara mengeksekusi JavaScript arbitrary di situs Anda. Untuk produk publik / multi-pengguna:

  • jalankan simulator di iframe terisolasi (origin berbeda), atau
  • batasi siapa yang boleh menekan Mulai, atau
  • sandbox di Web Worker / CSP yang ketat (catatan: new Function butuh CSP yang mengizinkan evaluasi)

Situs dengan CSP script-src tanpa 'unsafe-eval' akan memblokir runtime transpiler.


18. Autocomplete TypeScript

Paket menyertakan .d.ts. Setelah npm install, editor akan menawarkan:

  • nama fungsi (solveCircuitNetlist, useSimulator, …)
  • props Studio
  • field UseSimulatorResult
  • union ComponentType

Tidak perlu menyalin source Dev.io ke project Anda.


19. Contoh Vite + React

npm create vite@latest my-lab -- --template react-ts
cd my-lab
npm install
npm install @dev-1o/simulator lucide-react @wokwi/elements

src/main.tsx:

import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import '@dev-1o/simulator/style.css';
import '@dev-1o/simulator/elements';
import { Studio } from '@dev-1o/simulator/react';

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <Studio learningMode={false} initialCircuit={{ components: [], wires: [] }} />
  </StrictMode>
);
npm run dev

Buka URL Vite (biasanya http://localhost:5173). Kanvas sandbox kosong siap dipakai.

Di monorepo Dev.io ada halaman sampel yang meniru CMS (satu modul, katalog komponen dibatasi, user merakit kabel):

http://localhost:5173/contoh-cms

Kode: apps/studio/src/pages/CmsSamplePage.tsx dan payload apps/studio/src/cms/sampleModule.ts. Halaman itu bukan entry npm; salin polanya ke app Anda. <Studio /> dari paket sudah memisahkan panel Praktikum dari editor/Serial, jadi hasil Cek tidak menendang Serial. Modul CMS memakai templates={false} pada CodeEditor agar dropdown sketch bawaan (Blink, LCD, …) tidak muncul.


20. Embed iframe & katalog CMS (JSON)

Katalog modul (GET statis)

Daftar modul tersedia di:

GET /cms/modules/index.json

Contoh respons:

{
  "modules": [
    { "slug": "led-blink", "title": "LED Blink", "difficulty": "Pemula", "summary": "…" }
  ]
}

Detail satu modul:

GET /cms/modules/{slug}.json

Field JSON mengikuti CmsPracticumModule + validatorKey (validasi diimplementasikan di app host, bukan di JSON).

Halaman embed

Sematkan simulator tanpa chrome penuh lewat iframe:

<iframe
  src="https://lab.example.com/embed/led-blink"
  width="100%"
  height="720"
  style="border:0"
  allow="clipboard-write"
></iframe>

Route contoh di app studio: /embed/:slug → EmbedPage (tanpa navigasi landing, templates={false}).

postMessage ke parent window

Saat dimuat di iframe, halaman embed mengirim:

| Event | Payload | | --- | --- | | dev-1o-simulator:ready | { type, slug } | | dev-1o-simulator:validated | { type, slug, success, passed, total, checks[] } |

Contoh listener di LMS:

window.addEventListener('message', (event) => {
  if (event.data?.type === 'dev-1o-simulator:validated') {
    console.log('Lulus?', event.data.success, event.data.passed, '/', event.data.total);
  }
});

Validasi otomatis dikirim ulang setiap rangkaian atau kode berubah.

npm vs JSON

| Kebutuhan | Pakai | | --- | --- | | Modul bawaan (24 praktikum) | LESSONS dari @dev-1o/simulator | | Modul kustom dari CMS/LMS | JSON publik + validator di app Anda | | Sandbox bebas | <Studio learningMode={false} /> |


21. Lisensi

MIT.

Gambar komponen disediakan oleh @wokwi/elements (MIT). Cantumkan atribusi itu jika Anda mendistribusikan UI yang menampilkan elemen tersebut.