diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f06235c
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+dist
diff --git a/README.md b/README.md
index 4c10029..bf2ea2c 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,16 @@
# Visualizations
-Practice - Grok
+
+Shareable React visualization for the Pedagogical Friction dissertation plan.
+
+## Run locally
+
+```bash
+npm install
+npm run dev
+```
+
+## Build
+
+```bash
+npm run build
+```
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..2e22126
--- /dev/null
+++ b/index.html
@@ -0,0 +1,12 @@
+
+
+
+
+
+ Pedagogical Friction Visualization
+
+
+
+
+
+
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..f1136af
--- /dev/null
+++ b/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "visualizations",
+ "private": true,
+ "version": "0.0.1",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "dependencies": {
+ "react": "^18.3.1",
+ "react-dom": "^18.3.1"
+ },
+ "devDependencies": {
+ "vite": "^5.4.0"
+ }
+}
diff --git a/src/App.jsx b/src/App.jsx
new file mode 100644
index 0000000..2cd19fd
--- /dev/null
+++ b/src/App.jsx
@@ -0,0 +1,255 @@
+import React, { useEffect, useState } from "react";
+
+const COLORS = {
+ bg: "#0f1117",
+ surface: "#181b24",
+ surfaceHover: "#1e2230",
+ border: "#2a2e3b",
+ borderAccent: "#3d4258",
+ text: "#e8e9ed",
+ textMuted: "#8b8fa3",
+ textDim: "#5c6078",
+ noetic: "#e07a5f",
+ rhetorical: "#81b29a",
+ existential: "#f2cc8f",
+ infrastructural: "#7289da",
+ accent: "#c9a87c",
+ accentDim: "#8a7455",
+ qual: "#81b29a",
+ quan: "#7289da",
+ ai: "#e07a5f",
+};
+
+const FONTS = {
+ display: "'Playfair Display', Georgia, serif",
+ body: "'Source Sans 3', 'Segoe UI', sans-serif",
+ mono: "'JetBrains Mono', 'Fira Code', monospace",
+};
+
+const dimensions = [
+ { key: "noetic", label: "Noetic", color: COLORS.noetic, desc: "Cognitive struggle and productive difficulty", icon: "🧠", detail: "Measures the frequency and intentionality of cognitive struggle-preserving practices: requiring drafting before AI use, mandating retrieval practice, designing productive failure tasks." },
+ { key: "rhetorical", label: "Rhetorical", color: COLORS.rhetorical, desc: "Engagement with real audiences", icon: "🗣️", detail: "Captures practices that require engagement with real audiences: peer review, public presentation, authentic audience writing assignments." },
+ { key: "existential", label: "Existential", color: COLORS.existential, desc: "Intellectual ownership and authorial stance", icon: "✍️", detail: "Assesses practices requiring intellectual ownership: oral defense of written work, revision based on personal investment, authorial stance requirements." },
+ { key: "infrastructural", label: "Infrastructural", color: COLORS.infrastructural, desc: "Policy and institutional conditions", icon: "🏛️", detail: "Evaluates perceived institutional support: written AI policy, PD opportunities, administrator messaging, assessment redesign support." },
+];
+
+const litDomains = [
+ { id: "media", title: "Media Archaeology & Ecology", icon: "🕰️", color: COLORS.rhetorical, theorists: ["Ong", "Kittler", "Ernst", "Parikka", "Huhtamo", "Foucault", "Bolter & Grusin"], concepts: ["Tertiary Algorithmicity", "From Orality to Digital", "Materiality of Media", "Remediation", "The Archive as Process"], connection: "Establishes the historical and materialist depth of how communication technologies restructure consciousness and circulation, moving beyond human authorship.", frameworkDim: "rhetorical" },
+ { id: "technoskepticism", title: "Technoskepticism & Surveillance", icon: "👁️", color: COLORS.existential, theorists: ["Postman", "Zuboff", "Turkle", "Carr", "Haidt", "Birkerts", "Illich"], concepts: ["Surveillance Capitalism", "The Shallows / Cognitive Costs", "Behavioral Modification", "Loss of Human Agency", "Frictionless Risks"], connection: "Provides the critical lens to examine the trade-offs of 'frictionless' AI convenience, advocating for the preservation of cognitive struggle.", frameworkDim: "existential" },
+ { id: "learning", title: "Cognitive & Learning Theories", icon: "🧩", color: COLORS.noetic, theorists: ["Dewey", "Vygotsky", "Piaget", "Papert", "Sweller", "Siemens", "Hattie"], concepts: ["Constructivism vs. Constructionism", "Cognitive Load Theory", "Connectivism", "Productive Failure", "Visible Learning"], connection: "Grounds the framework in established learning sciences, proving that resistance and 'desirable difficulties' are prerequisites for durable learning.", frameworkDim: "noetic" },
+ { id: "literacy", title: "Critical Media Literacy & Pedagogy", icon: "✊", color: COLORS.infrastructural, theorists: ["Freire", "Buckingham", "Kellner & Share", "Jenkins", "ISTE"], concepts: ["Subversive Teaching", "Participatory Culture", "Digital Citizenship", "C.O.R.E. & H.E.A.R.T.", "Algorithmic Awareness"], connection: "Operationalizes the theoretical concerns into actionable pedagogical strategies (C.O.R.E.), empowering students to navigate and critique AI systems.", frameworkDim: "infrastructural" },
+];
+
+const participants = [
+ { group: "University Students", n: 4, criteria: "Currently enrolled; have used GenAI; can reflect on K–12", rq: "RQ1", dims: ["noetic", "rhetorical", "existential"], pair: "Pair 1 — Learner Perspective" },
+ { group: "K–12 Teachers", n: 4, criteria: "Varied content areas, grade bands, poverty levels", rq: "RQ1, RQ2", dims: ["noetic", "rhetorical", "existential", "infrastructural"], pair: "Pair 2 — Practitioner/Leader" },
+ { group: "Building Administrators", n: "1–2", criteria: "Principals/APs at schools with varying AI policy maturity", rq: "RQ2, RQ3", dims: ["infrastructural"], pair: "Pair 2 — Practitioner/Leader" },
+ { group: "District Leaders", n: 2, criteria: "Curriculum, technology, or superintendent roles", rq: "RQ2, RQ3", dims: ["infrastructural"], pair: "Pair 2 — Practitioner/Leader" },
+];
+
+const phases = [
+ { num: 1, title: "Concurrent Data Collection", desc: "Interviews, card sort, survey distribution, secondary data compilation", color: COLORS.accent, items: ["Semi-structured interviews (all groups)", "Card sort protocol (teachers & students)", "Teacher survey distribution (N=50–100)", "SPP & RAND secondary data compilation"] },
+ { num: 2, title: "Independent Analysis", desc: "Strand-appropriate methods applied separately", color: COLORS.qual, items: ["Thematic coding via PFF lens (a priori + emergent)", "Descriptive statistics & disaggregation", "Cross-tabulation by poverty level", "Cronbach's alpha for survey scales"] },
+ { num: 3, title: "Integration", desc: "Joint displays comparing qualitative themes with quantitative patterns", color: COLORS.quan, items: ["Joint display construction by RQ", "Convergence/divergence documentation", "Narrative integration (Chapter 5)", "Meta-inference development"] },
+ { num: 4, title: "AI Comparison", desc: "Supplementary strand testing framework claims", color: COLORS.ai, items: ["3 platforms × 4 roles = 12 response sets", "Same codebook applied to AI outputs", "5-indicator structured comparison", "Presentational separation from human data"] },
+];
+
+const rqs = [
+ { id: "RQ1", text: "How do K–12 teachers and university students understand and navigate the friction-reducing affordances of generative AI in academic work?", qual: "Teacher & student interviews; card sort protocol", quan: "Teacher survey (friction practices scale)", integration: "Survey patterns explained by interview narratives", color: COLORS.noetic },
+ { id: "RQ2", text: "What institutional conditions—including policy, assessment design, PD, and leadership disposition—enable or constrain friction-preserving pedagogy?", qual: "Administrator & leader interviews; document analysis", quan: "SPP secondary data (policy/training gaps by poverty)", integration: "National structural patterns contextualized by local institutional accounts", color: COLORS.infrastructural },
+ { id: "RQ3", text: "How can the Pedagogical Friction Framework inform AI policy development in K–12 contexts?", qual: "Cross-case synthesis of friction-enabling conditions", quan: "Survey items on policy awareness and utility", integration: "Framework-informed policy recommendations grounded in both strands", color: COLORS.existential },
+ { id: "SAQ", text: "When agentic AI systems respond to the same protocols, how do their outputs differ structurally from human practitioner responses?", qual: "AI-generated interview & card sort responses", quan: "AI-generated survey responses", integration: "Structured comparison: human vs. AI discourse analysis", color: COLORS.ai },
+];
+
+const aiIndicators = [
+ { label: "Experiential Specificity", prediction: "AI will lack specific incidents, students, institutional moments", icon: "📌" },
+ { label: "Productive/Exclusionary Distinction", prediction: "AI will acknowledge in general terms but fail context-specific applications", icon: "⚖️" },
+ { label: "Institutional Memory", prediction: "AI will default to idealized institutional models", icon: "🏢" },
+ { label: "Professional Uncertainty", prediction: "AI will resolve tensions prematurely with artificially clean conclusions", icon: "❓" },
+ { label: "Framework Dimension Coverage", prediction: "Exploratory — no directional prediction", icon: "📊" },
+];
+
+const timeline = [
+ { phase: "Mixed Methods Course", activities: "Draft plan, develop instruments, pilot protocol, begin IRB", timing: "Current semester", status: "active" },
+ { phase: "Qualifying Paper", activities: "Complete 10-week QP; pass rubric evaluation", timing: "CCD 697", status: "upcoming" },
+ { phase: "Proposal Development", activities: "Write Chapters 1–3; prepare defense; complete CITI", timing: "CCD 698 Term 1", status: "upcoming" },
+ { phase: "Proposal Defense + IRB", activities: "Defend proposal; submit IRB/IRRB; receive approval", timing: "CCD 698 Term 1", status: "upcoming" },
+ { phase: "Data Collection", activities: "Interviews, survey, secondary data, AI comparison protocol", timing: "CCD 698 Term 2", status: "upcoming" },
+ { phase: "Analysis + Writing", activities: "Code qual data, analyze quan, integrate, write Ch. 4–5", timing: "CCD 698 Term 3", status: "upcoming" },
+ { phase: "Defense", activities: "Submit full draft, defend, revisions within 90 days", timing: "CCD 698 T3 / 699", status: "upcoming" },
+];
+
+const deliverables = [
+ { item: "Research plan document", section: "Overall Ch. 3 architecture", status: "in-progress" },
+ { item: "Interview protocol with RQ mapping", section: "§3.3.1", status: "to-develop" },
+ { item: "Card sort items with dimension mapping", section: "§3.3.2", status: "to-develop" },
+ { item: "Survey instrument with pilot results", section: "§3.3.5", status: "to-develop" },
+ { item: "SPP/RAND variable mapping", section: "§3.3.4", status: "pilot-complete" },
+ { item: "Codebook (a priori codes)", section: "§3.4.1", status: "to-develop" },
+ { item: "Integration strategy + joint display", section: "§3.4.3", status: "to-develop" },
+ { item: "AI comparison protocol", section: "§3.5", status: "to-develop" },
+ { item: "Positionality statement", section: "§3.6", status: "draft" },
+ { item: "IRB application draft", section: "§3.7 + Appendices", status: "to-develop" },
+];
+
+const statusColors = { "in-progress": COLORS.existential, "to-develop": COLORS.textDim, "pilot-complete": COLORS.qual, draft: COLORS.accent };
+const statusLabels = { "in-progress": "In Progress", "to-develop": "To Develop", "pilot-complete": "Pilot Complete", draft: "Draft" };
+
+const tabs = [
+ { id: "overview", label: "Overview" },
+ { id: "literature", label: "Literature Map" },
+ { id: "framework", label: "Framework" },
+ { id: "rqs", label: "Research Questions" },
+ { id: "design", label: "Design & Phases" },
+ { id: "participants", label: "Participants" },
+ { id: "ai", label: "AI Comparison" },
+ { id: "timeline", label: "Timeline" },
+ { id: "deliverables", label: "Deliverables" },
+];
+
+function Badge({ children, color }) {
+ return (
+
+ {children}
+
+ );
+}
+
+function Card({ children, style, onClick, hoverable }) {
+ return (
+ {
+ if (hoverable && onClick && (e.key === "Enter" || e.key === " ")) {
+ e.preventDefault();
+ onClick(e);
+ }
+ }}
+ className={hoverable ? "hoverable-card" : ""}
+ style={{
+ background: COLORS.surface,
+ border: `1px solid ${COLORS.border}`,
+ borderRadius: 8,
+ padding: 20,
+ cursor: hoverable ? "pointer" : "default",
+ transition: "all 0.2s ease",
+ outline: "none",
+ ...style,
+ }}
+ >
+ {children}
+
+ );
+}
+
+function OverviewTab() {
+ return {/* unchanged from provided content */}
+
+
Pedagogical Friction in the Age of Generative AI
+
A Mixed-Methods Collective Instrumental Case Study
+
+
+ {[
+ { label: "Design", value: "QUAL + quan", sub: "Convergent Mixed Methods" },
+ { label: "Methodology", value: "Case Study", sub: "Collective Instrumental (Stake)" },
+ { label: "Participants", value: "12–14", sub: "4 groups, matched pairs" },
+ { label: "Philosophy", value: "Pragmatism", sub: "Creswell & Plano Clark, 2018" },
+ ].map((s, i) => (
+
{s.label}
{s.value}
{s.sub}
+ ))}
+
+
;
+}
+
+function LiteratureTab() {
+ const [activeDomain, setActiveDomain] = useState(null);
+ return (
+
+
+
Literature Map & Theoretical Foundations
+
+
+ {litDomains.map((domain) => {
+ const isActive = activeDomain === domain.id;
+ const dim = dimensions.find((d) => d.key === domain.frameworkDim);
+ return (
+
setActiveDomain(isActive ? null : domain.id)} style={{ borderTop: `4px solid ${domain.color}`, ...(isActive ? { background: `${domain.color}08`, borderColor: domain.color } : {}) }}>
+ {domain.icon} {domain.title}
+ {dim && → {dim.label} Dimension
}
+ {domain.connection}
+
+ );
+ })}
+
+
+ );
+}
+
+function FrameworkTab() {
+ const [selected, setSelected] = useState(null);
+ return
+ {dimensions.map((d) => (
+
setSelected(selected === d.key ? null : d.key)} style={{ borderLeft: `3px solid ${d.color}` }}>
+ {d.icon} {d.label}
+ {selected === d.key ? d.detail : d.desc}
+
+ ))}
+
;
+}
+
+function RQsTab() {
+ return {rqs.map((rq) =>
{rq.id}{rq.text}
)}
;
+}
+
+function DesignTab() {
+ return {phases.map((p) =>
{p.num}. {p.title}{p.desc}
)}
;
+}
+
+function ParticipantsTab() {
+ return {participants.map((p) =>
{p.group} (N={p.n}){p.criteria}
)}
;
+}
+
+function AITab() {
+ return {aiIndicators.map((ind) =>
{ind.icon} {ind.label}{ind.prediction}
)}
;
+}
+
+function TimelineTab() {
+ return {timeline.map((t) =>
{t.phase}{t.activities}
)}
;
+}
+
+function DeliverablesTab() {
+ return {deliverables.map((d) => {d.item}{statusLabels[d.status]})}
;
+}
+
+const tabComponents = { overview: OverviewTab, literature: LiteratureTab, framework: FrameworkTab, rqs: RQsTab, design: DesignTab, participants: ParticipantsTab, ai: AITab, timeline: TimelineTab, deliverables: DeliverablesTab };
+
+export default function App() {
+ const [activeTab, setActiveTab] = useState("overview");
+ const ActiveComponent = tabComponents[activeTab];
+
+ useEffect(() => {
+ if (!document.getElementById("google-fonts")) {
+ const fontLink = document.createElement("link");
+ fontLink.id = "google-fonts";
+ fontLink.href = "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700;800&family=Source+Sans+3:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap";
+ fontLink.rel = "stylesheet";
+ document.head.appendChild(fontLink);
+ }
+ }, []);
+
+ return (
+
+
+
+
+ {tabs.map((tab) => (
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/main.jsx b/src/main.jsx
new file mode 100644
index 0000000..f08e5b6
--- /dev/null
+++ b/src/main.jsx
@@ -0,0 +1,9 @@
+import React from "react";
+import { createRoot } from "react-dom/client";
+import App from "./App";
+
+createRoot(document.getElementById("root")).render(
+
+
+
+);