diff --git a/packages/hikkaku/src/blocks/index.ts b/packages/hikkaku/src/blocks/index.ts index 0eebc3f..3ace958 100644 --- a/packages/hikkaku/src/blocks/index.ts +++ b/packages/hikkaku/src/blocks/index.ts @@ -9,3 +9,6 @@ export * from './pen' export * from './procedures' export * from './sensing' export * from './sound' +export * from './text2speech' +export * from './translate' +export * from './videosensing' diff --git a/packages/hikkaku/src/blocks/text2speech.test.ts b/packages/hikkaku/src/blocks/text2speech.test.ts new file mode 100644 index 0000000..22691b4 --- /dev/null +++ b/packages/hikkaku/src/blocks/text2speech.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, test } from 'vite-plus/test' +import { block, createBlocks } from '../core/composer' +import { setLanguage, setVoice, speakAndWait } from './text2speech' + +describe('blocks/text2speech', () => { + test('creates text to speech extension blocks', () => { + const blocks = createBlocks(() => { + block('event_whenflagclicked', { topLevel: true }) + setVoice('TENOR') + setLanguage('ja') + speakAndWait('hello') + }) + + const opcodes = Object.values(blocks).map((b) => b.opcode) + expect(opcodes).toContain('text2speech_setVoice') + expect(opcodes).toContain('text2speech_setLanguage') + expect(opcodes).toContain('text2speech_speakAndWait') + }) +}) diff --git a/packages/hikkaku/src/blocks/text2speech.ts b/packages/hikkaku/src/blocks/text2speech.ts new file mode 100644 index 0000000..8b6128c --- /dev/null +++ b/packages/hikkaku/src/blocks/text2speech.ts @@ -0,0 +1,36 @@ +import { InputType } from 'sb3-types/enum' +import { fromPrimitiveSource } from '../core/block-helper' +import { block } from '../core/composer' +import type { HikkakuString, PrimitiveSource } from '../core/types' + +export type TextToSpeechVoice = + | 'ALTO' + | 'TENOR' + | 'SQUEAK' + | 'GIANT' + | 'KITTEN' + | 'GOOGLE' + +export const speakAndWait = (words: PrimitiveSource) => { + return block('text2speech_speakAndWait', { + inputs: { + WORDS: fromPrimitiveSource(InputType.String, words, 'hello'), + }, + }) +} + +export const setVoice = (voice: PrimitiveSource) => { + return block('text2speech_setVoice', { + inputs: { + VOICE: fromPrimitiveSource(InputType.String, voice, 'ALTO'), + }, + }) +} + +export const setLanguage = (language: PrimitiveSource) => { + return block('text2speech_setLanguage', { + inputs: { + LANGUAGE: fromPrimitiveSource(InputType.String, language, 'en'), + }, + }) +} diff --git a/packages/hikkaku/src/blocks/translate.test.ts b/packages/hikkaku/src/blocks/translate.test.ts new file mode 100644 index 0000000..2f46b9b --- /dev/null +++ b/packages/hikkaku/src/blocks/translate.test.ts @@ -0,0 +1,18 @@ +import { describe, expect, test } from 'vite-plus/test' +import { block, createBlocks } from '../core/composer' +import { say } from './looks' +import { getViewerLanguage, translate } from './translate' + +describe('blocks/translate', () => { + test('creates translate extension blocks', () => { + const blocks = createBlocks(() => { + block('event_whenflagclicked', { topLevel: true }) + say(translate('hello', 'ja')) + say(getViewerLanguage()) + }) + + const opcodes = Object.values(blocks).map((b) => b.opcode) + expect(opcodes).toContain('translate_getTranslate') + expect(opcodes).toContain('translate_getViewerLanguage') + }) +}) diff --git a/packages/hikkaku/src/blocks/translate.ts b/packages/hikkaku/src/blocks/translate.ts new file mode 100644 index 0000000..03cdbbe --- /dev/null +++ b/packages/hikkaku/src/blocks/translate.ts @@ -0,0 +1,20 @@ +import { InputType } from 'sb3-types/enum' +import { fromPrimitiveSource } from '../core/block-helper' +import { valueBlock } from '../core/composer' +import type { HikkakuString, PrimitiveSource } from '../core/types' + +export const translate = ( + words: PrimitiveSource, + language: PrimitiveSource, +) => { + return valueBlock('translate_getTranslate', { + inputs: { + WORDS: fromPrimitiveSource(InputType.String, words, 'hello'), + LANGUAGE: fromPrimitiveSource(InputType.String, language, 'ja'), + }, + }) +} + +export const getViewerLanguage = () => { + return valueBlock('translate_getViewerLanguage', {}) +} diff --git a/packages/hikkaku/src/blocks/videosensing.test.ts b/packages/hikkaku/src/blocks/videosensing.test.ts new file mode 100644 index 0000000..b19c111 --- /dev/null +++ b/packages/hikkaku/src/blocks/videosensing.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, test } from 'vite-plus/test' +import { block, createBlocks } from '../core/composer' +import { say } from './looks' +import { + setVideoTransparency, + videoOn, + videoToggle, + whenMotionGreaterThan, +} from './videosensing' + +describe('blocks/videosensing', () => { + test('creates video sensing extension blocks', () => { + const blocks = createBlocks(() => { + block('event_whenflagclicked', { topLevel: true }) + whenMotionGreaterThan(10) + say(videoOn('motion', 'this sprite')) + videoToggle('on') + setVideoTransparency(50) + }) + + const opcodes = Object.values(blocks).map((b) => b.opcode) + expect(opcodes).toContain('videoSensing_whenMotionGreaterThan') + expect(opcodes).toContain('videoSensing_videoOn') + expect(opcodes).toContain('videoSensing_videoToggle') + expect(opcodes).toContain('videoSensing_setVideoTransparency') + }) +}) diff --git a/packages/hikkaku/src/blocks/videosensing.ts b/packages/hikkaku/src/blocks/videosensing.ts new file mode 100644 index 0000000..6b4e04f --- /dev/null +++ b/packages/hikkaku/src/blocks/videosensing.ts @@ -0,0 +1,52 @@ +import { InputType } from 'sb3-types/enum' +import { fromPrimitiveSource } from '../core/block-helper' +import { block, valueBlock } from '../core/composer' +import type { + HikkakuNumber, + HikkakuString, + PrimitiveSource, +} from '../core/types' + +export type VideoSensingAttribute = 'motion' | 'direction' +export type VideoSensingSubject = 'this sprite' | 'stage' +export type VideoState = 'on' | 'off' | 'on-flipped' + +export const whenMotionGreaterThan = ( + reference: PrimitiveSource, +) => { + return block('videoSensing_whenMotionGreaterThan', { + inputs: { + REFERENCE: fromPrimitiveSource(InputType.Number, reference, 10), + }, + }) +} + +export const videoOn = ( + attribute: PrimitiveSource, + subject: PrimitiveSource, +) => { + return valueBlock('videoSensing_videoOn', { + inputs: { + ATTRIBUTE: fromPrimitiveSource(InputType.String, attribute, 'motion'), + SUBJECT: fromPrimitiveSource(InputType.String, subject, 'this sprite'), + }, + }) +} + +export const videoToggle = (state: PrimitiveSource) => { + return block('videoSensing_videoToggle', { + inputs: { + VIDEO_STATE: fromPrimitiveSource(InputType.String, state, 'on'), + }, + }) +} + +export const setVideoTransparency = ( + transparency: PrimitiveSource, +) => { + return block('videoSensing_setVideoTransparency', { + inputs: { + TRANSPARENCY: fromPrimitiveSource(InputType.Number, transparency, 50), + }, + }) +}