X3D Model Documentation: PushButtonPrototype.x3d

  1  <?xml version="1.0" encoding="UTF-8"?>
  2  <!DOCTYPE X3D PUBLIC "ISO//Web3D//DTD X3D 3.3//EN" "https://www.web3d.org/specifications/x3d-3.3.dtd">
  3  <X3D profile='Immersive' version='3.3 xmlns:xsd='http://www.w3.org/2001/XMLSchema-instance' xsd:noNamespaceSchemaLocation='https://www.web3d.org/specifications/x3d-3.3.xsd'>
  4       <head>
  5            <meta name='titlecontent='PushButtonPrototype.x3d'/>
  6            <meta name='descriptioncontent='PushButton widget prototype declaration, inner button and outer shape can be round or square'/>
  7            <meta name='creatorcontent='Don Brutzman, Murat Onder and MV4205 class, Spring 2004 Quarter'/>
  8            <meta name='createdcontent='11 May 2004'/>
  9            <meta name='modifiedcontent='2 January 2025'/>
 10            <meta name='referencecontent='PushButtonExample.x3d'/>
 11            <meta name='identifiercontent='https://savage.nps.edu/Savage/Tools/Animation/PushButtonPrototype.x3d'/>
 12            <meta name='generatorcontent='X3D-Edit 4.0, https://savage.nps.edu/X3D-Edit'/>
 13            <meta name='licensecontent='../../license.html'/>
 14       </head>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->
<!-- to top Index for DEF nodes: AnimationGroup, Blue, BooleanToggler, ClickAudio, Clock1, Clock2, DelayTimer, Green, InnerShapeSwitchRound, InnerShapeSwitchSquare, InnerShapeTransform, OuterShapeSwitchRound, OuterShapeSwitchSquare, OuterShapeTransform, PushButtonToggleMaterial, Red, SwitchAnimator1, SwitchAnimator2, Toucher

Index for ExternProtoDeclare definitions: MaterialToggle, TimeDelaySensor

Index for ProtoDeclare definition: PushButton
-->
 15       <Scene>
 16            <!-- Material Toggle Prototype is being used to be able to provide the color toggle. -->
 17            <WorldInfo title='PushButtonPrototype.x3d'/>
 18            <ExternProtoDeclare name='MaterialToggleappinfo='MaterialToggle selects one of two different Material values'   url=' "MaterialTogglePrototype.x3d#MaterialToggle" "../../Tools/Animation/MaterialTogglePrototype.x3d#MaterialToggle" "https://savage.nps.edu/Savage/Tools/Animation/MaterialTogglePrototype.x3d#MaterialToggle" "../../Tools/Animation/MaterialTogglePrototype.wrl#MaterialToggle" "MaterialTogglePrototype.wrl#MaterialToggle" "https://savage.nps.edu/Savage/Tools/Animation/MaterialTogglePrototype.wrl#MaterialToggle" '>
 19                 <field name='defaultMaterialtype='SFNodeaccessType='initializeOnly'
                appinfo='Material node that is enabled when toggle=false'/>
 20                 <field name='toggleMaterialtype='SFNodeaccessType='initializeOnly'
                appinfo='Material node that is enabled when toggle=true'/>
 21                 <field name='set_toggletype='SFBoolaccessType='inputOnly'/>
 22                 <field name='set_defaultMaterialtype='SFNodeaccessType='inputOnly'
                appinfo='provide replacement default Material node'/>
 23                 <field name='toggletype='SFBoolaccessType='initializeOnly'
                appinfo='whether to use DefaultMaterial or ToggleMaterial'/>
 24                 <field name='toggle_changedtype='SFBoolaccessType='outputOnly'/>
 25                 <field name='set_toggleMaterialtype='SFNodeaccessType='inputOnly'
                appinfo='provide replacement toggle Material node'/>
 26            </ExternProtoDeclare>
 27            <!-- TimeDelaySensor is being used to provide the time delay for button's color change delay -->
 28            <ExternProtoDeclare name='TimeDelaySensorappinfo='TimeSensor functionality commences after delayInterval pause'   url=' "TimeDelaySensorPrototype.x3d#TimeDelaySensor" "../../Tools/Animation/TimeDelaySensorPrototype.x3d#TimeDelaySensor" "https://savage.nps.edu/Savage/Tools/Animation/TimeDelaySensorPrototype.x3d#TimeDelaySensor" "../../Tools/Animation/TimeDelaySensorPrototype.wrl#TimeDelaySensor" "TimeDelaySensorPrototype.wrl#TimeDelaySensor" "https://savage.nps.edu/Savage/Tools/Animation/TimeDelaySensorPrototype.wrl#TimeDelaySensor" '>
 29                 <field name='startTimetype='SFTimeaccessType='inputOutput'
                appinfo='when current time exceeds startTime, isActive becomes true and sensor becomes active'/>
 30                 <field name='delayIntervaltype='SFTimeaccessType='inputOutput'
                appinfo='seconds'/>
 31                 <field name='delayCompleteTimetype='SFTimeaccessType='outputOnly'/>
 32                 <field name='enabledtype='SFBoolaccessType='inputOutput'
                appinfo='whether sensor is active'/>
 33                 <field name='descriptiontype='SFStringaccessType='inputOutput'
                appinfo='describe the purpose of this sensor'/>
 34                 <field name='traceEnabledtype='SFBoolaccessType='initializeOnly'/>
 35            </ExternProtoDeclare>
 36            <!-- PushButton Prototype definition starts here.. -->
 37            <ProtoDeclare name='PushButtonappinfo='PushButton widget, inner button and outer shape can be round or square'>
 38                 <ProtoInterface>
 39                      <field name='traceEnabledtype='SFBoolvalue='trueaccessType='initializeOnly'
                     appinfo='enables the console print-out in case of assigning wrong values default is true'/>
 40                      <field name='outerShapeMaterialtype='SFNodeaccessType='initializeOnly'>
 41                           <Material DEF='BluediffuseColor='0 0 1'/>
 42                      </field>
 43                      <field name='defaultMaterialtype='SFNodeaccessType='initializeOnly'
                     appinfo='defaultMaterial for inner pushbutton'>
 44                           <Material DEF='ReddiffuseColor='0.8 0.1 0'/>
 45                      </field>
 46                      <field name='toggleMaterialtype='SFNodeaccessType='initializeOnly'
                     appinfo='toggleMaterial for inner pushbutton'>
 47                           <Material DEF='GreendiffuseColor='0.1 0.8 0'/>
 48                      </field>
 49                      <field name='value_changedtype='SFBoolaccessType='outputOnly'
                     appinfo='boolean output of button selection'/>
 50                      <!-- switch values for combination of the button, default: round-round -->
 51                      <field name='outerSwitchStyletype='SFStringvalue='roundaccessType='initializeOnly'
                     appinfo='allowed values: round or square default is round'/>
 52                      <field name='set_outerSwitchStyletype='SFStringaccessType='inputOnly'
                     appinfo='allowed values: round or square default is round'/>
 53                      <field name='innerSwitchStyletype='SFStringvalue='roundaccessType='initializeOnly'
                     appinfo='allowed values: round square. default is round'/>
 54                      <field name='set_innerSwitchStyletype='SFStringaccessType='inputOnly'
                     appinfo='allowed values: round square. default is round'/>
 55                      <field name='delayIntervaltype='SFTimevalue='.5accessType='initializeOnly'
                     appinfo='time delay for button movement so for color change default is 0.5 sec.'/>
 56                 </ProtoInterface>
 57                 <ProtoBody>
 58                      <Group>
 59 
                         <!-- ROUTE information for DelayTimer node:  [from Toucher.touchTime to startTime ] [from delayCompleteTime to Clock2.set_startTime ] -->
                         <ProtoInstance name='TimeDelaySensorDEF='DelayTimer'>
 60                                <IS>
 61                                     <connect nodeField='delayIntervalprotoField='delayInterval'/>
 62                                </IS>
 63                           </ProtoInstance>
 64                           <Transform DEF='OuterShapeTransformrotation='1 0 0 1.57'>
 65 
                              <!-- Switch OuterShapeSwitchRound is a DEF node that has 1 USE node: USE_1 -->
                              <Switch DEF='OuterShapeSwitchRoundwhichChoice='-1'>
 66                                     <Shape>
 67                                          <Cylinder height='.12radius='.5'/>
 68                                          <Appearance>
 69                                               <IS>
 70                                                    <connect nodeField='materialprotoField='outerShapeMaterial'/>
 71                                               </IS>
 72                                          </Appearance>
 73                                     </Shape>
 74                                </Switch>
 75 
                              <!-- Switch OuterShapeSwitchSquare is a DEF node that has 1 USE node: USE_1 -->
                              <Switch DEF='OuterShapeSwitchSquarewhichChoice='-1'>
 76                                     <Shape>
 77                                          <Box size='1 .12 1'/>
 78                                          <Appearance>
 79                                               <IS>
 80                                                    <connect nodeField='materialprotoField='outerShapeMaterial'/>
 81                                               </IS>
 82                                          </Appearance>
 83                                     </Shape>
 84                                </Switch>
 85                           </Transform>
 86 
                         <!-- ROUTE information for InnerShapeTransform node:  [from SwitchAnimator1.value_changed to set_translation ] [from SwitchAnimator2.value_changed to set_translation ] -->
                         <Transform DEF='InnerShapeTransformrotation='1 0 0 1.57translation='0 0 .1'>
 87 
                              <!-- Switch InnerShapeSwitchRound is a DEF node that has 1 USE node: USE_1 -->
                              <Switch DEF='InnerShapeSwitchRoundwhichChoice='-1'>
 88                                     <Shape>
 89                                          <Cylinder height='.12radius='.35'/>
 90                                          <Appearance>
 91 
                                             <!-- ProtoInstance PushButtonToggleMaterial is a DEF node that has 1 USE node: USE_1
                                             <!-- ROUTE information for PushButtonToggleMaterial node:  [from BooleanToggler.toggle_changed to set_toggle ] -->
                                             <ProtoInstance name='MaterialToggleDEF='PushButtonToggleMaterialcontainerField='material'>
 92                                                    <IS>
 93                                                         <connect nodeField='defaultMaterialprotoField='defaultMaterial'/>
 94                                                         <connect nodeField='toggleMaterialprotoField='toggleMaterial'/>
 95                                                    </IS>
 96                                               </ProtoInstance>
 97                                          </Appearance>
 98                                     </Shape>
 99                                </Switch>
100 
                              <!-- Switch InnerShapeSwitchSquare is a DEF node that has 1 USE node: USE_1 -->
                              <Switch DEF='InnerShapeSwitchSquarewhichChoice='-1'>
101                                     <Shape>
102                                          <Box size='.57 .12 .57'/>
103                                          <Appearance>
104                                               <ProtoInstance USE='PushButtonToggleMaterialcontainerField='material'/>
105                                          </Appearance>
106                                     </Shape>
107                                </Switch>
108                                <Sound>
109 
                                   <!-- ROUTE information for ClickAudio node:  [from Toucher.touchTime to set_startTime ] -->
                                   <AudioClip DEF='ClickAudiodescription='click sound'   url=' "click.wav" "https://savage.nps.edu/Savage/Tools/Animation/click.wav" '/>
110                                </Sound>
111 
                              <!-- ROUTE information for Toucher node:  [from touchTime to ClickAudio.set_startTime ] [from touchTime to DelayTimer.startTime ] [from touchTime to Clock1.set_startTime ] -->
                              <TouchSensor DEF='Toucherdescription='touch to push the button'/>
112                                < ROUTE  fromNode='Toucher' fromField='touchTime' toNode='ClickAudio' toField='set_startTime'/>
113                                < ROUTE  fromNode='Toucher' fromField='touchTime' toNode='DelayTimer' toField='startTime'/>
114                           </Transform>
115                           <Group DEF='AnimationGroup'>
116                                <!-- ============================= -->
117 
                              <!-- TimeSensor Clock1 is a DEF node that has 1 USE node: USE_1
                              <!-- ROUTE information for Clock1 node:  [from Toucher.touchTime to set_startTime ] [from fraction_changed to SwitchAnimator1.set_fraction ] -->
                              <TimeSensor DEF='Clock1'/>
118                                < ROUTE  fromNode='Toucher' fromField='touchTime' toNode='Clock1' toField='set_startTime'/>
119                                <!-- ============================= -->
120 
                              <!-- ROUTE information for SwitchAnimator1 node:  [from Clock1.fraction_changed to set_fraction ] [from value_changed to InnerShapeTransform.set_translation ] -->
                              <PositionInterpolator DEF='SwitchAnimator1key='0 .5 1keyValue='0 0 .1 0 0 .05 0 0 .007'/>
121                                < ROUTE  fromNode='Clock1' fromField='fraction_changed' toNode='SwitchAnimator1' toField='set_fraction'/>
122                                < ROUTE  fromNode='SwitchAnimator1' fromField='value_changed' toNode='InnerShapeTransform' toField='set_translation'/>
123                                <!-- ============================= -->
124 
                              <!-- TimeSensor Clock2 is a DEF node that has 1 USE node: USE_1
                              <!-- ROUTE information for Clock2 node:  [from DelayTimer.delayCompleteTime to set_startTime ] [from fraction_changed to SwitchAnimator2.set_fraction ] [from isActive to BooleanToggler.set_boolean ] -->
                              <TimeSensor DEF='Clock2'/>
125                                < ROUTE  fromNode='DelayTimer' fromField='delayCompleteTime' toNode='Clock2' toField='set_startTime'/>
126                                <!-- ============================= -->
127 
                              <!-- ROUTE information for SwitchAnimator2 node:  [from Clock2.fraction_changed to set_fraction ] [from value_changed to InnerShapeTransform.set_translation ] -->
                              <PositionInterpolator DEF='SwitchAnimator2key='0 .5 1keyValue='0 0 .007 0 0 .05 0 0 .1'/>
128                                < ROUTE  fromNode='Clock2' fromField='fraction_changed' toNode='SwitchAnimator2' toField='set_fraction'/>
129                                < ROUTE  fromNode='SwitchAnimator2' fromField='value_changed' toNode='InnerShapeTransform' toField='set_translation'/>
130                                <!-- ============================= -->
131 
                              <!-- ROUTE information for BooleanToggler node:  [from Clock2.isActive to set_boolean ] [from toggle_changed to PushButtonToggleMaterial.set_toggle ] -->
                              <BooleanToggle DEF='BooleanTogglercontainerField='children'>
132                                     <IS>
133                                          <connect nodeField='toggle_changedprotoField='value_changed'/>
134                                     </IS>
135                                </BooleanToggle>
136                                < ROUTE  fromNode='Clock2' fromField='isActive' toNode='BooleanToggler' toField='set_boolean'/>
137                                < ROUTE  fromNode='BooleanToggler' fromField='toggle_changed' toNode='PushButtonToggleMaterial' toField='set_toggle'/>
138                           </Group>
139                      </Group>
140                      <!-- Only first node in ProtoBody is rendered -->
141                      <Script directOutput='true'>
142                           <field name='traceEnabledtype='SFBoolaccessType='initializeOnly'/>
143                           <field name='delayIntervaltype='SFTimeaccessType='initializeOnly'/>
144                           <field name='outerSwitchStyletype='SFStringaccessType='initializeOnly'
                          appinfo='allowed values: round square. default is round'/>
145                           <field name='set_outerSwitchStyletype='SFStringaccessType='inputOnly'
                          appinfo='allowed values: round square. default is round'/>
146                           <field name='innerSwitchStyletype='SFStringaccessType='initializeOnly'
                          appinfo='allowed values: round square. default is round'/>
147                           <field name='set_innerSwitchStyletype='SFStringaccessType='inputOnly'
                          appinfo='allowed values: round square. default is round'/>
148                           <field name='switchOuterRoundtype='SFNodeaccessType='initializeOnly'>
149                                <Switch USE='OuterShapeSwitchRound'/>
150                           </field>
151                           <field name='switchOuterSquaretype='SFNodeaccessType='initializeOnly'>
152                                <Switch USE='OuterShapeSwitchSquare'/>
153                           </field>
154                           <field name='switchInnerRoundtype='SFNodeaccessType='initializeOnly'>
155                                <Switch USE='InnerShapeSwitchRound'/>
156                           </field>
157                           <field name='switchInnerSquaretype='SFNodeaccessType='initializeOnly'>
158                                <Switch USE='InnerShapeSwitchSquare'/>
159                           </field>
160                           <field name='clock1type='SFNodeaccessType='initializeOnly'>
161                                <TimeSensor USE='Clock1'/>
162                           </field>
163                           <field name='clock2type='SFNodeaccessType='initializeOnly'>
164                                <TimeSensor USE='Clock2'/>
165                           </field>
166                           <IS>
167                                <connect nodeField='traceEnabledprotoField='traceEnabled'/>
168                                <connect nodeField='outerSwitchStyleprotoField='outerSwitchStyle'/>
169                                <connect nodeField='set_outerSwitchStyleprotoField='set_outerSwitchStyle'/>
170                                <connect nodeField='innerSwitchStyleprotoField='innerSwitchStyle'/>
171                                <connect nodeField='set_innerSwitchStyleprotoField='set_innerSwitchStyle'/>
172                                <connect nodeField='delayIntervalprotoField='delayInterval'/>
173                           </IS>
  <![CDATA[
          
ecmascript:

function initialize()
{
   clock1.cycleInterval = delayInterval;
   clock2.cycleInterval = delayInterval;

   set_innerSwitchStyle(innerSwitchStyle);
   set_outerSwitchStyle(outerSwitchStyle);
}

function set_innerSwitchStyle(stringValue)
{
   if (stringValue != null)  //security check
   {
      if (stringValue != 'round')
      {
         if (stringValue != 'square')
         {
            printError(stringValue, 'inner');
            innerSwitchStyle = 'round';
         }
         else
         {
            innerSwitchStyle = stringValue;
         }
      }
      else
      {
          innerSwitchStyle = stringValue;
      }
   }

   if      (innerSwitchStyle == 'round')
   {
        switchInnerSquare.whichChoice = -1;
         switchInnerRound.whichChoice =  0;
   }
   else // (innerSwitchStyle == 'square')
   {
        switchInnerSquare.whichChoice =  0;
         switchInnerRound.whichChoice = -1;
   }
}

function set_outerSwitchStyle(stringValue)
{
   if (stringValue != null)    //security check
   {
      if (stringValue != 'round')
      {
         if (stringValue != 'square')
         {
            printError(stringValue, 'outer');
            outerSwitchStyle = 'round';
         }
         else
         {
            outerSwitchStyle = stringValue;
         }
      }
      else
      {
          outerSwitchStyle = stringValue;
      }
   }

   if      (outerSwitchStyle == 'round')
   {
        switchOuterSquare.whichChoice = -1;
         switchOuterRound.whichChoice =  0;
   }
   else // (outerSwitchStyle == 'square')
   {
        switchOuterSquare.whichChoice =  0;
         switchOuterRound.whichChoice = -1;
   }
}

function printError(s1, s2)
{
    if (traceEnabled)
    {
        Browser.println ('\nAllowed values are [round] and [square].');
        Browser.println ('Assigned value [' + s1 + '] (The values are case/whitespace-sensitive).');
        Browser.println ('Default value  [round] will be used for [' + s2 + 'SwitchStyle].');
    }
}

        
]]>
175                      </Script>
176                 </ProtoBody>
177            </ProtoDeclare>
178            <!-- ==================== -->
179            <Anchor description='PushButtonExampleparameter='"target=_blank"'   url=' "PushButtonExample.x3d" "../../Tools/Animation/PushButtonExample.x3d" "https://savage.nps.edu/Savage/Tools/Animation/PushButtonExample.x3d" "../../Tools/Animation/PushButtonExample.wrl" "PushButtonExample.wrl" "https://savage.nps.edu/Savage/Tools/Animation/PushButtonExample.wrl" '>
180                 <Shape>
181                      <Text string='"PushButtonPrototype" "defines a prototype" "" "Click text to see example scene" "" "You can define 4 different buttons" "with the combination of round and square" "(default is round-round)"'>
182                           <FontStyle justify='"MIDDLE" "MIDDLE"size='0.7'/>
183                      </Text>
184                      <Appearance>
185                           <Material diffuseColor='.8 .7 0.2'/>
186                      </Appearance>
187                 </Shape>
188            </Anchor>
189       </Scene>
190  </X3D>
<!--

<!--
Event Graph ROUTE Table shows event connections.
-->
<!-- to top Index for DEF nodes: AnimationGroup, Blue, BooleanToggler, ClickAudio, Clock1, Clock2, DelayTimer, Green, InnerShapeSwitchRound, InnerShapeSwitchSquare, InnerShapeTransform, OuterShapeSwitchRound, OuterShapeSwitchSquare, OuterShapeTransform, PushButtonToggleMaterial, Red, SwitchAnimator1, SwitchAnimator2, Toucher

Index for ExternProtoDeclare definitions: MaterialToggle, TimeDelaySensor

Index for ProtoDeclare definition: PushButton
-->
X3D Tooltips element index: Anchor, Appearance, AudioClip, BooleanToggle, Box, connect, Cylinder, ExternProtoDeclare, field, FontStyle, Group, head, IS, Material, meta, PositionInterpolator, ProtoBody, ProtoDeclare, ProtoInstance, ProtoInterface, ROUTE, Scene, Script, Shape, Sound, Switch, Text, TimeSensor, TouchSensor, Transform, WorldInfo, X3D, plus documentation for accessType definitions, type definitions, XML data types, and field types

Event Graph ROUTE Table entries with 10 ROUTE connections total, showing X3D event-model relationships for this scene.

Each row shows an event cascade that may occur during a single timestamp interval between frame renderings, as part of the X3D execution model.

Toucher
TouchSensor
touchTime
SFTime

ROUTE
event to
(1)
ClickAudio
AudioClip
set_startTime
SFTime
Toucher
TouchSensor
touchTime
SFTime

ROUTE
event to
(1)
DelayTimer
ProtoInstance
startTime
SFTime
then
 
 
 
DelayTimer
ProtoInstance
delayCompleteTime
SFTime

ROUTE
event to
(2)
Clock2
TimeSensor
set_startTime
SFTime
then
 
 
 
Clock2
TimeSensor
fraction_changed
SFFloat

ROUTE
event to
(3)
SwitchAnimator2
PositionInterpolator
set_fraction
SFFloat
then
 
 
 
SwitchAnimator2
PositionInterpolator
value_changed
SFVec3f

ROUTE
event to
(4)
InnerShapeTransform
Transform
set_translation
SFVec3f
  then
 
 
 
Clock2
TimeSensor
isActive
SFBool

ROUTE
event to
(3)
BooleanToggler
BooleanToggle
set_boolean
SFBool
then
 
 
 
BooleanToggler
BooleanToggle
toggle_changed
SFBool

ROUTE
event to
(4)
PushButtonToggleMaterial
ProtoInstance
set_toggle
SFBool
Toucher
TouchSensor
touchTime
SFTime

ROUTE
event to
(1)
Clock1
TimeSensor
set_startTime
SFTime
then
 
 
 
Clock1
TimeSensor
fraction_changed
SFFloat

ROUTE
event to
(2)
SwitchAnimator1
PositionInterpolator
set_fraction
SFFloat
then
 
 
 
SwitchAnimator1
PositionInterpolator
value_changed
SFVec3f

ROUTE
event to
(3)
InnerShapeTransform
Transform
set_translation
SFVec3f

line 141
Script
No ROUTE connection found for output events from this node.
Contains SFNode fields with direct access to another node. 

      DelayTimer
ProtoInstance
delayCompleteTime
SFTime

ROUTE
event to
(1)
Clock2
TimeSensor
set_startTime
SFTime
then
 
 
 
Clock2
TimeSensor
fraction_changed
SFFloat

ROUTE
event to
(2)
SwitchAnimator2
PositionInterpolator
set_fraction
SFFloat
then
 
 
 
SwitchAnimator2
PositionInterpolator
value_changed
SFVec3f

ROUTE
event to
(3)
InnerShapeTransform
Transform
set_translation
SFVec3f
  then
 
 
 
Clock2
TimeSensor
isActive
SFBool

ROUTE
event to
(2)
BooleanToggler
BooleanToggle
set_boolean
SFBool
then
 
 
 
BooleanToggler
BooleanToggle
toggle_changed
SFBool

ROUTE
event to
(3)
PushButtonToggleMaterial
ProtoInstance
set_toggle
SFBool

      PushButtonToggleMaterial
ProtoInstance
MaterialToggle
No ROUTE connection found for output events from this node.
This ProtoInstance contains SFNode/MFNode fieldValue declarations with
direct access to other nodes, and thus has potential to produce run-time animation. 

line 179
Anchor
description='PushButtonExample' 
User-interaction hint for this node. 

Additional guidance on X3D animation can be found in the 10-Step Animation Design Process and Event Tracing hint sheets. Have fun with X3D! 😀

-->
<!-- Online at
https://savage.nps.edu/Savage/Tools/Animation/PushButtonPrototypeIndex.html -->
<!-- Version control at
https://gitlab.nps.edu/Savage/Savage/Tools/Animation/PushButtonPrototype.x3d -->

<!-- Color-coding legend: X3D terminology <X3dNode  DEF='idNamefield='value'/> matches XML terminology <XmlElement  DEF='idNameattribute='value'/>
(Light-blue background: event-based behavior node or statement) (Grey background inside box: inserted documentation) (Magenta background: X3D Extensibility)
    <ProtoInstance name='ProtoName'> <field name='fieldName'/> </ProtoInstance> -->

to top <!-- For additional help information about X3D scenes, please see X3D Tooltips, X3D Resources, and X3D Scene Authoring Hints. -->