Forum Discussion

JohnCooper-be3c's avatar
JohnCooper-be3c
Community Member
22 days ago

Rise 360’s new Custom Code Block — how far can it go to replace the need for Storyline blocks?

Over the last few years we have completed numerous RISE projects which used Storyline blocks to add different kinds of additional functionality and interactions. So we were excited to learn about the new Custom Code Block and to see what it can (and cannot) do...

There is no doubt it provides a simpler (and less resource intensive) option for including many simple learner engagements and interactions directly in the RISE framework. But we thought we would give it a bit of a workout to see if it could replace the Storyline in one of our most popular client requests - capturing learner notes and including them in a downloadable pdf at the end of the course.

We have a simple demo on our website that needed a bit of updating - it is a RISE course with three lessons and, at the end of each lesson, the learner is invited to enter their own notes which are stored in local browser storage to be retrieved by some Javascript coding to open a pdf notebook template, insert the learner's own notes and offer the new pdf for download:

Demo - Downloadable Notes using Storyline and Local Browser storage

The challenge was - Could we do the whole thing using custom code blocks?

We were genuinely impressed at how simple it was to capture text input using the Custom Code Block. Here’s a simplified version of what one of the note-taking blocks looked like:

<textarea id="notesInput" placeholder="Type your notes here..."></textarea>
<button id="saveBtn">Save</button>
<p id="statusMsg">Saved ✅</p>

<script>
(function(){
  const key = 'eNotes1';
  const input = document.getElementById('notesInput');
  const msg = document.getElementById('statusMsg');
  input.value = localStorage.getItem(key) || '';
  document.getElementById('saveBtn').onclick = () => {
    localStorage.setItem(key, input.value.trim());
    msg.style.opacity = 1;
    setTimeout(()=> msg.style.opacity = 0, 1500);
  };
})();
</script>

Each block is independent and self-contained.
Once saved, that data is visible to any other Rise or Storyline block that runs in the same browser session, because they share the same domain and localStorage space.

Data persistence worked perfectly — notes and learner name fields reappeared even when the course was reopened.

However, In our Storyline demo, the final slide uses the excellent pdf-lib JavaScript library to fill a PDF template and download it using the tiny-save-as library:

const { PDFDocument } = await import('https://cdn.jsdelivr.net/npm/pdf-lib@1.17.1/dist/pdf-lib.esm.js');
const formUrl = 'notebookTemplate.pdf';
const pdfBytes = await fetch(formUrl).then(r => r.arrayBuffer());
const pdfDoc = await PDFDocument.load(pdfBytes);
const form = pdfDoc.getForm();
form.getTextField('pNotes1').setText(localStorage.getItem('eNotes1') || '');
...

Because Storyline runs outside of RISE’s strict sandbox, it can freely:

  • Fetch and modify local files,
  • Generate a new PDF,
  • And open a Save As dialog for the learner.

When we tried the same logic directly inside a Custom Code Block, RISE displayed a success message — but the file never actually downloaded.
That’s because the sandboxed iframe environment doesn’t allow blob downloads or file system access.

Our modified demo below uses Custom Code Blocks for data capture but the original Storyline Block for the final pdf file creation and download:

Demo - Downloadable Notes using Custom Code Blocks and Local Browser storage

The other limitation was that the 'Continue' divider blocks did not wait for completion of the preceding Custom Code Block even though that setting was selected. We found workarounds to this problem but it is definitely a feature we would like to see in future releases.

In summary:

The new Custom Code Block is a fantastic addition to Rise 360 — it finally gives developers a way to embed real interactivity and persistence without leaving the platform.

For me, it opens up a lot of flexibility for client projects:
We can now build lightweight interactive elements directly in Rise, and still use our existing Storyline-based tools (like the Notes-to-PDF generator) where more advanced browser functionality is needed.

It’s not yet a full Storyline replacement, but it’s a strong step in that direction.

8 Replies

  • Hello,

    Luv the sample above. I experimented with the code you used to capture the notes in Rise Code block, but it only created the text entry field far to the left with no way to center it and have it look like your Rise version.

    Was there other "trickery" you did in your Rise version of the note capture?

    I'm loving learning about this new block. Thank you for sharing.

    Lisa

    • JohnCooper-be3c's avatar
      JohnCooper-be3c
      Community Member

      Hi LisaAnderson-57​ 

      Sorry that was a very simplified example block I posted and, as you say, nothing like the actual code I used - here's the actual code block I:

      <link href="https://fonts.googleapis.com/css2?family=Quicksand:wght@400;600&display=swap" rel="stylesheet">
      
      <div style="font-family: 'Quicksand', sans-serif; max-width: 700px; margin: 0 auto; padding: 1rem; background: #f8f9fa; border-radius: 12px; box-shadow: 0 2px 6px rgba(0,0,0,0.1);">
        <h3 style="margin-bottom: 0.5rem;">📝 Your Notes</h3>
      
        <textarea id="notesInput" rows="8"
          style="width: 100%; padding: 0.75rem; border-radius: 8px; border: 1px solid #ccc;
          resize: vertical; font-size: 1rem; font-family: 'Quicksand', sans-serif;"></textarea>
      
        <!-- Flexbox row: Saved! stays left, Save button stays right -->
        <div style="display: flex; justify-content: space-between; align-items: center; margin-top: 0.5rem;">
          <p id="statusMsg"
            style="
              font-size: 0.9rem;
              color: #28a745;
              opacity: 0;
              transition: opacity 0.4s ease;
              margin: 0;
              min-width: 60px;   /* ✅ reserves space so button doesn't move */
            ">Saved!</p>
          <button id="saveBtn"
            style="background-color: #0066ff; color: white; border: none; border-radius: 6px;
            padding: 0.5rem 1.25rem; font-size: 1rem; cursor: pointer;
            font-family: 'Quicksand', sans-serif;">Save</button>
        </div>
      </div>
      
      <script>
      (function() {
        const textArea = document.getElementById('notesInput');
        const saveBtn = document.getElementById('saveBtn');
        const statusMsg = document.getElementById('statusMsg');
      
        // Each lesson uses a unique key (example: eNotes1, eNotes2, eNotes3)
        const STORAGE_KEY = 'eNotes1';
      
        // Load existing note (if any)
        const savedNote = localStorage.getItem(STORAGE_KEY);
        if (savedNote) textArea.value = savedNote;
      
        // Save on button click
        saveBtn.addEventListener('click', () => {
          localStorage.setItem(STORAGE_KEY, textArea.value.trim());
      
          // Fade in "Saved!"
          statusMsg.style.opacity = '1';
          setTimeout(() => statusMsg.style.opacity = '0', 1500);
        });
      
        // Optional: auto-save while typing
        textArea.addEventListener('input', () => {
          localStorage.setItem(STORAGE_KEY, textArea.value.trim());
        });
      })();
      </script>

       

  • Amazing what you are doing here. Thank you for sharing, John. The coding of the Storyline Block (notes to PDF) is not shared. I presume because it is a building block in Articulate that you cannot share as a code, right?

    • JohnCooper-be3c's avatar
      JohnCooper-be3c
      Community Member

      ClaudiaGruarin​ I have shared the Storyline JavaScript code to do this on this site - but some time ago - AND, the code I shared is old, and now has an issue with some browsers because of the JavaScript code repository the libraries were loaded from - I also had two free courses on my website last year that went through this in detail for (a) Storyline and (b) RISE. These have been withdrawn awaiting an update - I will get a wiggle on and finish at least the new FREE Storyline course ASAP - in the meantime, if you need it urgently, send me a personal message and I will give you a sneak preview! 

  • I am not in a hurry, John, just staying tuned on the newest developments and learn. So no worry, take your time and I will follow your course when it is ready. Thank you so much for your reaction. 

  • JohnCooper-be3c​

    Hi John,

    I applied the updated code, thank you, and it worked beautifully. I didn't have an interest to save to PDF, so I didn't pursue further. 

    Here's what I did notice. I tested using the code for additional reflections in different lessons in a Rise course and when I entered my test text entry in one lesson and then went to the next lesson with the reflection code, I saw my text entry in the reflection text box from the previous lesson. When I inserted new text in the 2nd reflection then went back to the first, my text entry from the second lesson carried over to the first.

    I tried some other code assistance, but to no avail, could we solve it. Do you happen to have any ideas on what might clear the reflection entry for each time the reflection appears in the course?

    Just thought I'd try here.

    Thank you! Luv your work!

    Lisa

    • JohnCooper-be3c's avatar
      JohnCooper-be3c
      Community Member

      Hi LisaAnderson-57​ 

      If you are retrieving the previous lesson's text input it may be that you aren't changing the stored variable name for each lesson. In the code there is a line:

      // Each lesson uses a unique key (example: eNotes1, eNotes2, eNotes3)

      const STORAGE_KEY = 'eNotes1';

      You need to change this for each lesson. So lesson 1 would be eNotes1, lesson 2 would be eNotes2 and so on.

      Or am I misunderstanding the problem??

      Best regards, John