<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en"><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://dcamacho.site/feed.xml" rel="self" type="application/atom+xml"/><link href="https://dcamacho.site/" rel="alternate" type="text/html" hreflang="en"/><updated>2026-05-26T13:07:31+00:00</updated><id>https://dcamacho.site/feed.xml</id><title type="html">blank</title><subtitle>Personal website of Daniel Camacho — Telecommunications Engineering student at UCAM with professional experience in data analytics, ETL pipelines, and systems integration. </subtitle><entry><title type="html">How to make Simulink and an ESP32 speak the same binary language</title><link href="https://dcamacho.site/blog/2026/simulink-esp32-binary-serial-protocol/" rel="alternate" type="text/html" title="How to make Simulink and an ESP32 speak the same binary language"/><published>2026-05-26T10:00:00+00:00</published><updated>2026-05-26T10:00:00+00:00</updated><id>https://dcamacho.site/blog/2026/simulink-esp32-binary-serial-protocol</id><content type="html" xml:base="https://dcamacho.site/blog/2026/simulink-esp32-binary-serial-protocol/"><![CDATA[<figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/projects/sdp-minihvac-hero-480.webp 480w,/assets/img/projects/sdp-minihvac-hero-800.webp 800w,/assets/img/projects/sdp-minihvac-hero-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/projects/sdp-minihvac-hero.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" data-zoomable="" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <p>If you’ve ever tried to exchange structured data between Simulink and a microcontroller, you’ve probably hit the same wall I did: <strong>Simulink wants to send and receive tidy signal vectors, while your firmware thinks in C structs and raw bytes.</strong> ASCII-based protocols like printing comma-separated values over serial are tempting, but they’re slow, fragile, and a nightmare to parse at 115200 baud when your control loop needs deterministic timing.</p> <p>This post walks through the binary serial protocol I built for <a href="https://github.com/dcamacho16/sdp-minihvac">Mini-HVAC</a>, an IoT Hardware-in-the-Loop platform that pairs a five-subsystem Simulink model with an ESP32-WROVER running custom FreeRTOS firmware. The protocol is simple, but getting it right required thinking carefully about struct layout, byte ordering, and how to prove correctness <em>before</em> plugging in a single wire.</p> <h2 id="the-problem">The problem</h2> <p>The Mini-HVAC system needs two-way real-time communication between a PC running Simulink and an ESP32 microcontroller:</p> <ul> <li><strong>PC to ESP32</strong>: simulated plant state (temperature, humidity, pressure) plus actuator commands (fan duty, heater duty, alarm flag).</li> <li><strong>ESP32 to PC</strong>: real sensor readings, user-selected setpoints, operating mode (AUTO/MANUAL), and HVAC enable flag.</li> </ul> <p>An ASCII protocol — something like <code class="language-plaintext highlighter-rouge">"25.0,50.0,0.5,0.3,0.1,1\n"</code> — would work for a demo, but it has real problems in a control loop:</p> <ol> <li><strong>Variable-length messages</strong> make framing unreliable. A dropped byte shifts every field.</li> <li><strong>Float-to-string-to-float round trips</strong> lose precision and burn CPU cycles on both ends.</li> <li><strong>Parsing overhead</strong> on the ESP32 side (<code class="language-plaintext highlighter-rouge">sscanf</code>, <code class="language-plaintext highlighter-rouge">strtok</code>, etc.) is surprisingly expensive when you’re also running FreeRTOS tasks for sensors, actuators, and an LCD.</li> </ol> <p>Binary structs solve all three. Fixed-length packets, zero conversion loss, and reception is just <code class="language-plaintext highlighter-rouge">Serial.readBytes</code> into a struct.</p> <h2 id="the-solution-matched-c-structs-and-byte-packunpack">The solution: matched C structs and Byte Pack/Unpack</h2> <p>The protocol is built around two packed C structs — one for each direction:</p> <div class="language-c highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">// PC (Simulink) → ESP32: 24 bytes</span>
<span class="k">struct</span> <span class="n">PcToEsp</span> <span class="p">{</span>
  <span class="kt">float</span> <span class="n">T_sim</span><span class="p">;</span>         <span class="c1">// simulated temperature</span>
  <span class="kt">float</span> <span class="n">RH_sim</span><span class="p">;</span>        <span class="c1">// simulated humidity</span>
  <span class="kt">float</span> <span class="n">P_sim</span><span class="p">;</span>         <span class="c1">// simulated pressure/flow</span>
  <span class="kt">float</span> <span class="n">u_fan_sim</span><span class="p">;</span>     <span class="c1">// fan duty cycle [0, 1]</span>
  <span class="kt">float</span> <span class="n">u_heater_sim</span><span class="p">;</span>  <span class="c1">// heater duty cycle [0, 1]</span>
  <span class="kt">float</span> <span class="n">alarm_flag</span><span class="p">;</span>    <span class="c1">// alarm active (0.0 or 1.0)</span>
<span class="p">};</span>  <span class="c1">// 6 × 4 = 24 bytes</span>

<span class="c1">// ESP32 → PC (Simulink): 32 bytes</span>
<span class="k">struct</span> <span class="n">EspToPc</span> <span class="p">{</span>
  <span class="kt">float</span> <span class="n">T_real</span><span class="p">;</span>            <span class="c1">// measured temperature</span>
  <span class="kt">float</span> <span class="n">RH_real</span><span class="p">;</span>           <span class="c1">// measured humidity</span>
  <span class="kt">float</span> <span class="n">u_fan_real</span><span class="p">;</span>        <span class="c1">// actual fan state</span>
  <span class="kt">float</span> <span class="n">u_heater_real</span><span class="p">;</span>     <span class="c1">// actual heater state</span>
  <span class="kt">float</span> <span class="n">T_set</span><span class="p">;</span>             <span class="c1">// temperature setpoint</span>
  <span class="kt">float</span> <span class="n">RH_set</span><span class="p">;</span>            <span class="c1">// humidity setpoint</span>
  <span class="kt">float</span> <span class="n">mode_auto_manual</span><span class="p">;</span>  <span class="c1">// 0.0 = MANUAL, 1.0 = AUTO</span>
  <span class="kt">float</span> <span class="n">hvac_enable</span><span class="p">;</span>       <span class="c1">// 0.0 = OFF, 1.0 = ON</span>
<span class="p">};</span>  <span class="c1">// 8 × 4 = 32 bytes</span>
</code></pre></div></div> <p>Every field is a <code class="language-plaintext highlighter-rouge">float</code> (IEEE 754 single-precision, 4 bytes). This is a deliberate choice: Simulink’s <code class="language-plaintext highlighter-rouge">single</code> type and C’s <code class="language-plaintext highlighter-rouge">float</code> use the same representation, so there’s no conversion step — just a <code class="language-plaintext highlighter-rouge">memcpy</code>-equivalent in both directions.</p> <h3 id="on-the-esp32-side">On the ESP32 side</h3> <p>Sending is a one-liner. The FreeRTOS <code class="language-plaintext highlighter-rouge">TaskTX</code> task reads sensors, updates the state struct, and writes it directly to the UART:</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">Serial</span><span class="p">.</span><span class="n">write</span><span class="p">((</span><span class="kt">uint8_t</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">toSend</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">toSend</span><span class="p">));</span>  <span class="c1">// 32 raw bytes</span>
</code></pre></div></div> <p>Receiving is equally simple. <code class="language-plaintext highlighter-rouge">TaskRX</code> waits for exactly 24 bytes, then casts them straight into the command struct:</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="n">Serial</span><span class="p">.</span><span class="n">available</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="k">sizeof</span><span class="p">(</span><span class="n">PcToEsp</span><span class="p">))</span> <span class="p">{</span>
  <span class="n">Serial</span><span class="p">.</span><span class="n">readBytes</span><span class="p">((</span><span class="kt">uint8_t</span> <span class="o">*</span><span class="p">)</span><span class="o">&amp;</span><span class="n">localCmd</span><span class="p">,</span> <span class="k">sizeof</span><span class="p">(</span><span class="n">PcToEsp</span><span class="p">));</span>
  <span class="n">safeUpdatePcCmd</span><span class="p">(</span><span class="n">localCmd</span><span class="p">);</span>
  <span class="n">applyPCCommands</span><span class="p">(</span><span class="n">localCmd</span><span class="p">);</span>
<span class="p">}</span>
</code></pre></div></div> <p>No parsing. No delimiters. No state machine. The struct <em>is</em> the wire format.</p> <h3 id="on-the-simulink-side">On the Simulink side</h3> <p>Simulink mirrors this with its <strong>Byte Pack</strong> and <strong>Byte Unpack</strong> blocks (from the Simulink Real-Time / Utility Blocks library):</p> <ul> <li> <p><strong><code class="language-plaintext highlighter-rouge">TX_To_ESP32</code> subsystem</strong>: takes 6 <code class="language-plaintext highlighter-rouge">single</code> signals, feeds them into a Byte Pack block configured for 6 inputs of type <code class="language-plaintext highlighter-rouge">single</code>, and outputs a <code class="language-plaintext highlighter-rouge">uint8[24]</code> vector. The signal connection order must <em>exactly</em> match the field order of <code class="language-plaintext highlighter-rouge">PcToEsp</code>.</p> </li> <li> <p><strong><code class="language-plaintext highlighter-rouge">RX_From_ESP32</code> subsystem</strong>: takes a <code class="language-plaintext highlighter-rouge">uint8[32]</code> vector from the Serial Receive block, feeds it into a Byte Unpack block configured for 8 outputs of type <code class="language-plaintext highlighter-rouge">single</code>, and produces the 8 signals that map back to <code class="language-plaintext highlighter-rouge">EspToPc</code> fields.</p> </li> </ul> <p>The critical configuration on the Simulink side:</p> <ul> <li><strong>Data type</strong>: <code class="language-plaintext highlighter-rouge">single</code> (not <code class="language-plaintext highlighter-rouge">double</code> — Simulink defaults to <code class="language-plaintext highlighter-rouge">double</code> internally, so you need explicit Data Type Conversion blocks).</li> <li><strong>Byte order</strong>: <code class="language-plaintext highlighter-rouge">little-endian</code> (matches the ESP32’s Xtensa architecture).</li> <li><strong>Alignment</strong>: 1 byte (no padding between fields).</li> </ul> <h2 id="the-gotchas">The gotchas</h2> <h3 id="endianness">Endianness</h3> <p>Both the ESP32 (Xtensa LX6) and x86/ARM PCs are <strong>little-endian</strong>, so the bytes land in the same order on both sides. If you’re targeting a big-endian platform, you’d need to byte-swap each float — but for the ESP32 + modern PC combination, this is a non-issue. Still, it’s worth verifying explicitly: the Serial Configuration block in Simulink has a byte-order setting, and it <em>must</em> be set to <code class="language-plaintext highlighter-rouge">little-endian</code>.</p> <h3 id="struct-padding">Struct padding</h3> <p>C compilers are free to insert padding bytes between struct fields for alignment. A struct with a <code class="language-plaintext highlighter-rouge">uint8_t</code> followed by a <code class="language-plaintext highlighter-rouge">float</code> might silently grow from 5 to 8 bytes. By using <em>only</em> <code class="language-plaintext highlighter-rouge">float</code> fields (all 4 bytes, naturally aligned), padding never kicks in. The struct size is always <code class="language-plaintext highlighter-rouge">N × 4</code> bytes, exactly matching what Byte Pack/Unpack expects.</p> <p>If your protocol needs mixed types (say, a <code class="language-plaintext highlighter-rouge">uint8_t</code> flag alongside floats), you’d need <code class="language-plaintext highlighter-rouge">__attribute__((packed))</code> on the C side — but then you pay a performance penalty on some architectures. The all-float approach avoids this entirely.</p> <h3 id="compile-time-size-checks-with-static_assert">Compile-time size checks with <code class="language-plaintext highlighter-rouge">static_assert</code></h3> <p>Even with an all-float layout, a typo (an extra field, a wrong type) could silently change the struct size and break the protocol. The firmware guards against this with compile-time assertions:</p> <div class="language-cpp highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">static_assert</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">PcToEsp</span><span class="p">)</span> <span class="o">==</span> <span class="mi">24</span><span class="p">,</span> <span class="s">"PcToEsp must be 24 bytes"</span><span class="p">);</span>
<span class="k">static_assert</span><span class="p">(</span><span class="k">sizeof</span><span class="p">(</span><span class="n">EspToPc</span><span class="p">)</span> <span class="o">==</span> <span class="mi">32</span><span class="p">,</span> <span class="s">"EspToPc must be 32 bytes"</span><span class="p">);</span>
</code></pre></div></div> <p>If someone adds a field and forgets to update the Simulink side, the build fails immediately instead of producing a subtle runtime bug where fields shift by 4 bytes and the fan duty cycle ends up in the temperature slot.</p> <h3 id="field-ordering">Field ordering</h3> <p>The most insidious bug in binary protocols is a field-order mismatch. The bytes are <em>correct</em> — the same floats, the same endianness, the same total size — but field 3 on one side is field 4 on the other. Nothing will catch this at compile time.</p> <p>The defense is a single source of truth. In this project, the C struct definition in the firmware <em>is</em> the spec. The Simulink subsystem wires its signals in the same order, and the MATLAB validation scripts (next section) verify byte-for-byte equivalence against that order.</p> <h2 id="the-validation-proving-correctness-without-hardware">The validation: proving correctness without hardware</h2> <p>Here’s the part I found most valuable in practice. Before the ESP32 was even connected, two MATLAB scripts validated that Simulink and the firmware would agree on every byte.</p> <h3 id="test_tx_to_esp32_bytesm--validating-the-transmit-path"><code class="language-plaintext highlighter-rouge">TEST_TX_To_ESP32_bytes.m</code> — validating the transmit path</h3> <p>This script builds the expected <code class="language-plaintext highlighter-rouge">uint8[24]</code> byte vector for a known set of <code class="language-plaintext highlighter-rouge">PcToEsp</code> values:</p> <div class="language-matlab highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">% Define test values matching the C struct field order</span>
<span class="n">T_sim</span> <span class="o">=</span> <span class="mf">25.0</span><span class="p">;</span> <span class="n">RH_sim</span> <span class="o">=</span> <span class="mf">50.0</span><span class="p">;</span> <span class="n">P_sim</span> <span class="o">=</span> <span class="mf">0.5</span><span class="p">;</span>
<span class="n">u_fan_sim</span> <span class="o">=</span> <span class="mf">0.3</span><span class="p">;</span> <span class="n">u_heater_sim</span> <span class="o">=</span> <span class="mf">0.1</span><span class="p">;</span> <span class="n">alarm_flag</span> <span class="o">=</span> <span class="mf">1.0</span><span class="p">;</span>

<span class="c1">% Pack as single-precision floats, then reinterpret as bytes</span>
<span class="n">vals</span> <span class="o">=</span> <span class="nb">single</span><span class="p">([</span><span class="n">T_sim</span><span class="p">,</span> <span class="n">RH_sim</span><span class="p">,</span> <span class="n">P_sim</span><span class="p">,</span> <span class="n">u_fan_sim</span><span class="p">,</span> <span class="n">u_heater_sim</span><span class="p">,</span> <span class="n">alarm_flag</span><span class="p">]);</span>
<span class="n">expected_bytes</span> <span class="o">=</span> <span class="nb">typecast</span><span class="p">(</span><span class="n">vals</span><span class="p">,</span> <span class="s1">'uint8'</span><span class="p">);</span>  <span class="c1">% uint8[24]</span>
</code></pre></div></div> <p>After running the Simulink model, the <code class="language-plaintext highlighter-rouge">tx_bytes</code> output from the <code class="language-plaintext highlighter-rouge">TX_To_ESP32</code> subsystem is compared against this reference:</p> <div class="language-matlab highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">isequal</span><span class="p">(</span><span class="n">expected_bytes</span><span class="p">,</span> <span class="n">out</span><span class="o">.</span><span class="n">tx_bytes</span><span class="p">)</span>  <span class="c1">% must return 1 (true)</span>
</code></pre></div></div> <p>If there’s a mismatch, the script reports <em>which byte</em> differs — making it trivial to trace back to a wiring or type-conversion error in the Simulink model.</p> <h3 id="test_rx_from_esp32_bytesm--validating-the-receive-path"><code class="language-plaintext highlighter-rouge">TEST_RX_From_ESP32_bytes.m</code> — validating the receive path</h3> <p>The reverse direction: generate the 32 bytes that an ESP32 <em>would</em> send, inject them into the <code class="language-plaintext highlighter-rouge">RX_From_ESP32</code> subsystem via a Constant block, and verify that the unpacked signals match the original values.</p> <div class="language-matlab highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1">% Build the EspToPc byte vector</span>
<span class="n">vals</span> <span class="o">=</span> <span class="nb">single</span><span class="p">([</span><span class="n">T_real</span><span class="p">,</span> <span class="n">RH_real</span><span class="p">,</span> <span class="n">u_fan_real</span><span class="p">,</span> <span class="n">u_heater_real</span><span class="p">,</span> <span class="k">...</span>
               <span class="n">T_set</span><span class="p">,</span> <span class="n">RH_set</span><span class="p">,</span> <span class="n">mode_auto_manual</span><span class="p">,</span> <span class="n">hvac_enable</span><span class="p">]);</span>
<span class="n">esp_bytes</span> <span class="o">=</span> <span class="nb">typecast</span><span class="p">(</span><span class="n">vals</span><span class="p">,</span> <span class="s1">'uint8'</span><span class="p">);</span>  <span class="c1">% uint8[32]</span>

<span class="c1">% Verify round-trip: bytes → singles → check against originals</span>
<span class="n">vals_recovered</span> <span class="o">=</span> <span class="nb">typecast</span><span class="p">(</span><span class="n">esp_bytes</span><span class="p">,</span> <span class="s1">'single'</span><span class="p">);</span>
</code></pre></div></div> <p>Both scripts also perform a <strong>round-trip check</strong>: bytes back to floats, compared against the originals. This catches subtle issues like accidentally using <code class="language-plaintext highlighter-rouge">double</code> instead of <code class="language-plaintext highlighter-rouge">single</code> somewhere in the chain (which would produce 48 or 64 bytes instead of 24 or 32).</p> <h3 id="why-this-matters">Why this matters</h3> <p>This validation strategy means that by the time the ESP32 is physically connected, the <em>only</em> things that can go wrong are hardware-level issues: a loose wire, a wrong baud rate, a task-scheduling conflict. The data packing and unpacking layer has already been proven correct. In practice, this saved significant debugging time — the first hardware test worked on the first try.</p> <h2 id="putting-it-all-together">Putting it all together</h2> <p>The full data flow looks like this:</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>┌─────────────────────────────────────────────────────┐
│                  PC (Simulink)                       │
│                                                      │
│  MiniHVAC_Zone ──► TX_To_ESP32 ──► Serial Send      │
│  (plant model)     (Byte Pack)     (uint8[24])       │
│                                        │             │
│  Scopes/Control ◄── RX_From_ESP32 ◄── Serial Recv   │
│                     (Byte Unpack)     (uint8[32])    │
│                                        │             │
└────────────────────────────────────────┼─────────────┘
                                    USB Serial
                                    115200 baud
┌────────────────────────────────────────┼─────────────┐
│                  ESP32-WROVER          │             │
│                                        │             │
│  TaskRX ──────► applyPCCommands()      │             │
│  (24 bytes in)   (fan PWM, heater,     │             │
│                   alarm LED)           │             │
│                                        │             │
│  TaskTX ◄────── updateSensorsAndInputs()            │
│  (32 bytes out)  (DHT22, pots, buttons)             │
│                                                      │
│  TaskLCD ──────► 16×2 I²C display                   │
│                                                      │
└──────────────────────────────────────────────────────┘
</code></pre></div></div> <p>Three FreeRTOS tasks share the <code class="language-plaintext highlighter-rouge">PcToEsp</code> and <code class="language-plaintext highlighter-rouge">EspToPc</code> structs through mutex-protected accessors (<code class="language-plaintext highlighter-rouge">safeUpdatePcCmd</code>, <code class="language-plaintext highlighter-rouge">safeReadEspState</code>, etc.), keeping synchronization simple and deterministic.</p> <h2 id="key-takeaways">Key takeaways</h2> <ol> <li> <p><strong>Use all-float structs</strong> to avoid padding issues. If you need boolean flags, encode them as <code class="language-plaintext highlighter-rouge">0.0</code>/<code class="language-plaintext highlighter-rouge">1.0</code> floats — it’s 3 extra bytes per flag, but it eliminates an entire class of alignment bugs.</p> </li> <li> <p><strong><code class="language-plaintext highlighter-rouge">static_assert</code> the struct sizes</strong> in firmware. It’s one line of code that catches protocol-breaking changes at compile time.</p> </li> <li> <p><strong>Validate byte-for-byte in MATLAB</strong> before touching hardware. MATLAB’s <code class="language-plaintext highlighter-rouge">typecast(single(...), 'uint8')</code> gives you the exact wire representation. Compare it against Simulink’s output and the firmware’s expected input.</p> </li> <li> <p><strong>Set Simulink’s byte order explicitly</strong> to <code class="language-plaintext highlighter-rouge">little-endian</code>. Don’t rely on defaults — the Serial Configuration block’s byte-order setting is easy to miss.</p> </li> <li> <p><strong>Keep one source of truth</strong> for field ordering. The C struct definition is the spec; everything else (Simulink wiring, MATLAB test vectors) derives from it.</p> </li> </ol> <p>The full project — firmware, Simulink models, MATLAB validation scripts, schematics, and 11 chapters of documentation — is on GitHub: <a href="https://github.com/dcamacho16/sdp-minihvac">dcamacho16/sdp-minihvac</a>.</p>]]></content><author><name></name></author><category term="engineering"/><category term="embedded"/><category term="simulink"/><category term="esp32"/><category term="serial-protocol"/><category term="freertos"/><category term="matlab"/><summary type="html"><![CDATA[Designing a binary serial protocol between a Simulink plant model and ESP32 FreeRTOS firmware — matching C structs to Byte Pack/Unpack blocks and validating everything in MATLAB before the hardware is even connected.]]></summary></entry><entry><title type="html">a post with plotly.js</title><link href="https://dcamacho.site/blog/2025/plotly/" rel="alternate" type="text/html" title="a post with plotly.js"/><published>2025-03-26T14:24:00+00:00</published><updated>2025-03-26T14:24:00+00:00</updated><id>https://dcamacho.site/blog/2025/plotly</id><content type="html" xml:base="https://dcamacho.site/blog/2025/plotly/"><![CDATA[<p>This is an example post with some <a href="https://plotly.com/javascript/">plotly</a> code.</p> <div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">```</span><span class="nl">plotly
</span><span class="sb">{
  "data": [
    {
      "x": [1, 2, 3, 4],
      "y": [10, 15, 13, 17],
      "type": "scatter"
    },
    {
      "x": [1, 2, 3, 4],
      "y": [16, 5, 11, 9],
      "type": "scatter"
    }
  ]
}</span>
<span class="p">```</span>
</code></pre></div></div> <p>Which generates:</p> <pre><code class="language-plotly">{
  "data": [
    {
      "x": [1, 2, 3, 4],
      "y": [10, 15, 13, 17],
      "type": "scatter"
    },
    {
      "x": [1, 2, 3, 4],
      "y": [16, 5, 11, 9],
      "type": "scatter"
    }
  ]
}
</code></pre> <p>Also another example chart.</p> <div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">```</span><span class="nl">plotly
</span><span class="sb">{
  "data": [
    {
      "x": [1, 2, 3, 4],
      "y": [10, 15, 13, 17],
      "mode": "markers"
    },
    {
      "x": [2, 3, 4, 5],
      "y": [16, 5, 11, 9],
      "mode": "lines"
    },
    {
      "x": [1, 2, 3, 4],
      "y": [12, 9, 15, 12],
      "mode": "lines+markers"
    }
  ],
  "layout": {
    "title": {
      "text": "Line and Scatter Plot"
    }
  }
}</span>
<span class="p">```</span>
</code></pre></div></div> <p>This is how it looks like:</p> <pre><code class="language-plotly">{
  "data": [
    {
      "x": [1, 2, 3, 4],
      "y": [10, 15, 13, 17],
      "mode": "markers"
    },
    {
      "x": [2, 3, 4, 5],
      "y": [16, 5, 11, 9],
      "mode": "lines"
    },
    {
      "x": [1, 2, 3, 4],
      "y": [12, 9, 15, 12],
      "mode": "lines+markers"
    }
  ],
  "layout": {
    "title": {
      "text": "Line and Scatter Plot"
    }
  }
}
</code></pre>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="charts"/><summary type="html"><![CDATA[this is what included plotly.js code could look like]]></summary></entry><entry><title type="html">a post with image galleries</title><link href="https://dcamacho.site/blog/2024/photo-gallery/" rel="alternate" type="text/html" title="a post with image galleries"/><published>2024-12-04T01:59:00+00:00</published><updated>2024-12-04T01:59:00+00:00</updated><id>https://dcamacho.site/blog/2024/photo-gallery</id><content type="html" xml:base="https://dcamacho.site/blog/2024/photo-gallery/"><![CDATA[<p>The images in this post are all zoomable, arranged into different mini-galleries using different libraries.</p> <h2 id="lightbox2"><a href="https://lokeshdhakar.com/projects/lightbox2/">Lightbox2</a></h2> <p><a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-2500.jpg" data-lightbox="roadtrip"><img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-200.jpg"/></a> <a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-2500.jpg" data-lightbox="roadtrip"><img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-200.jpg"/></a> <a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-2500.jpg" data-lightbox="roadtrip"><img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-200.jpg"/></a></p> <hr/> <h2 id="photoswipe"><a href="https://photoswipe.com/">PhotoSwipe</a></h2> <div class="pswp-gallery pswp-gallery--single-column" id="gallery--getting-started"> <a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-2500.jpg" data-pswp-width="1669" data-pswp-height="2500" target="_blank"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-200.jpg" alt=""/> </a> <a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/7/img-2500.jpg" data-pswp-width="1875" data-pswp-height="2500" data-cropped="true" target="_blank"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/7/img-200.jpg" alt=""/> </a> <a href="https://unsplash.com" data-pswp-src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-2500.jpg" data-pswp-width="2500" data-pswp-height="1666" target="_blank"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-200.jpg" alt=""/> </a> <div> <a href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/6/img-2500.jpg" data-pswp-width="2500" data-pswp-height="1667" target="_blank"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/6/img-200.jpg" alt=""/> </a> </div> </div> <hr/> <h2 id="spotlight-js"><a href="https://nextapps-de.github.io/spotlight/">Spotlight JS</a></h2> <div class="spotlight-group"> <a class="spotlight" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-2500.jpg"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-200.jpg"/> </a> <a class="spotlight" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-2500.jpg"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-200.jpg"/> </a> <a class="spotlight" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-2500.jpg"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-200.jpg"/> </a> </div> <div class="spotlight-group"> <a class="spotlight" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/4/img-2500.jpg"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/4/img-200.jpg"/> </a> <a class="spotlight" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/5/img-2500.jpg"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/5/img-200.jpg"/> </a> <a class="spotlight" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/6/img-2500.jpg"> <img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/6/img-200.jpg"/> </a> </div> <hr/> <h2 id="venobox"><a href="https://veno.es/venobox/">Venobox</a></h2> <p><a class="venobox" data-gall="myGallery" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-2500.jpg"><img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/1/img-200.jpg"/></a> <a class="venobox" data-gall="myGallery" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-2500.jpg"><img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/2/img-200.jpg"/></a> <a class="venobox" data-gall="myGallery" href="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-2500.jpg"><img src="https://cdn.photoswipe.com/photoswipe-demo-images/photos/3/img-200.jpg"/></a></p>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="images"/><summary type="html"><![CDATA[this is what included image galleries could look like]]></summary></entry><entry><title type="html">Google Gemini updates: Flash 1.5, Gemma 2 and Project Astra</title><link href="https://dcamacho.site/blog/2024/google-gemini-updates-flash-15-gemma-2-and-project-astra/" rel="alternate" type="text/html" title="Google Gemini updates: Flash 1.5, Gemma 2 and Project Astra"/><published>2024-05-14T00:00:00+00:00</published><updated>2024-05-14T00:00:00+00:00</updated><id>https://dcamacho.site/blog/2024/google-gemini-updates-flash-15-gemma-2-and-project-astra</id><content type="html" xml:base="https://dcamacho.site/blog/2024/google-gemini-updates-flash-15-gemma-2-and-project-astra/"><![CDATA[<p>Learn more:Learn more:Learn more:Learn more:Learn more:Learn more:May 14, 2024 We’re introducing a series of updates across the Gemini family of models, including the new 1.5 Flash, our lightweight model for speed and efficiency, and Project Astra, our vision for the future of AI assistants. In December, we launched our first natively multimodal model Gemini 1.0 in three sizes: Ultra, Pro and Nano. Just a few months later we released 1.5 Pro, with enhanced performance and a breakthrough long context window of 1 million tokens.Developers and enterprise customers have been putting 1.5 Pro to use in incredible ways and finding its long context window, multimodal reasoning capabilities and impressive overall performance incredibly useful.We know from user feedback that some applications need lower latency and a lower cost to serve. This inspired us to keep innovating, so today, we’re introducing Gemini 1.5 Flash: a model that’s lighter-weight than 1.5 Pro, and designed to be fast and efficient to serve at scale.Both 1.5 Pro and 1.5 Flash are available in public preview with a 1 million token context window in Google AI Studio and Vertex AI. And now, 1.5 Pro is also available with a 2 million token context window via waitlist to developers using the API and to Google Cloud customers.We’re also introducing updates across the Gemini family of models, announcing our next generation of open models, Gemma 2, and sharing progress on the future of AI assistants, with Project Astra.Context lengths of leading foundation models compared with Gemini 1.5’s 2 million token capability1.5 Flash is the newest addition to the Gemini model family and the fastest Gemini model served in the API. It’s optimized for high-volume, high-frequency tasks at scale, is more cost-efficient to serve and features our breakthrough long context window.While it’s a lighter weight model than 1.5 Pro, it’s highly capable of multimodal reasoning across vast amounts of information and delivers impressive quality for its size.The new Gemini 1.5 Flash model is optimized for speed and efficiency, is highly capable of multimodal reasoning and features our breakthrough long context window.1.5 Flash excels at summarization, chat applications, image and video captioning, data extraction from long documents and tables, and more. This is because it’s been trained by 1.5 Pro through a process called “distillation,” where the most essential knowledge and skills from a larger model are transferred to a smaller, more efficient model.Read more about 1.5 Flash in our updated Gemini 1.5 technical report, on the Gemini technology page, and learn about 1.5 Flash’s availability and pricing.Over the last few months, we’ve significantly improved 1.5 Pro, our best model for general performance across a wide range of tasks.Beyond extending its context window to 2 million tokens, we’ve enhanced its code generation, logical reasoning and planning, multi-turn conversation, and audio and image understanding through data and algorithmic advances. We see strong improvements on public and internal benchmarks for each of these tasks.1.5 Pro can now follow increasingly complex and nuanced instructions, including ones that specify product-level behavior involving role, format and style. We’ve improved control over the model’s responses for specific use cases, like crafting the persona and response style of a chat agent or automating workflows through multiple function calls. And we’ve enabled users to steer model behavior by setting system instructions.We added audio understanding in the Gemini API and Google AI Studio, so 1.5 Pro can now reason across image and audio for videos uploaded in Google AI Studio. And we’re now integrating 1.5 Pro into Google products, including Gemini Advanced and in Workspace apps.Read more about 1.5 Pro in our updated Gemini 1.5 technical report and on the Gemini technology page.Gemini Nano is expanding beyond text-only inputs to include images as well. Starting with Pixel, applications using Gemini Nano with Multimodality will be able to understand the world the way people do — not just through text, but also through sight, sound and spoken language.Read more about Gemini 1.0 Nano on Android.Today, we’re also sharing a series of updates to Gemma, our family of open models built from the same research and technology used to create the Gemini models.We’re announcing Gemma 2, our next generation of open models for responsible AI innovation. Gemma 2 has a new architecture designed for breakthrough performance and efficiency, and will be available in new sizes.The Gemma family is also expanding with PaliGemma, our first vision-language model inspired by PaLI-3. And we’ve upgraded our Responsible Generative AI Toolkit with LLM Comparator for evaluating the quality of model responses.Read more on the Developer blog.As part of Google DeepMind’s mission to build AI responsibly to benefit humanity, we’ve always wanted to develop universal AI agents that can be helpful in everyday life. That’s why today, we’re sharing our progress in building the future of AI assistants with Project Astra (advanced seeing and talking responsive agent).To be truly useful, an agent needs to understand and respond to the complex and dynamic world just like people do — and take in and remember what it sees and hears to understand context and take action. It also needs to be proactive, teachable and personal, so users can talk to it naturally and without lag or delay.While we’ve made incredible progress developing AI systems that can understand multimodal information, getting response time down to something conversational is a difficult engineering challenge. Over the past few years, we’ve been working to improve how our models perceive, reason and converse to make the pace and quality of interaction feel more natural.Building on Gemini, we’ve developed prototype agents that can process information faster by continuously encoding video frames, combining the video and speech input into a timeline of events, and caching this information for efficient recall.By leveraging our leading speech models, we also enhanced how they sound, giving the agents a wider range of intonations. These agents can better understand the context they’re being used in, and respond quickly, in conversation.With technology like this, it’s easy to envision a future where people could have an expert AI assistant by their side, through a phone or glasses. And some of these capabilities are coming to Google products, like the Gemini app and web experience, later this year.We’ve made incredible progress so far with our family of Gemini models, and we’re always striving to advance the state-of-the-art even further. By investing in a relentless production line of innovation, we’re able to explore new ideas at the frontier, while also unlocking the possibility of new and exciting Gemini use cases.Learn more about Gemini and its capabilities. Your information will be used in accordance with Google’s privacy policy.</p> <div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>      Done. Just one step more.
    
      Check your inbox to confirm your subscription.
    You are already subscribed to our newsletter.
    You can also subscribe with a
    different email address
    
    .
    
  Let’s stay in touch. Get the latest news from Google in your inbox.
          Follow Us
</code></pre></div></div>]]></content><author><name></name></author><category term="external-posts"/><category term="google"/><summary type="html"><![CDATA[We’re sharing updates across our Gemini family of models and a glimpse of Project Astra, our vision for the future of AI assistants.]]></summary></entry><entry><title type="html">a post with tabs</title><link href="https://dcamacho.site/blog/2024/tabs/" rel="alternate" type="text/html" title="a post with tabs"/><published>2024-05-01T00:32:13+00:00</published><updated>2024-05-01T00:32:13+00:00</updated><id>https://dcamacho.site/blog/2024/tabs</id><content type="html" xml:base="https://dcamacho.site/blog/2024/tabs/"><![CDATA[<p>This is how a post with <a href="https://github.com/Ovski4/jekyll-tabs">tabs</a> looks like. Note that the tabs could be used for different purposes, not only for code.</p> <h2 id="first-tabs">First tabs</h2> <p>To add tabs, use the following syntax:</p> <div class="language-liquid highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="cp">{%</span><span class="w"> </span><span class="nt">tabs</span><span class="w"> </span><span class="nv">group-name</span><span class="w"> </span><span class="cp">%}</span>

<span class="cp">{%</span><span class="w"> </span><span class="nt">tab</span><span class="w"> </span><span class="nv">group-name</span><span class="w"> </span><span class="nv">tab-name-1</span><span class="w"> </span><span class="cp">%}</span>

Content 1

<span class="cp">{%</span><span class="w"> </span><span class="nt">endtab</span><span class="w"> </span><span class="cp">%}</span>

<span class="cp">{%</span><span class="w"> </span><span class="nt">tab</span><span class="w"> </span><span class="nv">group-name</span><span class="w"> </span><span class="nv">tab-name-2</span><span class="w"> </span><span class="cp">%}</span>

Content 2

<span class="cp">{%</span><span class="w"> </span><span class="nt">endtab</span><span class="w"> </span><span class="cp">%}</span>

<span class="cp">{%</span><span class="w"> </span><span class="nt">endtabs</span><span class="w"> </span><span class="cp">%}</span>
</code></pre></div></div> <p>With this you can generate visualizations like:</p> <ul id="log" class="tab" data-tab="f0d73f7f-17bb-4c7c-9221-c60c8b4f6781" data-name="log"> <li class="active" id="log-php"> <a href="#">php </a> </li> <li id="log-js"> <a href="#">js </a> </li> <li id="log-ruby"> <a href="#">ruby </a> </li> </ul> <ul class="tab-content" id="f0d73f7f-17bb-4c7c-9221-c60c8b4f6781" data-name="log"> <li class="active"> <div class="language-php highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">var_dump</span><span class="p">(</span><span class="s1">'hello'</span><span class="p">);</span>
</code></pre></div></div> </li> <li> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">console</span><span class="p">.</span><span class="nf">log</span><span class="p">(</span><span class="dl">"</span><span class="s2">hello</span><span class="dl">"</span><span class="p">);</span>
</code></pre></div></div> </li> <li> <div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nx">pputs</span> <span class="dl">'</span><span class="s1">hello</span><span class="dl">'</span>
</code></pre></div></div> </li> </ul> <h2 id="another-example">Another example</h2> <ul id="data-struct" class="tab" data-tab="cf1c035f-69f7-40bc-9cdf-f47c6294193d" data-name="data-struct"> <li class="active" id="data-struct-yaml"> <a href="#">yaml </a> </li> <li id="data-struct-json"> <a href="#">json </a> </li> </ul> <ul class="tab-content" id="cf1c035f-69f7-40bc-9cdf-f47c6294193d" data-name="data-struct"> <li class="active"> <div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="na">hello</span><span class="pi">:</span>
  <span class="pi">-</span> <span class="s2">"</span><span class="s">whatsup"</span>
  <span class="pi">-</span> <span class="s2">"</span><span class="s">hi"</span>
</code></pre></div></div> </li> <li> <div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
  </span><span class="nl">"hello"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"whatsup"</span><span class="p">,</span><span class="w"> </span><span class="s2">"hi"</span><span class="p">]</span><span class="w">
</span><span class="p">}</span><span class="w">
</span></code></pre></div></div> </li> </ul> <h2 id="tabs-for-something-else">Tabs for something else</h2> <ul id="something-else" class="tab" data-tab="23d84ab5-35d7-442b-ab16-b1c600c7c664" data-name="something-else"> <li class="active" id="something-else-text"> <a href="#">text </a> </li> <li id="something-else-quote"> <a href="#">quote </a> </li> <li id="something-else-list"> <a href="#">list </a> </li> </ul> <ul class="tab-content" id="23d84ab5-35d7-442b-ab16-b1c600c7c664" data-name="something-else"> <li class="active"> <p>Regular text</p> </li> <li> <blockquote> <p>A quote</p> </blockquote> </li> <li> <p>Hipster list</p> <ul> <li>brunch</li> <li>fixie</li> <li>raybans</li> <li>messenger bag</li> </ul> </li> </ul>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="code"/><summary type="html"><![CDATA[this is what included tabs in a post could look like]]></summary></entry><entry><title type="html">a post with typograms</title><link href="https://dcamacho.site/blog/2024/typograms/" rel="alternate" type="text/html" title="a post with typograms"/><published>2024-04-29T23:36:10+00:00</published><updated>2024-04-29T23:36:10+00:00</updated><id>https://dcamacho.site/blog/2024/typograms</id><content type="html" xml:base="https://dcamacho.site/blog/2024/typograms/"><![CDATA[<p>This is an example post with some <a href="https://github.com/google/typograms/">typograms</a> code.</p> <div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">```</span><span class="nl">typograms
</span><span class="sb">+----+
|    |---&gt; My first diagram!
+----+</span>
<span class="p">```</span>
</code></pre></div></div> <p>Which generates:</p> <pre><code class="language-typograms">+----+
|    |---&gt; My first diagram!
+----+
</code></pre> <p>Another example:</p> <div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">```</span><span class="nl">typograms
</span><span class="sb">.------------------------.
|.----------------------.|
||"https://example.com" ||
|'----------------------'|
| ______________________ |
||                      ||
||   Welcome!           ||
||                      ||
||                      ||
||  .----------------.  ||
||  | username       |  ||
||  '----------------'  ||
||  .----------------.  ||
||  |"*******"       |  ||
||  '----------------'  ||
||                      ||
||  .----------------.  ||
||  |   "Sign-up"    |  ||
||  '----------------'  ||
||                      ||
|+----------------------+|
.------------------------.</span>
<span class="p">```</span>
</code></pre></div></div> <p>which generates:</p> <pre><code class="language-typograms">.------------------------.
|.----------------------.|
||"https://example.com" ||
|'----------------------'|
| ______________________ |
||                      ||
||   Welcome!           ||
||                      ||
||                      ||
||  .----------------.  ||
||  | username       |  ||
||  '----------------'  ||
||  .----------------.  ||
||  |"*******"       |  ||
||  '----------------'  ||
||                      ||
||  .----------------.  ||
||  |   "Sign-up"    |  ||
||  '----------------'  ||
||                      ||
|+----------------------+|
.------------------------.
</code></pre> <p>For more examples, check out the <a href="https://google.github.io/typograms/#examples">typograms documentation</a>.</p>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="diagrams"/><summary type="html"><![CDATA[this is what included typograms code could look like]]></summary></entry><entry><title type="html">a post that can be cited</title><link href="https://dcamacho.site/blog/2024/post-citation/" rel="alternate" type="text/html" title="a post that can be cited"/><published>2024-04-28T15:06:00+00:00</published><updated>2024-04-28T15:06:00+00:00</updated><id>https://dcamacho.site/blog/2024/post-citation</id><content type="html" xml:base="https://dcamacho.site/blog/2024/post-citation/"><![CDATA[<p>This is an example post that can be cited. The content of the post ends here, while the citation information is automatically provided below. The only thing needed is for you to set the <code class="language-plaintext highlighter-rouge">citation</code> key in the front matter to <code class="language-plaintext highlighter-rouge">true</code>.</p>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="citation"/><summary type="html"><![CDATA[this is what a post that can be cited looks like]]></summary></entry><entry><title type="html">a post with pseudo code</title><link href="https://dcamacho.site/blog/2024/pseudocode/" rel="alternate" type="text/html" title="a post with pseudo code"/><published>2024-04-15T00:01:00+00:00</published><updated>2024-04-15T00:01:00+00:00</updated><id>https://dcamacho.site/blog/2024/pseudocode</id><content type="html" xml:base="https://dcamacho.site/blog/2024/pseudocode/"><![CDATA[<p>This is an example post with some pseudo code rendered by <a href="https://github.com/SaswatPadhi/pseudocode.js">pseudocode</a>. The example presented here is the same as the one in the <a href="https://saswat.padhi.me/pseudocode.js/">pseudocode.js</a> documentation, with only one simple but important change: everytime you would use <code class="language-plaintext highlighter-rouge">$</code>, you should use <code class="language-plaintext highlighter-rouge">$$</code> instead. Also, note that the <code class="language-plaintext highlighter-rouge">pseudocode</code> key in the front matter is set to <code class="language-plaintext highlighter-rouge">true</code> to enable the rendering of pseudo code. As an example, using this code:</p> <div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">```</span><span class="nl">pseudocode
</span><span class="sb">% This quicksort algorithm is extracted from Chapter 7, Introduction to Algorithms (3rd edition)
\begin{algorithm}
\caption{Quicksort}
\begin{algorithmic}
\PROCEDURE{Quicksort}{$$A, p, r$$}
    \IF{$$p &lt; r$$}
        \STATE $$q = $$ \CALL{Partition}{$$A, p, r$$}
        \STATE \CALL{Quicksort}{$$A, p, q - 1$$}
        \STATE \CALL{Quicksort}{$$A, q + 1, r$$}
    \ENDIF
\ENDPROCEDURE
\PROCEDURE{Partition}{$$A, p, r$$}
    \STATE $$x = A[r]$$
    \STATE $$i = p - 1$$
    \FOR{$$j = p$$ \TO $$r - 1$$}
        \IF{$$A[j] &lt; x$$}
            \STATE $$i = i + 1$$
            \STATE exchange
            $$A[i]$$ with $$A[j]$$
        \ENDIF
        \STATE exchange $$A[i]$$ with $$A[r]$$
    \ENDFOR
\ENDPROCEDURE
\end{algorithmic}
\end{algorithm}</span>
<span class="p">```</span>
</code></pre></div></div> <p>Generates:</p> <pre><code class="language-pseudocode">% This quicksort algorithm is extracted from Chapter 7, Introduction to Algorithms (3rd edition)
\begin{algorithm}
\caption{Quicksort}
\begin{algorithmic}
\PROCEDURE{Quicksort}{$$A, p, r$$}
    \IF{$$p &lt; r$$}
        \STATE $$q = $$ \CALL{Partition}{$$A, p, r$$}
        \STATE \CALL{Quicksort}{$$A, p, q - 1$$}
        \STATE \CALL{Quicksort}{$$A, q + 1, r$$}
    \ENDIF
\ENDPROCEDURE
\PROCEDURE{Partition}{$$A, p, r$$}
    \STATE $$x = A[r]$$
    \STATE $$i = p - 1$$
    \FOR{$$j = p$$ \TO $$r - 1$$}
        \IF{$$A[j] &lt; x$$}
            \STATE $$i = i + 1$$
            \STATE exchange
            $$A[i]$$ with $$A[j]$$
        \ENDIF
        \STATE exchange $$A[i]$$ with $$A[r]$$
    \ENDFOR
\ENDPROCEDURE
\end{algorithmic}
\end{algorithm}
</code></pre>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="code"/><summary type="html"><![CDATA[this is what included pseudo code could look like]]></summary></entry><entry><title type="html">a post with code diff</title><link href="https://dcamacho.site/blog/2024/code-diff/" rel="alternate" type="text/html" title="a post with code diff"/><published>2024-01-27T19:22:00+00:00</published><updated>2024-01-27T19:22:00+00:00</updated><id>https://dcamacho.site/blog/2024/code-diff</id><content type="html" xml:base="https://dcamacho.site/blog/2024/code-diff/"><![CDATA[<p>You can display diff code by using the regular markdown syntax:</p> <div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">```</span><span class="nl">diff
</span><span class="gh">diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
</span><span class="gd">--- a/sample.js
</span><span class="gi">+++ b/sample.js
</span><span class="p">@@ -1 +1 @@</span>
<span class="gd">-console.log("Hello World!")
</span><span class="gi">+console.log("Hello from Diff2Html!")</span>
<span class="p">```</span>
</code></pre></div></div> <p>Which generates:</p> <div class="language-diff highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="gh">diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
</span><span class="gd">--- a/sample.js
</span><span class="gi">+++ b/sample.js
</span><span class="p">@@ -1 +1 @@</span>
<span class="gd">-console.log("Hello World!")
</span><span class="gi">+console.log("Hello from Diff2Html!")
</span></code></pre></div></div> <p>But this is difficult to read, specially if you have a large diff. You can use <a href="https://diff2html.xyz/">diff2html</a> to display a more readable version of the diff. For this, just use <code class="language-plaintext highlighter-rouge">diff2html</code> instead of <code class="language-plaintext highlighter-rouge">diff</code> for the code block language:</p> <div class="language-markdown highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">```</span><span class="nl">diff2html
</span><span class="sb">diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")</span>
<span class="p">```</span>
</code></pre></div></div> <p>If we use a longer example, for example <a href="https://github.com/rtfpessoa/diff2html/commit/c2c253d3e3f8b8b267f551e659f72b44ca2ac927">this commit from diff2html</a>, it will generate the following output:</p> <pre><code class="language-diff2html">From 2aaae31cc2a37bfff83430c2c914b140bee59b6a Mon Sep 17 00:00:00 2001
From: Rodrigo Fernandes &lt;rtfrodrigo@gmail.com&gt;
Date: Sun, 9 Oct 2016 16:41:54 +0100
Subject: [PATCH 1/2] Initial template override support

---
 scripts/hulk.js                    |  4 ++--
 src/diff2html.js                   |  3 +--
 src/file-list-printer.js           | 11 ++++++++---
 src/hoganjs-utils.js               | 29 +++++++++++++++++------------
 src/html-printer.js                |  6 ++++++
 src/line-by-line-printer.js        |  6 +++++-
 src/side-by-side-printer.js        |  6 +++++-
 test/file-list-printer-tests.js    |  2 +-
 test/hogan-cache-tests.js          | 18 +++++++++++++++---
 test/line-by-line-tests.js         |  3 +--
 test/side-by-side-printer-tests.js |  3 +--
 11 files changed, 62 insertions(+), 29 deletions(-)

diff --git a/scripts/hulk.js b/scripts/hulk.js
index 5a793c18..a4b1a4d5 100755
--- a/scripts/hulk.js
+++ b/scripts/hulk.js
@@ -173,11 +173,11 @@ function namespace(name) {
 // write a template foreach file that matches template extension
 templates = extractFiles(options.argv.remain)
   .map(function(file) {
-    var openedFile = fs.readFileSync(file, 'utf-8');
+    var openedFile = fs.readFileSync(file, 'utf-8').trim();
     var name;
     if (!openedFile) return;
     name = namespace(path.basename(file).replace(/\..*$/, ''));
-    openedFile = removeByteOrderMark(openedFile.trim());
+    openedFile = removeByteOrderMark(openedFile);
     openedFile = wrap(file, name, openedFile);
     if (!options.outputdir) return openedFile;
     fs.writeFileSync(path.join(options.outputdir, name + '.js')
diff --git a/src/diff2html.js b/src/diff2html.js
index 21b0119e..64e138f5 100644
--- a/src/diff2html.js
+++ b/src/diff2html.js
@@ -7,7 +7,6 @@

 (function() {
   var diffParser = require('./diff-parser.js').DiffParser;
-  var fileLister = require('./file-list-printer.js').FileListPrinter;
   var htmlPrinter = require('./html-printer.js').HtmlPrinter;

   function Diff2Html() {
@@ -43,7 +42,7 @@

     var fileList = '';
     if (configOrEmpty.showFiles === true) {
-      fileList = fileLister.generateFileList(diffJson, configOrEmpty);
+      fileList = htmlPrinter.generateFileListSummary(diffJson, configOrEmpty);
     }

     var diffOutput = '';
diff --git a/src/file-list-printer.js b/src/file-list-printer.js
index e408d9b2..1e0a2c61 100644
--- a/src/file-list-printer.js
+++ b/src/file-list-printer.js
@@ -8,11 +8,16 @@
 (function() {
   var printerUtils = require('./printer-utils.js').PrinterUtils;

-  var hoganUtils = require('./hoganjs-utils.js').HoganJsUtils;
+  var hoganUtils;
+
   var baseTemplatesPath = 'file-summary';
   var iconsBaseTemplatesPath = 'icon';

-  function FileListPrinter() {
+  function FileListPrinter(config) {
+    this.config = config;
+
+    var HoganJsUtils = require('./hoganjs-utils.js').HoganJsUtils;
+    hoganUtils = new HoganJsUtils(config);
   }

   FileListPrinter.prototype.generateFileList = function(diffFiles) {
@@ -38,5 +43,5 @@
     });
   };

-  module.exports.FileListPrinter = new FileListPrinter();
+  module.exports.FileListPrinter = FileListPrinter;
 })();
diff --git a/src/hoganjs-utils.js b/src/hoganjs-utils.js
index 9949e5fa..0dda08d7 100644
--- a/src/hoganjs-utils.js
+++ b/src/hoganjs-utils.js
@@ -8,18 +8,19 @@
 (function() {
   var fs = require('fs');
   var path = require('path');
-
   var hogan = require('hogan.js');

   var hoganTemplates = require('./templates/diff2html-templates.js');

-  var templatesPath = path.resolve(__dirname, 'templates');
+  var extraTemplates;

-  function HoganJsUtils() {
+  function HoganJsUtils(configuration) {
+    this.config = configuration || {};
+    extraTemplates = this.config.templates || {};
   }

-  HoganJsUtils.prototype.render = function(namespace, view, params, configuration) {
-    var template = this.template(namespace, view, configuration);
+  HoganJsUtils.prototype.render = function(namespace, view, params) {
+    var template = this.template(namespace, view);
     if (template) {
       return template.render(params);
     }
@@ -27,17 +28,16 @@
     return null;
   };

-  HoganJsUtils.prototype.template = function(namespace, view, configuration) {
-    var config = configuration || {};
+  HoganJsUtils.prototype.template = function(namespace, view) {
     var templateKey = this._templateKey(namespace, view);

-    return this._getTemplate(templateKey, config);
+    return this._getTemplate(templateKey);
   };

-  HoganJsUtils.prototype._getTemplate = function(templateKey, config) {
+  HoganJsUtils.prototype._getTemplate = function(templateKey) {
     var template;

-    if (!config.noCache) {
+    if (!this.config.noCache) {
       template = this._readFromCache(templateKey);
     }

@@ -53,6 +53,7 @@

     try {
       if (fs.readFileSync) {
+        var templatesPath = path.resolve(__dirname, 'templates');
         var templatePath = path.join(templatesPath, templateKey);
         var templateContent = fs.readFileSync(templatePath + '.mustache', 'utf8');
         template = hogan.compile(templateContent);
@@ -66,12 +67,16 @@
   };

   HoganJsUtils.prototype._readFromCache = function(templateKey) {
-    return hoganTemplates[templateKey];
+    return extraTemplates[templateKey] || hoganTemplates[templateKey];
   };

   HoganJsUtils.prototype._templateKey = function(namespace, view) {
     return namespace + '-' + view;
   };

-  module.exports.HoganJsUtils = new HoganJsUtils();
+  HoganJsUtils.prototype.compile = function(templateStr) {
+    return hogan.compile(templateStr);
+  };
+
+  module.exports.HoganJsUtils = HoganJsUtils;
 })();
diff --git a/src/html-printer.js b/src/html-printer.js
index 585d5b66..13f83047 100644
--- a/src/html-printer.js
+++ b/src/html-printer.js
@@ -8,6 +8,7 @@
 (function() {
   var LineByLinePrinter = require('./line-by-line-printer.js').LineByLinePrinter;
   var SideBySidePrinter = require('./side-by-side-printer.js').SideBySidePrinter;
+  var FileListPrinter = require('./file-list-printer.js').FileListPrinter;

   function HtmlPrinter() {
   }
@@ -22,5 +23,10 @@
     return sideBySidePrinter.generateSideBySideJsonHtml(diffFiles);
   };

+  HtmlPrinter.prototype.generateFileListSummary = function(diffJson, config) {
+    var fileListPrinter = new FileListPrinter(config);
+    return fileListPrinter.generateFileList(diffJson);
+  };
+
   module.exports.HtmlPrinter = new HtmlPrinter();
 })();
diff --git a/src/line-by-line-printer.js b/src/line-by-line-printer.js
index b07eb53c..d230bedd 100644
--- a/src/line-by-line-printer.js
+++ b/src/line-by-line-printer.js
@@ -11,7 +11,8 @@
   var utils = require('./utils.js').Utils;
   var Rematch = require('./rematch.js').Rematch;

-  var hoganUtils = require('./hoganjs-utils.js').HoganJsUtils;
+  var hoganUtils;
+
   var genericTemplatesPath = 'generic';
   var baseTemplatesPath = 'line-by-line';
   var iconsBaseTemplatesPath = 'icon';
@@ -19,6 +20,9 @@

   function LineByLinePrinter(config) {
     this.config = config;
+
+    var HoganJsUtils = require('./hoganjs-utils.js').HoganJsUtils;
+    hoganUtils = new HoganJsUtils(config);
   }

   LineByLinePrinter.prototype.makeFileDiffHtml = function(file, diffs) {
diff --git a/src/side-by-side-printer.js b/src/side-by-side-printer.js
index bbf1dc8d..5e3033b3 100644
--- a/src/side-by-side-printer.js
+++ b/src/side-by-side-printer.js
@@ -11,7 +11,8 @@
   var utils = require('./utils.js').Utils;
   var Rematch = require('./rematch.js').Rematch;

-  var hoganUtils = require('./hoganjs-utils.js').HoganJsUtils;
+  var hoganUtils;
+
   var genericTemplatesPath = 'generic';
   var baseTemplatesPath = 'side-by-side';
   var iconsBaseTemplatesPath = 'icon';
@@ -26,6 +27,9 @@

   function SideBySidePrinter(config) {
     this.config = config;
+
+    var HoganJsUtils = require('./hoganjs-utils.js').HoganJsUtils;
+    hoganUtils = new HoganJsUtils(config);
   }

   SideBySidePrinter.prototype.makeDiffHtml = function(file, diffs) {
diff --git a/test/file-list-printer-tests.js b/test/file-list-printer-tests.js
index a502a46f..60ea3208 100644
--- a/test/file-list-printer-tests.js
+++ b/test/file-list-printer-tests.js
@@ -1,6 +1,6 @@
 var assert = require('assert');

-var fileListPrinter = require('../src/file-list-printer.js').FileListPrinter;
+var fileListPrinter = new (require('../src/file-list-printer.js').FileListPrinter)();

 describe('FileListPrinter', function() {
   describe('generateFileList', function() {
diff --git a/test/hogan-cache-tests.js b/test/hogan-cache-tests.js
index 190bf6f8..3bb754ac 100644
--- a/test/hogan-cache-tests.js
+++ b/test/hogan-cache-tests.js
@@ -1,6 +1,6 @@
 var assert = require('assert');

-var HoganJsUtils = require('../src/hoganjs-utils.js').HoganJsUtils;
+var HoganJsUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)();
 var diffParser = require('../src/diff-parser.js').DiffParser;

 describe('HoganJsUtils', function() {
@@ -21,16 +21,28 @@ describe('HoganJsUtils', function() {
       });
       assert.equal(emptyDiffHtml, result);
     });
+
     it('should render view without cache', function() {
       var result = HoganJsUtils.render('generic', 'empty-diff', {
         contentClass: 'd2h-code-line',
         diffParser: diffParser
       }, {noCache: true});
-      assert.equal(emptyDiffHtml + '\n', result);
+      assert.equal(emptyDiffHtml, result);
     });
+
     it('should return null if template is missing', function() {
-      var result = HoganJsUtils.render('generic', 'missing-template', {}, {noCache: true});
+      var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)({noCache: true});
+      var result = hoganUtils.render('generic', 'missing-template', {});
       assert.equal(null, result);
     });
+
+    it('should allow templates to be overridden', function() {
+      var emptyDiffTemplate = HoganJsUtils.compile('&lt;p&gt;&lt;/p&gt;');
+
+      var config = {templates: {'generic-empty-diff': emptyDiffTemplate}};
+      var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)(config);
+      var result = hoganUtils.render('generic', 'empty-diff', {myName: 'Rodrigo Fernandes'});
+      assert.equal('&lt;p&gt;Rodrigo Fernandes&lt;/p&gt;', result);
+    });
   });
 });
diff --git a/test/line-by-line-tests.js b/test/line-by-line-tests.js
index 1cd92073..8869b3df 100644
--- a/test/line-by-line-tests.js
+++ b/test/line-by-line-tests.js
@@ -14,7 +14,7 @@ describe('LineByLinePrinter', function() {
         '            File without changes\n' +
         '        &lt;/div&gt;\n' +
         '    &lt;/td&gt;\n' +
-        '&lt;/tr&gt;\n';
+        '&lt;/tr&gt;';

       assert.equal(expected, fileHtml);
     });
@@ -422,7 +422,6 @@ describe('LineByLinePrinter', function() {
         '        &lt;/div&gt;\n' +
         '    &lt;/td&gt;\n' +
         '&lt;/tr&gt;\n' +
-        '\n' +
         '                &lt;/tbody&gt;\n' +
         '            &lt;/table&gt;\n' +
         '        &lt;/div&gt;\n' +
diff --git a/test/side-by-side-printer-tests.js b/test/side-by-side-printer-tests.js
index 76625f8e..771daaa5 100644
--- a/test/side-by-side-printer-tests.js
+++ b/test/side-by-side-printer-tests.js
@@ -14,7 +14,7 @@ describe('SideBySidePrinter', function() {
         '            File without changes\n' +
         '        &lt;/div&gt;\n' +
         '    &lt;/td&gt;\n' +
-        '&lt;/tr&gt;\n';
+        '&lt;/tr&gt;';

       assert.equal(expectedRight, fileHtml.right);
       assert.equal(expectedLeft, fileHtml.left);
@@ -324,7 +324,6 @@ describe('SideBySidePrinter', function() {
         '        &lt;/div&gt;\n' +
         '    &lt;/td&gt;\n' +
         '&lt;/tr&gt;\n' +
-        '\n' +
         '                    &lt;/tbody&gt;\n' +
         '                &lt;/table&gt;\n' +
         '            &lt;/div&gt;\n' +

From f3cadb96677d0eb82fc2752dc3ffbf35ca9b5bdb Mon Sep 17 00:00:00 2001
From: Rodrigo Fernandes &lt;rtfrodrigo@gmail.com&gt;
Date: Sat, 15 Oct 2016 13:21:22 +0100
Subject: [PATCH 2/2] Allow uncompiled templates

---
 README.md                 |  3 +++
 src/hoganjs-utils.js      |  7 +++++++
 test/hogan-cache-tests.js | 24 +++++++++++++++++++++++-
 3 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/README.md b/README.md
index 132c8a28..46909f25 100644
--- a/README.md
+++ b/README.md
@@ -98,6 +98,9 @@ The HTML output accepts a Javascript object with configuration. Possible options
   - `synchronisedScroll`: scroll both panes in side-by-side mode: `true` or `false`, default is `false`
   - `matchWordsThreshold`: similarity threshold for word matching, default is 0.25
   - `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is `2500`
+  - `templates`: object with previously compiled templates to replace parts of the html
+  - `rawTemplates`: object with raw not compiled templates to replace parts of the html
+  &gt; For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)

 ## Diff2HtmlUI Helper

diff --git a/src/hoganjs-utils.js b/src/hoganjs-utils.js
index 0dda08d7..b2e9c275 100644
--- a/src/hoganjs-utils.js
+++ b/src/hoganjs-utils.js
@@ -17,6 +17,13 @@
   function HoganJsUtils(configuration) {
     this.config = configuration || {};
     extraTemplates = this.config.templates || {};
+
+    var rawTemplates = this.config.rawTemplates || {};
+    for (var templateName in rawTemplates) {
+      if (rawTemplates.hasOwnProperty(templateName)) {
+        if (!extraTemplates[templateName]) extraTemplates[templateName] = this.compile(rawTemplates[templateName]);
+      }
+    }
   }

   HoganJsUtils.prototype.render = function(namespace, view, params) {
diff --git a/test/hogan-cache-tests.js b/test/hogan-cache-tests.js
index 3bb754ac..a34839c0 100644
--- a/test/hogan-cache-tests.js
+++ b/test/hogan-cache-tests.js
@@ -36,7 +36,7 @@ describe('HoganJsUtils', function() {
       assert.equal(null, result);
     });

-    it('should allow templates to be overridden', function() {
+    it('should allow templates to be overridden with compiled templates', function() {
       var emptyDiffTemplate = HoganJsUtils.compile('&lt;p&gt;&lt;/p&gt;');

       var config = {templates: {'generic-empty-diff': emptyDiffTemplate}};
@@ -44,5 +44,27 @@ describe('HoganJsUtils', function() {
       var result = hoganUtils.render('generic', 'empty-diff', {myName: 'Rodrigo Fernandes'});
       assert.equal('&lt;p&gt;Rodrigo Fernandes&lt;/p&gt;', result);
     });
+
+    it('should allow templates to be overridden with uncompiled templates', function() {
+      var emptyDiffTemplate = '&lt;p&gt;&lt;/p&gt;';
+
+      var config = {rawTemplates: {'generic-empty-diff': emptyDiffTemplate}};
+      var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)(config);
+      var result = hoganUtils.render('generic', 'empty-diff', {myName: 'Rodrigo Fernandes'});
+      assert.equal('&lt;p&gt;Rodrigo Fernandes&lt;/p&gt;', result);
+    });
+
+    it('should allow templates to be overridden giving priority to compiled templates', function() {
+      var emptyDiffTemplate = HoganJsUtils.compile('&lt;p&gt;&lt;/p&gt;');
+      var emptyDiffTemplateUncompiled = '&lt;p&gt;Not used!&lt;/p&gt;';
+
+      var config = {
+        templates: {'generic-empty-diff': emptyDiffTemplate},
+        rawTemplates: {'generic-empty-diff': emptyDiffTemplateUncompiled}
+      };
+      var hoganUtils = new (require('../src/hoganjs-utils.js').HoganJsUtils)(config);
+      var result = hoganUtils.render('generic', 'empty-diff', {myName: 'Rodrigo Fernandes'});
+      assert.equal('&lt;p&gt;Rodrigo Fernandes&lt;/p&gt;', result);
+    });
   });
 });
</code></pre>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="code"/><summary type="html"><![CDATA[this is how you can display code diffs]]></summary></entry><entry><title type="html">a post with advanced image components</title><link href="https://dcamacho.site/blog/2024/advanced-images/" rel="alternate" type="text/html" title="a post with advanced image components"/><published>2024-01-27T11:46:00+00:00</published><updated>2024-01-27T11:46:00+00:00</updated><id>https://dcamacho.site/blog/2024/advanced-images</id><content type="html" xml:base="https://dcamacho.site/blog/2024/advanced-images/"><![CDATA[<p>This is an example post with advanced image components.</p> <h2 id="image-slider">Image Slider</h2> <p>This is a simple image slider. It uses the <a href="https://swiperjs.com/">Swiper</a> library. Check the <a href="https://swiperjs.com/demos">examples page</a> for more information of what you can achieve with it.</p> <swiper-container keyboard="true" navigation="true" pagination="true" pagination-clickable="true" pagination-dynamic-bullets="true" rewind="true"> <swiper-slide> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/9-480.webp 480w,/assets/img/9-800.webp 800w,/assets/img/9-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/9.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </swiper-slide> <swiper-slide> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/7-480.webp 480w,/assets/img/7-800.webp 800w,/assets/img/7-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/7.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </swiper-slide> <swiper-slide> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/8-480.webp 480w,/assets/img/8-800.webp 800w,/assets/img/8-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/8.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </swiper-slide> <swiper-slide> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/10-480.webp 480w,/assets/img/10-800.webp 800w,/assets/img/10-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/10.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </swiper-slide> <swiper-slide> <figure> <picture> <source class="responsive-img-srcset" srcset="/assets/img/12-480.webp 480w,/assets/img/12-800.webp 800w,/assets/img/12-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/12.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="eager" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </swiper-slide> </swiper-container> <h2 id="image-comparison-slider">Image Comparison Slider</h2> <p>This is a simple image comparison slider. It uses the <a href="https://img-comparison-slider.sneas.io/">img-comparison-slider</a> library. Check the <a href="https://img-comparison-slider.sneas.io/examples.html">examples page</a> for more information of what you can achieve with it.</p> <img-comparison-slider> <figure slot="first"> <picture> <source class="responsive-img-srcset" srcset="/assets/img/prof_pic-480.webp 480w,/assets/img/prof_pic-800.webp 800w,/assets/img/prof_pic-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/prof_pic.jpg" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> <figure slot="second"> <picture> <source class="responsive-img-srcset" srcset="/assets/img/prof_pic_color-480.webp 480w,/assets/img/prof_pic_color-800.webp 800w,/assets/img/prof_pic_color-1400.webp 1400w," type="image/webp" sizes="95vw"/> <img src="/assets/img/prof_pic_color.png" class="img-fluid rounded z-depth-1" width="100%" height="auto" loading="lazy" onerror="this.onerror=null; $('.responsive-img-srcset').remove();"/> </picture> </figure> </img-comparison-slider>]]></content><author><name></name></author><category term="sample-posts"/><category term="formatting"/><category term="images"/><summary type="html"><![CDATA[this is what advanced image components could look like]]></summary></entry></feed>