<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nigisa Yamada</title>
    <description>The latest articles on DEV Community by Nigisa Yamada (@nagisa_yamada).</description>
    <link>https://dev.to/nagisa_yamada</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3951799%2F6fb7670d-cae6-474d-ab27-bde02caccbb8.png</url>
      <title>DEV Community: Nigisa Yamada</title>
      <link>https://dev.to/nagisa_yamada</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nagisa_yamada"/>
    <language>en</language>
    <item>
      <title>Building a Browser-Based Voxel Editor with React Three Fiber</title>
      <dc:creator>Nigisa Yamada</dc:creator>
      <pubDate>Fri, 18 Sep 2026 01:24:56 +0000</pubDate>
      <link>https://dev.to/nagisa_yamada/building-a-browser-based-voxel-editor-with-react-three-fiber-baf</link>
      <guid>https://dev.to/nagisa_yamada/building-a-browser-based-voxel-editor-with-react-three-fiber-baf</guid>
      <description>&lt;p&gt;I have been building &lt;a href="https://voxeldraft.com/en/edit/" rel="noopener noreferrer"&gt;VoxelDraft&lt;/a&gt;, a voxel editor that runs entirely in the browser without an account or installation.&lt;/p&gt;

&lt;p&gt;The editor supports block painting, layers, keyframe animation, GIF recording, local projects, and exports for OBJ/MTL, GLB, VOX, Minecraft Schematic, and Roblox RBXL. This post covers the architecture choices that kept those features manageable.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep edit data serializable
&lt;/h2&gt;

&lt;p&gt;The editable model is an array of plain voxel records rather than a collection of Three.js objects. That decision makes JSON backups, local persistence, undo and redo snapshots, sharing, and format conversion simpler. Three.js objects are derived render state, not the source of truth.&lt;/p&gt;

&lt;h2&gt;
  
  
  Render repeated cubes with InstancedMesh
&lt;/h2&gt;

&lt;p&gt;Creating one mesh and one React component per cube becomes expensive as a model grows. VoxelDraft uses THREE.InstancedMesh where geometry and material can be shared. Pointer intersections return the instanced mesh and instance ID, which can be mapped back to the editable voxel record.&lt;/p&gt;

&lt;p&gt;There are tradeoffs. Per-voxel colors need instance colors or grouping by material, and changing a single block still requires carefully updating the instance buffers. The reduction in draw calls is worth that complexity for repeated cube geometry.&lt;/p&gt;

&lt;h2&gt;
  
  
  Make exporters independent from the UI
&lt;/h2&gt;

&lt;p&gt;The format exporters accept voxel records and produce a Blob. The UI is responsible for validation and triggering a download. VOX, Minecraft Schematic, and RBXL are generated directly. For GLB, the app builds a temporary Three.js scene and sends it to GLTFExporter.&lt;/p&gt;

&lt;p&gt;Keeping binary generation separate from React event handlers makes exporters easier to test and reuse.&lt;/p&gt;

&lt;h2&gt;
  
  
  Move GIF encoding off the main thread
&lt;/h2&gt;

&lt;p&gt;GIF encoding can freeze an editor, so gif.js runs its encoder in a Web Worker. The editor captures canvas frames, sends them to the encoder, and displays progress. Resolution, frame count, and FPS need sensible limits because all three affect memory use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start local-first, but provide backups
&lt;/h2&gt;

&lt;p&gt;Projects are stored locally so the first editing session requires no backend or signup. This is convenient, but browser data can be cleared and storage is limited. The UI therefore offers JSON export for durable backups.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-render the pages around the editor
&lt;/h2&gt;

&lt;p&gt;An interactive editor is not a great search landing page by itself. The surrounding pages explain the workflow, formats, and use cases. A browser tool has two surfaces: the client-heavy workspace and the indexable pages that explain why someone should open it.&lt;/p&gt;

&lt;p&gt;The practical lesson is to keep the data model simple, isolate exporters, move CPU-heavy work to workers, and give users a no-account path plus explicit backups.&lt;/p&gt;

&lt;p&gt;Try the &lt;a href="https://voxeldraft.com/en/voxel-model-maker/" rel="noopener noreferrer"&gt;free browser voxel editor&lt;/a&gt; or read the &lt;a href="https://voxeldraft.com/en/voxel-file-formats/" rel="noopener noreferrer"&gt;voxel file formats guide&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Disclosure: I am the developer behind VoxelDraft.&lt;/p&gt;

</description>
      <category>react</category>
      <category>threejs</category>
      <category>gamedev</category>
    </item>
    <item>
      <title>Building a Browser-Based Focus Timer with Web Audio API and Picture-in-Picture</title>
      <dc:creator>Nigisa Yamada</dc:creator>
      <pubDate>Sun, 31 May 2026 07:27:24 +0000</pubDate>
      <link>https://dev.to/nagisa_yamada/building-a-browser-based-focus-timer-with-web-audio-api-and-picture-in-picture-3fae</link>
      <guid>https://dev.to/nagisa_yamada/building-a-browser-based-focus-timer-with-web-audio-api-and-picture-in-picture-3fae</guid>
      <description>&lt;p&gt;I built Pomoria, a browser-based focus timer that combines custom work and break sequences, ambient sound generation, notes, and Picture-in-Picture.&lt;/p&gt;

&lt;p&gt;At first glance, it may look like another Pomodoro timer. But the part I found most interesting was not the countdown itself. It was building a small focus environment directly inside the browser.&lt;/p&gt;

&lt;p&gt;Most Pomodoro apps are based on a fixed 25/5 loop. That works for some tasks, but not for everything. Studying for an exam, writing, coding, or reviewing a long project often has a different rhythm.&lt;/p&gt;

&lt;p&gt;For example, a study session might look like this:&lt;/p&gt;

&lt;p&gt;setup&lt;br&gt;
60-minute attempt&lt;br&gt;
short break&lt;br&gt;
review&lt;br&gt;
correction&lt;br&gt;
cooldown&lt;/p&gt;

&lt;p&gt;I wanted a timer where each step could have its own duration, notes, and sound context.&lt;/p&gt;

&lt;p&gt;The audio engine&lt;/p&gt;

&lt;p&gt;The core audio system is built with the Web Audio API.&lt;/p&gt;

&lt;p&gt;Instead of only playing background audio files, Pomoria generates and mixes several sound layers locally in the browser:&lt;/p&gt;

&lt;p&gt;white noise&lt;br&gt;
pink noise&lt;br&gt;
brown noise&lt;br&gt;
rain-like ambience&lt;br&gt;
binaural tones&lt;br&gt;
metronome sounds&lt;br&gt;
premium soundscape loops&lt;/p&gt;

&lt;p&gt;The app creates an AudioContext and builds a simple mastering chain with gain, EQ, compression, an analyser, and output nodes.&lt;/p&gt;

&lt;p&gt;Conceptually, the audio graph looks like this:&lt;/p&gt;

&lt;p&gt;sound layers&lt;br&gt;
-&amp;gt; atmosphere / binaural / generative buses&lt;br&gt;
-&amp;gt; master gain&lt;br&gt;
-&amp;gt; EQ&lt;br&gt;
-&amp;gt; compressor&lt;br&gt;
-&amp;gt; output gain&lt;br&gt;
-&amp;gt; analyser&lt;br&gt;
-&amp;gt; speakers&lt;/p&gt;

&lt;p&gt;This makes it possible to control the whole sound environment from one place while still letting each layer behave independently.&lt;/p&gt;

&lt;p&gt;Noise colors&lt;/p&gt;

&lt;p&gt;White noise is generated by filling an audio buffer with random values.&lt;/p&gt;

&lt;p&gt;Pink noise and brown noise need a little more shaping.&lt;/p&gt;

&lt;p&gt;Pink noise feels softer and more balanced than white noise. Brown noise is deeper and warmer. This difference matters because in a focus app, sound is not just decoration. It changes how aggressive or calm the work environment feels.&lt;/p&gt;

&lt;p&gt;I wanted users to be able to choose the kind of masking that fits the session.&lt;/p&gt;

&lt;p&gt;Smooth transitions&lt;/p&gt;

&lt;p&gt;One thing I learned quickly: sudden audio changes are distracting.&lt;/p&gt;

&lt;p&gt;So volume changes are scheduled gradually instead of jumping immediately. For longer soundscape loops, I also used crossfading so the loop does not restart in an obvious way.&lt;/p&gt;

&lt;p&gt;This is a small detail, but it matters a lot for an app that is supposed to help people stay focused.&lt;/p&gt;

&lt;p&gt;Picture-in-Picture without a real video&lt;/p&gt;

&lt;p&gt;Another feature I wanted was a timer that stays visible while working in another tab or app.&lt;/p&gt;

&lt;p&gt;To do this, Pomoria draws the timer interface to a canvas, turns that canvas into a video source, and sends the video element into Picture-in-Picture.&lt;/p&gt;

&lt;p&gt;So the PiP window is not a normal video. It is a live timer view.&lt;/p&gt;

&lt;p&gt;It can show the current step, remaining time, visual progress, and different timer styles.&lt;/p&gt;

&lt;p&gt;I also connected the timer state to the Media Session API, so play and pause controls can reflect the session state.&lt;/p&gt;

&lt;p&gt;Why build it this way?&lt;/p&gt;

&lt;p&gt;Because I think a focus timer is not only about measuring time.&lt;/p&gt;

&lt;p&gt;It is also about rhythm, sound, visibility, and flow.&lt;/p&gt;

&lt;p&gt;A normal timer asks: how much time is left?&lt;/p&gt;

&lt;p&gt;I wanted Pomoria to ask a slightly different question: what kind of environment helps you stay with the work?&lt;/p&gt;

&lt;p&gt;That is why I am trying to describe it as a focus environment rather than only a Pomodoro timer.&lt;/p&gt;

&lt;p&gt;What I learned&lt;/p&gt;

&lt;p&gt;Web Audio API is powerful enough for lightweight generative ambience.&lt;/p&gt;

&lt;p&gt;Picture-in-Picture can be useful even when the app is not a video app.&lt;/p&gt;

&lt;p&gt;Browser autoplay restrictions force you to design around user interaction.&lt;/p&gt;

&lt;p&gt;Small UX details, like fade-ins and persistent visibility, matter a lot in productivity tools.&lt;/p&gt;

&lt;p&gt;A timer becomes more interesting when time, sound, notes, and session structure are designed together.&lt;/p&gt;

&lt;p&gt;Try it&lt;/p&gt;

&lt;p&gt;Pomoria is live here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://pomoria.app" rel="noopener noreferrer"&gt;https://pomoria.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I would love feedback, especially on the audio controls, the Picture-in-Picture experience, and whether “focus environment” makes sense as positioning.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>javascript</category>
      <category>react</category>
      <category>web</category>
    </item>
  </channel>
</rss>
