top of page

Articulate Riseに「Codeブロック」が登場



生成AIと組み合わせて広がるeラーニングの可能性


Articulate Riseに新しく「Codeブロック」機能が追加されました。この機能により、HTML・CSS・JavaScriptなどのコードをRiseのレッスン内に直接埋め込むことができるようになりました。Riseはこれまで、シンプルで直感的に美しいeラーニングを作れることが特徴でしたが、Codeブロックの登場によって表現の自由度はさらに広がります。


本ブログでは、この新機能の概要と、実際に使えるシンプルなコードサンプルを紹介します。



Codeブロックとは


Codeブロックは、HTML・CSS・JavaScriptを使ったコンテンツをRiseのコース内に埋め込める機能です。


これにより、例えば次のようなことが可能になります。


  • ミニクイズ

  • カウントダウンタイマー

  • シミュレーション

  • インタラクティブな診断

  • カスタムUI


これまでRiseだけでは難しかったインタラクティブ要素も、簡単に追加できるようになります。



Codeブロックの簡単なサンプル


例えば、次のようなミニクイズを作ることができます。動画を再生してご覧ください。




以下のコードをそのままCodeブロックに貼り付けるだけで動作します。 (コード例が、少し長いですがご容赦ください)


<!DOCTYPE html>

<html lang="ja">

<head>

<meta charset="UTF-8" />

<meta name="viewport" content="width=device-width, initial-scale=1.0" />

<title>今日の気分は? - Game UI Edition</title>

<style>

* {

box-sizing: border-box;

}


:root {

--bg1: #0f1021;

--bg2: #1b1f4a;

--text: #ffffff;

--panel: rgba(255, 255, 255, 0.12);

--panel-border: rgba(255, 255, 255, 0.2);

--glow: 0 0 20px rgba(255, 255, 255, 0.25);

}


body {

margin: 0;

min-height: 100vh;

overflow: hidden;

font-family: "Segoe UI", "Hiragino Sans", "Yu Gothic", sans-serif;

color: var(--text);

background:

radial-gradient(circle at 20% 20%, rgba(255, 0, 128, 0.25), transparent 30%),

radial-gradient(circle at 80% 30%, rgba(0, 255, 255, 0.2), transparent 30%),

radial-gradient(circle at 50% 80%, rgba(255, 255, 0, 0.18), transparent 35%),

linear-gradient(135deg, var(--bg1), var(--bg2));

display: flex;

align-items: center;

justify-content: center;

position: relative;

}


.stars,

.effects,

.bg-bursts,

.rain-layer {

position: fixed;

inset: 0;

pointer-events: none;

overflow: hidden;

}


.star {

position: absolute;

width: 3px;

height: 3px;

background: white;

border-radius: 50%;

opacity: 0.7;

animation: twinkle linear infinite;

}


@keyframes twinkle {

0% { transform: translateY(0) scale(0.6); opacity: 0.2; }

50% { opacity: 1; }

100% { transform: translateY(-20px) scale(1.2); opacity: 0.2; }

}


.app {

width: min(920px, calc(100vw - 32px));

padding: 28px;

border-radius: 28px;

background: rgba(12, 15, 38, 0.62);

backdrop-filter: blur(12px);

border: 1px solid var(--panel-border);

box-shadow:

0 20px 60px rgba(0, 0, 0, 0.45),

inset 0 0 30px rgba(255, 255, 255, 0.06);

position: relative;

z-index: 2;

}


.topbar {

display: flex;

justify-content: space-between;

gap: 12px;

align-items: center;

margin-bottom: 16px;

flex-wrap: wrap;

}


.badge,

.score {

padding: 10px 16px;

border-radius: 999px;

background: rgba(255, 255, 255, 0.08);

border: 1px solid rgba(255,255,255,0.18);

box-shadow: var(--glow);

font-weight: 700;

letter-spacing: 0.06em;

}


h1 {

margin: 8px 0 6px;

font-size: clamp(2rem, 4vw, 3.2rem);

text-align: center;

text-shadow: 0 0 18px rgba(255,255,255,0.35);

}


.sub {

text-align: center;

opacity: 0.88;

margin-bottom: 26px;

font-size: 1rem;

}


.buttons {

display: grid;

grid-template-columns: repeat(3, 1fr);

gap: 16px;

}


.mood-btn {

position: relative;

overflow: hidden;

border: none;

border-radius: 22px;

padding: 18px 14px;

min-height: 120px;

cursor: pointer;

color: white;

font-size: 1.05rem;

font-weight: 800;

letter-spacing: 0.04em;

transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease;

box-shadow: 0 10px 24px rgba(0,0,0,0.3);

}


.mood-btn:hover {

transform: translateY(-4px) scale(1.02);

filter: brightness(1.08);

}


.mood-btn:active {

transform: scale(0.98);

}


.mood-btn::before {

content: "";

position: absolute;

inset: 0;

background: linear-gradient(120deg, transparent 30%, rgba(255,255,255,0.32), transparent 70%);

transform: translateX(-120%);

transition: transform 0.6s ease;

}


.mood-btn:hover::before {

transform: translateX(120%);

}


.best-btn {

background: linear-gradient(135deg, #ffb703, #ff5e00, #ff2e63);

}


.normal-btn {

background: linear-gradient(135deg, #38bdf8, #6366f1, #8b5cf6);

}


.worst-btn {

background: linear-gradient(135deg, #475569, #334155, #0f172a);

}


.btn-emoji {

display: block;

font-size: 2rem;

margin-bottom: 10px;

}


.result-panel {

margin-top: 22px;

padding: 22px;

border-radius: 24px;

background: rgba(255,255,255,0.08);

border: 1px solid rgba(255,255,255,0.14);

min-height: 290px;

position: relative;

overflow: hidden;

}


.result-bg-glow {

position: absolute;

inset: -20%;

opacity: 0.35;

filter: blur(50px);

transition: background 0.5s ease, opacity 0.5s ease;

z-index: 0;

}


.result-content {

position: relative;

z-index: 1;

text-align: center;

}


#emojiStage {

min-height: 140px;

display: flex;

align-items: center;

justify-content: center;

font-size: clamp(4rem, 10vw, 7rem);

margin-top: 10px;

text-shadow:

0 0 16px rgba(255,255,255,0.25),

0 0 28px rgba(255,255,255,0.18);

}


#mainEmoji {

display: inline-block;

transform-origin: center;

}


#message {

font-size: clamp(1.3rem, 2.4vw, 2rem);

font-weight: 900;

margin-top: 12px;

letter-spacing: 0.03em;

}


#subMessage {

margin-top: 10px;

font-size: 1rem;

opacity: 0.9;

}


.meter-wrap {

width: min(460px, 100%);

margin: 22px auto 0;

text-align: left;

}


.meter-label {

font-size: 0.95rem;

margin-bottom: 8px;

opacity: 0.9;

}


.meter {

width: 100%;

height: 18px;

border-radius: 999px;

background: rgba(255,255,255,0.1);

overflow: hidden;

border: 1px solid rgba(255,255,255,0.16);

}


.meter-bar {

height: 100%;

width: 0%;

border-radius: 999px;

transition: width 0.7s cubic-bezier(.2,.8,.2,1), background 0.4s ease;

box-shadow: 0 0 18px rgba(255,255,255,0.4);

}


.floating-text {

position: absolute;

font-weight: 900;

font-size: 1.1rem;

opacity: 0;

animation: floatUp 1.2s ease forwards;

text-shadow: 0 0 12px rgba(255,255,255,0.4);

pointer-events: none;

white-space: nowrap;

}


@keyframes floatUp {

0% { transform: translateY(0) scale(0.8); opacity: 0; }

20% { opacity: 1; }

100% { transform: translateY(-70px) scale(1.15); opacity: 0; }

}


.bounce {

animation: bounceEmoji 0.9s cubic-bezier(.2,.8,.2,1);

}


.gentle {

animation: gentleFloat 2.2s ease-in-out infinite;

}


.shake {

animation: shakeSad 0.6s linear 2;

}


@keyframes bounceEmoji {

0% { transform: scale(0.3) rotate(-20deg); }

30% { transform: scale(1.35) rotate(8deg); }

55% { transform: scale(0.92) rotate(-6deg); }

75% { transform: scale(1.1) rotate(4deg); }

100% { transform: scale(1) rotate(0deg); }

}


@keyframes gentleFloat {

0% { transform: translateY(0) rotate(0deg); }

25% { transform: translateY(-8px) rotate(-2deg); }

50% { transform: translateY(0) rotate(0deg); }

75% { transform: translateY(8px) rotate(2deg); }

100% { transform: translateY(0) rotate(0deg); }

}


@keyframes shakeSad {

0% { transform: translateX(0); }

20% { transform: translateX(-8px); }

40% { transform: translateX(8px); }

60% { transform: translateX(-6px); }

80% { transform: translateX(6px); }

100% { transform: translateX(0); }

}


.confetti,

.spark,

.rain-drop,

.burst-ring {

position: absolute;

pointer-events: none;

}


.confetti {

width: 12px;

height: 22px;

opacity: 0.95;

animation: confettiFall 2.8s linear forwards;

}


@keyframes confettiFall {

0% {

transform: translateY(-10vh) rotate(0deg);

opacity: 1;

}

100% {

transform: translateY(110vh) translateX(var(--drift, 0px)) rotate(720deg);

opacity: 0;

}

}


.spark {

font-size: 1.6rem;

animation: sparkFly 1s ease-out forwards;

opacity: 0;

}


@keyframes sparkFly {

0% {

transform: translate(0, 0) scale(0.4);

opacity: 0;

}

20% {

opacity: 1;

}

100% {

transform: translate(var(--x), var(--y)) scale(1.3);

opacity: 0;

}

}


.burst-ring {

width: 30px;

height: 30px;

border: 4px solid rgba(255,255,255,0.8);

border-radius: 50%;

animation: burst 0.7s ease-out forwards;

}


@keyframes burst {

0% {

transform: scale(0.2);

opacity: 1;

}

100% {

transform: scale(6);

opacity: 0;

}

}


.rain-drop {

width: 2px;

height: 18px;

background: linear-gradient(to bottom, rgba(180,220,255,0), rgba(180,220,255,0.95));

animation: rainFall linear forwards;

}


@keyframes rainFall {

from {

transform: translateY(-20px);

opacity: 0.8;

}

to {

transform: translateY(110vh);

opacity: 0.1;

}

}


.flash-happy {

animation: bgFlashHappy 1s ease;

}


.flash-normal {

animation: bgFlashNormal 1s ease;

}


.flash-worst {

animation: bgFlashWorst 1s ease;

}


@keyframes bgFlashHappy {

0%,100% { filter: brightness(1); }

20% { filter: brightness(1.5) saturate(1.4); }

50% { filter: brightness(1.2) saturate(1.3); }

}


@keyframes bgFlashNormal {

0%,100% { filter: brightness(1); }

30% { filter: brightness(1.25) hue-rotate(20deg); }

}


@keyframes bgFlashWorst {

0%,100% { filter: brightness(1); }

30% { filter: brightness(0.75) saturate(0.7); }

}


.footer-tip {

margin-top: 16px;

text-align: center;

font-size: 0.92rem;

opacity: 0.78;

}


@media (max-width: 720px) {

.buttons {

grid-template-columns: 1fr;

}


.mood-btn {

min-height: 96px;

}


.app {

padding: 20px;

}


.result-panel {

min-height: 260px;

}

}

</style>

</head>

<body>

<div class="stars" id="stars"></div>

<div class="bg-bursts" id="bgBursts"></div>

<div class="rain-layer" id="rainLayer"></div>

<div class="effects" id="effects"></div>


<main class="app" id="app">

<div class="topbar">

<div class="badge">MOOD SELECT</div>

<div class="score" id="scoreBoard">テンション: --</div>

</div>


<h1>今日の気分は?</h1>

<div class="sub">ボタンを押すと、ゲームみたいな演出で気分を表示します</div>


<section class="buttons">

<button class="mood-btn best-btn" onclick="setMood('best')">

<span class="btn-emoji">😆🎉</span>

最高

</button>


<button class="mood-btn normal-btn" onclick="setMood('normal')">

<span class="btn-emoji">🙂✨</span>

普通

</button>


<button class="mood-btn worst-btn" onclick="setMood('worst')">

<span class="btn-emoji">😭🌧️</span>

最悪

</button>

</section>


<section class="result-panel" id="resultPanel">

<div class="result-bg-glow" id="resultGlow"></div>


<div class="result-content">

<div id="emojiStage">

<span id="mainEmoji">🎮</span>

</div>


<div id="message">気分を選んでスタート!</div>

<div id="subMessage">今日はどんな一日?</div>


<div class="meter-wrap">

<div class="meter-label">気分ゲージ</div>

<div class="meter">

<div class="meter-bar" id="meterBar"></div>

</div>

</div>

</div>

</section>


<div class="footer-tip">最高で祝福演出 / 普通でやさしい演出 / 最悪で雨とダーク演出</div>

</main>


<script>

const mainEmoji = document.getElementById("mainEmoji");

const message = document.getElementById("message");

const subMessage = document.getElementById("subMessage");

const meterBar = document.getElementById("meterBar");

const effects = document.getElementById("effects");

const app = document.getElementById("app");

const body = document.body;

const scoreBoard = document.getElementById("scoreBoard");

const rainLayer = document.getElementById("rainLayer");

const bgBursts = document.getElementById("bgBursts");

const resultGlow = document.getElementById("resultGlow");


createStars();


function createStars() {

const stars = document.getElementById("stars");

for (let i = 0; i < 60; i++) {

const s = document.createElement("div");

s.className = "star";

s.style.left = Math.random() * 100 + "vw";

s.style.top = Math.random() * 100 + "vh";

s.style.animationDuration = (2 + Math.random() * 4) + "s";

s.style.animationDelay = (Math.random() * 3) + "s";

s.style.opacity = 0.2 + Math.random() * 0.8;

const size = 2 + Math.random() * 3;

s.style.width = size + "px";

s.style.height = size + "px";

stars.appendChild(s);

}

}


function resetAnimations() {

mainEmoji.className = "";

body.classList.remove("flash-happy", "flash-normal", "flash-worst");

rainLayer.innerHTML = "";

}


function setMood(mood) {

resetAnimations();

clearOldEffects();


if (mood === "best") {

mainEmoji.textContent = "😆";

mainEmoji.classList.add("bounce");

message.textContent = "SUPER HAPPY !!";

subMessage.textContent = "今日はノリノリ!最強の一日が始まる!";

meterBar.style.width = "100%";

meterBar.style.background = "linear-gradient(90deg, #ffe600, #ff7b00, #ff2e63)";

scoreBoard.textContent = "テンション: MAX";

resultGlow.style.background = "radial-gradient(circle, rgba(255,230,0,0.75), rgba(255,100,0,0.2), transparent 60%)";

body.classList.add("flash-happy");


launchConfetti(80);

launchSparks(26, ["✨", "🎉", "⭐", "💥"]);

launchBurstRings(5);

spawnFloatingText(["GREAT!", "PERFECT!", "HAPPY!", "BONUS!"], "#ffe96b");

}


if (mood === "normal") {

mainEmoji.textContent = "🙂";

mainEmoji.classList.add("gentle");

message.textContent = "NORMAL MODE";

subMessage.textContent = "今日は落ち着いて、いい感じに過ごせそう。";

meterBar.style.width = "55%";

meterBar.style.background = "linear-gradient(90deg, #60a5fa, #6366f1, #a855f7)";

scoreBoard.textContent = "テンション: MID";

resultGlow.style.background = "radial-gradient(circle, rgba(96,165,250,0.55), rgba(99,102,241,0.18), transparent 60%)";

body.classList.add("flash-normal");


launchSparks(12, ["✨", "💫", "🫧"]);

pulseBackground(4, "rgba(120,160,255,0.18)");

spawnFloatingText(["GOOD", "CALM", "OK!"], "#b9c8ff");

}


if (mood === "worst") {

mainEmoji.textContent = "😭";

mainEmoji.classList.add("shake");

message.textContent = "CRITICAL DAMAGE...";

subMessage.textContent = "今日は無理せず、ゆっくり休もう。";

meterBar.style.width = "15%";

meterBar.style.background = "linear-gradient(90deg, #64748b, #334155, #0f172a)";

scoreBoard.textContent = "テンション: LOW";

resultGlow.style.background = "radial-gradient(circle, rgba(90,110,140,0.35), rgba(20,25,40,0.12), transparent 60%)";

body.classList.add("flash-worst");


startRain(80);

launchSparks(8, ["💧", "🌧️", "☔"]);

spawnFloatingText(["OOPS...", "SAD...", "REST"], "#cbd5e1");

}

}


function clearOldEffects() {

effects.innerHTML = "";

bgBursts.innerHTML = "";

}


function launchConfetti(count) {

const colors = ["#ff4d6d", "#ffd60a", "#00f5d4", "#ffffff", "#7b2cff", "#ff8c42"];

for (let i = 0; i < count; i++) {

const piece = document.createElement("div");

piece.className = "confetti";

piece.style.left = Math.random() * 100 + "vw";

piece.style.top = (-10 - Math.random() * 20) + "vh";

piece.style.background = colors[Math.floor(Math.random() * colors.length)];

piece.style.borderRadius = Math.random() > 0.5 ? "2px" : "999px";

piece.style.animationDuration = (1.8 + Math.random() * 1.6) + "s";

piece.style.animationDelay = (Math.random() * 0.35) + "s";

piece.style.setProperty("--drift", (Math.random() * 220 - 110) + "px");

effects.appendChild(piece);

setTimeout(() => piece.remove(), 3600);

}

}


function launchSparks(count, icons) {

for (let i = 0; i < count; i++) {

const spark = document.createElement("div");

spark.className = "spark";

spark.textContent = icons[Math.floor(Math.random() * icons.length)];

spark.style.left = "50vw";

spark.style.top = "42vh";

const angle = Math.random() * Math.PI * 2;

const distance = 80 + Math.random() * 220;

spark.style.setProperty("--x", Math.cos(angle) * distance + "px");

spark.style.setProperty("--y", Math.sin(angle) * distance + "px");

spark.style.animationDuration = (0.8 + Math.random() * 0.7) + "s";

effects.appendChild(spark);

setTimeout(() => spark.remove(), 1800);

}

}


function launchBurstRings(count) {

for (let i = 0; i < count; i++) {

const ring = document.createElement("div");

ring.className = "burst-ring";

ring.style.left = (45 + Math.random() * 10) + "vw";

ring.style.top = (34 + Math.random() * 12) + "vh";

ring.style.animationDelay = (i * 0.08) + "s";

effects.appendChild(ring);

setTimeout(() => ring.remove(), 1200);

}

}


function startRain(count) {

for (let i = 0; i < count; i++) {

const drop = document.createElement("div");

drop.className = "rain-drop";

drop.style.left = Math.random() * 100 + "vw";

drop.style.top = (-20 - Math.random() * 400) + "px";

drop.style.animationDuration = (0.7 + Math.random() * 0.8) + "s";

drop.style.animationDelay = (Math.random() * 0.6) + "s";

rainLayer.appendChild(drop);

setTimeout(() => drop.remove(), 2200);

}

}


function pulseBackground(count, color) {

for (let i = 0; i < count; i++) {

const pulse = document.createElement("div");

pulse.className = "burst-ring";

pulse.style.left = "50vw";

pulse.style.top = "45vh";

pulse.style.borderColor = color;

pulse.style.animationDuration = (0.8 + i * 0.2) + "s";

bgBursts.appendChild(pulse);

setTimeout(() => pulse.remove(), 1800);

}

}


function spawnFloatingText(words, color) {

for (let i = 0; i < 4; i++) {

const text = document.createElement("div");

text.className = "floating-text";

text.textContent = words[Math.floor(Math.random() * words.length)];

text.style.color = color;

text.style.left = (20 + Math.random() * 60) + "%";

text.style.top = (52 + Math.random() * 18) + "%";

text.style.animationDelay = (i * 0.08) + "s";

effects.appendChild(text);

setTimeout(() => text.remove(), 1600);

}

}

</script>

</body>

</html>



生成AIを使えばコード作成も簡単


上記のような「コードを書くのは難しそう」と感じる方もいるかもしれません。

しかし、ChatGPTのような生成AIを使えば、コード作成のハードルは大きく下がります。このコードもわずか数分で生成できました。


例えば今回は次のように依頼しました。


  • HTMLで下記の動作をするコードを生成して。 今日の気分はという問いに対して、選択肢が、最高、普通、最悪とあり、最高を選ぶとハッピーな表現、普通を選ぶと普通の表現、最悪を選ぶと最悪な表現がされる



するとAIがHTMLやJavaScriptのコードを生成してくれます。


今回は続いて次のような依頼をしました。


  • 絵文字を派手にアニメーションさせて



さらに次の依頼をしました。


  • さらに派手にして、ゲームレベルのUIにして。



以下が生成されたコードを埋め込んだものです。この部分をRiseにも簡単に埋め込めるようになりました。



コードをRiseのCodeブロックに貼り付けるだけで、インタラクティブなコンテンツを作ることができます。


つまり、


Rise × 生成AI


という組み合わせによって、専門的なプログラミング知識がなくても、より高度な学習体験を作れるようになります。



将来はRise単体でAI生成ができる?


現在は別途、生成AIでコードを作り、それをRiseに貼り付ける形になります。


しかし将来的には、Riseの中で直接同様のことができるようになるかもしれません。


こうした指示を出すだけで、Riseが自動的にコードを生成し、Codeブロックとして配置してくれる未来も想像できます。

もしそれが実現すれば、eラーニング制作のハードルはさらに下がるでしょう。



まとめ


Articulate RiseのCodeブロックは、これまでのRiseの可能性を大きく広げる機能です。

HTML・CSS・JavaScriptを活用することで、


  • インタラクティブな学習

  • カスタムUI

  • シミュレーション

  • ミニゲーム


など、より豊かな学習体験を作ることができます。

さらに生成AIを組み合わせれば、コード作成の難易度も大きく下がります。


これからのeラーニング制作は、このような新しい形に進化していくのかもしれません。


RiseのCodeブロックは、その第一歩となる機能と言えるでしょう。



Articulate 360を試してみたい方は、Articulate 360の30日間の無料トライアルをお試しください。ご登録にクレジットカードは必要ありません!!

株式会社ディーシェは日本におけるArticulate製品の販売代理店です



1件のコメント


linn paul
linn paul
6時間前

I particularly liked how you touched on the practical side of it—being able to either write code directly or upload a complete project makes it accessible for both beginners and more advanced users. Features like real-time previews and embedding custom interactions really expand what instructional designers can achieve inside Rise . It’s a great step toward more flexible and engaging e-learning design.What stands out most is how this bridges the gap between traditional block-based content and fully customized experiences, giving creators much more creative control without leaving the platform . It definitely feels like a feature that can transform how courses are built moving forward.This actually reminded me of a similar perspective I came across on a review blog fake…

いいね!
bottom of page