Skip to content

Instantly share code, notes, and snippets.

@pleabargain
Created February 24, 2026 09:43
Show Gist options
  • Select an option

  • Save pleabargain/6e092b1e9cb413b1883c2314464c5c63 to your computer and use it in GitHub Desktop.

Select an option

Save pleabargain/6e092b1e9cb413b1883c2314464c5c63 to your computer and use it in GitHub Desktop.
google apps script that takes a google sheet and generate flash cards in google slides
/**
* CONFIGURATION & STYLING
*/
const CONFIG = {
MENU_NAME: "🎲 SLIDE APP",
TAGS: {
WORD: "word_txt_v6",
HEADER: "header_txt_v6",
BACK: "back_btn_v6"
},
STYLES: {
TEXT_COLOR: "#000000",
HEADER_COLOR: "#D93025", // Bright Red for ID/D/T
WORD_FONT_SIZE: 80,
HEADER_FONT_SIZE: 60,
FONT_FAMILY: "Arial"
}
};
function onOpen() {
SlidesApp.getUi().createMenu(CONFIG.MENU_NAME)
.addItem('🚀 Import & Build Deck', 'startWorkflow')
.addSeparator()
.addItem('🧹 Clear All Slides', 'clearAll')
.addToUi();
}
/**
* Main Workflow
*/
function startWorkflow() {
const ui = SlidesApp.getUi();
const url = "https://docs.google.com/spreadsheets/d/1K6cfV_c0aQhHmBRtuZgDtP2d8XvQfyIi2gwvRPEi6Is/edit?gid=510679276#gid=510679276";
try {
// 1. Fetch Data
const data = fetchData(url);
if (!data.length) throw new Error("No data found in columns A, B, or C.");
// 2. Shuffle Data (Fisher-Yates)
const shuffled = shuffle(data);
// 3. Build Slides
const deck = SlidesApp.getActivePresentation();
buildSlides(deck, shuffled);
ui.alert("Success!", `Deck built with ${shuffled.length} words.\n\nInstructions:\n1. Enter Present Mode.\n2. Space bar = Reveal ID/D/T.\n3. Space bar again = Next Word.`, ui.ButtonSet.OK);
} catch (e) {
ui.alert("Error", e.message, ui.ButtonSet.OK);
}
}
/**
* Grabs words from Col A (ID), B (D), and C (T)
*/
function fetchData(url) {
const ss = SpreadsheetApp.openByUrl(url);
const sheet = ss.getSheets()[0];
const values = sheet.getDataRange().getValues();
const results = [];
const headers = ["ID", "D", "T"];
// Skip the first row (headers)
for (let r = 1; r < values.length; r++) {
for (let c = 0; c < 3; c++) {
let word = values[r][c];
if (word && word.toString().trim() !== "") {
results.push({
word: word.toString().trim(),
category: headers[c]
});
}
}
}
return results;
}
/**
* Builds the two-slide sequence for the reveal effect
*/
function buildSlides(deck, data) {
// Clear existing
const slides = deck.getSlides();
for (let i = slides.length - 1; i > 0; i--) slides[i].remove();
const pWidth = deck.getPageWidth();
const pHeight = deck.getPageHeight();
data.forEach((item, index) => {
// --- SLIDE 1: WORD ONLY ---
let s1 = (index === 0) ? deck.getSlides()[0] : deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
s1.getShapes().forEach(s => s.remove());
createTextBox(s1, item.word, CONFIG.STYLES.WORD_FONT_SIZE, false, CONFIG.STYLES.TEXT_COLOR, pWidth, pHeight, 0);
// --- SLIDE 2: HEADER + WORD ---
let s2 = deck.appendSlide(SlidesApp.PredefinedLayout.BLANK);
// Add Header (ID/D/T) at the top
createTextBox(s2, item.category, CONFIG.STYLES.HEADER_FONT_SIZE, true, CONFIG.STYLES.HEADER_COLOR, pWidth, pHeight, -100);
// Add Word in the middle
createTextBox(s2, item.word, CONFIG.STYLES.WORD_FONT_SIZE, false, CONFIG.STYLES.TEXT_COLOR, pWidth, pHeight, 40);
// Optional: Add a back button to s1 to skip back to the PREVIOUS word's Slide 1
if (index > 0) {
const btn = s1.insertShape(SlidesApp.ShapeType.RECTANGLE, 20, pHeight - 50, 80, 30);
btn.getFill().setSolidFill("#eeeeee");
btn.getText().setText("◀ BACK").getTextStyle().setFontSize(10);
// Link to the first slide of the previous pair
btn.setLinkSlide(deck.getSlides()[(index - 1) * 2]);
}
});
}
/**
* Helper to center text boxes
*/
function createTextBox(slide, text, size, isBold, color, pWidth, pHeight, yOffset) {
const w = 700, h = 150;
const box = slide.insertShape(SlidesApp.ShapeType.TEXT_BOX, (pWidth/2)-(w/2), (pHeight/2)-(h/2) + yOffset, w, h);
const range = box.getText();
range.setText(text);
range.getTextStyle()
.setFontSize(size)
.setBold(isBold)
.setForegroundColor(color)
.setFontFamily(CONFIG.STYLES.FONT_FAMILY);
range.getParagraphStyle().setParagraphAlignment(SlidesApp.ParagraphAlignment.CENTER);
box.setContentAlignment(SlidesApp.ContentAlignment.MIDDLE);
}
function shuffle(array) {
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
function clearAll() {
const deck = SlidesApp.getActivePresentation();
deck.getSlides().forEach((s, i) => {
if (i > 0) s.remove();
else s.getShapes().forEach(sh => sh.remove());
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment