From edca20ae8fd8a6aeedc7d68635ec4fb730174728 Mon Sep 17 00:00:00 2001
From: Chris Zetter <253059100+zetter-rpf@users.noreply.github.com>
Date: Wed, 26 Aug 2026 16:56:58 +0100
Subject: [PATCH 1/3] Seed a Python, HTML/CSS and Scratch lesson for each class
Previously the education seed tasks only ever created Python
lessons/projects, with lesson names drawn from a random Faker
programming language that had no relation to the actual project
content. This made it harder to manually test school class
flows, or run E2E tests, against Scratch or HTML/CSS lessons using
the seed data.
This change makes create_lessons build one lesson per entry in
LESSON_PROJECT_TYPES (python, html/css, scratch) for a school class,
naming each lesson after its project type (e.g. "Lesson 3 scratch")
and generating a project with matching starter content via
create_project: a .py component for Python, an .html/.css pair for
HTML/CSS, and a Scratch component (seeded from
lib/tasks/seed_data/lesson_scratch_starter.json) for Scratch.
"Project type" is used instead of "language" throughout, since
Scratch and HTML/CSS aren't languages. Both for_education.rake and
test_seeds.rake share this behaviour, and the seeded school gets
scratch_enabled set in both, matching the real constraint enforced
when a teacher creates a Scratch lesson via
LessonCreation#verify_lesson_scratch!.
Existing specs for for_education and test_seeds are updated for the
new lesson counts and assert on the specific lesson names/project
types for the Scratch and HTML/CSS lessons.
---
lib/tasks/for_education.rake | 6 +-
.../seed_data/lesson_scratch_starter.json | 98 +++++++++++++++++++
lib/tasks/seeds_helper.rb | 54 +++++++---
lib/tasks/test_seeds.rake | 6 +-
spec/lib/tasks/for_education_spec.rb | 16 +--
spec/lib/tasks/seeds_helper_spec.rb | 45 +++++++++
spec/lib/test_seeds_spec.rb | 29 ++++--
7 files changed, 220 insertions(+), 34 deletions(-)
create mode 100644 lib/tasks/seed_data/lesson_scratch_starter.json
create mode 100644 spec/lib/tasks/seeds_helper_spec.rb
diff --git a/lib/tasks/for_education.rake b/lib/tasks/for_education.rake
index fa1d1ab19..d222abe32 100644
--- a/lib/tasks/for_education.rake
+++ b/lib/tasks/for_education.rake
@@ -91,15 +91,13 @@ namespace :for_education do
school = create_school(creator_id, TEST_SCHOOL)
verify_school(school)
+ school.update!(scratch_enabled: true)
assign_a_teacher(teacher_id, school)
school_class = create_school_class(creator_id, school)
assign_students(school_class, school)
- lessons = create_lessons(creator_id, school, school_class)
- lessons.each do |lesson|
- create_project(creator_id, school, lesson)
- end
+ create_lessons(creator_id, school, school_class)
Rails.logger.info 'Done...'
end
end
diff --git a/lib/tasks/seed_data/lesson_scratch_starter.json b/lib/tasks/seed_data/lesson_scratch_starter.json
new file mode 100644
index 000000000..6a808308b
--- /dev/null
+++ b/lib/tasks/seed_data/lesson_scratch_starter.json
@@ -0,0 +1,98 @@
+{
+ "targets": [
+ {
+ "isStage": true,
+ "name": "Stage",
+ "variables": { "`jEk@4|i[#Fk?(8x)AV.-my variable": ["my variable", 0] },
+ "lists": {},
+ "broadcasts": {},
+ "blocks": {},
+ "comments": {},
+ "currentCostume": 0,
+ "costumes": [
+ {
+ "name": "backdrop1",
+ "dataFormat": "svg",
+ "assetId": "cd21514d0531fdffb22204e0ec5ed84a",
+ "md5ext": "cd21514d0531fdffb22204e0ec5ed84a.svg",
+ "rotationCenterX": 240,
+ "rotationCenterY": 180
+ }
+ ],
+ "sounds": [
+ {
+ "name": "pop",
+ "assetId": "83a9787d4cb6f3b7632b4ddfebf74367",
+ "dataFormat": "wav",
+ "format": "",
+ "rate": 48000,
+ "sampleCount": 1123,
+ "md5ext": "83a9787d4cb6f3b7632b4ddfebf74367.wav"
+ }
+ ],
+ "volume": 100,
+ "layerOrder": 0,
+ "tempo": 60,
+ "videoTransparency": 50,
+ "videoState": "on",
+ "textToSpeechLanguage": null
+ },
+ {
+ "isStage": false,
+ "name": "Sprite1",
+ "variables": {},
+ "lists": {},
+ "broadcasts": {},
+ "blocks": {},
+ "comments": {},
+ "currentCostume": 0,
+ "costumes": [
+ {
+ "name": "costume1",
+ "bitmapResolution": 1,
+ "dataFormat": "svg",
+ "assetId": "bcf454acf82e4504149f7ffe07081dbc",
+ "md5ext": "bcf454acf82e4504149f7ffe07081dbc.svg",
+ "rotationCenterX": 48,
+ "rotationCenterY": 50
+ },
+ {
+ "name": "costume2",
+ "bitmapResolution": 1,
+ "dataFormat": "svg",
+ "assetId": "0fb9be3e8397c983338cb71dc84d0b25",
+ "md5ext": "0fb9be3e8397c983338cb71dc84d0b25.svg",
+ "rotationCenterX": 46,
+ "rotationCenterY": 53
+ }
+ ],
+ "sounds": [
+ {
+ "name": "Meow",
+ "assetId": "83c36d806dc92327b9e7049a565c6bff",
+ "dataFormat": "wav",
+ "format": "",
+ "rate": 48000,
+ "sampleCount": 40681,
+ "md5ext": "83c36d806dc92327b9e7049a565c6bff.wav"
+ }
+ ],
+ "volume": 100,
+ "layerOrder": 1,
+ "visible": true,
+ "x": 0,
+ "y": 0,
+ "size": 100,
+ "direction": 90,
+ "draggable": false,
+ "rotationStyle": "all around"
+ }
+ ],
+ "monitors": [],
+ "extensions": [],
+ "meta": {
+ "semver": "3.0.0",
+ "vm": "12.7.0",
+ "agent": "default"
+ }
+}
diff --git a/lib/tasks/seeds_helper.rb b/lib/tasks/seeds_helper.rb
index df0a5992e..0efec2feb 100644
--- a/lib/tasks/seeds_helper.rb
+++ b/lib/tasks/seeds_helper.rb
@@ -2,6 +2,7 @@
require_relative 'project_preview_seeds_helper'
+# rubocop:disable Metrics/ModuleLength
module SeedsHelper
include ProjectPreviewSeedsHelper
@@ -93,21 +94,39 @@ def assign_students(school_class, school)
end
end
+ LESSON_PROJECT_TYPES = ['python', 'html/css', 'scratch'].freeze
+
+ LESSON_SCRATCH_CONTENT_PATH = Rails.root.join('lib/tasks/seed_data/lesson_scratch_starter.json')
+
+ LESSON_HTML_CONTENT = <<~HTML
+
+
+
+
+
+ Heading
+ Paragraph
+
+
+ HTML
+
def create_lessons(user_id, school, school_class, visibility = 'students')
- Array.new(2) do |i|
- lesson_name = "Lesson #{i + 1}: #{Faker::ProgrammingLanguage.name}"
- Lesson.find_or_create_by!(school:, school_class:, name: lesson_name, user_id:) do |lesson|
+ LESSON_PROJECT_TYPES.each_with_index.map do |project_type, i|
+ lesson_name = "Lesson #{i + 1} #{project_type}"
+ lesson = Lesson.find_or_create_by!(school:, school_class:, name: lesson_name, user_id:) do |l|
Rails.logger.info "Seeding Lesson #{i + 1}..."
- lesson.user_id = user_id
- lesson.school = school
- lesson.school_class = school_class
- lesson.name = lesson_name
- lesson.visibility = visibility
+ l.user_id = user_id
+ l.school = school
+ l.school_class = school_class
+ l.name = lesson_name
+ l.visibility = visibility
end
+ create_project(user_id, school, lesson, project_type)
+ lesson
end
end
- def create_project(user_id, school, lesson, code = '')
+ def create_project(user_id, school, lesson, project_type)
Project.find_or_create_by!(user_id:, school:, lesson:) do |project|
Rails.logger.info "Seeding a project for #{lesson.name}..."
project.name = lesson.name
@@ -115,9 +134,20 @@ def create_project(user_id, school, lesson, code = '')
project.school = school
project.lesson = lesson
project.locale = 'en'
- project.project_type = Project::Types::PYTHON
- project.components << Component.new({ extension: 'py', name: 'main',
- content: code })
+
+ case project_type
+ when 'scratch'
+ project.project_type = Project::Types::CODE_EDITOR_SCRATCH
+ project.build_scratch_component(content: JSON.parse(File.read(LESSON_SCRATCH_CONTENT_PATH)))
+ when 'html/css'
+ project.project_type = Project::Types::HTML
+ project.components << Component.new(extension: 'html', name: 'index', content: LESSON_HTML_CONTENT)
+ project.components << Component.new(extension: 'css', name: 'style', content: "h1 {\n color: blue;\n}")
+ else
+ project.project_type = Project::Types::PYTHON
+ project.components << Component.new(extension: 'py', name: 'main', content: 'print("Hello World!")')
+ end
end
end
end
+# rubocop:enable Metrics/ModuleLength
diff --git a/lib/tasks/test_seeds.rake b/lib/tasks/test_seeds.rake
index 05cadbe3b..e667caee5 100644
--- a/lib/tasks/test_seeds.rake
+++ b/lib/tasks/test_seeds.rake
@@ -65,6 +65,7 @@ namespace :test_seeds do
school = create_school(creator_id, TEST_SCHOOL)
verify_school(school)
+ school.update!(scratch_enabled: true)
school.school_email_domains.build(domain: 'example.com').save!
@@ -77,10 +78,7 @@ namespace :test_seeds do
school_class = create_school_class(user_id, school, "#{teacher_name}'s Class", "A class for #{teacher_name}'s students")
assign_students(school_class, school)
- lessons = create_lessons(user_id, school, school_class)
- lessons.each do |lesson|
- create_project(user_id, school, lesson, 'print("Hello World!")')
- end
+ create_lessons(user_id, school, school_class)
end
Rails.logger.info 'Done...'
end
diff --git a/spec/lib/tasks/for_education_spec.rb b/spec/lib/tasks/for_education_spec.rb
index aab58523d..9189baab1 100644
--- a/spec/lib/tasks/for_education_spec.rb
+++ b/spec/lib/tasks/for_education_spec.rb
@@ -70,22 +70,26 @@
expect(SchoolClass.where(school_id: school.id)).to exist
end
- it 'adds two lessons to the school' do
- lesson = Lesson.where(school_id: school.id)
- expect(lesson.length).to eq(2)
+ it 'adds three lessons to the school, one per project type' do
+ lessons = Lesson.where(school_id: school.id)
+ expect(lessons.pluck(:name)).to contain_exactly(
+ 'Lesson 1 python', 'Lesson 2 html/css', 'Lesson 3 scratch'
+ )
end
- it 'adds two projects' do
+ it 'adds three projects, matching each lesson project type' do
lessons = Lesson.where(school_id: school.id)
projects = Project.where(lesson_id: lessons.pluck(:id))
- if projects.length != 2
+ if projects.length != 3
$stdout.puts('Debug info for intermittent test')
lessons.each { |lesson| $stdout.puts(lesson.inspect) }
projects.each { |project| $stdout.puts(project.inspect) }
end
- expect(projects.length).to eq(2)
+ expect(projects.length).to eq(3)
+ expect(projects.find_by(name: 'Lesson 2 html/css').project_type).to eq(Project::Types::HTML)
+ expect(projects.find_by(name: 'Lesson 3 scratch').project_type).to eq(Project::Types::CODE_EDITOR_SCRATCH)
end
it 'does not add more lessons or projects when run again' do
diff --git a/spec/lib/tasks/seeds_helper_spec.rb b/spec/lib/tasks/seeds_helper_spec.rb
new file mode 100644
index 000000000..5b174e6c2
--- /dev/null
+++ b/spec/lib/tasks/seeds_helper_spec.rb
@@ -0,0 +1,45 @@
+# frozen_string_literal: true
+
+require 'rails_helper'
+require_relative '../../../lib/tasks/seeds_helper'
+
+RSpec.describe SeedsHelper do
+ subject(:seeder) { Class.new { include SeedsHelper }.new }
+
+ describe '#create_lessons' do
+ let(:teacher_id) { SecureRandom.uuid }
+ let(:school) { create(:school) }
+ let(:school_class) { create(:school_class, school:, teacher_ids: [teacher_id]) }
+
+ let(:lessons) { seeder.create_lessons(teacher_id, school, school_class) }
+
+ before { create(:teacher_role, user_id: teacher_id, school:) }
+
+ it 'creates a lesson with a Python project' do
+ lesson = lessons.find { |l| l.name == 'Lesson 1 python' }
+
+ expect(lesson.project.project_type).to eq(Project::Types::PYTHON)
+ component = lesson.project.components.find_by(extension: 'py')
+ expect(component.name).to eq('main')
+ expect(component.content).to eq('print("Hello World!")')
+ end
+
+ it 'creates a lesson with an HTML/CSS project' do
+ lesson = lessons.find { |l| l.name == 'Lesson 2 html/css' }
+
+ expect(lesson.project.project_type).to eq(Project::Types::HTML)
+ html_component = lesson.project.components.find_by(extension: 'html')
+ css_component = lesson.project.components.find_by(extension: 'css')
+ expect(html_component.content).to include('Heading
')
+ expect(css_component.content).to include('color: blue')
+ end
+
+ it 'creates a lesson with a Scratch project' do
+ lesson = lessons.find { |l| l.name == 'Lesson 3 scratch' }
+
+ expect(lesson.project.project_type).to eq(Project::Types::CODE_EDITOR_SCRATCH)
+ content = lesson.project.scratch_component.content.to_h
+ expect(content).to include('targets', 'monitors', 'extensions')
+ end
+ end
+end
diff --git a/spec/lib/test_seeds_spec.rb b/spec/lib/test_seeds_spec.rb
index 1dd11cb5e..7f9f84594 100644
--- a/spec/lib/test_seeds_spec.rb
+++ b/spec/lib/test_seeds_spec.rb
@@ -164,12 +164,20 @@
)
end
- it 'creates lessons with projects' do
+ it 'creates lessons with projects, one per language, for each class' do
school = School.find_by(creator_id:)
expect(SchoolClass.where(school_id: school.id)).to exist
lesson = Lesson.where(school_id: school.id)
- expect(lesson.length).to eq(4)
- expect(Project.where(lesson_id: lesson.pluck(:id)).length).to eq(4)
+ expect(lesson.length).to eq(6)
+ expect(lesson.pluck(:name)).to contain_exactly(
+ 'Lesson 1 python', 'Lesson 2 html/css', 'Lesson 3 scratch',
+ 'Lesson 1 python', 'Lesson 2 html/css', 'Lesson 3 scratch'
+ )
+
+ projects = Project.where(lesson_id: lesson.pluck(:id))
+ expect(projects.length).to eq(6)
+ expect(projects.find_by(name: 'Lesson 2 html/css').project_type).to eq(Project::Types::HTML)
+ expect(projects.find_by(name: 'Lesson 3 scratch').project_type).to eq(Project::Types::CODE_EDITOR_SCRATCH)
end
it 'assigns a teacher' do
@@ -182,7 +190,7 @@
school_class = SchoolClass.joins(:teachers).find_by(school_id:, teachers: { teacher_id: creator_id })
expect(school_class).not_to be_nil
- expect(Lesson.where(school_id:, school_class_id: school_class.id).length).to eq(2)
+ expect(Lesson.where(school_id:, school_class_id: school_class.id).length).to eq(3)
end
it 'creates a class teacher association for the owner' do
@@ -193,7 +201,7 @@
school_id = School.find_by(creator_id:).id
school_class = SchoolClass.joins(:teachers).find_by(school_id:, teachers: { teacher_id: })
expect(school_class).not_to be_nil
- expect(Lesson.where(school_id:, school_class_id: school_class.id).length).to eq(2)
+ expect(Lesson.where(school_id:, school_class_id: school_class.id).length).to eq(3)
end
it 'creates a class teacher association for the teacher' do
@@ -210,8 +218,8 @@
task.invoke
end.not_to change { [SchoolClass.where(school_id: school.id).count, Lesson.where(school_id: school.id).count, Project.where(school_id: school.id).count] }
- expect(owner_class.reload.lessons.count).to eq(2)
- expect(teacher_class.reload.lessons.count).to eq(2)
+ expect(owner_class.reload.lessons.count).to eq(3)
+ expect(teacher_class.reload.lessons.count).to eq(3)
end
it 'assigns students' do
@@ -223,6 +231,11 @@
expect(ClassStudent.where(student_id: student_2, school_class_id:)).to exist
end
+ it 'enables scratch for the school' do
+ school = School.find_by(creator_id:)
+ expect(school.scratch_enabled?).to be true
+ end
+
context 'when the seeded school is in the US' do
let(:seed_country_code) { 'US' }
@@ -234,7 +247,7 @@
expect(school.district_nces_id).to match(/\A\d{7}\z/)
expect(school.district_name).to be_present
expect(school_class).not_to be_nil
- expect(Lesson.where(school_id: school.id, school_class_id: school_class.id).length).to eq(2)
+ expect(Lesson.where(school_id: school.id, school_class_id: school_class.id).length).to eq(3)
end
end
end
From 8e53c74b35e36dff7c2e1cb136a632518073d4d2 Mon Sep 17 00:00:00 2001
From: Chris Zetter <253059100+zetter-rpf@users.noreply.github.com>
Date: Thu, 27 Aug 2026 14:06:33 +0100
Subject: [PATCH 2/3] Combine two sample scratch files
These are both the same and are just used to represent the Scratch Starter project
---
lib/tasks/project_preview_seeds_helper.rb | 2 +-
lib/tasks/seed_data/excs_preview_starter.json | 100 ------------------
...rter.json => scratch_starter_example.json} | 0
lib/tasks/seeds_helper.rb | 2 +-
4 files changed, 2 insertions(+), 102 deletions(-)
delete mode 100644 lib/tasks/seed_data/excs_preview_starter.json
rename lib/tasks/seed_data/{lesson_scratch_starter.json => scratch_starter_example.json} (100%)
diff --git a/lib/tasks/project_preview_seeds_helper.rb b/lib/tasks/project_preview_seeds_helper.rb
index e09590017..2aab9738c 100644
--- a/lib/tasks/project_preview_seeds_helper.rb
+++ b/lib/tasks/project_preview_seeds_helper.rb
@@ -7,7 +7,7 @@ module ProjectPreviewSeedsHelper
PROJECT_PREVIEW_LOCALE_FR = 'fr-FR'
PROJECT_PREVIEW_NAME = 'Experience CS Preview Starter'
PROJECT_PREVIEW_NAME_FR = 'Démo Aperçu Experience CS'
- PROJECT_PREVIEW_CONTENT_PATH = Rails.root.join('lib/tasks/seed_data/excs_preview_starter.json')
+ PROJECT_PREVIEW_CONTENT_PATH = Rails.root.join('lib/tasks/seed_data/scratch_starter_example.json')
PROJECT_PREVIEW_INSTRUCTIONS_PATH = Rails.root.join('lib/tasks/seed_data/excs_preview_starter_instructions.json')
PROJECT_PREVIEW_INSTRUCTIONS_FR_PATH = Rails.root.join('lib/tasks/seed_data/excs_preview_starter_instructions_fr.json')
diff --git a/lib/tasks/seed_data/excs_preview_starter.json b/lib/tasks/seed_data/excs_preview_starter.json
deleted file mode 100644
index 298a4f11b..000000000
--- a/lib/tasks/seed_data/excs_preview_starter.json
+++ /dev/null
@@ -1,100 +0,0 @@
-{
- "targets": [
- {
- "isStage": true,
- "name": "Stage",
- "variables": {
- "`jEk@4|i[#Fk?(8x)AV.-my variable": ["my variable", 0]
- },
- "lists": {},
- "broadcasts": {},
- "blocks": {},
- "comments": {},
- "currentCostume": 0,
- "costumes": [
- {
- "name": "backdrop1",
- "dataFormat": "svg",
- "assetId": "cd21514d0531fdffb22204e0ec5ed84a",
- "md5ext": "cd21514d0531fdffb22204e0ec5ed84a.svg",
- "rotationCenterX": 240,
- "rotationCenterY": 180
- }
- ],
- "sounds": [
- {
- "name": "pop",
- "assetId": "83a9787d4cb6f3b7632b4ddfebf74367",
- "dataFormat": "wav",
- "format": "",
- "rate": 48000,
- "sampleCount": 1123,
- "md5ext": "83a9787d4cb6f3b7632b4ddfebf74367.wav"
- }
- ],
- "volume": 100,
- "layerOrder": 0,
- "tempo": 60,
- "videoTransparency": 50,
- "videoState": "on",
- "textToSpeechLanguage": null
- },
- {
- "isStage": false,
- "name": "Sprite1",
- "variables": {},
- "lists": {},
- "broadcasts": {},
- "blocks": {},
- "comments": {},
- "currentCostume": 0,
- "costumes": [
- {
- "name": "costume1",
- "bitmapResolution": 1,
- "dataFormat": "svg",
- "assetId": "bcf454acf82e4504149f7ffe07081dbc",
- "md5ext": "bcf454acf82e4504149f7ffe07081dbc.svg",
- "rotationCenterX": 48,
- "rotationCenterY": 50
- },
- {
- "name": "costume2",
- "bitmapResolution": 1,
- "dataFormat": "svg",
- "assetId": "0fb9be3e8397c983338cb71dc84d0b25",
- "md5ext": "0fb9be3e8397c983338cb71dc84d0b25.svg",
- "rotationCenterX": 46,
- "rotationCenterY": 53
- }
- ],
- "sounds": [
- {
- "name": "Meow",
- "assetId": "83c36d806dc92327b9e7049a565c6bff",
- "dataFormat": "wav",
- "format": "",
- "rate": 48000,
- "sampleCount": 40681,
- "md5ext": "83c36d806dc92327b9e7049a565c6bff.wav"
- }
- ],
- "volume": 100,
- "layerOrder": 1,
- "visible": true,
- "x": 0,
- "y": 0,
- "size": 100,
- "direction": 90,
- "draggable": false,
- "rotationStyle": "all around"
- }
- ],
- "monitors": [],
- "extensions": [],
- "meta": {
- "semver": "3.0.0",
- "vm": "12.7.0",
- "agent": "default"
- }
-}
diff --git a/lib/tasks/seed_data/lesson_scratch_starter.json b/lib/tasks/seed_data/scratch_starter_example.json
similarity index 100%
rename from lib/tasks/seed_data/lesson_scratch_starter.json
rename to lib/tasks/seed_data/scratch_starter_example.json
diff --git a/lib/tasks/seeds_helper.rb b/lib/tasks/seeds_helper.rb
index 0efec2feb..c13ec74b0 100644
--- a/lib/tasks/seeds_helper.rb
+++ b/lib/tasks/seeds_helper.rb
@@ -96,7 +96,7 @@ def assign_students(school_class, school)
LESSON_PROJECT_TYPES = ['python', 'html/css', 'scratch'].freeze
- LESSON_SCRATCH_CONTENT_PATH = Rails.root.join('lib/tasks/seed_data/lesson_scratch_starter.json')
+ LESSON_SCRATCH_CONTENT_PATH = Rails.root.join('lib/tasks/seed_data/scratch_starter_example.json')
LESSON_HTML_CONTENT = <<~HTML
From d474ec11ec7cd1972b2da4ed375f625d8704565b Mon Sep 17 00:00:00 2001
From: Chris Zetter <253059100+zetter-rpf@users.noreply.github.com>
Date: Thu, 27 Aug 2026 14:07:23 +0100
Subject: [PATCH 3/3] Remove unused scratch project json
This was added in as a stub before we saved projects to the db
---
app/views/api/scratch/projects/show.json | 264 -----------------------
1 file changed, 264 deletions(-)
delete mode 100644 app/views/api/scratch/projects/show.json
diff --git a/app/views/api/scratch/projects/show.json b/app/views/api/scratch/projects/show.json
deleted file mode 100644
index 501c70955..000000000
--- a/app/views/api/scratch/projects/show.json
+++ /dev/null
@@ -1,264 +0,0 @@
-{
- "targets": [
- {
- "isStage": true,
- "name": "Stage",
- "variables": {
- "`jEk@4|i[#Fk?(8x)AV.-my variable": [
- "my variable",
- "1"
- ]
- },
- "lists": {},
- "broadcasts": {},
- "blocks": {
- "Q*IGJj0mdm@]wJ,v%1M5": {
- "opcode": "event_whenflagclicked",
- "next": "]ML!StPuGDgh@B`^[v0d",
- "parent": null,
- "inputs": {},
- "fields": {},
- "shadow": false,
- "topLevel": true,
- "x": 188,
- "y": 132
- },
- "]ML!StPuGDgh@B`^[v0d": {
- "opcode": "data_setvariableto",
- "next": null,
- "parent": "Q*IGJj0mdm@]wJ,v%1M5",
- "inputs": {
- "VALUE": [
- 1,
- [
- 10,
- "1"
- ]
- ]
- },
- "fields": {
- "VARIABLE": [
- "my variable",
- "`jEk@4|i[#Fk?(8x)AV.-my variable"
- ]
- },
- "shadow": false,
- "topLevel": false
- }
- },
- "comments": {},
- "currentCostume": 0,
- "costumes": [
- {
- "name": "backdrop1",
- "dataFormat": "svg",
- "assetId": "cd21514d0531fdffb22204e0ec5ed84a",
- "md5ext": "cd21514d0531fdffb22204e0ec5ed84a.svg",
- "rotationCenterX": 240,
- "rotationCenterY": 180
- }
- ],
- "sounds": [],
- "volume": 100,
- "layerOrder": 0,
- "tempo": 60,
- "videoTransparency": 50,
- "videoState": "on",
- "textToSpeechLanguage": null
- },
- {
- "isStage": false,
- "name": "teapot",
- "variables": {},
- "lists": {},
- "broadcasts": {},
- "blocks": {
- "+7D@27U/UaREbT1:$D2p": {
- "opcode": "motion_goto_menu",
- "next": null,
- "parent": "WQem=5FI$H@eF8Oy8=%m",
- "inputs": {},
- "fields": {
- "TO": [
- "_random_"
- ]
- },
- "shadow": true,
- "topLevel": false
- },
- ":Cul13Fz-$kW#uI)b3Ih": {
- "opcode": "motion_turnright",
- "next": "`HzTVWK}[NHS}n(wXj(~",
- "parent": "o6dY$%i#z$_:%J%y.1Uv",
- "inputs": {
- "DEGREES": [
- 1,
- [
- 4,
- "15"
- ]
- ]
- },
- "fields": {},
- "shadow": false,
- "topLevel": false
- },
- "El0`*m+.st%JF!*L54E,": {
- "opcode": "control_repeat",
- "next": null,
- "parent": "JP;xPsfOSUqBfPdVA)C9",
- "inputs": {
- "TIMES": [
- 1,
- [
- 6,
- "5"
- ]
- ],
- "SUBSTACK": [
- 2,
- "WQem=5FI$H@eF8Oy8=%m"
- ]
- },
- "fields": {},
- "shadow": false,
- "topLevel": false
- },
- "JP;xPsfOSUqBfPdVA)C9": {
- "opcode": "event_whenflagclicked",
- "next": "El0`*m+.st%JF!*L54E,",
- "parent": null,
- "inputs": {},
- "fields": {},
- "shadow": false,
- "topLevel": true,
- "x": 5,
- "y": -1196
- },
- "Lf3w#r641AVS(Z;,+4y3": {
- "opcode": "event_whenthisspriteclicked",
- "next": "o6dY$%i#z$_:%J%y.1Uv",
- "parent": null,
- "inputs": {},
- "fields": {},
- "shadow": false,
- "topLevel": true,
- "x": 277,
- "y": -1199
- },
- "TFT|@Y(or^}uOFGDC|FB": {
- "opcode": "looks_setsizeto",
- "next": null,
- "parent": "`HzTVWK}[NHS}n(wXj(~",
- "inputs": {
- "SIZE": [
- 1,
- [
- 4,
- "100"
- ]
- ]
- },
- "fields": {},
- "shadow": false,
- "topLevel": false
- },
- "WQem=5FI$H@eF8Oy8=%m": {
- "opcode": "motion_goto",
- "next": "k`v/#:wkfU{|QkjM)6G|",
- "parent": "El0`*m+.st%JF!*L54E,",
- "inputs": {
- "TO": [
- 1,
- "+7D@27U/UaREbT1:$D2p"
- ]
- },
- "fields": {},
- "shadow": false,
- "topLevel": false
- },
- "`HzTVWK}[NHS}n(wXj(~": {
- "opcode": "control_wait",
- "next": "TFT|@Y(or^}uOFGDC|FB",
- "parent": ":Cul13Fz-$kW#uI)b3Ih",
- "inputs": {
- "DURATION": [
- 1,
- [
- 5,
- "1"
- ]
- ]
- },
- "fields": {},
- "shadow": false,
- "topLevel": false
- },
- "k`v/#:wkfU{|QkjM)6G|": {
- "opcode": "control_wait",
- "next": null,
- "parent": "WQem=5FI$H@eF8Oy8=%m",
- "inputs": {
- "DURATION": [
- 1,
- [
- 5,
- "0.1"
- ]
- ]
- },
- "fields": {},
- "shadow": false,
- "topLevel": false
- },
- "o6dY$%i#z$_:%J%y.1Uv": {
- "opcode": "looks_setsizeto",
- "next": ":Cul13Fz-$kW#uI)b3Ih",
- "parent": "Lf3w#r641AVS(Z;,+4y3",
- "inputs": {
- "SIZE": [
- 1,
- [
- 4,
- "200"
- ]
- ]
- },
- "fields": {},
- "shadow": false,
- "topLevel": false
- }
- },
- "comments": {},
- "currentCostume": 0,
- "costumes": [
- {
- "name": "teapot",
- "bitmapResolution": 1,
- "dataFormat": "svg",
- "assetId": "8a9dadf4eea61892ec6908b1c99e4961",
- "md5ext": "8a9dadf4eea61892ec6908b1c99e4961.svg",
- "rotationCenterX": 23.171110153198242,
- "rotationCenterY": 22.78113555908203
- }
- ],
- "sounds": [],
- "volume": 100,
- "layerOrder": 1,
- "visible": true,
- "x": 0,
- "y": 6,
- "size": 100,
- "direction": 105,
- "draggable": false,
- "rotationStyle": "all around"
- }
- ],
- "monitors": [],
- "extensions": [],
- "meta": {
- "semver": "3.0.0",
- "vm": "12.2.2",
- "agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36"
- }
-}
\ No newline at end of file